diff --git a/include/app.hpp b/include/app.hpp index 9cb56c09..0f6e5bba 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -14,6 +14,7 @@ struct Wire; struct RackWidget; struct ParamWidget; struct Port; +struct SVGPanel; //////////////////// // module @@ -23,11 +24,15 @@ struct Port; #define RACK_GRID_WIDTH 15 #define RACK_GRID_HEIGHT 380 +static const Vec RACK_GRID_SIZE = Vec(15, 380); + + struct ModuleWidget : OpaqueWidget { Model *model = NULL; /** Owns the module pointer */ Module *module = NULL; + SVGPanel *panel = NULL; std::vector inputs; std::vector outputs; std::vector params; @@ -38,6 +43,7 @@ struct ModuleWidget : OpaqueWidget { void addInput(Port *input); void addOutput(Port *output); void addParam(ParamWidget *param); + void setPanel(std::shared_ptr svg); virtual json_t *toJson(); virtual void fromJson(json_t *rootJ); diff --git a/include/components.hpp b/include/components.hpp index 32adf720..640618f9 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -446,8 +446,6 @@ struct NKK : SVGSwitch, ToggleSwitch { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/NKK_0.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/NKK_1.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/NKK_2.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; @@ -455,8 +453,6 @@ struct CKSS : SVGSwitch, ToggleSwitch { CKSS() { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/CKSS_0.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/CKSS_1.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; @@ -464,8 +460,6 @@ struct CKD6 : SVGSwitch, MomentarySwitch { CKD6() { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/CKD6_0.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/CKD6_1.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; @@ -473,16 +467,12 @@ struct TL1105 : SVGSwitch, MomentarySwitch { TL1105() { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/TL1105_0.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/TL1105_1.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; struct LEDButton : SVGSwitch, MomentarySwitch { LEDButton() { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/LEDButton.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; @@ -491,8 +481,6 @@ struct BefacoSwitch : SVGSwitch, ToggleSwitch { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/BefacoSwitch_0.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/BefacoSwitch_1.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/BefacoSwitch_2.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; @@ -500,17 +488,12 @@ struct BefacoPush : SVGSwitch, MomentarySwitch { BefacoPush() { addFrame(SVG::load(assetGlobal("res/ComponentLibrary/BefacoPush_0.svg"))); addFrame(SVG::load(assetGlobal("res/ComponentLibrary/BefacoPush_1.svg"))); - sw->wrap(); - box.size = sw->box.size; } }; struct PB61303 : SVGSwitch, MomentarySwitch { PB61303() { - addFrame(SVG::load(assetGlobal("res/ComponentLibrary/PB61303_0.svg"))); - addFrame(SVG::load(assetGlobal("res/ComponentLibrary/PB61303_1.svg"))); - sw->wrap(); - box.size = sw->box.size; + addFrame(SVG::load(assetGlobal("res/ComponentLibrary/PB61303.svg"))); } }; @@ -521,16 +504,14 @@ struct PB61303 : SVGSwitch, MomentarySwitch { struct ScrewSilver : SVGScrew { ScrewSilver() { - sw->svg = SVG::load(assetGlobal("res/ComponentLibrary/ScrewSilver.svg")); - sw->wrap(); + sw->setSVG(SVG::load(assetGlobal("res/ComponentLibrary/ScrewSilver.svg"))); box.size = sw->box.size; } }; struct ScrewBlack : SVGScrew { ScrewBlack() { - sw->svg = SVG::load(assetGlobal("res/ComponentLibrary/ScrewBlack.svg")); - sw->wrap(); + sw->setSVG(SVG::load(assetGlobal("res/ComponentLibrary/ScrewBlack.svg"))); box.size = sw->box.size; } }; diff --git a/include/rack.hpp b/include/rack.hpp index 6b1595b7..9593d29f 100644 --- a/include/rack.hpp +++ b/include/rack.hpp @@ -18,15 +18,6 @@ namespace rack { //////////////////// -inline Vec in2px(Vec inches) { - return inches.mult(SVG_DPI); -} - -inline Vec mm2px(Vec millimeters) { - return millimeters.mult(SVG_DPI / 25.4); -} - - template Model *createModel(std::string manufacturerSlug, std::string manufacturerName, std::string slug, std::string name) { struct TModel : Model { diff --git a/include/widgets.hpp b/include/widgets.hpp index 9e974c61..18d7321d 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -16,6 +16,15 @@ namespace rack { +inline Vec in2px(Vec inches) { + return inches.mult(SVG_DPI); +} + +inline Vec mm2px(Vec millimeters) { + return millimeters.mult(SVG_DPI / 25.4); +} + + //////////////////// // resources //////////////////// diff --git a/res/ComponentLibrary/PB61303.svg b/res/ComponentLibrary/PB61303.svg new file mode 100644 index 00000000..42ac4a99 --- /dev/null +++ b/res/ComponentLibrary/PB61303.svg @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/res/ComponentLibrary/PB61303_0.svg b/res/ComponentLibrary/PB61303_0.svg deleted file mode 100644 index 80f0a6f3..00000000 --- a/res/ComponentLibrary/PB61303_0.svg +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/res/ComponentLibrary/PB61303_1.svg b/res/ComponentLibrary/PB61303_1.svg deleted file mode 100644 index d9c90ce8..00000000 --- a/res/ComponentLibrary/PB61303_1.svg +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 77f79b46..695fe0e9 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -42,6 +42,21 @@ void ModuleWidget::addParam(ParamWidget *param) { addChild(param); } +void ModuleWidget::setPanel(std::shared_ptr svg) { + // Remove old panel + if (panel) { + removeChild(panel); + panel = NULL; + } + + panel = new SVGPanel(); + panel->setBackground(svg); + addChild(panel); + + box.size = panel->box.size; +} + + json_t *ModuleWidget::toJson() { json_t *rootJ = json_object(); diff --git a/src/app/SVGPanel.cpp b/src/app/SVGPanel.cpp index 178d7d65..26a3b86b 100644 --- a/src/app/SVGPanel.cpp +++ b/src/app/SVGPanel.cpp @@ -19,19 +19,20 @@ struct PanelBorder : TransparentWidget { void SVGPanel::step() { if (nearf(gPixelRatio, 1.0)) { + // Small details draw poorly at low DPI, so oversample when drawing to the framebuffer oversample = 2.0; } FramebufferWidget::step(); } void SVGPanel::setBackground(std::shared_ptr svg) { - clearChildren(); - SVGWidget *sw = new SVGWidget(); - sw->wrap(); - sw->svg = svg; + sw->setSVG(svg); addChild(sw); + // Set size + box.size = sw->box.size.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE); + PanelBorder *pb = new PanelBorder(); pb->box.size = box.size; addChild(pb); diff --git a/src/app/SVGSwitch.cpp b/src/app/SVGSwitch.cpp index 1507a43e..3b48819d 100644 --- a/src/app/SVGSwitch.cpp +++ b/src/app/SVGSwitch.cpp @@ -11,10 +11,11 @@ SVGSwitch::SVGSwitch() { void SVGSwitch::addFrame(std::shared_ptr svg) { frames.push_back(svg); - // Automatically set the frame as this SVG file. - // This allows us to wrap() the widget after calling - if (!sw->svg) - sw->svg = svg; + // If this is our first frame, automatically set SVG and size + if (!sw->svg) { + sw->setSVG(svg); + box.size = sw->box.size; + } } void SVGSwitch::step() { @@ -22,9 +23,9 @@ void SVGSwitch::step() { } void SVGSwitch::onChange() { - int index = roundf(rescalef(value, minValue, maxValue, 0, frames.size() - 1)); - if (0 <= index && index < (int)frames.size()) - sw->svg = frames[index]; + assert(frames.size() > 0); + int index = clampi((int) roundf(value), 0, frames.size() - 1); + sw->setSVG(frames[index]); dirty = true; Switch::onChange(); } diff --git a/src/engine.cpp b/src/engine.cpp index d587e575..6663e2bf 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -35,13 +35,19 @@ static float smoothValue; float Light::getBrightness() { - // Scale by sqrt(2) since the RMS of a rectified sine is 1 / sqrt(2) - return sqrtf(fmaxf(0.0, value) * 2.0); + return sqrtf(fmaxf(0.0, value)); } void Light::setBrightnessSmooth(float brightness) { - // lambda = 3 * framerate - value += (brightness * brightness - value) * sampleTime * (60.0 * 3.0); + float v = brightness * brightness; + if (v < value) { + // Fade out light with lambda = 3 * framerate + value += (v - value) * sampleTime * (60.0 * 3.0); + } + else { + // Immediately illuminate light + value = v; + } } diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index d3e85016..9d4a633d 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -46,6 +46,8 @@ void FramebufferWidget::draw(NVGcontext *vg) { assert(fabsf(xform[2]) < 1e-6); Vec s = Vec(xform[0], xform[3]); Vec b = Vec(xform[4], xform[5]); + Vec bi = b.floor(); + Vec bf = b.minus(bi); // Render to framebuffer if (dirty) { @@ -78,8 +80,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { nvgScale(gFramebufferVg, gPixelRatio * oversample, gPixelRatio * oversample); // Use local scaling - Vec bFrac = Vec(fmodf(b.x, 1.0), fmodf(b.y, 1.0)); - nvgTranslate(gFramebufferVg, bFrac.x, bFrac.y); + nvgTranslate(gFramebufferVg, bf.x, bf.y); nvgScale(gFramebufferVg, s.x, s.y); Widget::draw(gFramebufferVg); @@ -92,10 +93,9 @@ void FramebufferWidget::draw(NVGcontext *vg) { } // Draw framebuffer image, using world coordinates - b = b.floor(); nvgSave(vg); nvgResetTransform(vg); - nvgTranslate(vg, b.x, b.y); + nvgTranslate(vg, bi.x, bi.y); nvgBeginPath(vg); nvgRect(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y);