| @@ -22,11 +22,14 @@ | |||
| #include <library.hpp> | |||
| #include <keyboard.hpp> | |||
| #include <midi.hpp> | |||
| #include <patch.hpp> | |||
| #include <plugin.hpp> | |||
| #include <random.hpp> | |||
| #include <settings.hpp> | |||
| #include <system.hpp> | |||
| #include <app/Scene.hpp> | |||
| #include <engine/Engine.hpp> | |||
| #include <ui/common.hpp> | |||
| #include <window/Window.hpp> | |||
| @@ -99,38 +102,23 @@ struct Initializer { | |||
| } | |||
| INFO("Initializing environment"); | |||
| // network::init(); | |||
| audio::init(); | |||
| // rtaudioInit(); | |||
| midi::init(); | |||
| // rtmidiInit(); | |||
| keyboard::init(); | |||
| #ifndef DPF_AS_GLFW | |||
| gamepad::init(); | |||
| #endif | |||
| plugin::init(); | |||
| library::init(); | |||
| // discord::init(); | |||
| ui::init(); | |||
| window::init(); | |||
| } | |||
| ~Initializer() | |||
| { | |||
| using namespace rack; | |||
| window::destroy(); | |||
| ui::destroy(); | |||
| // discord::destroy(); | |||
| library::destroy(); | |||
| midi::destroy(); | |||
| audio::destroy(); | |||
| plugin::destroy(); | |||
| #ifndef DPF_AS_GLFW | |||
| gamepad::destroy(); | |||
| #endif | |||
| INFO("Destroying logger"); | |||
| logger::destroy(); | |||
| } | |||
| @@ -146,10 +134,46 @@ static const Initializer& getInitializerInstance() | |||
| class CardinalPlugin : public Plugin | |||
| { | |||
| rack::Context* const fContext; | |||
| struct ScopedContext { | |||
| ScopedContext(CardinalPlugin* const plugin) | |||
| { | |||
| rack::contextSet(plugin->fContext); | |||
| } | |||
| ~ScopedContext() | |||
| { | |||
| rack::contextSet(nullptr); | |||
| } | |||
| }; | |||
| public: | |||
| CardinalPlugin() | |||
| : Plugin(0, 0, 0) | |||
| : Plugin(0, 0, 0), | |||
| fContext(new rack::Context) | |||
| { | |||
| const ScopedContext sc(this); | |||
| fContext->engine = new rack::engine::Engine; | |||
| fContext->history = new rack::history::State; | |||
| fContext->event = new rack::widget::EventState; | |||
| fContext->scene = new rack::app::Scene; | |||
| fContext->event->rootWidget = fContext->scene; | |||
| fContext->patch = new rack::patch::Manager; | |||
| fContext->engine->startFallbackThread(); | |||
| } | |||
| ~CardinalPlugin() override | |||
| { | |||
| const ScopedContext sc(this); | |||
| delete fContext; | |||
| } | |||
| rack::Context* getRackContext() const noexcept | |||
| { | |||
| return fContext; | |||
| } | |||
| protected: | |||
| @@ -246,6 +270,11 @@ private: | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalPlugin) | |||
| }; | |||
| rack::Context* getRackContextFromPlugin(void* const ptr) | |||
| { | |||
| return static_cast<CardinalPlugin*>(ptr)->getRackContext(); | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Plugin entry point, called by DPF to create a new plugin instance. */ | |||
| @@ -18,9 +18,6 @@ | |||
| #include <app/common.hpp> | |||
| #include <app/Scene.hpp> | |||
| #include <context.hpp> | |||
| #include <engine/Engine.hpp> | |||
| #include <network.hpp> | |||
| #include <patch.hpp> | |||
| #include <ui/common.hpp> | |||
| #include <window/Window.hpp> | |||
| @@ -30,15 +27,6 @@ | |||
| #include "DistrhoUI.hpp" | |||
| #include "ResizeHandle.hpp" | |||
| namespace rack { | |||
| namespace network { | |||
| std::string encodeUrl(const std::string&) { return {}; } | |||
| json_t* requestJson(Method, const std::string&, json_t*, const CookieMap&) { return nullptr; } | |||
| bool requestDownload(const std::string&, const std::string&, float*, const CookieMap&) { return false; } | |||
| } | |||
| } | |||
| #ifdef DPF_AS_GLFW | |||
| GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window) { return nullptr; } | |||
| GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char*) {} | |||
| GLFWAPI const char* glfwGetKeyName(int key, int scancode) { return nullptr; } | |||
| @@ -48,89 +36,66 @@ namespace rack { | |||
| namespace window { | |||
| DISTRHO_NAMESPACE::UI* lastUI = nullptr; | |||
| void mouseButtonCallback(Window* win, int button, int action, int mods); | |||
| void cursorPosCallback(Window* win, double xpos, double ypos); | |||
| void scrollCallback(Window* win, double x, double y); | |||
| void mouseButtonCallback(Context* ctx, int button, int action, int mods); | |||
| void cursorPosCallback(Context* ctx, double xpos, double ypos); | |||
| void cursorEnterCallback(Context* ctx, int entered); | |||
| void scrollCallback(Context* ctx, double x, double y); | |||
| void charCallback(Context* ctx, unsigned int codepoint); | |||
| void keyCallback(Context* ctx, int key, int scancode, int action, int mods); | |||
| } | |||
| } | |||
| #endif | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| struct Initializer2 { | |||
| Initializer2() | |||
| { | |||
| using namespace rack; | |||
| } | |||
| ~Initializer2() | |||
| { | |||
| using namespace rack; | |||
| } | |||
| }; | |||
| static const Initializer2& getInitializer2Instance() | |||
| { | |||
| static const Initializer2 init; | |||
| return init; | |||
| } | |||
| rack::Context* getRackContextFromPlugin(void* ptr); | |||
| class CardinalUI : public UI | |||
| { | |||
| rack::Context* const fContext; | |||
| ResizeHandle fResizeHandle; | |||
| struct ScopedContext { | |||
| ScopedContext(CardinalUI* const ui) | |||
| { | |||
| rack::contextSet(ui->fContext); | |||
| } | |||
| ~ScopedContext() | |||
| { | |||
| rack::contextSet(nullptr); | |||
| } | |||
| }; | |||
| public: | |||
| CardinalUI() | |||
| : UI(1280, 720), | |||
| fContext(getRackContextFromPlugin(getPluginInstancePointer())), | |||
| fResizeHandle(this) | |||
| { | |||
| using namespace rack; | |||
| /* | |||
| The following code was based from VCVRack adapters/standalone.cpp | |||
| Copyright (C) 2016-2021 VCV | |||
| const ScopedContext sc(this); | |||
| This program is free software: you can redistribute it and/or modify it under the terms of the | |||
| GNU General Public License as published by the Free Software Foundation, either version 3 of the | |||
| License, or (at your option) any later version. | |||
| */ | |||
| // Initialize context | |||
| d_stdout("UI context ptr %p", NanoVG::getContext()); | |||
| #ifdef DPF_AS_GLFW | |||
| window::lastUI = this; | |||
| #endif | |||
| contextSet(new Context); | |||
| APP->engine = new engine::Engine; | |||
| APP->history = new history::State; | |||
| APP->event = new widget::EventState; | |||
| APP->scene = new app::Scene; | |||
| APP->event->rootWidget = APP->scene; | |||
| APP->patch = new patch::Manager; | |||
| /*if (!settings::headless)*/ { | |||
| APP->window = new window::Window; | |||
| } | |||
| #ifdef DPF_AS_GLFW | |||
| window::lastUI = nullptr; | |||
| #endif | |||
| APP->engine->startFallbackThread(); | |||
| rack::window::lastUI = this; | |||
| fContext->window = new rack::window::Window; | |||
| rack::window::lastUI = nullptr; | |||
| } | |||
| ~CardinalUI() override | |||
| { | |||
| using namespace rack; | |||
| const ScopedContext sc(this); | |||
| delete APP; | |||
| contextSet(NULL); | |||
| delete fContext->window; | |||
| fContext->window = nullptr; | |||
| } | |||
| void onNanoDisplay() override | |||
| { | |||
| APP->window->step(); | |||
| const ScopedContext sc(this); | |||
| fContext->window->step(); | |||
| } | |||
| void uiIdle() override | |||
| @@ -152,9 +117,10 @@ protected: | |||
| // ------------------------------------------------------------------------------------------------------- | |||
| #ifdef DPF_AS_GLFW | |||
| bool onMouse(const MouseEvent& ev) override | |||
| { | |||
| const ScopedContext sc(this); | |||
| int button; | |||
| int mods = 0; | |||
| int action = ev.press; | |||
| @@ -206,22 +172,25 @@ protected: | |||
| } | |||
| #endif | |||
| mouseButtonCallback(APP->window, button, action, mods); | |||
| rack::window::mouseButtonCallback(fContext, button, action, mods); | |||
| return true; | |||
| } | |||
| bool onMotion(const MotionEvent& ev) override | |||
| { | |||
| cursorPosCallback(APP->window, ev.pos.getX(), ev.pos.getY()); | |||
| const ScopedContext sc(this); | |||
| rack::window::cursorPosCallback(fContext, ev.pos.getX(), ev.pos.getY()); | |||
| return true; | |||
| } | |||
| bool onScroll(const ScrollEvent& ev) override | |||
| { | |||
| scrollCallback(APP->window, ev.delta.getX(), ev.delta.getY()); | |||
| const ScopedContext sc(this); | |||
| rack::window::scrollCallback(fContext, ev.delta.getX(), ev.delta.getY()); | |||
| return true; | |||
| } | |||
| #endif | |||
| #if 0 | |||
| void onResize(const ResizeEvent& ev) override | |||
| @@ -233,6 +202,36 @@ protected: | |||
| // TODO uiFocus | |||
| bool onCharacterInput(const CharacterInputEvent& ev) override | |||
| { | |||
| if (ev.character == 0) | |||
| return false; | |||
| const ScopedContext sc(this); | |||
| rack::window::charCallback(fContext, ev.character); | |||
| return true; | |||
| } | |||
| bool onKeyboard(const KeyboardEvent& ev) override | |||
| { | |||
| const ScopedContext sc(this); | |||
| int mods = 0; | |||
| int action = ev.press; | |||
| if (ev.mod & kModifierControl) | |||
| mods |= GLFW_MOD_CONTROL; | |||
| if (ev.mod & kModifierShift) | |||
| mods |= GLFW_MOD_SHIFT; | |||
| if (ev.mod & kModifierAlt) | |||
| mods |= GLFW_MOD_ALT; | |||
| // TODO special key conversion | |||
| rack::window::keyCallback(fContext, ev.key, ev.keycode, action, mods); | |||
| return true; | |||
| } | |||
| private: | |||
| /** | |||
| Set our UI class as non-copyable and add a leak detector just in case. | |||
| @@ -245,7 +244,6 @@ private: | |||
| UI* createUI() | |||
| { | |||
| getInitializer2Instance(); | |||
| return new CardinalUI(); | |||
| } | |||
| @@ -28,12 +28,9 @@ | |||
| #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | |||
| // #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" | |||
| // #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Analyzer" | |||
| // #define DISTRHO_PLUGIN_HAS_EMBED_UI 1 | |||
| // #define DISTRHO_PLUGIN_HAS_EXTERNAL_UI 1 | |||
| #define DISTRHO_UI_USE_NANOVG 1 | |||
| #define DISTRHO_UI_USER_RESIZABLE 0 | |||
| #define DPF_AS_GLFW 1 | |||
| #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | |||
| enum Parameters { | |||
| kParameterCount | |||
| @@ -16,15 +16,13 @@ FILES_DSP = \ | |||
| CardinalPlugin.cpp | |||
| FILES_UI = \ | |||
| CardinalUI.cpp | |||
| FILES_UI += dep.cpp | |||
| FILES_UI += Window.cpp | |||
| CardinalUI.cpp \ | |||
| dep.cpp \ | |||
| Window.cpp | |||
| # -------------------------------------------------------------- | |||
| # Import base definitions | |||
| # UI_TYPE = external | |||
| USE_NANOVG_FBO = true | |||
| include ../../dpf/Makefile.base.mk | |||
| @@ -35,7 +33,6 @@ FILES_DSP += Rack/dep/pffft/pffft.c | |||
| FILES_DSP += Rack/dep/pffft/fftpack.c | |||
| FILES_UI += Rack/dep/oui-blendish/blendish.c | |||
| # FILES_UI += Rack/dep/nanovg/src/nanovg.c | |||
| # FIXME dont use this | |||
| FILES_UI += Rack/dep/osdialog/osdialog.c | |||
| @@ -63,10 +60,6 @@ endif | |||
| EXTRA_LIBS += Rack/dep/lib/libzstd.a | |||
| # for raw GLFW window | |||
| # EXTRA_LIBS += Rack/dep/lib/libglfw3.a | |||
| # FILES_DSP += Rack/src/gamepad.cpp Rack/src/window/Window.cpp | |||
| # -------------------------------------------------------------- | |||
| # Do some magic | |||
| @@ -87,8 +80,6 @@ Rack/dep/lib/libarchive.a: Rack/dep/lib/libzstd.a | |||
| Rack/dep/lib/libarchive_static.a: Rack/dep/lib/libzstd.a | |||
| Rack/dep/lib/libcrypto.a: Rack/dep/lib/libssl.a | |||
| # -------------------------------------------------------------- | |||
| # Extra flags for VCV stuff | |||
| @@ -98,10 +89,7 @@ BASE_FLAGS += -IRack/include | |||
| BASE_FLAGS += -IRack/dep/include | |||
| BASE_FLAGS += -IRack/dep/filesystem/include | |||
| BASE_FLAGS += -IRack/dep/fuzzysearchdatabase/src | |||
| # BASE_FLAGS += -IRack/dep/glew-2.1.0/include | |||
| # BASE_FLAGS += -IRack/dep/glfw/deps | |||
| BASE_FLAGS += -IRack/dep/glfw/include | |||
| # BASE_FLAGS += -IRack/dep/nanovg/src | |||
| BASE_FLAGS += -IRack/dep/nanosvg/src | |||
| BASE_FLAGS += -IRack/dep/osdialog | |||
| BASE_FLAGS += -IRack/dep/oui-blendish | |||
| @@ -363,7 +363,7 @@ bool& Window::fbDirtyOnSubpixelChange() { | |||
| } | |||
| void mouseButtonCallback(Window* win, int button, int action, int mods) { | |||
| void mouseButtonCallback(Context* ctx, int button, int action, int mods) { | |||
| /* | |||
| #if defined ARCH_MAC | |||
| // Remap Ctrl-left click to right click on Mac | |||
| @@ -379,29 +379,35 @@ void mouseButtonCallback(Window* win, int button, int action, int mods) { | |||
| #endif | |||
| */ | |||
| APP->event->handleButton(win->internal->lastMousePos, button, action, mods); | |||
| ctx->event->handleButton(ctx->window->internal->lastMousePos, button, action, mods); | |||
| } | |||
| void cursorPosCallback(Window* win, double xpos, double ypos) { | |||
| math::Vec mousePos = math::Vec(xpos, ypos).div(win->pixelRatio / win->windowRatio).round(); | |||
| math::Vec mouseDelta = mousePos.minus(win->internal->lastMousePos); | |||
| void cursorPosCallback(Context* ctx, double xpos, double ypos) { | |||
| math::Vec mousePos = math::Vec(xpos, ypos).div(ctx->window->pixelRatio / ctx->window->windowRatio).round(); | |||
| math::Vec mouseDelta = mousePos.minus(ctx->window->internal->lastMousePos); | |||
| // Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. | |||
| if (win->internal->ignoreNextMouseDelta) { | |||
| win->internal->ignoreNextMouseDelta = false; | |||
| if (ctx->window->internal->ignoreNextMouseDelta) { | |||
| ctx->window->internal->ignoreNextMouseDelta = false; | |||
| mouseDelta = math::Vec(); | |||
| } | |||
| win->internal->lastMousePos = mousePos; | |||
| ctx->window->internal->lastMousePos = mousePos; | |||
| APP->event->handleHover(mousePos, mouseDelta); | |||
| ctx->event->handleHover(mousePos, mouseDelta); | |||
| // Keyboard/mouse MIDI driver | |||
| math::Vec scaledPos(xpos / win->internal->ui->getWidth(), ypos / win->internal->ui->getHeight()); | |||
| math::Vec scaledPos(xpos / ctx->window->internal->ui->getWidth(), ypos / ctx->window->internal->ui->getHeight()); | |||
| keyboard::mouseMove(scaledPos); | |||
| } | |||
| void scrollCallback(Window* win, double x, double y) { | |||
| void cursorEnterCallback(Context* ctx, int entered) { | |||
| if (!entered) { | |||
| ctx->event->handleLeave(); | |||
| } | |||
| } | |||
| void scrollCallback(Context* ctx, double x, double y) { | |||
| math::Vec scrollDelta = math::Vec(x, y); | |||
| #if defined ARCH_MAC | |||
| scrollDelta = scrollDelta.mult(10.0); | |||
| @@ -409,14 +415,25 @@ void scrollCallback(Window* win, double x, double y) { | |||
| scrollDelta = scrollDelta.mult(50.0); | |||
| #endif | |||
| APP->event->handleScroll(win->internal->lastMousePos, scrollDelta); | |||
| ctx->event->handleScroll(ctx->window->internal->lastMousePos, scrollDelta); | |||
| } | |||
| void init() { | |||
| void charCallback(Context* ctx, unsigned int codepoint) { | |||
| if (ctx->event->handleText(ctx->window->internal->lastMousePos, codepoint)) | |||
| return; | |||
| } | |||
| void destroy() { | |||
| void keyCallback(Context* ctx, int key, int scancode, int action, int mods) { | |||
| if (ctx->event->handleKey(ctx->window->internal->lastMousePos, key, scancode, action, mods)) | |||
| return; | |||
| // Keyboard/mouse MIDI driver | |||
| if (action == GLFW_PRESS && (mods & RACK_MOD_MASK) == 0) { | |||
| keyboard::press(key); | |||
| } | |||
| if (action == GLFW_RELEASE) { | |||
| keyboard::release(key); | |||
| } | |||
| } | |||
| @@ -13,3 +13,13 @@ | |||
| #define NANOSVG_IMPLEMENTATION | |||
| #define NANOSVG_ALL_COLOR_KEYWORDS | |||
| #include <nanosvg.h> | |||
| #include <network.hpp> | |||
| namespace rack { | |||
| namespace network { | |||
| std::string encodeUrl(const std::string&) { return {}; } | |||
| json_t* requestJson(Method, const std::string&, json_t*, const CookieMap&) { return nullptr; } | |||
| bool requestDownload(const std::string&, const std::string&, float*, const CookieMap&) { return false; } | |||
| } | |||
| } | |||