From aad709e62c9592fc69cad6ba62b88cafec530c49 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 1 Feb 2017 03:21:37 -0500 Subject: [PATCH] Large refactor to modularize include files, add NanoSVG dependency, added Image/Font/SVG loader --- include/engine.hpp | 51 ++++++ include/gui.hpp | 17 ++ include/plugin.hpp | 51 ++++++ include/rack.hpp | 145 +---------------- include/{rackwidgets.hpp => scene.hpp} | 38 +++-- include/util.hpp | 6 + include/widgets.hpp | 57 ++++++- src/core/AudioInterface.cpp | 4 +- src/core/core.cpp | 18 ++- src/core/core.hpp | 2 - src/{Rack.cpp => engine.cpp} | 207 +++++++++++++------------ src/gui.cpp | 136 ++++++++-------- src/main.cpp | 20 +-- src/plugin.cpp | 7 +- src/scene.cpp | 22 +++ src/widgets.cpp | 13 ++ src/widgets/Button.cpp | 2 +- src/widgets/ChoiceButton.cpp | 2 +- src/widgets/InputPort.cpp | 2 +- src/widgets/Knob.cpp | 3 +- src/widgets/Label.cpp | 2 +- src/widgets/Light.cpp | 2 +- src/widgets/Menu.cpp | 2 +- src/widgets/MenuEntry.cpp | 2 +- src/widgets/MenuItem.cpp | 2 +- src/widgets/MenuLabel.cpp | 2 +- src/widgets/MenuOverlay.cpp | 3 +- src/widgets/ModulePanel.cpp | 9 +- src/widgets/ModuleWidget.cpp | 10 +- src/widgets/OutputPort.cpp | 2 +- src/widgets/ParamWidget.cpp | 5 +- src/widgets/Port.cpp | 2 +- src/widgets/QuantityWidget.cpp | 2 +- src/widgets/RackScene.cpp | 28 ++++ src/widgets/RackWidget.cpp | 21 ++- src/widgets/RadioButton.cpp | 2 +- src/widgets/Scene.cpp | 18 +-- src/widgets/Screw.cpp | 4 +- src/widgets/ScrollBar.cpp | 3 +- src/widgets/ScrollWidget.cpp | 2 +- src/widgets/Slider.cpp | 3 +- src/widgets/SpriteWidget.cpp | 12 +- src/widgets/Toolbar.cpp | 8 +- src/widgets/Tooltip.cpp | 2 +- src/widgets/Widget.cpp | 2 +- src/widgets/WireWidget.cpp | 11 +- 46 files changed, 539 insertions(+), 425 deletions(-) create mode 100644 include/engine.hpp create mode 100644 include/gui.hpp create mode 100644 include/plugin.hpp rename include/{rackwidgets.hpp => scene.hpp} (89%) rename src/{Rack.cpp => engine.cpp} (54%) create mode 100644 src/scene.cpp create mode 100644 src/widgets.cpp create mode 100644 src/widgets/RackScene.cpp diff --git a/include/engine.hpp b/include/engine.hpp new file mode 100644 index 00000000..bcc7f2c7 --- /dev/null +++ b/include/engine.hpp @@ -0,0 +1,51 @@ +#pragma once +#include + + +namespace rack { + + +struct Module { + std::vector params; + /** Pointers to voltage values at each port + If value is NULL, the input/output is disconnected + */ + std::vector inputs; + std::vector outputs; + /** For CPU usage */ + float cpuTime = 0.0; + + virtual ~Module() {} + + /** Advances the module by 1 audio frame with duration 1.0 / gSampleRate */ + virtual void step() {} +}; + +struct Wire { + Module *outputModule = NULL; + int outputId; + Module *inputModule = NULL; + int inputId; + /** The voltage connected to input ports */ + float inputValue = 0.0; + /** The voltage connected to output ports */ + float outputValue = 0.0; +}; + +void engineInit(); +void engineDestroy(); +/** Launches engine thread */ +void engineStart(); +void engineStop(); +/** Does not transfer pointer ownership */ +void engineAddModule(Module *module); +void engineRemoveModule(Module *module); +/** Does not transfer pointer ownership */ +void engineAddWire(Wire *wire); +void engineRemoveWire(Wire *wire); +void engineSetParamSmooth(Module *module, int paramId, float value); + +extern float gSampleRate; + + +} // namespace rack diff --git a/include/gui.hpp b/include/gui.hpp new file mode 100644 index 00000000..bd4e1881 --- /dev/null +++ b/include/gui.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "scene.hpp" + + +namespace rack { + + +void guiInit(); +void guiDestroy(); +void guiRun(); +void guiCursorLock(); +void guiCursorUnlock(); +const char *guiSaveDialog(const char *filters, const char *filename); +const char *guiOpenDialog(const char *filters, const char *filename); + + +} // namespace rack diff --git a/include/plugin.hpp b/include/plugin.hpp new file mode 100644 index 00000000..cb4c68b1 --- /dev/null +++ b/include/plugin.hpp @@ -0,0 +1,51 @@ +#pragma once +#include +#include + + +namespace rack { + + +struct ModuleWidget; +struct Model; + +// Subclass this and return a pointer to a new one when init() is called +struct Plugin { + virtual ~Plugin(); + + // A unique identifier for your plugin, e.g. "foo" + std::string slug; + // Human readable name for your plugin, e.g. "Foo Modular" + std::string name; + /** A list of the models made available by this plugin */ + std::list models; +}; + +struct Model { + virtual ~Model() {} + + Plugin *plugin; + // A unique identifier for the model in this plugin, e.g. "vco" + std::string slug; + // Human readable name for your model, e.g. "VCO" + std::string name; + virtual ModuleWidget *createModuleWidget() { return NULL; } +}; + +extern std::list gPlugins; + +void pluginInit(); +void pluginDestroy(); + +} // namespace rack + + +//////////////////// +// Implemented by plugin +//////////////////// + +/** Called once to initialize and return Plugin. +Plugin is destructed when Rack closes +*/ +extern "C" +rack::Plugin *init(); diff --git a/include/rack.hpp b/include/rack.hpp index 6f5ab5ec..6628cc6a 100644 --- a/include/rack.hpp +++ b/include/rack.hpp @@ -1,130 +1,14 @@ #pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "rackwidgets.hpp" +#include "plugin.hpp" +#include "engine.hpp" +#include "gui.hpp" namespace rack { -//////////////////// -// Plugin manager -//////////////////// - -struct Model; - -// Subclass this and return a pointer to a new one when init() is called -struct Plugin { - virtual ~Plugin(); - - // A unique identifier for your plugin, e.g. "foo" - std::string slug; - // Human readable name for your plugin, e.g. "Foo Modular" - std::string name; - // A list of the models made available by this plugin - std::list models; -}; - -struct Model { - virtual ~Model() {} - - Plugin *plugin; - // A unique identifier for the model in this plugin, e.g. "vco" - std::string slug; - // Human readable name for your model, e.g. "VCO" - std::string name; - virtual ModuleWidget *createModuleWidget() { return NULL; } -}; - -extern std::list gPlugins; - -void pluginInit(); -void pluginDestroy(); //////////////////// -// gui.cpp -//////////////////// - -extern Vec gMousePos; -extern Widget *gHoveredWidget; -extern Widget *gDraggedWidget; -extern Widget *gSelectedWidget; -extern int gGuiFrame; - -void guiInit(); -void guiDestroy(); -void guiRun(); -void guiCursorLock(); -void guiCursorUnlock(); -const char *guiSaveDialog(const char *filters, const char *filename); -const char *guiOpenDialog(const char *filters, const char *filename); - -int loadFont(std::string filename); -int loadImage(std::string filename); -void drawImage(NVGcontext *vg, Vec pos, int imageId); - -//////////////////// -// rack.cpp -//////////////////// - -struct Wire; - -struct Module { - std::vector params; - /** Pointers to voltage values at each port - If value is NULL, the input/output is disconnected - */ - std::vector inputs; - std::vector outputs; - /** For CPU usage */ - float cpuTime = 0.0; - - virtual ~Module() {} - - // Always called on each sample frame before calling getOutput() - virtual void step() {} -}; - -struct Wire { - Module *outputModule = NULL; - int outputId; - Module *inputModule = NULL; - int inputId; - /** The voltage connected to input ports */ - float inputValue = 0.0; - /** The voltage connected to output ports */ - float outputValue = 0.0; -}; - -struct Rack { - Rack(); - ~Rack(); - /** Launches rack thread */ - void start(); - void stop(); - void run(); - void step(); - /** Does not transfer pointer ownership */ - void addModule(Module *module); - void removeModule(Module *module); - /** Does not transfer pointer ownership */ - void addWire(Wire *wire); - void removeWire(Wire *wire); - void setParamSmooth(Module *module, int paramId, float value); - - float sampleRate; - - struct Impl; - Impl *impl; -}; - -//////////////////// -// Optional helpers for plugins +// helpers //////////////////// inline @@ -191,26 +75,5 @@ Screw *createScrew(Vec pos) { return screw; } -//////////////////// -// Globals -//////////////////// - -extern std::string gApplicationName; -extern std::string gApplicationVersion; - -extern Scene *gScene; -extern RackWidget *gRackWidget; - -extern Rack *gRack; } // namespace rack - - -//////////////////// -// Implemented by plugin -//////////////////// - -// Called once to initialize and return Plugin. -// Plugin is destructed when Rack closes -extern "C" -rack::Plugin *init(); diff --git a/include/rackwidgets.hpp b/include/scene.hpp similarity index 89% rename from include/rackwidgets.hpp rename to include/scene.hpp index ab6ca229..ee0bea1b 100644 --- a/include/rackwidgets.hpp +++ b/include/scene.hpp @@ -1,7 +1,7 @@ #pragma once - -#include "widgets.hpp" +#include #include +#include "widgets.hpp" namespace rack { @@ -14,7 +14,7 @@ struct RackWidget; struct ParamWidget; struct InputPort; struct OutputPort; - +struct Scene; //////////////////// // module @@ -76,6 +76,7 @@ struct RackWidget : OpaqueWidget { // Only put WireWidgets in here Widget *wireContainer; WireWidget *activeWire = NULL; + std::shared_ptr railsImage; RackWidget(); ~RackWidget(); @@ -94,7 +95,7 @@ struct RackWidget : OpaqueWidget { struct ModulePanel : TransparentWidget { NVGcolor backgroundColor; - std::string imageFilename; + std::shared_ptr backgroundImage; void draw(NVGcontext *vg); }; @@ -205,18 +206,17 @@ struct Toolbar : OpaqueWidget { void draw(NVGcontext *vg); }; -struct Scene : OpaqueWidget { +struct RackScene : Scene { Toolbar *toolbar; ScrollWidget *scrollWidget; - Widget *overlay = NULL; - Scene(); - void setOverlay(Widget *w); + RackScene(); void step(); }; + //////////////////// -// component library +// Component Library //////////////////// struct PJ301M : SpriteWidget { @@ -224,7 +224,7 @@ struct PJ301M : SpriteWidget { box.size = Vec(24, 24); spriteOffset = Vec(-10, -10); spriteSize = Vec(48, 48); - spriteFilename = "res/ComponentLibrary/PJ301M.png"; + spriteImage = Image::load("res/ComponentLibrary/PJ301M.png"); } }; struct InputPortPJ301M : InputPort, PJ301M {}; @@ -235,7 +235,7 @@ struct PJ3410 : SpriteWidget { box.size = Vec(31, 31); spriteOffset = Vec(-9, -9); spriteSize = Vec(54, 54); - spriteFilename = "res/ComponentLibrary/PJ3410.png"; + spriteImage = Image::load("res/ComponentLibrary/PJ3410.png"); } }; struct InputPortPJ3410 : InputPort, PJ3410 {}; @@ -246,10 +246,24 @@ struct CL1362 : SpriteWidget { box.size = Vec(33, 29); spriteOffset = Vec(-10, -10); spriteSize = Vec(57, 54); - spriteFilename = "res/ComponentLibrary/CL1362.png"; + spriteImage = Image::load("res/ComponentLibrary/CL1362.png"); } }; struct InputPortCL1362 : InputPort, CL1362 {}; struct OutputPortCL1362 : OutputPort, CL1362 {}; + +//////////////////// +// globals +//////////////////// + +extern std::string gApplicationName; +extern std::string gApplicationVersion; + +extern Scene *gScene; +extern RackWidget *gRackWidget; + +void sceneInit(); +void sceneDestroy(); + } // namespace rack diff --git a/include/util.hpp b/include/util.hpp index 7c6b423c..a351d7c4 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -1,6 +1,12 @@ #pragma once +// Include most of the C standard library for convenience +// (C++ programmers will hate me) +#include +#include #include +#include + #include diff --git a/include/widgets.hpp b/include/widgets.hpp index b60c7d0d..a50f327c 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -1,13 +1,10 @@ #pragma once - -#include -#include -#include #include -#include +#include #include "../ext/nanovg/src/nanovg.h" #include "../ext/oui/blendish.h" +#include "../ext/nanosvg/src/nanosvg.h" #include "math.hpp" #include "util.hpp" @@ -16,6 +13,35 @@ namespace rack { +//////////////////// +// resources +//////////////////// + +// Constructing these directly will load from the disk each time. Use the load() functions to load from disk and cache them as long as the shared_ptr is held. +// Implemented in gui.cpp + +struct Font { + int handle; + Font(const std::string &filename); + ~Font(); + static std::shared_ptr load(const std::string &filename); +}; + +struct Image { + int handle; + Image(const std::string &filename); + ~Image(); + static std::shared_ptr load(const std::string &filename); +}; + +struct SVG { + NSVGimage *image; + SVG(const std::string &filename); + ~SVG(); + static std::shared_ptr load(const std::string &filename); +}; + + //////////////////// // base class and traits //////////////////// @@ -122,7 +148,7 @@ struct OpaqueWidget : virtual Widget { struct SpriteWidget : virtual Widget { Vec spriteOffset; Vec spriteSize; - std::string spriteFilename; + std::shared_ptr spriteImage; int index = 0; void draw(NVGcontext *vg); }; @@ -276,5 +302,24 @@ struct Tooltip : Widget { void draw(NVGcontext *vg); }; +struct Scene : OpaqueWidget { + Widget *overlay = NULL; + void setOverlay(Widget *w); + void step(); +}; + + +//////////////////// +// globals +//////////////////// + +extern Vec gMousePos; +extern Widget *gHoveredWidget; +extern Widget *gDraggedWidget; +extern Widget *gSelectedWidget; +extern int gGuiFrame; + +extern Scene *gScene; + } // namespace rack diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 80bffdb4..e9b24778 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -99,7 +99,7 @@ void AudioInterface::step() { // Once full, sample rate convert the input if (inputBuffer.full()) { - inputSrc.setRatio(sampleRate / gRack->sampleRate); + inputSrc.setRatio(sampleRate / gSampleRate); int inLen = inputBuffer.size(); int outLen = inputSrcBuffer.capacity(); inputSrc.process((const float*) inputBuffer.startData(), &inLen, (float*) inputSrcBuffer.endData(), &outLen); @@ -127,7 +127,7 @@ void AudioInterface::step() { } // Pass output through sample rate converter - outputSrc.setRatio(gRack->sampleRate / sampleRate); + outputSrc.setRatio(gSampleRate / sampleRate); int inLen = blockSize; int outLen = outputBuffer.capacity(); outputSrc.process((float*) buf, &inLen, (float*) outputBuffer.endData(), &outLen); diff --git a/src/core/core.cpp b/src/core/core.cpp index d6a5aff5..f1bf4eb2 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -3,12 +3,20 @@ using namespace rack; -Plugin *coreInit() { + +struct CorePlugin : Plugin { + CorePlugin() { + slug = "Core"; + name = "Core"; + createModel(this, "AudioInterface", "Audio Interface"); + createModel(this, "MidiInterface", "MIDI Interface"); + } +}; + + +Plugin *init() { audioInit(); midiInit(); - Plugin *plugin = createPlugin("Core", "Core"); - createModel(plugin, "AudioInterface", "Audio Interface"); - createModel(plugin, "MidiInterface", "MIDI Interface"); - return plugin; + return new CorePlugin(); } diff --git a/src/core/core.hpp b/src/core/core.hpp index 434b7bc5..bf43aeef 100644 --- a/src/core/core.hpp +++ b/src/core/core.hpp @@ -3,8 +3,6 @@ using namespace rack; -Plugin *coreInit(); - void audioInit(); void midiInit(); diff --git a/src/Rack.cpp b/src/engine.cpp similarity index 54% rename from src/Rack.cpp rename to src/engine.cpp index c25acf9a..ed2b359c 100644 --- a/src/Rack.cpp +++ b/src/engine.cpp @@ -2,15 +2,20 @@ #include #include #include +#include #include +#include +#include #include #include -#include "rack.hpp" +#include "engine.hpp" namespace rack { +float gSampleRate; + /** Threads which obtain a VIPLock will cause wait() to block for other less important threads. This does not provide the VIPs with an exclusive lock. That should be left up to another mutex shared between the less important thread. */ @@ -42,90 +47,51 @@ struct VIPLock { }; -struct Rack::Impl { - bool running = false; +static bool running = false; - std::mutex mutex; - std::thread audioThread; - VIPMutex vipMutex; +static std::mutex mutex; +static std::thread thread; +static VIPMutex vipMutex; - std::set modules; - // Merely used for keeping track of which module inputs point to which module outputs, to prevent pointer mistakes and make the rack API more rigorous - std::set wires; +static std::set modules; +// Merely used for keeping track of which module inputs point to which module outputs, to prevent pointer mistakes and make the rack API more rigorous +static std::set wires; - // Parameter interpolation - Module *smoothModule = NULL; - int smoothParamId; - float smoothValue; -}; +// Parameter interpolation +static Module *smoothModule = NULL; +static int smoothParamId; +static float smoothValue; -Rack::Rack() { - impl = new Rack::Impl(); - sampleRate = 44100.0; +void engineInit() { + gSampleRate = 44100.0; } -Rack::~Rack() { +void engineDestroy() { // Make sure there are no wires or modules in the rack on destruction. This suggests that a module failed to remove itself before the GUI was destroyed. - assert(impl->wires.empty()); - assert(impl->modules.empty()); - delete impl; -} - -void Rack::start() { - impl->running = true; - impl->audioThread = std::thread(&Rack::run, this); -} - -void Rack::stop() { - impl->running = false; - impl->audioThread.join(); -} - -void Rack::run() { - // Set CPU to denormals-are-zero mode - // http://carlh.net/plugins/denormals.php - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - - // Every time the rack waits and locks a mutex, it steps this many frames - const int stepSize = 32; - - while (impl->running) { - impl->vipMutex.wait(); - - auto start = std::chrono::high_resolution_clock::now(); - { - std::lock_guard lock(impl->mutex); - for (int i = 0; i < stepSize; i++) { - step(); - } - } - auto end = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::nanoseconds((long) (0.9 * 1e9 * stepSize / sampleRate)) - (end - start); - // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate - std::this_thread::sleep_for(duration); - } + assert(wires.empty()); + assert(modules.empty()); } -void Rack::step() { +static void engineStep() { // Param interpolation - if (impl->smoothModule) { - float value = impl->smoothModule->params[impl->smoothParamId]; + if (smoothModule) { + float value = smoothModule->params[smoothParamId]; const float lambda = 60.0; // decay rate is 1 graphics frame const float snap = 0.0001; - float delta = impl->smoothValue - value; + float delta = smoothValue - value; if (fabsf(delta) < snap) { - impl->smoothModule->params[impl->smoothParamId] = impl->smoothValue; - impl->smoothModule = NULL; + smoothModule->params[smoothParamId] = smoothValue; + smoothModule = NULL; } else { - value += delta * lambda / sampleRate; - impl->smoothModule->params[impl->smoothParamId] = value; + value += delta * lambda / gSampleRate; + smoothModule->params[smoothParamId] = value; } } // Step all modules std::chrono::time_point start, end; - for (Module *module : impl->modules) { + for (Module *module : modules) { // Start clock for CPU usage start = std::chrono::high_resolution_clock::now(); // Step module by one frame @@ -133,91 +99,126 @@ void Rack::step() { // Stop clock and smooth step time value end = std::chrono::high_resolution_clock::now(); std::chrono::duration diff = end - start; - float elapsed = diff.count() * sampleRate; + float elapsed = diff.count() * gSampleRate; const float lambda = 1.0; - module->cpuTime += (elapsed - module->cpuTime) * lambda / sampleRate; + module->cpuTime += (elapsed - module->cpuTime) * lambda / gSampleRate; } // Step cables by moving their output values to inputs - for (Wire *wire : impl->wires) { + for (Wire *wire : wires) { wire->inputValue = wire->outputValue; wire->outputValue = 0.0; } } -void Rack::addModule(Module *module) { +static void engineRun() { + // Set CPU to denormals-are-zero mode + // http://carlh.net/plugins/denormals.php + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + + // Every time the engine waits and locks a mutex, it steps this many frames + const int stepSize = 32; + + while (running) { + vipMutex.wait(); + + auto start = std::chrono::high_resolution_clock::now(); + { + std::lock_guard lock(mutex); + for (int i = 0; i < stepSize; i++) { + engineStep(); + } + } + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::nanoseconds((long) (0.9 * 1e9 * stepSize / gSampleRate)) - (end - start); + // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate + std::this_thread::sleep_for(duration); + } +} + +void engineStart() { + running = true; + thread = std::thread(engineRun); +} + +void engineStop() { + running = false; + thread.join(); +} + +void engineAddModule(Module *module) { assert(module); - VIPLock vipLock(impl->vipMutex); - std::lock_guard lock(impl->mutex); + VIPLock vipLock(vipMutex); + std::lock_guard lock(mutex); // Check that the module is not already added - assert(impl->modules.find(module) == impl->modules.end()); - impl->modules.insert(module); + assert(modules.find(module) == modules.end()); + modules.insert(module); } -void Rack::removeModule(Module *module) { +void engineRemoveModule(Module *module) { assert(module); - VIPLock vipLock(impl->vipMutex); - std::lock_guard lock(impl->mutex); + VIPLock vipLock(vipMutex); + std::lock_guard lock(mutex); // Remove parameter interpolation which point to this module - if (module == impl->smoothModule) { - impl->smoothModule = NULL; + if (module == smoothModule) { + smoothModule = NULL; } // Check that all wires are disconnected - for (Wire *wire : impl->wires) { + for (Wire *wire : wires) { assert(wire->outputModule != module); assert(wire->inputModule != module); } - auto it = impl->modules.find(module); - if (it != impl->modules.end()) { - impl->modules.erase(it); + auto it = modules.find(module); + if (it != modules.end()) { + modules.erase(it); } } -void Rack::addWire(Wire *wire) { +void engineAddWire(Wire *wire) { assert(wire); - VIPLock vipLock(impl->vipMutex); - std::lock_guard lock(impl->mutex); + VIPLock vipLock(vipMutex); + std::lock_guard lock(mutex); // Check that the wire is not already added - assert(impl->wires.find(wire) == impl->wires.end()); + assert(wires.find(wire) == wires.end()); assert(wire->outputModule); assert(wire->inputModule); // Check that the inputs/outputs are not already used by another cable - for (Wire *wire2 : impl->wires) { + for (Wire *wire2 : wires) { assert(wire2 != wire); assert(!(wire2->outputModule == wire->outputModule && wire2->outputId == wire->outputId)); assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId)); } // Connect the wire to inputModule - impl->wires.insert(wire); + wires.insert(wire); wire->inputModule->inputs[wire->inputId] = &wire->inputValue; wire->outputModule->outputs[wire->outputId] = &wire->outputValue; } -void Rack::removeWire(Wire *wire) { +void engineRemoveWire(Wire *wire) { assert(wire); - VIPLock vipLock(impl->vipMutex); - std::lock_guard lock(impl->mutex); + VIPLock vipLock(vipMutex); + std::lock_guard lock(mutex); // Disconnect wire from inputModule wire->inputModule->inputs[wire->inputId] = NULL; wire->outputModule->outputs[wire->outputId] = NULL; - auto it = impl->wires.find(wire); - assert(it != impl->wires.end()); - impl->wires.erase(it); + auto it = wires.find(wire); + assert(it != wires.end()); + wires.erase(it); } -void Rack::setParamSmooth(Module *module, int paramId, float value) { - VIPLock vipLock(impl->vipMutex); - std::lock_guard lock(impl->mutex); +void engineSetParamSmooth(Module *module, int paramId, float value) { + VIPLock vipLock(vipMutex); + std::lock_guard lock(mutex); // Check existing parameter interpolation - if (impl->smoothModule) { - if (!(impl->smoothModule == module && impl->smoothParamId == paramId)) { + if (smoothModule) { + if (!(smoothModule == module && smoothParamId == paramId)) { // Jump param value to smooth value - impl->smoothModule->params[impl->smoothParamId] = impl->smoothValue; + smoothModule->params[smoothParamId] = smoothValue; } } - impl->smoothModule = module; - impl->smoothParamId = paramId; - impl->smoothValue = value; + smoothModule = module; + smoothParamId = paramId; + smoothValue = value; } diff --git a/src/gui.cpp b/src/gui.cpp index a113c803..52190683 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -1,16 +1,19 @@ -#include -#include "rack.hpp" +#include #include #include -// #define NANOVG_GLEW -#define NANOVG_IMPLEMENTATION -#include "../ext/nanovg/src/nanovg.h" +#include "gui.hpp" +#include "scene.hpp" + +// Include implementations here +// By the way, please stop packaging your libraries like this. It's easiest to use a single source file (e.g. foo.c) and a single header (e.g. foo.h) #define NANOVG_GL2_IMPLEMENTATION #include "../ext/nanovg/src/nanovg_gl.h" #define BLENDISH_IMPLEMENTATION #include "../ext/oui/blendish.h" +#define NANOSVG_IMPLEMENTATION +#include "../ext/nanosvg/src/nanosvg.h" extern "C" { #include "../ext/noc/noc_file_dialog.h" @@ -19,18 +22,9 @@ extern "C" { namespace rack { -Scene *gScene = NULL; -RackWidget *gRackWidget = NULL; - -Vec gMousePos; -Widget *gHoveredWidget = NULL; -Widget *gDraggedWidget = NULL; -Widget *gSelectedWidget = NULL; - -int gGuiFrame; - static GLFWwindow *window = NULL; static NVGcontext *vg = NULL; +static std::shared_ptr defaultFont; void windowSizeCallback(GLFWwindow* window, int width, int height) { @@ -178,7 +172,7 @@ void guiInit() { glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - window = glfwCreateWindow(1020, 700, gApplicationName.c_str(), NULL, NULL); + window = glfwCreateWindow(1000, 750, gApplicationName.c_str(), NULL, NULL); assert(window); glfwMakeContextCurrent(window); @@ -206,15 +200,13 @@ void guiInit() { assert(vg); // Set up Blendish - bndSetFont(loadFont("res/DejaVuSans.ttf")); + defaultFont = Font::load("res/DejaVuSans.ttf"); + bndSetFont(defaultFont->handle); // bndSetIconImage(loadImage("res/icons.png")); - - gScene = new Scene(); } void guiDestroy() { - delete gScene; - + defaultFont.reset(); nvgDeleteGL2(vg); glfwDestroyWindow(window); glfwTerminate(); @@ -264,61 +256,83 @@ const char *guiOpenDialog(const char *filters, const char *filename) { } +//////////////////// +// resources +//////////////////// +Font::Font(const std::string &filename) { + handle = nvgCreateFont(vg, filename.c_str(), filename.c_str()); + if (handle >= 0) { + fprintf(stderr, "Loaded font %s\n", filename.c_str()); + } + else { + fprintf(stderr, "Failed to load font %s\n", filename.c_str()); + } +} +Font::~Font() { + // There is no NanoVG deleteFont() function, so do nothing +} -std::map images; -std::map fonts; +std::shared_ptr Font::load(const std::string &filename) { + static std::map> cache; + auto sp = cache[filename].lock(); + if (!sp) + cache[filename] = sp = std::make_shared(filename); + return sp; +} -int loadImage(std::string filename) { - assert(vg); - int imageId; - auto it = images.find(filename); - if (it == images.end()) { - // Load image - imageId = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY | NVG_IMAGE_NEAREST); - if (imageId == 0) { - printf("Failed to load image %s\n", filename.c_str()); - } - else { - printf("Loaded image %s\n", filename.c_str()); - } - images[filename] = imageId; +//////////////////// +// Image +//////////////////// + +Image::Image(const std::string &filename) { + handle = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); + if (handle > 0) { + fprintf(stderr, "Loaded image %s\n", filename.c_str()); } else { - imageId = it->second; + fprintf(stderr, "Failed to load image %s\n", filename.c_str()); } - return imageId; } -int loadFont(std::string filename) { - assert(vg); - int fontId; - auto it = fonts.find(filename); - if (it == fonts.end()) { - fontId = nvgCreateFont(vg, filename.c_str(), filename.c_str()); - if (fontId < 0) { - printf("Failed to load font %s\n", filename.c_str()); - } - else { - printf("Loaded font %s\n", filename.c_str()); - } - fonts[filename] = fontId; +Image::~Image() { + // TODO What if handle is invalid? + nvgDeleteImage(vg, handle); +} + +std::shared_ptr Image::load(const std::string &filename) { + static std::map> cache; + auto sp = cache[filename].lock(); + if (!sp) + cache[filename] = sp = std::make_shared(filename); + return sp; +} + +//////////////////// +// SVG +//////////////////// + +SVG::SVG(const std::string &filename) { + image = nsvgParseFromFile(filename.c_str(), "px", 96.0); + if (image) { + fprintf(stderr, "Loaded SVG %s\n", filename.c_str()); } else { - fontId = it->second; + fprintf(stderr, "Failed to load SVG %s\n", filename.c_str()); } - return fontId; } +SVG::~SVG() { + nsvgDelete(image); +} -void drawImage(NVGcontext *vg, Vec pos, int imageId) { - int width, height; - nvgImageSize(vg, imageId, &width, &height); - NVGpaint paint = nvgImagePattern(vg, pos.x, pos.y, width, height, 0, imageId, 1.0); - nvgFillPaint(vg, paint); - nvgRect(vg, pos.x, pos.y, width, height); - nvgFill(vg); +std::shared_ptr SVG::load(const std::string &filename) { + static std::map> cache; + auto sp = cache[filename].lock(); + if (!sp) + cache[filename] = sp = std::make_shared(filename); + return sp; } diff --git a/src/main.cpp b/src/main.cpp index 9a0b1cb6..2612d491 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,16 +7,6 @@ #include "rack.hpp" -namespace rack { - -std::string gApplicationName = "VCV Rack"; -std::string gApplicationVersion = "v0.1.0 alpha"; - -Rack *gRack; - -} // namespace rack - - using namespace rack; int main() { @@ -34,18 +24,20 @@ int main() { } #endif - gRack = new Rack(); + engineInit(); guiInit(); + sceneInit(); pluginInit(); gRackWidget->loadPatch("autosave.json"); - gRack->start(); + engineStart(); guiRun(); - gRack->stop(); + engineStop(); gRackWidget->savePatch("autosave.json"); + sceneDestroy(); guiDestroy(); - delete gRack; + engineDestroy(); pluginDestroy(); return 0; } diff --git a/src/plugin.cpp b/src/plugin.cpp index 3870c76f..1c3db217 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -7,8 +7,7 @@ #include #endif -#include "rack.hpp" -#include "core/core.hpp" +#include "plugin.hpp" namespace rack { @@ -60,8 +59,10 @@ int loadPlugin(const char *path) { void pluginInit() { // Load core - Plugin *corePlugin = coreInit(); + // This function is defined in core.cpp + Plugin *corePlugin = init(); gPlugins.push_back(corePlugin); + // Search for plugin libraries #if defined(WINDOWS) WIN32_FIND_DATA ffd; diff --git a/src/scene.cpp b/src/scene.cpp new file mode 100644 index 00000000..cfbafe29 --- /dev/null +++ b/src/scene.cpp @@ -0,0 +1,22 @@ +#include "scene.hpp" + + +namespace rack { + +std::string gApplicationName = "VCV Rack"; +std::string gApplicationVersion = "v0.1.0 alpha"; + +RackWidget *gRackWidget = NULL; + + +void sceneInit() { + gScene = new RackScene(); +} + +void sceneDestroy() { + delete gScene; + gScene = NULL; +} + + +} // namespace rack diff --git a/src/widgets.cpp b/src/widgets.cpp new file mode 100644 index 00000000..09a54ec1 --- /dev/null +++ b/src/widgets.cpp @@ -0,0 +1,13 @@ +#include "widgets.hpp" + +namespace rack { + +Vec gMousePos; +Widget *gHoveredWidget = NULL; +Widget *gDraggedWidget = NULL; +Widget *gSelectedWidget = NULL; +int gGuiFrame; + +Scene *gScene = NULL; + +} // namespace rack diff --git a/src/widgets/Button.cpp b/src/widgets/Button.cpp index 23a49903..dbfa440d 100644 --- a/src/widgets/Button.cpp +++ b/src/widgets/Button.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/ChoiceButton.cpp b/src/widgets/ChoiceButton.cpp index 3e8fc75a..15481eb6 100644 --- a/src/widgets/ChoiceButton.cpp +++ b/src/widgets/ChoiceButton.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/InputPort.cpp b/src/widgets/InputPort.cpp index f91a8900..27f5b62e 100644 --- a/src/widgets/InputPort.cpp +++ b/src/widgets/InputPort.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "scene.hpp" namespace rack { diff --git a/src/widgets/Knob.cpp b/src/widgets/Knob.cpp index 178a8a5e..f51de5ee 100644 --- a/src/widgets/Knob.cpp +++ b/src/widgets/Knob.cpp @@ -1,4 +1,5 @@ -#include "rack.hpp" +#include "scene.hpp" +#include "gui.hpp" namespace rack { diff --git a/src/widgets/Label.cpp b/src/widgets/Label.cpp index aeaa32a2..3c810390 100644 --- a/src/widgets/Label.cpp +++ b/src/widgets/Label.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/Light.cpp b/src/widgets/Light.cpp index 16e079bd..d4caa354 100644 --- a/src/widgets/Light.cpp +++ b/src/widgets/Light.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "scene.hpp" namespace rack { diff --git a/src/widgets/Menu.cpp b/src/widgets/Menu.cpp index 38ba4283..00915d81 100644 --- a/src/widgets/Menu.cpp +++ b/src/widgets/Menu.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/MenuEntry.cpp b/src/widgets/MenuEntry.cpp index 84ef8d8e..1c685692 100644 --- a/src/widgets/MenuEntry.cpp +++ b/src/widgets/MenuEntry.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/MenuItem.cpp b/src/widgets/MenuItem.cpp index 4b37bf51..ccc92213 100644 --- a/src/widgets/MenuItem.cpp +++ b/src/widgets/MenuItem.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/MenuLabel.cpp b/src/widgets/MenuLabel.cpp index eb6903ed..464dd603 100644 --- a/src/widgets/MenuLabel.cpp +++ b/src/widgets/MenuLabel.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/MenuOverlay.cpp b/src/widgets/MenuOverlay.cpp index 2d2f2a92..5192219a 100644 --- a/src/widgets/MenuOverlay.cpp +++ b/src/widgets/MenuOverlay.cpp @@ -1,5 +1,4 @@ -#include "rack.hpp" - +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/ModulePanel.cpp b/src/widgets/ModulePanel.cpp index c5356c75..ec52523b 100644 --- a/src/widgets/ModulePanel.cpp +++ b/src/widgets/ModulePanel.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "scene.hpp" namespace rack { @@ -13,11 +13,10 @@ void ModulePanel::draw(NVGcontext *vg) { nvgFill(vg); // Background image - if (!imageFilename.empty()) { - int imageId = loadImage(imageFilename); + if (backgroundImage) { int width, height; - nvgImageSize(vg, imageId, &width, &height); - paint = nvgImagePattern(vg, box.pos.x, box.pos.y, width, height, 0.0, imageId, 1.0); + nvgImageSize(vg, backgroundImage->handle, &width, &height); + paint = nvgImagePattern(vg, box.pos.x, box.pos.y, width, height, 0.0, backgroundImage->handle, 1.0); nvgFillPaint(vg, paint); nvgFill(vg); } diff --git a/src/widgets/ModuleWidget.cpp b/src/widgets/ModuleWidget.cpp index bfe1d2d6..6386d020 100644 --- a/src/widgets/ModuleWidget.cpp +++ b/src/widgets/ModuleWidget.cpp @@ -1,4 +1,6 @@ -#include "rack.hpp" +#include "scene.hpp" +#include "engine.hpp" +#include "plugin.hpp" namespace rack { @@ -6,7 +8,7 @@ namespace rack { ModuleWidget::ModuleWidget(Module *module) { this->module = module; if (module) { - gRack->addModule(module); + engineAddModule(module); } } @@ -14,7 +16,7 @@ ModuleWidget::~ModuleWidget() { // Make sure WireWidget destructors are called *before* removing `module` from the rack. disconnectPorts(); if (module) { - gRack->removeModule(module); + engineRemoveModule(module); delete module; } } @@ -100,7 +102,7 @@ void ModuleWidget::draw(NVGcontext *vg) { bndBevel(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); // CPU usage text - if (gScene->toolbar->cpuUsageButton->value != 0.0) { + if (dynamic_cast(gScene)->toolbar->cpuUsageButton->value != 0.0) { float cpuTime = module ? module->cpuTime : 0.0; std::string text = stringf("%.1f%%", cpuTime * 100.0); diff --git a/src/widgets/OutputPort.cpp b/src/widgets/OutputPort.cpp index 64e8586f..32348d14 100644 --- a/src/widgets/OutputPort.cpp +++ b/src/widgets/OutputPort.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "scene.hpp" namespace rack { diff --git a/src/widgets/ParamWidget.cpp b/src/widgets/ParamWidget.cpp index 233c8829..086469a9 100644 --- a/src/widgets/ParamWidget.cpp +++ b/src/widgets/ParamWidget.cpp @@ -1,4 +1,5 @@ -#include "rack.hpp" +#include "scene.hpp" +#include "engine.hpp" namespace rack { @@ -23,7 +24,7 @@ void ParamWidget::onChange() { return; // moduleWidget->module->params[paramId] = value; - gRack->setParamSmooth(module, paramId, value); + engineSetParamSmooth(module, paramId, value); } diff --git a/src/widgets/Port.cpp b/src/widgets/Port.cpp index 2cf80cc1..0686871b 100644 --- a/src/widgets/Port.cpp +++ b/src/widgets/Port.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "scene.hpp" namespace rack { diff --git a/src/widgets/QuantityWidget.cpp b/src/widgets/QuantityWidget.cpp index 07794005..a2dcf3ad 100644 --- a/src/widgets/QuantityWidget.cpp +++ b/src/widgets/QuantityWidget.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/RackScene.cpp b/src/widgets/RackScene.cpp new file mode 100644 index 00000000..20b654a9 --- /dev/null +++ b/src/widgets/RackScene.cpp @@ -0,0 +1,28 @@ +#include "scene.hpp" + + +namespace rack { + +RackScene::RackScene() { + scrollWidget = new ScrollWidget(); + { + assert(!gRackWidget); + gRackWidget = new RackWidget(); + scrollWidget->container->addChild(gRackWidget); + } + addChild(scrollWidget); + + toolbar = new Toolbar(); + addChild(toolbar); + scrollWidget->box.pos.y = toolbar->box.size.y; +} + +void RackScene::step() { + toolbar->box.size.x = box.size.x; + scrollWidget->box.size = box.size.minus(scrollWidget->box.pos); + + Scene::step(); +} + + +} // namespace rack diff --git a/src/widgets/RackWidget.cpp b/src/widgets/RackWidget.cpp index b216d64e..323a4aad 100644 --- a/src/widgets/RackWidget.cpp +++ b/src/widgets/RackWidget.cpp @@ -1,5 +1,9 @@ -#include "rack.hpp" +#include #include +#include "scene.hpp" +#include "engine.hpp" +#include "plugin.hpp" +#include "gui.hpp" namespace rack { @@ -10,6 +14,8 @@ RackWidget::RackWidget() { wireContainer = new TransparentWidget(); addChild(wireContainer); + + railsImage = Image::load("res/rails.png"); } RackWidget::~RackWidget() { @@ -65,11 +71,11 @@ json_t *RackWidget::toJson() { json_object_set_new(root, "version", versionJ); // wireOpacity - json_t *wireOpacityJ = json_real(gScene->toolbar->wireOpacitySlider->value); + json_t *wireOpacityJ = json_real(dynamic_cast(gScene)->toolbar->wireOpacitySlider->value); json_object_set_new(root, "wireOpacity", wireOpacityJ); // wireTension - json_t *wireTensionJ = json_real(gScene->toolbar->wireTensionSlider->value); + json_t *wireTensionJ = json_real(dynamic_cast(gScene)->toolbar->wireTensionSlider->value); json_object_set_new(root, "wireTension", wireTensionJ); // modules @@ -140,12 +146,12 @@ void RackWidget::fromJson(json_t *root) { // wireOpacity json_t *wireOpacityJ = json_object_get(root, "wireOpacity"); if (wireOpacityJ) - gScene->toolbar->wireOpacitySlider->value = json_number_value(wireOpacityJ); + dynamic_cast(gScene)->toolbar->wireOpacitySlider->value = json_number_value(wireOpacityJ); // wireTension json_t *wireTensionJ = json_object_get(root, "wireTension"); if (wireTensionJ) - gScene->toolbar->wireTensionSlider->value = json_number_value(wireTensionJ); + dynamic_cast(gScene)->toolbar->wireTensionSlider->value = json_number_value(wireTensionJ); // modules std::map moduleWidgets; @@ -296,10 +302,9 @@ void RackWidget::draw(NVGcontext *vg) { nvgFill(vg); } { - int imageId = loadImage("res/rails.png"); int imageWidth, imageHeight; - nvgImageSize(vg, imageId, &imageWidth, &imageHeight); - paint = nvgImagePattern(vg, box.pos.x, box.pos.y, imageWidth, imageHeight, 0.0, imageId, 1.0); + nvgImageSize(vg, railsImage->handle, &imageWidth, &imageHeight); + paint = nvgImagePattern(vg, box.pos.x, box.pos.y, imageWidth, imageHeight, 0.0, railsImage->handle, 1.0); nvgFillPaint(vg, paint); nvgFill(vg); } diff --git a/src/widgets/RadioButton.cpp b/src/widgets/RadioButton.cpp index 02a5105c..fe8a6540 100644 --- a/src/widgets/RadioButton.cpp +++ b/src/widgets/RadioButton.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/Scene.cpp b/src/widgets/Scene.cpp index 727d0111..e215b9eb 100644 --- a/src/widgets/Scene.cpp +++ b/src/widgets/Scene.cpp @@ -1,22 +1,8 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { -Scene::Scene() { - scrollWidget = new ScrollWidget(); - { - assert(!gRackWidget); - gRackWidget = new RackWidget(); - scrollWidget->container->addChild(gRackWidget); - } - addChild(scrollWidget); - - toolbar = new Toolbar(); - addChild(toolbar); - scrollWidget->box.pos.y = toolbar->box.size.y; -} - void Scene::setOverlay(Widget *w) { if (overlay) { removeChild(overlay); @@ -31,8 +17,6 @@ void Scene::setOverlay(Widget *w) { } void Scene::step() { - toolbar->box.size.x = box.size.x; - scrollWidget->box.size = box.size.minus(scrollWidget->box.pos); if (overlay) { overlay->box.size = box.size; } diff --git a/src/widgets/Screw.cpp b/src/widgets/Screw.cpp index ac7e154d..973fd6b4 100644 --- a/src/widgets/Screw.cpp +++ b/src/widgets/Screw.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "scene.hpp" namespace rack { @@ -7,7 +7,7 @@ Screw::Screw() { box.size = Vec(15, 15); spriteOffset = Vec(-7, -7); spriteSize = Vec(29, 29); - spriteFilename = "res/screw.png"; + spriteImage = Image::load("res/screw.png"); index = randomu32() % 5; } diff --git a/src/widgets/ScrollBar.cpp b/src/widgets/ScrollBar.cpp index b66de879..ce0b049d 100644 --- a/src/widgets/ScrollBar.cpp +++ b/src/widgets/ScrollBar.cpp @@ -1,4 +1,5 @@ -#include "rack.hpp" +#include "widgets.hpp" +#include "gui.hpp" namespace rack { diff --git a/src/widgets/ScrollWidget.cpp b/src/widgets/ScrollWidget.cpp index c4a33632..6e0549ba 100644 --- a/src/widgets/ScrollWidget.cpp +++ b/src/widgets/ScrollWidget.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/Slider.cpp b/src/widgets/Slider.cpp index 29328b44..9f4414cc 100644 --- a/src/widgets/Slider.cpp +++ b/src/widgets/Slider.cpp @@ -1,4 +1,5 @@ -#include "rack.hpp" +#include "widgets.hpp" +#include "gui.hpp" namespace rack { diff --git a/src/widgets/SpriteWidget.cpp b/src/widgets/SpriteWidget.cpp index d1f97eb0..09e2981a 100644 --- a/src/widgets/SpriteWidget.cpp +++ b/src/widgets/SpriteWidget.cpp @@ -1,26 +1,20 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { void SpriteWidget::draw(NVGcontext *vg) { - int imageId = loadImage(spriteFilename); - if (imageId < 0) { - // printf("Could not load image %s for SpriteWidget\n", spriteFilename.c_str()); - return; - } - Vec pos = box.pos.plus(spriteOffset); int width, height; - nvgImageSize(vg, imageId, &width, &height); + nvgImageSize(vg, spriteImage->handle, &width, &height); int stride = width / spriteSize.x; if (stride == 0) { printf("Size of SpriteWidget is %d, %d but spriteSize is %f, %f\n", width, height, spriteSize.x, spriteSize.y); return; } Vec offset = Vec((index % stride) * spriteSize.x, (index / stride) * spriteSize.y); - NVGpaint paint = nvgImagePattern(vg, pos.x - offset.x, pos.y - offset.y, width, height, 0.0, imageId, 1.0); + NVGpaint paint = nvgImagePattern(vg, pos.x - offset.x, pos.y - offset.y, width, height, 0.0, spriteImage->handle, 1.0); nvgFillPaint(vg, paint); nvgBeginPath(vg); nvgRect(vg, pos.x, pos.y, spriteSize.x, spriteSize.y); diff --git a/src/widgets/Toolbar.cpp b/src/widgets/Toolbar.cpp index f8ad8688..c0596763 100644 --- a/src/widgets/Toolbar.cpp +++ b/src/widgets/Toolbar.cpp @@ -1,4 +1,6 @@ -#include "rack.hpp" +#include "scene.hpp" +#include "gui.hpp" +#include "engine.hpp" namespace rack { @@ -62,7 +64,7 @@ struct FileChoice : ChoiceButton { struct SampleRateItem : MenuItem { float sampleRate; void onAction() { - gRack->sampleRate = sampleRate; + gSampleRate = sampleRate; } }; @@ -85,7 +87,7 @@ struct SampleRateChoice : ChoiceButton { gScene->setOverlay(overlay); } void step() { - text = stringf("%.0f Hz", gRack->sampleRate); + text = stringf("%.0f Hz", gSampleRate); } }; diff --git a/src/widgets/Tooltip.cpp b/src/widgets/Tooltip.cpp index 3bf8de6b..a804ef18 100644 --- a/src/widgets/Tooltip.cpp +++ b/src/widgets/Tooltip.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" namespace rack { diff --git a/src/widgets/Widget.cpp b/src/widgets/Widget.cpp index 6c661d8d..280537e9 100644 --- a/src/widgets/Widget.cpp +++ b/src/widgets/Widget.cpp @@ -1,4 +1,4 @@ -#include "rack.hpp" +#include "widgets.hpp" #include diff --git a/src/widgets/WireWidget.cpp b/src/widgets/WireWidget.cpp index 1b240862..9caabc77 100644 --- a/src/widgets/WireWidget.cpp +++ b/src/widgets/WireWidget.cpp @@ -1,4 +1,5 @@ -#include "rack.hpp" +#include "scene.hpp" +#include "engine.hpp" namespace rack { @@ -112,7 +113,7 @@ WireWidget::~WireWidget() { void WireWidget::updateWire() { if (wire) { - gRack->removeWire(wire); + engineRemoveWire(wire); delete wire; wire = NULL; } @@ -122,14 +123,15 @@ void WireWidget::updateWire() { wire->outputId = outputPort->outputId; wire->inputModule = inputPort->module; wire->inputId = inputPort->inputId; - gRack->addWire(wire); + engineAddWire(wire); } } void WireWidget::draw(NVGcontext *vg) { Vec outputPos, inputPos; Vec absolutePos = getAbsolutePos(); - float opacity = gScene->toolbar->wireOpacitySlider->value / 100.0; + float opacity = dynamic_cast(gScene)->toolbar->wireOpacitySlider->value / 100.0; + float tension = dynamic_cast(gScene)->toolbar->wireTensionSlider->value; // Compute location of pos1 and pos2 if (outputPort) { @@ -150,7 +152,6 @@ void WireWidget::draw(NVGcontext *vg) { outputPos = outputPos.minus(absolutePos); inputPos = inputPos.minus(absolutePos); - float tension = gScene->toolbar->wireTensionSlider->value; drawWire(vg, outputPos, inputPos, tension, color, opacity); }