diff --git a/Makefile b/Makefile index bcb3faf3c..8ee3726b4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CXX := g++ CXXFLAGS := -std=c++20 -pthread -fno-strict-aliasing -pedantic -Wall -flto -I/usr/local/include/opencv4/ -I/usr/local/include/nanovg LDFLAGS := -L/opt/local/lib -flto -L/usr/local/lib64 -L../common/ -LIBS := -lnanogui -lopencv_viz2d +LIBS := -lnanogui -lviz2d .PHONY: all release debian-release info debug asan clean debian-clean distclean DESTDIR := / PREFIX := /usr/local diff --git a/src/common/Makefile b/src/common/Makefile index 9437c6fdc..c2d00c4d3 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -1,6 +1,6 @@ -TARGET := libopencv_viz2d.so +TARGET := libviz2d.so -SRCS := clglcontext.cpp clvacontext.cpp nanovgcontext.cpp viz2d.cpp util.cpp +SRCS := detail/clglcontext.cpp detail/clvacontext.cpp detail/nanovgcontext.cpp viz2d.cpp util.cpp nvg.cpp #precompiled headers HEADERS := diff --git a/src/common/clglcontext.cpp b/src/common/detail/clglcontext.cpp similarity index 97% rename from src/common/clglcontext.cpp rename to src/common/detail/clglcontext.cpp index 2ff973f0e..d8301b891 100644 --- a/src/common/clglcontext.cpp +++ b/src/common/detail/clglcontext.cpp @@ -1,8 +1,11 @@ #include "clglcontext.hpp" -#include "util.hpp" -#include "viz2d.hpp" +#include "../util.hpp" +#include "../viz2d.hpp" namespace kb { +namespace viz2d { +namespace detail { + //FIXME use cv::ogl CLGLContext::CLGLContext(const cv::Size& frameBufferSize) : frameBufferSize_(frameBufferSize) { @@ -96,5 +99,6 @@ void CLGLContext::releaseToGL(cv::UMat &m) { cv::flip(m, m, 0); GL_CHECK(cv::ogl::convertToGLTexture2D(m, getTexture2D())); } - -} /* namespace kb */ +} +} +} diff --git a/src/common/clglcontext.hpp b/src/common/detail/clglcontext.hpp similarity index 88% rename from src/common/clglcontext.hpp rename to src/common/detail/clglcontext.hpp index b4c173981..48a6d6d8e 100644 --- a/src/common/clglcontext.hpp +++ b/src/common/detail/clglcontext.hpp @@ -12,16 +12,20 @@ #define GLFW_INCLUDE_GLCOREARB #include -#include "util.hpp" +#include "../util.hpp" -namespace kb { +namespace kb { +namespace viz2d { class Viz2D; +namespace detail { +typedef cv::ocl::OpenCLExecutionContext CLExecContext_t; +typedef cv::ocl::OpenCLExecutionContextScope CLExecScope_t; class CLGLContext { friend class CLVAContext; friend class NanoVGContext; - friend class Viz2D; + friend class kb::viz2d::Viz2D; cv::ogl::Texture2D *frameBufferTex_; GLuint frameBufferID; GLuint renderBufferID; @@ -69,6 +73,8 @@ protected: void releaseToGL(cv::UMat &m); cv::UMat frameBuffer_; }; -} /* namespace kb */ +} +} +} #endif /* SRC_COMMON_CLGLCONTEXT_HPP_ */ diff --git a/src/common/clvacontext.cpp b/src/common/detail/clvacontext.cpp similarity index 96% rename from src/common/clvacontext.cpp rename to src/common/detail/clvacontext.cpp index 4af967429..c08bc59a6 100644 --- a/src/common/clvacontext.cpp +++ b/src/common/detail/clvacontext.cpp @@ -1,8 +1,10 @@ #include "clvacontext.hpp" -#include "viz2d.hpp" +#include "../viz2d.hpp" namespace kb { +namespace viz2d { +namespace detail { CLVAContext::CLVAContext(CLGLContext &clglContext) : clglContext_(clglContext) { @@ -17,7 +19,6 @@ void CLVAContext::setVideoFrameSize(const cv::Size& sz) { cv::Size CLVAContext::getVideoFrameSize() { assert(videoFrameSize_ == cv::Size(0,0) || "Video frame size not initialized"); - return videoFrameSize_; } @@ -71,4 +72,6 @@ void CLVAContext::copyContext() { CLExecContext_t CLVAContext::getCLExecContext() { return context_; } -} /* namespace kb */ +} +} +} diff --git a/src/common/clvacontext.hpp b/src/common/detail/clvacontext.hpp similarity index 91% rename from src/common/clvacontext.hpp rename to src/common/detail/clvacontext.hpp index 025c60b88..eb247f735 100644 --- a/src/common/clvacontext.hpp +++ b/src/common/detail/clvacontext.hpp @@ -2,13 +2,14 @@ #define SRC_COMMON_CLVACONTEXT_HPP_ #include "clglcontext.hpp" -#include "util.hpp" namespace kb { +namespace viz2d { class Viz2D; +namespace detail { class CLVAContext { - friend class Viz2D; + friend class kb::viz2d::Viz2D; CLExecContext_t context_; CLGLContext &clglContext_; cv::UMat frameBuffer_; @@ -29,6 +30,8 @@ public: bool hasContext(); void copyContext(); }; -} /* namespace kb */ +} +} +} #endif /* SRC_COMMON_CLVACONTEXT_HPP_ */ diff --git a/src/common/nanovgcontext.cpp b/src/common/detail/nanovgcontext.cpp similarity index 77% rename from src/common/nanovgcontext.cpp rename to src/common/detail/nanovgcontext.cpp index a3e49669e..5cd8cbca4 100644 --- a/src/common/nanovgcontext.cpp +++ b/src/common/detail/nanovgcontext.cpp @@ -1,9 +1,10 @@ #include "nanovgcontext.hpp" -#include "viz2d.hpp" +#include "../viz2d.hpp" namespace kb { - +namespace viz2d { +namespace detail { NanoVGContext::NanoVGContext(Viz2D &v2d, NVGcontext *context, CLGLContext &fbContext) : v2d_(v2d), context_(context), clglContext_(fbContext) { nvgCreateFont(context_, "libertine", "assets/LinLibertine_RB.ttf"); @@ -13,11 +14,12 @@ NanoVGContext::NanoVGContext(Viz2D &v2d, NVGcontext *context, CLGLContext &fbCon CLGLContext::FrameBufferScope fbScope(clglContext_, tmp); } -void NanoVGContext::render(std::function fn) { +void NanoVGContext::render(std::function fn) { CLExecScope_t scope(clglContext_.getCLExecContext()); CLGLContext::GLScope glScope(clglContext_); NanoVGContext::Scope nvgScope(*this); - fn(context_, clglContext_.getSize()); + kb::nvg::detail::set_current_context(context_), + fn(clglContext_.getSize()); } void NanoVGContext::begin() { @@ -31,7 +33,10 @@ void NanoVGContext::begin() { } void NanoVGContext::end() { + //FIXME make nvgCancelFrame possible nvgEndFrame(context_); nvgRestore(context_); } -} /* namespace kb */ +} +} +} diff --git a/src/common/nanovgcontext.hpp b/src/common/detail/nanovgcontext.hpp similarity index 82% rename from src/common/nanovgcontext.hpp rename to src/common/detail/nanovgcontext.hpp index 3e3de2646..54cd26f39 100644 --- a/src/common/nanovgcontext.hpp +++ b/src/common/detail/nanovgcontext.hpp @@ -5,9 +5,12 @@ #include "clglcontext.hpp" #include #include -#include "util.hpp" +#include "../util.hpp" +#include "../nvg.hpp" namespace kb { +namespace viz2d { +namespace detail { class NanoVGContext { Viz2D& v2d_; NVGcontext *context_; @@ -25,11 +28,13 @@ public: } }; NanoVGContext(Viz2D& v2d, NVGcontext *context, CLGLContext &fbContext); - void render(std::function fn); + void render(std::function fn); private: void begin(); void end(); }; -} /* namespace kb */ +} +} +} #endif /* SRC_COMMON_NANOVGCONTEXT_HPP_ */ diff --git a/src/common/nvg.cpp b/src/common/nvg.cpp new file mode 100644 index 000000000..fba8b96aa --- /dev/null +++ b/src/common/nvg.cpp @@ -0,0 +1,599 @@ +#include "nvg.hpp" + +namespace kb { +namespace nvg { +namespace detail { +class NVG; + +void set_current_context(NVGcontext* ctx) { + if(nvg_instance != nullptr) + delete nvg_instance; + nvg_instance = new NVG(ctx); +} + +NVG* get_current_context() { + assert(nvg_instance != nullptr); + return nvg_instance; +} + +int NVG::createFont(const char* name, const char* filename) { + return nvgCreateFont(getContext(), name, filename); +} + +int NVG::createFontMem(const char* name, unsigned char* data, int ndata, int freeData) { + return nvgCreateFontMem(getContext(), name, data, ndata, freeData); +} + +int NVG::findFont(const char* name) { + return nvgFindFont(getContext(), name); +} + +int NVG::addFallbackFontId(int baseFont, int fallbackFont) { + return nvgAddFallbackFontId(getContext(), baseFont, fallbackFont); +} + +int NVG::addFallbackFont(const char* baseFont, const char* fallbackFont) { + return nvgAddFallbackFont(getContext(), baseFont, fallbackFont); +} + +void NVG::fontSize(float size) { + nvgFontSize(getContext(), size); +} + +void NVG::fontBlur(float blur) { + nvgFontBlur(getContext(), blur); +} + +void NVG::textLetterSpacing(float spacing) { + nvgTextLetterSpacing(getContext(), spacing); +} + +void NVG::textLineHeight(float lineHeight) { + nvgTextLineHeight(getContext(), lineHeight); +} + +void NVG::textAlign(int align) { + nvgTextAlign(getContext(), align); +} + +void NVG::fontFaceId(int font) { + nvgFontFaceId(getContext(), font); +} + +void NVG::fontFace(const char* font) { + nvgFontFace(getContext(), font); +} + +float NVG::text(float x, float y, const char* string, const char* end) { + return nvgText(getContext(), x, y, string, end); +} + +void NVG::textBox(float x, float y, float breakRowWidth, const char* string, const char* end) { + nvgTextBox(getContext(), x, y, breakRowWidth, string, end); +} + +float NVG::textBounds(float x, float y, const char* string, const char* end, float* bounds) { + return nvgTextBounds(getContext(), x, y, string, end, bounds); +} + +void NVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds) { + nvgTextBoxBounds(getContext(), x, y, breakRowWidth, string, end, bounds); +} + +int NVG::textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition* positions, int maxPositions) { + std::vector gp(maxPositions); + int result = nvgTextGlyphPositions(getContext(), x, y, string, end, gp.data(), maxPositions); + for(int i = 0; i < maxPositions; ++i) { + positions[i].str = gp[i].str; + positions[i].x = gp[i].x; + positions[i].minx = gp[i].minx; + positions[i].maxx = gp[i].maxx; + } + return result; +} + +void NVG::textMetrics(float* ascender, float* descender, float* lineh) { + nvgTextMetrics(getContext(), ascender, descender, lineh); +} + +int NVG::textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow* rows, int maxRows) { + NVGtextRow tr[maxRows]; + int result = nvgTextBreakLines(getContext(),string, end, breakRowWidth, tr, maxRows); + for(int i = 0; i < maxRows; ++i) { + rows[i].start = tr[i].start; + rows[i].end = tr[i].end; + rows[i].next = tr[i].next; + rows[i].width = tr[i].width; + rows[i].minx = tr[i].minx; + rows[i].maxx = tr[i].maxx; + } + return result; +} + +void NVG::save() { + nvgSave(getContext()); +} + +void NVG::restore() { + nvgRestore(getContext()); +} + +void NVG::reset() { + nvgReset(getContext()); +} + +void NVG::shapeAntiAlias(int enabled) { + nvgShapeAntiAlias(getContext(), enabled); +} + +void NVG::strokeColor(const cv::Scalar& bgra) { + nvgStrokeColor(getContext(), nvgRGBA(bgra[2],bgra[1],bgra[0],bgra[3])); +} + +void NVG::strokePaint(Paint paint) { + NVGpaint np; + memcpy(paint.xform, np.xform, 6); + memcpy(paint.extent, np.extent, 2); + np.radius = paint.radius; + np.feather = paint.feather; + np.innerColor = nvgRGBA(paint.innerColor[2],paint.innerColor[1],paint.innerColor[0],paint.innerColor[3]); + np.outerColor = nvgRGBA(paint.outerColor[2],paint.outerColor[1],paint.outerColor[0],paint.outerColor[3]);; + np.image = paint.image; + + nvgStrokePaint(getContext(), np); +} + +void NVG::fillColor(const cv::Scalar& bgra) { + nvgFillColor(getContext(), nvgRGBA(bgra[2],bgra[1],bgra[0],bgra[3])); +} + +void NVG::fillPaint(Paint paint) { + NVGpaint np; + memcpy(paint.xform, np.xform, 6); + memcpy(paint.extent, np.extent, 2); + np.radius = paint.radius; + np.feather = paint.feather; + np.innerColor = nvgRGBA(paint.innerColor[2],paint.innerColor[1],paint.innerColor[0],paint.innerColor[3]); + np.outerColor = nvgRGBA(paint.outerColor[2],paint.outerColor[1],paint.outerColor[0],paint.outerColor[3]);; + np.image = paint.image; + + nvgFillPaint(getContext(), np); +} + +void NVG::miterLimit(float limit) { + nvgMiterLimit(getContext(), limit); +} + +void NVG::strokeWidth(float size) { + nvgStrokeWidth(getContext(), size); +} + +void NVG::lineCap(int cap) { + nvgLineCap(getContext(), cap); +} + +void NVG::lineJoin(int join) { + nvgLineJoin(getContext(), join); +} + +void NVG::globalAlpha(float alpha) { + nvgGlobalAlpha(getContext(), alpha); +} + +void NVG::resetTransform() { + nvgResetTransform(getContext()); +} + +void NVG::transform(float a, float b, float c, float d, float e, float f) { + nvgTransform(getContext(), a, b, c, d, e, f); +} + +void NVG::translate(float x, float y) { + nvgTranslate(getContext(), x, y); +} + +void NVG::rotate(float angle) { + nvgRotate(getContext(), angle); +} + +void NVG::skewX(float angle) { + nvgSkewX(getContext(), angle); +} + +void NVG::skewY(float angle) { + nvgSkewY(getContext(), angle); +} + +void NVG::scale(float x, float y) { + nvgScale(getContext(), x, y); +} + +void NVG::currentTransform(float* xform) { + nvgCurrentTransform(getContext(), xform); +} + +void NVG::transformIdentity(float* dst) { + nvgTransformIdentity(dst); +} + +void NVG::transformTranslate(float* dst, float tx, float ty) { + nvgTransformTranslate(dst, tx, ty); +} + +void NVG::transformScale(float* dst, float sx, float sy) { + nvgTransformScale(dst, sx, sy); +} + +void NVG::transformRotate(float* dst, float a) { + nvgTransformRotate(dst, a); +} + +void NVG::transformSkewX(float* dst, float a) { + nvgTransformSkewX(dst, a); +} + +void NVG::transformSkewY(float* dst, float a) { + nvgTransformSkewY(dst, a); +} + +void NVG::transformMultiply(float* dst, const float* src) { + nvgTransformMultiply(dst, src); +} + +void NVG::transformPremultiply(float* dst, const float* src) { + nvgTransformPremultiply(dst, src); +} + +int NVG::transformInverse(float* dst, const float* src) { + return nvgTransformInverse(dst, src); +} + +void NVG::transformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy) { + nvgTransformPoint(dstx, dsty, xform, srcx, srcy); +} + +float NVG::degToRad(float deg) { + return nvgDegToRad(deg); +} + +float NVG::radToDeg(float rad) { + return nvgRadToDeg(rad); +} + +void NVG::beginPath() { + nvgBeginPath(getContext()); +} + +void NVG::moveTo(float x, float y) { + nvgMoveTo(getContext(), x, y); +} + +void NVG::lineTo(float x, float y) { + nvgLineTo(getContext(), x, y); +} + +void NVG::bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y) { + nvgBezierTo(getContext(), c1x, c1y, c2x, c2y, x, y); +} + +void NVG::quadTo(float cx, float cy, float x, float y) { + nvgQuadTo(getContext(), cx, cy, x, y); +} + +void NVG::arcTo(float x1, float y1, float x2, float y2, float radius) { + nvgArcTo(getContext(), x1, y1, x2, y2, radius); +} + +void NVG::closePath() { + nvgClosePath(getContext()); +} + +void NVG::pathWinding(int dir) { + nvgPathWinding(getContext(), dir); +} + +void NVG::arc(float cx, float cy, float r, float a0, float a1, int dir) { + nvgArc(getContext(), cx, cy, r, a0, a1, dir); +} + +void NVG::rect(float x, float y, float w, float h) { + nvgRect(getContext(), x, y, w, h); +} + +void NVG::roundedRect(float x, float y, float w, float h, float r) { + nvgRoundedRect(getContext(), x, y, w, h, r); +} + +void NVG::roundedRectVarying(float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft) { + nvgRoundedRectVarying(getContext(), x, y, w, h, radTopLeft, radTopRight, radBottomRight, radBottomLeft); +} + +void NVG::ellipse(float cx, float cy, float rx, float ry) { + nvgEllipse(getContext(), cx, cy, rx, ry); +} + +void NVG::circle(float cx, float cy, float r) { + nvgCircle(getContext(), cx, cy, r); +} + +void NVG::fill() { + nvgFill(getContext()); +} + +void NVG::stroke() { + nvgStroke(getContext()); +} +} //namespace detail + +int createFont(const char* name, const char* filename) { + return detail::get_current_context()->createFont(name,filename); +} + +int createFontMem(const char* name, unsigned char* data, int ndata, int freeData) { + return detail::get_current_context()->createFontMem(name, data, ndata, freeData); +} + +int findFont(const char* name) { + return detail::get_current_context()->findFont(name); +} + +int addFallbackFontId(int baseFont, int fallbackFont) { + return detail::get_current_context()->addFallbackFontId(baseFont, fallbackFont); +} +int addFallbackFont(const char* baseFont, const char* fallbackFont) { + return detail::get_current_context()->addFallbackFont(baseFont, fallbackFont); +} + +void fontSize(float size) { + detail::get_current_context()->fontSize(size); +} + +void fontBlur(float blur) { + detail::get_current_context()->fontBlur(blur); +} + +void textLetterSpacing(float spacing) { + detail::get_current_context()->textLetterSpacing(spacing); +} + +void textLineHeight(float lineHeight) { + detail::get_current_context()->textLineHeight(lineHeight); +} + +void textAlign(int align) { + detail::get_current_context()->textAlign(align); +} + +void fontFaceId(int font) { + detail::get_current_context()->fontFaceId(font); +} + +void fontFace(const char* font) { + detail::get_current_context()->fontFace(font); +} + +float text(float x, float y, const char* string, const char* end) { + return detail::get_current_context()->text(x, y, string, end); +} + +void textBox(float x, float y, float breakRowWidth, const char* string, const char* end) { + detail::get_current_context()->textBox(x, y, breakRowWidth, string, end); +} + +float textBounds(float x, float y, const char* string, const char* end, float* bounds) { + return detail::get_current_context()->textBounds(x, y, string, end, bounds); +} + +void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds) { + detail::get_current_context()->textBoxBounds(x, y, breakRowWidth, string, end, bounds); +} + +int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition* positions, int maxPositions) { + return detail::get_current_context()->textGlyphPositions(x, y, string, end, positions, maxPositions); +} + +void textMetrics(float* ascender, float* descender, float* lineh) { + detail::get_current_context()->textMetrics(ascender, descender, lineh); +} + +int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow* rows, int maxRows) { + return detail::get_current_context()->textBreakLines(string, end, breakRowWidth, rows, maxRows); +} + +void save() { + detail::get_current_context()->save(); +} + +void restore() { + detail::get_current_context()->restore(); +} + +void reset() { + detail::get_current_context()->reset(); +} + +void shapeAntiAlias(int enabled) { + detail::get_current_context()->strokeColor(enabled); +} + +void strokeColor(const cv::Scalar& bgra) { + detail::get_current_context()->strokeColor(bgra); +} + +void strokePaint(Paint paint) { + detail::get_current_context()->strokePaint(paint); +} + +void fillColor(const cv::Scalar& color) { + detail::get_current_context()->fillColor(color); +} + +void fillPaint(Paint paint) { + detail::get_current_context()->fillPaint(paint); +} + +void miterLimit(float limit) { + detail::get_current_context()->miterLimit(limit); +} + +void strokeWidth(float size) { + detail::get_current_context()->strokeWidth(size); +} + +void lineCap(int cap) { + detail::get_current_context()->lineCap(cap); +} + +void lineJoin(int join) { + detail::get_current_context()->lineJoin(join); +} + +void globalAlpha(float alpha) { + detail::get_current_context()->globalAlpha(alpha); +} + +void resetTransform() { + detail::get_current_context()->resetTransform(); +} + +void transform(float a, float b, float c, float d, float e, float f) { + detail::get_current_context()->transform(a, b, c, d, e, f); +} + +void translate(float x, float y) { + detail::get_current_context()->translate(x, y); +} + +void rotate(float angle) { + detail::get_current_context()->rotate(angle); +} + +void skewX(float angle) { + detail::get_current_context()->skewX(angle); +} + +void skewY(float angle) { + detail::get_current_context()->skewY(angle); +} + +void scale(float x, float y) { + detail::get_current_context()->scale(x, y); +} + +void currentTransform(float* xform) { + detail::get_current_context()->currentTransform(xform); +} + +void transformIdentity(float* dst) { + detail::get_current_context()->transformIdentity(dst); +} + +void transformTranslate(float* dst, float tx, float ty) { + detail::get_current_context()->transformTranslate(dst, tx, ty); +} + +void transformScale(float* dst, float sx, float sy) { + detail::get_current_context()->transformScale(dst, sx, sy); +} + +void transformRotate(float* dst, float a) { + detail::get_current_context()->transformRotate(dst, a); +} + +void transformSkewX(float* dst, float a) { + detail::get_current_context()->transformSkewX(dst, a); +} + +void transformSkewY(float* dst, float a) { + detail::get_current_context()->transformSkewY(dst, a); +} + +void transformMultiply(float* dst, const float* src) { + detail::get_current_context()->transformMultiply(dst, src); +} + +void transformPremultiply(float* dst, const float* src) { + detail::get_current_context()->transformPremultiply(dst, src); +} + +int transformInverse(float* dst, const float* src) { + return detail::get_current_context()->transformInverse(dst, src); +} + +void transformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy) { + return detail::get_current_context()->transformPoint(dstx, dsty, xform, srcx, srcy); +} + +float degToRad(float deg) { + return detail::get_current_context()->degToRad(deg); +} + +float radToDeg(float rad) { + return detail::get_current_context()->radToDeg(rad); +} + +void beginPath() { + detail::get_current_context()->beginPath(); +} +void moveTo(float x, float y) { + detail::get_current_context()->moveTo(x, y); +} + +void lineTo(float x, float y) { + detail::get_current_context()->lineTo(x, y); +} + +void bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y) { + detail::get_current_context()->bezierTo(c1x, c1y, c2x, c2y, x, y); +} + +void quadTo(float cx, float cy, float x, float y) { + detail::get_current_context()->quadTo(cx, cy, x, y); +} + +void arcTo(float x1, float y1, float x2, float y2, float radius) { + detail::get_current_context()->arcTo(x1, y1, x2, y2, radius); +} + +void closePath() { + detail::get_current_context()->closePath(); +} + +void pathWinding(int dir) { + detail::get_current_context()->pathWinding(dir); +} + +void arc(float cx, float cy, float r, float a0, float a1, int dir) { + detail::get_current_context()->arc(cx, cy, r, a0, a1, dir); +} + +void rect(float x, float y, float w, float h) { + detail::get_current_context()->rect(x, y, w, h); +} + +void roundedRect(float x, float y, float w, float h, float r) { + detail::get_current_context()->roundedRect(x, y, w, h, r); +} + +void roundedRectVarying(float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft) { + detail::get_current_context()->roundedRectVarying(x, y, w, h, radTopLeft, radTopRight, radBottomRight, radBottomLeft); +} + +void ellipse(float cx, float cy, float rx, float ry) { + detail::get_current_context()->ellipse(cx, cy, rx, ry); +} + +void circle(float cx, float cy, float r) { + detail::get_current_context()->circle(cx, cy, r); +} + +void fill() { + detail::get_current_context()->fill(); +} + +void stroke() { + detail::get_current_context()->stroke(); +} + +} //namespace nvg +} //namespace kb diff --git a/src/common/nvg.hpp b/src/common/nvg.hpp new file mode 100644 index 000000000..71996fb04 --- /dev/null +++ b/src/common/nvg.hpp @@ -0,0 +1,208 @@ +#ifndef SRC_COMMON_NVG_HPP_ +#define SRC_COMMON_NVG_HPP_ + +#include "viz2d.hpp" +#define NANOGUI_USE_OPENGL +#include + +namespace kb { +namespace nvg { + +struct TextRow { + const char* start; // Pointer to the input text where the row starts. + const char* end; // Pointer to the input text where the row ends (one past the last character). + const char* next; // Pointer to the beginning of the next row. + float width; // Logical width of the row. + float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending. +}; + +struct GlyphPosition { + const char* str; // Position of the glyph in the input string. + float x; // The x-coordinate of the logical glyph position. + float minx, maxx; // The bounds of the glyph shape. +}; + +struct Paint { + float xform[6]; + float extent[2]; + float radius; + float feather; + cv::Scalar innerColor; + cv::Scalar outerColor; + int image; +}; + +namespace detail { + +class NVG { + friend class Viz2D; + NVGcontext* ctx_; +public: + NVG(NVGcontext* ctx) : ctx_(ctx) { + } + + NVGcontext* getContext() { + return ctx_; + } +public: + +int createFont(const char* name, const char* filename); +int createFontMem(const char* name, unsigned char* data, int ndata, int freeData); +int findFont(const char* name); +int addFallbackFontId(int baseFont, int fallbackFont); +int addFallbackFont(const char* baseFont, const char* fallbackFont); +void fontSize(float size); +void fontBlur(float blur); +void textLetterSpacing(float spacing); +void textLineHeight(float lineHeight); +void textAlign(int align); +void fontFaceId(int font); +void fontFace(const char* font); +float text(float x, float y, const char* string, const char* end); +void textBox(float x, float y, float breakRowWidth, const char* string, const char* end); +float textBounds(float x, float y, const char* string, const char* end, float* bounds); +void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); +int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition* positions, int maxPositions); +void textMetrics(float* ascender, float* descender, float* lineh); +int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow* rows, int maxRows); + +void save(); +void restore(); +void reset(); + +void shapeAntiAlias(int enabled); +void strokeColor(const cv::Scalar& bgra); +void strokePaint(Paint paint); +void fillColor(const cv::Scalar& bgra); +void fillPaint(Paint paint); +void miterLimit(float limit); +void strokeWidth(float size); +void lineCap(int cap); +void lineJoin(int join); +void globalAlpha(float alpha); + +void resetTransform(); +void transform(float a, float b, float c, float d, float e, float f); +void translate(float x, float y); +void rotate(float angle); +void skewX(float angle); +void skewY(float angle); +void scale(float x, float y); +void currentTransform(float* xform); +void transformIdentity(float* dst); +void transformTranslate(float* dst, float tx, float ty); +void transformScale(float* dst, float sx, float sy); +void transformRotate(float* dst, float a); +void transformSkewX(float* dst, float a); +void transformSkewY(float* dst, float a); +void transformMultiply(float* dst, const float* src); +void transformPremultiply(float* dst, const float* src); +int transformInverse(float* dst, const float* src); +void transformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy); + +float degToRad(float deg); +float radToDeg(float rad); + +void beginPath(); +void moveTo(float x, float y); +void lineTo(float x, float y); +void bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y); +void quadTo(float cx, float cy, float x, float y); +void arcTo(float x1, float y1, float x2, float y2, float radius); +void closePath(); +void pathWinding(int dir); +void arc(float cx, float cy, float r, float a0, float a1, int dir); +void rect(float x, float y, float w, float h); +void roundedRect(float x, float y, float w, float h, float r); +void roundedRectVarying(float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft); +void ellipse(float cx, float cy, float rx, float ry); +void circle(float cx, float cy, float r); +void fill(); +void stroke(); +}; + +static NVG* nvg_instance; + +void set_current_context(NVGcontext* ctx); +NVG* get_current_context(); +} // namespace detail + +int createFont(const char* name, const char* filename); +int createFontMem(const char* name, unsigned char* data, int ndata, int freeData); +int findFont(const char* name); +int addFallbackFontId(int baseFont, int fallbackFont); +int addFallbackFont(const char* baseFont, const char* fallbackFont); +void fontSize(float size); +void fontBlur(float blur); +void textLetterSpacing(float spacing); +void textLineHeight(float lineHeight); +void textAlign(int align); +void fontFaceId(int font); +void fontFace(const char* font); +float text(float x, float y, const char* string, const char* end); +void textBox(float x, float y, float breakRowWidth, const char* string, const char* end); +float textBounds(float x, float y, const char* string, const char* end, float* bounds); +void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); +int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition* positions, int maxPositions); +void textMetrics(float* ascender, float* descender, float* lineh); +int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow* rows, int maxRows); + +void save(); +void restore(); +void reset(); + +void shapeAntiAlias(int enabled); +void strokeColor(const cv::Scalar& bgra); +void strokePaint(Paint paint); +void fillColor(const cv::Scalar& color); +void fillPaint(Paint paint); +void miterLimit(float limit); +void strokeWidth(float size); +void lineCap(int cap); +void lineJoin(int join); +void globalAlpha(float alpha); + +void resetTransform(); +void transform(float a, float b, float c, float d, float e, float f); +void translate(float x, float y); +void rotate(float angle); +void skewX(float angle); +void skewY(float angle); +void scale(float x, float y); +void currentTransform(float* xform); +void transformIdentity(float* dst); +void transformTranslate(float* dst, float tx, float ty); +void transformScale(float* dst, float sx, float sy); +void transformRotate(float* dst, float a); +void transformSkewX(float* dst, float a); +void transformSkewY(float* dst, float a); +void transformMultiply(float* dst, const float* src); +void transformPremultiply(float* dst, const float* src); +int transformInverse(float* dst, const float* src); +void transformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy); + +float degToRad(float deg); +float radToDeg(float rad); + +void beginPath(); +void moveTo(float x, float y); +void lineTo(float x, float y); +void bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y); +void quadTo(float cx, float cy, float x, float y); +void arcTo(float x1, float y1, float x2, float y2, float radius); +void closePath(); +void pathWinding(int dir); +void arc(float cx, float cy, float r, float a0, float a1, int dir); +void rect(float x, float y, float w, float h); +void roundedRect(float x, float y, float w, float h, float r); +void roundedRectVarying(float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft); +void ellipse(float cx, float cy, float rx, float ry); +void circle(float cx, float cy, float r); +void fill(); +void stroke(); +} // namespace nvg +} // namespace kb + + + +#endif /* SRC_COMMON_NVG_HPP_ */ diff --git a/src/common/util.cpp b/src/common/util.cpp index 5afc9f234..379056e11 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -1,8 +1,19 @@ #include "util.hpp" #include "viz2d.hpp" +#include "nvg.hpp" namespace kb { +namespace viz2d { + +void gl_check_error(const std::filesystem::path &file, unsigned int line, const char *expression) { + int errorCode = glGetError(); + + if (errorCode != 0) { + std::cerr << "GL failed in " << file.filename() << " (" << line << ") : " << "\nExpression:\n " << expression << "\nError code:\n " << errorCode << "\n " << std::endl; + assert(false); + } +} void error_callback(int error, const char *description) { fprintf(stderr, "GLFW Error: %s\n", description); @@ -41,7 +52,7 @@ void print_system_info() { cerr << "OpenCL Platforms: " << get_cl_info() << endl; } -void update_fps(cv::Ptr window, bool graphical) { +void update_fps(cv::Ptr window, bool graphical) { static uint64_t cnt = 0; static cv::TickMeter tick; float fps; @@ -52,19 +63,20 @@ void update_fps(cv::Ptr window, bool graphical) { if (tick.getTimeMilli() > 1000) { cerr << "FPS : " << (fps = tick.getFPS()) << '\r'; if (graphical) { - window->nanovg([&](NVGcontext *vg, const cv::Size &size) { + window->nanovg([&](const cv::Size &size) { + using namespace kb; string text = "FPS: " + std::to_string(fps); - nvgBeginPath(vg); - nvgRoundedRect(vg, 10, 10, 30 * text.size() + 10, 60, 10); - nvgFillColor(vg, nvgRGBA(255, 255, 255, 180)); - nvgFill(vg); + nvg::beginPath(); + nvg::roundedRect(10, 10, 30 * text.size() + 10, 60, 10); + nvg::fillColor(cv::Scalar(255, 255, 255, 180)); + nvg::fill(); - nvgBeginPath(vg); - nvgFontSize(vg, 60.0f); - nvgFontFace(vg, "mono"); - nvgFillColor(vg, nvgRGBA(90, 90, 90, 255)); - nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgText(vg, 22, 37, text.c_str(), nullptr); + nvg::beginPath(); + nvg::fontSize(60.0f); + nvg::fontFace("mono"); + nvg::fillColor(cv::Scalar(90, 90, 90, 255)); + nvg::textAlign(NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + nvg::text(22, 37, text.c_str(), nullptr); }); } cnt = 0; @@ -74,5 +86,5 @@ void update_fps(cv::Ptr window, bool graphical) { tick.start(); ++cnt; } - +} } //namespace kb diff --git a/src/common/util.hpp b/src/common/util.hpp index cd2d77873..20af3cc43 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -8,17 +8,20 @@ #include namespace kb { +namespace viz2d { -class Viz2D; +void gl_check_error(const std::filesystem::path &file, unsigned int line, const char *expression); -typedef cv::ocl::OpenCLExecutionContext CLExecContext_t; -typedef cv::ocl::OpenCLExecutionContextScope CLExecScope_t; +#define GL_CHECK(expr) \ + expr; \ + kb::viz2d::gl_check_error(__FILE__, __LINE__, #expr); void error_callback(int error, const char *description); std::string get_gl_info(); std::string get_cl_info(); void print_system_info(); -void update_fps(cv::Ptr viz2d, bool graphical); -} //namespace kb +//void update_fps(cv::Ptr viz2d, bool graphical); +} +} #endif /* SRC_COMMON_UTIL_HPP_ */ diff --git a/src/common/viz2d.cpp b/src/common/viz2d.cpp index 0d504e6e1..acfe90496 100644 --- a/src/common/viz2d.cpp +++ b/src/common/viz2d.cpp @@ -1,16 +1,10 @@ #include "viz2d.hpp" - -#include "util.hpp" +#include "detail/clglcontext.hpp" +#include "detail/clvacontext.hpp" +#include "detail/nanovgcontext.hpp" namespace kb { -void gl_check_error(const std::filesystem::path &file, unsigned int line, const char *expression) { - int errorCode = glGetError(); - - if (errorCode != 0) { - std::cerr << "GL failed in " << file.filename() << " (" << line << ") : " << "\nExpression:\n " << expression << "\nError code:\n " << errorCode << "\n " << std::endl; - assert(false); - } -} +namespace viz2d { Viz2D::Viz2D(const cv::Size &size, const cv::Size& frameBufferSize, bool offscreen, const string &title, int major, int minor, int samples, bool debug) : size_(size), frameBufferSize_(frameBufferSize), offscreen_(offscreen), title_(title), major_(major), minor_(minor), samples_(samples), debug_(debug) { @@ -18,9 +12,7 @@ Viz2D::Viz2D(const cv::Size &size, const cv::Size& frameBufferSize, bool offscre } Viz2D::~Viz2D() { - //don't delete form_. it is autmatically cleaned up by screen_ - if (screen_) - delete screen_; + //don't delete form_. it is autmatically cleaned up by the base class (nanogui::Screen) if (writer_) delete writer_; if (capture_) @@ -37,7 +29,7 @@ Viz2D::~Viz2D() { void Viz2D::initialize() { assert(glfwInit() == GLFW_TRUE); - glfwSetErrorCallback(kb::error_callback); + glfwSetErrorCallback(kb::viz2d::error_callback); if (debug_) glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); @@ -81,45 +73,43 @@ void Viz2D::initialize() { } glfwMakeContextCurrent(getGLFWWindow()); - screen_ = new nanogui::Screen(); - screen_->initialize(getGLFWWindow(), false); - form_ = new nanogui::FormHelper(screen_); + screen().initialize(getGLFWWindow(), false); + form_ = new nanogui::FormHelper(this); this->setSize(size_); glfwSetWindowUserPointer(getGLFWWindow(), this); glfwSetCursorPosCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, double x, double y) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->cursor_pos_callback_event(x, y); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().cursor_pos_callback_event(x, y); } ); glfwSetMouseButtonCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, int button, int action, int modifiers) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->mouse_button_callback_event(button, action, modifiers); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().mouse_button_callback_event(button, action, modifiers); } ); glfwSetKeyCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, int key, int scancode, int action, int mods) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->key_callback_event(key, scancode, action, mods); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().key_callback_event(key, scancode, action, mods); } ); glfwSetCharCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, unsigned int codepoint) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->char_callback_event(codepoint); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().char_callback_event(codepoint); } ); glfwSetDropCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, int count, const char **filenames) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->drop_callback_event(count, filenames); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().drop_callback_event(count, filenames); } ); glfwSetScrollCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, double x, double y) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->scroll_callback_event(x, y); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().scroll_callback_event(x, y); } ); - //FIXME resize internal buffers? // glfwSetWindowContentScaleCallback(getGLFWWindow(), // [](GLFWwindow* glfwWin, float xscale, float yscale) { @@ -127,14 +117,14 @@ void Viz2D::initialize() { // ); glfwSetFramebufferSizeCallback(getGLFWWindow(), [](GLFWwindow *glfwWin, int width, int height) { - Viz2D *v2d = (Viz2D*) glfwGetWindowUserPointer(glfwWin); - v2d->screen_->resize_callback_event(width, height); + Viz2D* v2d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v2d->screen().resize_callback_event(width, height); } ); - clglContext_ = new CLGLContext(this->getFrameBufferSize()); - clvaContext_ = new CLVAContext(*clglContext_); - nvgContext_ = new NanoVGContext(*this, getNVGcontext(), *clglContext_); + clglContext_ = new detail::CLGLContext(this->getFrameBufferSize()); + clvaContext_ = new detail::CLVAContext(*clglContext_); + nvgContext_ = new detail::NanoVGContext(*this, getNVGcontext(), *clglContext_); } cv::ogl::Texture2D& Viz2D::texture() { @@ -145,6 +135,23 @@ nanogui::FormHelper* Viz2D::form() { return form_; } +bool Viz2D::keyboard_event(int key, int scancode, int action, int modifiers) { + if (nanogui::Screen::keyboard_event(key, scancode, action, modifiers)) + return true; + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + nanogui::Screen::set_visible(!screen().visible()); + return true; + } else if (key == GLFW_KEY_TAB && action == GLFW_PRESS) { + auto children = nanogui::Screen::children(); + for(auto* child : children) { + child->set_visible(!child->visible()); + } + + return true; + } + return false; +} + CLGLContext& Viz2D::clgl() { return *clglContext_; } @@ -157,6 +164,10 @@ NanoVGContext& Viz2D::nvg() { return *nvgContext_; } +nanogui::Screen& Viz2D::screen() { + return *dynamic_cast(this); +} + cv::Size Viz2D::getVideoFrameSize() { return clva().getVideoFrameSize(); } @@ -166,8 +177,8 @@ void Viz2D::setVideoFrameSize(const cv::Size& sz) { } void Viz2D::opengl(std::function fn) { - CLExecScope_t scope(clglContext_->getCLExecContext()); - CLGLContext::GLScope glScope(*clglContext_); + detail::CLExecScope_t scope(clglContext_->getCLExecContext()); + detail::CLGLContext::GLScope glScope(*clglContext_); fn(getFrameBufferSize()); } @@ -175,7 +186,7 @@ void Viz2D::opencl(std::function fn) { clgl().opencl(fn); } -void Viz2D::nanovg(std::function fn) { +void Viz2D::nanovg(std::function fn) { nvg().render(fn); } @@ -265,7 +276,7 @@ float Viz2D::getYPixelRatio() { } void Viz2D::setSize(const cv::Size &sz) { - screen_->set_size(nanogui::Vector2i(sz.width / getXPixelRatio(), sz.height / getYPixelRatio())); + screen().set_size(nanogui::Vector2i(sz.width / getXPixelRatio(), sz.height / getYPixelRatio())); } bool Viz2D::isFullscreen() { @@ -296,9 +307,9 @@ bool Viz2D::isVisible() { } void Viz2D::setVisible(bool v) { - screen_->perform_layout(); + screen().perform_layout(); glfwWindowHint(GLFW_VISIBLE, v ? GLFW_TRUE : GLFW_FALSE); - screen_->set_visible(v); + screen().set_visible(v); setSize(size_); } @@ -331,9 +342,9 @@ bool Viz2D::display() { bool result = true; if (!offscreen_) { glfwPollEvents(); - screen_->draw_contents(); + screen().draw_contents(); clglContext_->blitFrameBufferToScreen(getSize()); - screen_->draw_widgets(); + screen().draw_widgets(); glfwSwapBuffers(glfwWindow_); result = !glfwWindowShouldClose(glfwWindow_); } @@ -355,6 +366,7 @@ GLFWwindow* Viz2D::getGLFWWindow() { } NVGcontext* Viz2D::getNVGcontext() { - return screen_->nvg_context(); + return screen().nvg_context(); +} +} } -} /* namespace kb */ diff --git a/src/common/viz2d.hpp b/src/common/viz2d.hpp index 0d3d4aac0..708c77227 100644 --- a/src/common/viz2d.hpp +++ b/src/common/viz2d.hpp @@ -4,10 +4,8 @@ #include #include #include - -#include "clglcontext.hpp" -#include "clvacontext.hpp" -#include "nanovgcontext.hpp" +#include +#include using std::cout; using std::cerr; @@ -15,13 +13,17 @@ using std::endl; using std::string; namespace kb { +namespace viz2d { +namespace detail { +class CLGLContext; +class CLVAContext; +class NanoVGContext; +} +using namespace kb::viz2d::detail; -void gl_check_error(const std::filesystem::path &file, unsigned int line, const char *expression); -#define GL_CHECK(expr) \ - expr; \ - kb::gl_check_error(__FILE__, __LINE__, #expr); +class NVG; -class Viz2D { +class Viz2D: private nanogui::Screen { cv::Size size_; cv::Size frameBufferSize_; bool offscreen_; @@ -36,19 +38,18 @@ class Viz2D { NanoVGContext* nvgContext_ = nullptr; cv::VideoCapture* capture_ = nullptr; cv::VideoWriter* writer_ = nullptr; - nanogui::Screen* screen_ = nullptr; nanogui::FormHelper* form_ = nullptr; bool closed_ = false; cv::Size videoFrameSize_ = cv::Size(0,0); public: Viz2D(const cv::Size &size, const cv::Size& frameBufferSize, bool offscreen, const string &title, int major = 4, int minor = 6, int samples = 0, bool debug = false); - ~Viz2D(); + virtual ~Viz2D(); void initialize(); cv::ogl::Texture2D& texture(); void opengl(std::function fn); void opencl(std::function fn); - void nanovg(std::function fn); + void nanovg(std::function fn); void clear(const cv::Scalar& rgba = cv::Scalar(0,0,0,255)); bool captureVA(); @@ -92,15 +93,18 @@ public: } void setUseOpenCL(bool u); + NVGcontext* getNVGcontext(); private: + virtual bool keyboard_event(int key, int scancode, int action, int modifiers); + CLGLContext& clgl(); CLVAContext& clva(); NanoVGContext& nvg(); + nanogui::Screen& screen(); void makeGLFWContextCurrent(); GLFWwindow* getGLFWWindow(); - NVGcontext* getNVGcontext(); }; - +} } /* namespace kb */ #endif /* SRC_COMMON_VIZ2D_HPP_ */ diff --git a/src/optflow/optflow-demo.cpp b/src/optflow/optflow-demo.cpp index ea91a4dda..ff339584e 100644 --- a/src/optflow/optflow-demo.cpp +++ b/src/optflow/optflow-demo.cpp @@ -2,6 +2,10 @@ #define CL_TARGET_OPENCL_VERSION 120 #include "../common/viz2d.hpp" +#include "../common/nvg.hpp" +#include "../common/util.hpp" + + #include #include #include @@ -10,6 +14,7 @@ #include #include #include +#include using std::cerr; using std::endl; @@ -92,7 +97,7 @@ bool detect_scene_change(const cv::UMat& srcMotionMaskGrey, const float thresh, return result; } -void visualize_sparse_optical_flow(NVGcontext* vg, const cv::UMat &prevGrey, const cv::UMat &nextGrey, vector &detectedPoints, +void visualize_sparse_optical_flow(const cv::UMat &prevGrey, const cv::UMat &nextGrey, vector &detectedPoints, const float scaleFactor, const int maxStrokeSize, const cv::Scalar color, const int maxPoints, const float pointLossPercent) { static vector hull, prevPoints, nextPoints, newPoints; static vector upPrevPoints, upNextPoints; @@ -127,9 +132,10 @@ void visualize_sparse_optical_flow(NVGcontext* vg, const cv::UMat &prevGrey, con upNextPoints.push_back(pt /= scaleFactor); } - nvgBeginPath(vg); - nvgStrokeWidth(vg, stroke); - nvgStrokeColor(vg, nvgRGBA(color[0], color[1], color[2], color[3])); + using namespace kb; + nvg::beginPath(); + nvg::strokeWidth(stroke); + nvg::strokeColor(color); for (size_t i = 0; i < prevPoints.size(); i++) { if (status[i] == 1 && err[i] < (1.0 / density) @@ -139,12 +145,12 @@ void visualize_sparse_optical_flow(NVGcontext* vg, const cv::UMat &prevGrey, con float len = hypot(fabs(upPrevPoints[i].x - upNextPoints[i].x), fabs(upPrevPoints[i].y - upNextPoints[i].y)); if (len > 0 && len < sqrt(area)) { newPoints.push_back(nextPoints[i]); - nvgMoveTo(vg, upNextPoints[i].x, upNextPoints[i].y); - nvgLineTo(vg, upPrevPoints[i].x, upPrevPoints[i].y); + nvg::moveTo(upNextPoints[i].x, upNextPoints[i].y); + nvg::lineTo(upPrevPoints[i].x, upPrevPoints[i].y); } } } - nvgStroke(vg); + nvg::stroke(); } prevPoints = newPoints; } @@ -184,60 +190,61 @@ void composite_layers(const cv::UMat background, const cv::UMat foreground, cons cv::add(background, glow, dst); } -void setup_gui(cv::Ptr window) { - window->makeWindow(5, 45, "Settings"); +void setup_gui(cv::Ptr v2d) { + v2d->makeWindow(5, 45, "Settings"); + v2d->makeFormVariable("Use OpenCL", use_opencl, "Enable or disable OpenCL acceleration"); + v2d->makeGroup("Foreground"); + v2d->makeFormVariable("Scale", fg_scale, 0.1f, 4.0f, true, "", "Generate the foreground at this scale"); + v2d->makeFormVariable("Loss", fg_loss, 0.1f, 99.9f, true, "%", "On every frame the foreground loses on brightness"); - window->makeFormVariable("Use OpenCL", use_opencl, "Enable or disable OpenCL acceleration"); - window->makeGroup("Foreground"); - window->makeFormVariable("Scale", fg_scale, 0.1f, 4.0f, true, "", "Generate the foreground at this scale"); - window->makeFormVariable("Loss", fg_loss, 0.1f, 99.9f, true, "%", "On every frame the foreground loses on brightness"); + v2d->makeGroup("Scene Change Detection"); + v2d->makeFormVariable("Threshold", scene_change_thresh, 0.1f, 1.0f, true, "", "Peak threshold. Lowering it makes detection more sensitive"); + v2d->makeFormVariable("Threshold Diff", scene_change_thresh_diff, 0.1f, 1.0f, true, "", "Difference of peak thresholds. Lowering it makes detection more sensitive"); - window->makeGroup("Scene Change Detection"); - window->makeFormVariable("Threshold", scene_change_thresh, 0.1f, 1.0f, true, "", "Peak threshold. Lowering it makes detection more sensitive"); - window->makeFormVariable("Threshold Diff", scene_change_thresh_diff, 0.1f, 1.0f, true, "", "Difference of peak thresholds. Lowering it makes detection more sensitive"); + v2d->makeGroup("Points"); + v2d->makeFormVariable("Max. Points", max_points, 10, 1000000, true, "", "The theoretical maximum number of points to track which is scaled by the density of detected points and therefor is usually much smaller"); + v2d->makeFormVariable("Point Loss", point_loss, 0.0f, 100.0f, true, "%", "How many of the tracked points to lose intentionally"); - window->makeGroup("Points"); - window->makeFormVariable("Max. Points", max_points, 10, 1000000, true, "", "The theoretical maximum number of points to track which is scaled by the density of detected points and therefor is usually much smaller"); - window->makeFormVariable("Point Loss", point_loss, 0.0f, 100.0f, true, "%", "How many of the tracked points to lose intentionally"); - - window->makeGroup("Effect"); - window->makeFormVariable("Max. Stroke Size", max_stroke, 1, 100, true, "px", "The theoretical maximum size of the drawing stroke which is scaled by the area of the convex hull of tracked points and therefor is usually much smaller"); - auto glowKernel = window->makeFormVariable("Glow Kernel Size", glow_kernel_size, 1, 63, true, "", "Intensity of glow defined by kernel size"); + v2d->makeGroup("Effect"); + v2d->makeFormVariable("Max. Stroke Size", max_stroke, 1, 100, true, "px", "The theoretical maximum size of the drawing stroke which is scaled by the area of the convex hull of tracked points and therefor is usually much smaller"); + auto glowKernel = v2d->makeFormVariable("Glow Kernel Size", glow_kernel_size, 1, 63, true, "", "Intensity of glow defined by kernel size"); glowKernel->set_callback([](const int& k) { glow_kernel_size = std::max(int(k % 2 == 0 ? k + 1 : k), 1); }); - auto color = window->form()->add_variable("Color", effect_color); + auto color = v2d->form()->add_variable("Color", effect_color); color->set_tooltip("The effect color"); color->set_final_callback([](const nanogui::Color &c) { effect_color[0] = c[0]; effect_color[1] = c[1]; effect_color[2] = c[2]; }); - window->makeFormVariable("Alpha", alpha, 0.0f, 1.0f, true, "", "The opacity of the effect"); + v2d->makeFormVariable("Alpha", alpha, 0.0f, 1.0f, true, "", "The opacity of the effect"); - window->makeWindow(240, 45, "Display"); - window->makeGroup("Display"); - window->makeFormVariable("Show FPS", show_fps, "Enable or disable the On-screen FPS display"); - window->form()->add_button("Fullscreen", [=]() { - window->setFullscreen(!window->isFullscreen()); + v2d->makeWindow(240, 45, "Display"); + v2d->makeGroup("Display"); + v2d->makeFormVariable("Show FPS", show_fps, "Enable or disable the On-screen FPS display"); + v2d->form()->add_button("Fullscreen", [=]() { + v2d->setFullscreen(!v2d->isFullscreen()); }); - if(!window->isOffscreen()) - window->setVisible(true); + if(!v2d->isOffscreen()) + v2d->setVisible(true); } int main(int argc, char **argv) { + using namespace kb::viz2d; if (argc != 2) { std::cerr << "Usage: optflow " << endl; exit(1); } - cv::Ptr v2d = new kb::Viz2D(cv::Size(WIDTH, HEIGHT), cv::Size(WIDTH, HEIGHT), OFFSCREEN, "Sparse Optical Flow Demo"); + cv::Ptr v2d = new Viz2D(cv::Size(WIDTH, HEIGHT), cv::Size(WIDTH, HEIGHT), OFFSCREEN, "Sparse Optical Flow Demo"); v2d->initialize(); - kb::print_system_info(); + print_system_info(); + setup_gui(v2d); auto capture = v2d->makeVACapture(argv[1], VA_HW_DEVICE_INDEX); @@ -278,14 +285,14 @@ int main(int argc, char **argv) { //Detect trackable points in the motion mask detect_points(downMotionMaskGrey, detectedPoints); - v2d->nanovg([&](NVGcontext* vg, const cv::Size& sz) { + v2d->nanovg([&](const cv::Size& sz) { v2d->clear(); if (!downPrevGrey.empty()) { //We don't want the algorithm to get out of hand when there is a scene change, so we suppress it when we detect one. if (!detect_scene_change(downMotionMaskGrey, scene_change_thresh, scene_change_thresh_diff)) { //Visualize the sparse optical flow using nanovg - cv::Scalar color = cv::Scalar(effect_color.r() * 255.0f, effect_color.g() * 255.0f, effect_color.b() * 255.0f, alpha * 255.0f); - visualize_sparse_optical_flow(vg, downPrevGrey, downNextGrey, detectedPoints, fg_scale, max_stroke, color, max_points, point_loss); + cv::Scalar color = cv::Scalar(effect_color.b() * 255.0f, effect_color.g() * 255.0f, effect_color.r() * 255.0f, alpha * 255.0f); + visualize_sparse_optical_flow(downPrevGrey, downNextGrey, detectedPoints, fg_scale, max_stroke, color, max_points, point_loss); } } }); @@ -299,7 +306,7 @@ int main(int argc, char **argv) { v2d->writeVA(); - update_fps(v2d, show_fps); +// update_fps(v2d, show_fps); //If onscreen rendering is enabled it displays the framebuffer in the native window. Returns false if the window was closed. if(!v2d->display()) diff --git a/src/video/video-demo.cpp b/src/video/video-demo.cpp index 725874944..6c91328d3 100644 --- a/src/video/video-demo.cpp +++ b/src/video/video-demo.cpp @@ -1,6 +1,8 @@ #define CL_TARGET_OPENCL_VERSION 120 #include "../common/viz2d.hpp" +#include "../common/util.hpp" + #include constexpr long unsigned int WIDTH = 1920; @@ -80,20 +82,20 @@ void glow_effect(const cv::UMat &src, cv::UMat &dst, const int ksize) { } int main(int argc, char **argv) { - using namespace kb; + using namespace kb::viz2d; if(argc != 2) { cerr << "Usage: video-demo " << endl; exit(1); } - cv::Ptr v2d = new kb::Viz2D(cv::Size(WIDTH, HEIGHT), cv::Size(WIDTH, HEIGHT), OFFSCREEN, "Video Demo"); + cv::Ptr v2d = new Viz2D(cv::Size(WIDTH, HEIGHT), cv::Size(WIDTH, HEIGHT), OFFSCREEN, "Video Demo"); v2d->initialize(); if(!v2d->isOffscreen()) v2d->setVisible(true); //Print system information - kb::print_system_info(); + print_system_info(); auto capture = v2d->makeVACapture(argv[1], VA_HW_DEVICE_INDEX);