From 59b39bf8764f9fc7111a1a9d8eb3ca472421b3dd Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Tue, 4 Apr 2017 00:07:21 -0700 Subject: [PATCH] Add CircularShadow and add it to the SVGKnob framebuffer --- Makefile-plugin.inc | 32 +++++++++++++++++++++++++++++++ include/app.hpp | 14 +++++++++++++- include/components.hpp | 16 +++++++++++++++- include/widgets.hpp | 10 +++------- src/app/CircularShadow.cpp | 21 ++++++++++++++++++++ src/app/SVGKnob.cpp | 31 +++++++++--------------------- src/app/SVGPort.cpp | 2 +- src/gui.cpp | 1 + src/widgets/FramebufferWidget.cpp | 31 +++++++++++++++--------------- 9 files changed, 111 insertions(+), 47 deletions(-) create mode 100644 Makefile-plugin.inc create mode 100644 src/app/CircularShadow.cpp diff --git a/Makefile-plugin.inc b/Makefile-plugin.inc new file mode 100644 index 00000000..42b772ee --- /dev/null +++ b/Makefile-plugin.inc @@ -0,0 +1,32 @@ +ARCH ?= lin + + +FLAGS += -fPIC -g -Wall -O3 -msse -mfpmath=sse -ffast-math \ + -I../../include +LDFLAGS += + + +ifeq ($(ARCH), lin) +LDFLAGS += -shared +TARGET = plugin.so +endif + +ifeq ($(ARCH), mac) +LDFLAGS += -shared -undefined dynamic_lookup +TARGET = plugin.dylib +endif + +ifeq ($(ARCH), win) +LDFLAGS += -shared -L../../ -lRack +TARGET = plugin.dll +endif + + + +all: $(TARGET) + +clean: + rm -rfv build $(TARGET) + + +include ../../Makefile.inc diff --git a/include/app.hpp b/include/app.hpp index 02d99a3b..2c501261 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -104,6 +104,11 @@ struct Panel : TransparentWidget { // params //////////////////// +struct CircularShadow : TransparentWidget { + float blur = 0.0; + void draw(NVGcontext *vg); +}; + struct Light : TransparentWidget { NVGcolor color; void draw(NVGcontext *vg); @@ -137,17 +142,24 @@ struct SVGKnob : Knob, FramebufferWidget { /** Not owned */ TransformWidget *tw; SVGWidget *sw; + CircularShadow *shadow; SVGKnob(); void setSVG(std::shared_ptr svg); void step(); - void draw(NVGcontext *vg); void onChange(); }; struct Switch : ParamWidget, SpriteWidget { }; +struct SVGSwitch : ParamWidget, FramebufferWidget { + /** Not owned */ + TransformWidget *tw; + SVGWidget *swPressed; + SVGWidget *swReleased; +}; + struct ToggleSwitch : virtual Switch { void onDragStart() { index = 1; diff --git a/include/components.hpp b/include/components.hpp index 1fa8ed01..15b0e1e9 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -360,7 +360,7 @@ struct CL1362Port : SpritePort { }; //////////////////// -// Lights +// LEDs //////////////////// struct ValueLight : Light { @@ -413,6 +413,20 @@ struct SmallLight : BASE { } }; +//////////////////// +// Switches +//////////////////// + +// struct BefacoBigKnob : { +// BefacoBigKnob() { +// box.size = Vec(75, 75); +// minAngle = -0.75*M_PI; +// maxAngle = 0.75*M_PI; +// setSVG(SVG::load("res/ComponentLibrary/BefacoBigKnob.svg")); +// } +// }; + + //////////////////// // Misc //////////////////// diff --git a/include/widgets.hpp b/include/widgets.hpp index 135ff1c4..d9e57f6f 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -186,28 +186,24 @@ struct SVGWidget : virtual Widget { }; /** Caches a widget's draw() result to a framebuffer so it is called less frequently -When `dirty` is true, `scene` will be re-rendered on the next call to step(). +When `dirty` is true, its children will be re-rendered on the next call to step(). Events are not passed to the underlying scene. */ struct FramebufferWidget : virtual Widget { - /** Set this to true to re-render the scene to the framebuffer in the next step() */ + /** Set this to true to re-render the children to the framebuffer in the next step() */ bool dirty = true; - /** A margin in pixels around the scene in the framebuffer + /** A margin in pixels around the children in the framebuffer This prevents cutting the rendered SVG off on the box edges. */ int margin = 0; /** The root object in the framebuffer scene The FramebufferWidget owns the pointer */ - Widget *scene = NULL; struct Internal; Internal *internal; FramebufferWidget(); ~FramebufferWidget(); - void setScene(Widget *w) { - scene = w; - } void step(); void draw(NVGcontext *vg); }; diff --git a/src/app/CircularShadow.cpp b/src/app/CircularShadow.cpp new file mode 100644 index 00000000..3d3ec3fe --- /dev/null +++ b/src/app/CircularShadow.cpp @@ -0,0 +1,21 @@ +#include "app.hpp" + + +namespace rack { + + +void CircularShadow::draw(NVGcontext *vg) { + nvgBeginPath(vg); + nvgRect(vg, -blur, -blur, box.size.x + 2*blur, box.size.y + 2*blur); + nvgFillColor(vg, nvgRGBAf(0.0, 0.0, 0.0, 0.25)); + Vec c = box.size.div(2.0); + float radius = c.x; + NVGcolor icol = nvgRGBAf(0.0, 0.0, 0.0, 0.25); + NVGcolor ocol = nvgRGBAf(0.0, 0.0, 0.0, 0.0); + NVGpaint paint = nvgRadialGradient(vg, c.x, c.y, radius - blur/2, radius + blur/2, icol, ocol); + nvgFillPaint(vg, paint); + nvgFill(vg); +} + + +} // namespace rack diff --git a/src/app/SVGKnob.cpp b/src/app/SVGKnob.cpp index 494b23ba..0288e184 100644 --- a/src/app/SVGKnob.cpp +++ b/src/app/SVGKnob.cpp @@ -5,10 +5,15 @@ namespace rack { SVGKnob::SVGKnob() { - margin = 1; + margin = 4; + + shadow = new CircularShadow(); + shadow->blur = 5.0; + shadow->box.pos = Vec(0, 1); + addChild(shadow); tw = new TransformWidget(); - setScene(tw); + addChild(tw); sw = new SVGWidget(); tw->addChild(sw); @@ -33,30 +38,12 @@ void SVGKnob::step() { tw->translate(center); tw->rotate(angle); tw->translate(center.neg()); + // Resize shadow + shadow->box.size = box.size; } FramebufferWidget::step(); } -void SVGKnob::draw(NVGcontext *vg) { - // Draw circular shadow below knob - // TODO This is a hack. Make a CircularShadow its own class - { - nvgBeginPath(vg); - float margin = 5.0; - nvgRect(vg, -margin, -margin, box.size.x + 2*margin, box.size.y + 2*margin); - nvgFillColor(vg, nvgRGBAf(0.0, 0.0, 0.0, 0.25)); - Vec c = box.size.div(2.0); - float radius = c.x; - NVGcolor icol = nvgRGBAf(0.0, 0.0, 0.0, 0.25); - NVGcolor ocol = nvgRGBAf(0.0, 0.0, 0.0, 0.0); - NVGpaint paint = nvgRadialGradient(vg, c.x, c.y + 1, radius, radius + 3, icol, ocol); - nvgFillPaint(vg, paint); - nvgFill(vg); - } - - FramebufferWidget::draw(vg); -} - void SVGKnob::onChange() { dirty = true; ParamWidget::onChange(); diff --git a/src/app/SVGPort.cpp b/src/app/SVGPort.cpp index 6a9c760e..56329278 100644 --- a/src/app/SVGPort.cpp +++ b/src/app/SVGPort.cpp @@ -6,7 +6,7 @@ namespace rack { SVGPort::SVGPort() { sw = new SVGWidget(); - setScene(sw); + addChild(sw); } void SVGPort::setSVG(std::shared_ptr svg) { diff --git a/src/gui.cpp b/src/gui.cpp index 4c814617..3817ef01 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -197,6 +197,7 @@ void guiInit() { // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE); std::string title = gApplicationName + " " + gApplicationVersion; window = glfwCreateWindow(1000, 750, title.c_str(), NULL, NULL); assert(window); diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index 828f6b0b..7037c7f8 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -10,6 +10,7 @@ namespace rack { struct FramebufferWidget::Internal { NVGLUframebuffer *fb = NULL; + Vec offset; ~Internal() { setFramebuffer(NULL); @@ -26,24 +27,23 @@ FramebufferWidget::FramebufferWidget() { } FramebufferWidget::~FramebufferWidget() { - if (scene) { - delete scene; - } delete internal; } void FramebufferWidget::step() { - if (!scene) + if (children.empty()) return; - // Step scene before rendering - scene->step(); + // Step children before rendering + Widget::step(); // Render the scene to the framebuffer if dirty if (dirty) { - assert(scene->box.size.isFinite()); - int width = ceilf(scene->box.size.x) + 2*margin; - int height = ceilf(scene->box.size.y) + 2*margin; + Rect childrenBox = getChildrenBoundingBox(); + assert(childrenBox.size.isFinite()); + int width = ceilf(childrenBox.size.x) + 2*margin; + int height = ceilf(childrenBox.size.y) + 2*margin; + internal->offset = childrenBox.pos.minus(Vec(margin, margin)); internal->setFramebuffer(NULL); NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, width, height, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); @@ -59,8 +59,8 @@ void FramebufferWidget::step() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); nvgBeginFrame(gVg, width, height, pixelRatio); - nvgTranslate(gVg, margin, margin); - scene->draw(gVg); + nvgTranslate(gVg, -internal->offset.x, -internal->offset.y); + Widget::draw(gVg); nvgEndFrame(gVg); nvgluBindFramebuffer(NULL); @@ -72,17 +72,18 @@ void FramebufferWidget::step() { void FramebufferWidget::draw(NVGcontext *vg) { if (!internal->fb) return; - if (!scene) - return; // Draw framebuffer image int width, height; nvgImageSize(vg, internal->fb->image, &width, &height); nvgBeginPath(vg); - nvgRect(vg, -margin, -margin, width, height); - NVGpaint paint = nvgImagePattern(vg, -margin + scene->box.pos.x, -margin + scene->box.pos.y, width, height, 0.0, internal->fb->image, 1.0); + nvgRect(vg, internal->offset.x, internal->offset.y, width, height); + NVGpaint paint = nvgImagePattern(vg, internal->offset.x, internal->offset.y, width, height, 0.0, internal->fb->image, 1.0); nvgFillPaint(vg, paint); nvgFill(vg); + + // nvgFillColor(vg, nvgRGBA(255, 0, 0, 64)); + // nvgFill(vg); }