Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
@@ -1 +1 @@ | |||
Subproject commit 564f6519b4bbf1c6cc8791a9adbb377f6cfd4984 | |||
Subproject commit 79948069d581c64bd19bc454234550de88b459a2 |
@@ -293,6 +293,10 @@ PLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp | |||
PLUGIN_FILES += Cardinal/src/SassyScope.cpp | |||
PLUGIN_FILES += Cardinal/src/DearImGui.cpp | |||
PLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp | |||
MINIPLUGIN_FILES += Cardinal/src/ImGuiWidget.cpp | |||
MINIPLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp | |||
MINIPLUGIN_FILES += Cardinal/src/DearImGui.cpp | |||
MINIPLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp | |||
endif | |||
ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) | |||
@@ -1290,7 +1294,7 @@ endif | |||
ifeq ($(NOPLUGINS),true) | |||
TARGETS = noplugins$(TARGET_SUFFIX).a | |||
else | |||
TARGETS = plugins$(TARGET_SUFFIX).a plugins-mini-headless.a | |||
TARGETS = plugins$(TARGET_SUFFIX).a plugins-mini.a | |||
endif | |||
all: $(TARGETS) | |||
@@ -189,6 +189,7 @@ void destroyStaticPlugins() | |||
void updateStaticPluginsDarkMode() | |||
{ | |||
d_stdout("TODO"); | |||
} | |||
} | |||
@@ -38,6 +38,7 @@ | |||
#include <settings.hpp> | |||
#include <string.hpp> | |||
#include <system.hpp> | |||
#include <app/Browser.hpp> | |||
#include <app/Scene.hpp> | |||
#include <window/Window.hpp> | |||
@@ -65,6 +66,27 @@ | |||
# define HEADLESS | |||
#endif | |||
#if CARDINAL_VARIANT_FX | |||
# define CARDINAL_TEMPLATE_NAME "init/fx.vcv" | |||
#elif CARDINAL_VARIANT_NATIVE | |||
# define CARDINAL_TEMPLATE_NAME "init/native.vcv" | |||
#elif CARDINAL_VARIANT_SYNTH | |||
# define CARDINAL_TEMPLATE_NAME "init/synth.vcv" | |||
#else | |||
# define CARDINAL_TEMPLATE_NAME "init/main.vcv" | |||
#endif | |||
namespace rack { | |||
namespace asset { | |||
std::string patchesPath(); | |||
void destroy(); | |||
} | |||
namespace plugin { | |||
void initStaticPlugins(); | |||
void destroyStaticPlugins(); | |||
} | |||
} | |||
const std::string CARDINAL_VERSION = "22.12"; | |||
START_NAMESPACE_DISTRHO | |||
@@ -172,6 +194,284 @@ void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, | |||
plugin->writeMidiEvent(event); | |||
} | |||
// ----------------------------------------------------------------------------------------------------------- | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
static void osc_error_handler(int num, const char* msg, const char* path) | |||
{ | |||
d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path); | |||
} | |||
static int osc_fallback_handler(const char* const path, const char* const types, lo_arg**, int, lo_message, void*) | |||
{ | |||
d_stderr("Cardinal OSC unhandled message \"%s\" with types \"%s\"", path, types); | |||
return 0; | |||
} | |||
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self) | |||
{ | |||
d_stdout("osc_hello_handler()"); | |||
const lo_address source = lo_message_get_source(m); | |||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); | |||
return 0; | |||
} | |||
static int osc_load_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||
{ | |||
d_stdout("osc_load_handler()"); | |||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||
const int32_t size = argv[0]->blob.size; | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||
bool ok = false; | |||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||
{ | |||
CardinalPluginContext* const context = plugin->context; | |||
std::vector<uint8_t> data(size); | |||
std::memcpy(data.data(), blob, size); | |||
rack::contextSet(context); | |||
rack::system::removeRecursively(context->patch->autosavePath); | |||
rack::system::createDirectories(context->patch->autosavePath); | |||
try { | |||
rack::system::unarchiveToDirectory(data, context->patch->autosavePath); | |||
context->patch->loadAutosave(); | |||
ok = true; | |||
} | |||
catch (rack::Exception& e) { | |||
WARN("%s", e.what()); | |||
} | |||
rack::contextSet(nullptr); | |||
} | |||
const lo_address source = lo_message_get_source(m); | |||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||
LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); | |||
return 0; | |||
} | |||
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||
{ | |||
d_stdout("osc_screenshot_handler()"); | |||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||
const int32_t size = argv[0]->blob.size; | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||
bool ok = false; | |||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||
ok = plugin->updateStateValue("screenshot", String::asBase64(blob, size).buffer()); | |||
const lo_address source = lo_message_get_source(m); | |||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||
LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); | |||
return 0; | |||
} | |||
#endif | |||
Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalBaseUI* const ui) | |||
{ | |||
using namespace rack; | |||
#ifdef DISTRHO_OS_WASM | |||
settings::allowCursorLock = true; | |||
#else | |||
settings::allowCursorLock = false; | |||
#endif | |||
settings::autoCheckUpdates = false; | |||
settings::autosaveInterval = 0; | |||
settings::devMode = true; | |||
settings::isPlugin = true; | |||
settings::skipLoadOnLaunch = true; | |||
settings::showTipsOnLaunch = false; | |||
settings::windowPos = math::Vec(0, 0); | |||
#ifdef HEADLESS | |||
settings::headless = true; | |||
#endif | |||
// copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 | |||
settings::cableColors = { | |||
color::fromHexString("#ff5252"), | |||
color::fromHexString("#ff9352"), | |||
color::fromHexString("#ffd452"), | |||
color::fromHexString("#e8ff52"), | |||
color::fromHexString("#a8ff52"), | |||
color::fromHexString("#67ff52"), | |||
color::fromHexString("#52ff7d"), | |||
color::fromHexString("#52ffbe"), | |||
color::fromHexString("#52ffff"), | |||
color::fromHexString("#52beff"), | |||
color::fromHexString("#527dff"), | |||
color::fromHexString("#6752ff"), | |||
color::fromHexString("#a852ff"), | |||
color::fromHexString("#e952ff"), | |||
color::fromHexString("#ff52d4"), | |||
color::fromHexString("#ff5293"), | |||
}; | |||
system::init(); | |||
logger::init(); | |||
random::init(); | |||
ui::init(); | |||
if (asset::systemDir.empty()) | |||
{ | |||
if (const char* const bundlePath = (plugin != nullptr ? plugin->getBundlePath() : | |||
ui != nullptr ? ui->getBundlePath() : nullptr)) | |||
{ | |||
if (const char* const resourcePath = getResourcePath(bundlePath)) | |||
{ | |||
asset::systemDir = resourcePath; | |||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||
} | |||
} | |||
if (asset::systemDir.empty() || ! system::exists(asset::systemDir) || ! system::exists(asset::bundlePath)) | |||
{ | |||
#ifdef CARDINAL_PLUGIN_SOURCE_DIR | |||
// Make system dir point to source code location as fallback | |||
asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; | |||
asset::bundlePath.clear(); | |||
// If source code dir does not exist use install target prefix as system dir | |||
if (!system::exists(system::join(asset::systemDir, "res"))) | |||
#endif | |||
{ | |||
#if defined(DISTRHO_OS_WASM) | |||
asset::systemDir = "/resources"; | |||
#elif defined(ARCH_MAC) | |||
asset::systemDir = "/Library/Application Support/Cardinal"; | |||
#elif defined(ARCH_WIN) | |||
const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); | |||
if (! commonprogfiles.empty()) | |||
asset::systemDir = system::join(commonprogfiles, "Cardinal"); | |||
#else | |||
asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | |||
#endif | |||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||
} | |||
} | |||
asset::userDir = asset::systemDir; | |||
} | |||
const std::string patchesPath = asset::patchesPath(); | |||
#ifdef DISTRHO_OS_WASM | |||
templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); | |||
#else | |||
templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||
#endif | |||
factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||
// Log environment | |||
INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); | |||
INFO("%s", system::getOperatingSystemInfo().c_str()); | |||
INFO("Binary filename: %s", getBinaryFilename()); | |||
if (plugin != nullptr) { | |||
INFO("Bundle path: %s", plugin->getBundlePath()); | |||
} else if (ui != nullptr) { | |||
INFO("Bundle path: %s", ui->getBundlePath()); | |||
} | |||
INFO("System directory: %s", asset::systemDir.c_str()); | |||
INFO("User directory: %s", asset::userDir.c_str()); | |||
INFO("Template patch: %s", templatePath.c_str()); | |||
INFO("System template patch: %s", factoryTemplatePath.c_str()); | |||
// Report to user if something is wrong with the installation | |||
if (asset::systemDir.empty()) | |||
{ | |||
d_stderr2("Failed to locate Cardinal plugin bundle.\n" | |||
"Install Cardinal with its bundle folder intact and try again."); | |||
} | |||
else if (! system::exists(asset::systemDir)) | |||
{ | |||
d_stderr2("System directory \"%s\" does not exist.\n" | |||
"Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); | |||
} | |||
INFO("Initializing plugins"); | |||
plugin::initStaticPlugins(); | |||
INFO("Initializing plugin browser DB"); | |||
app::browserInit(); | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
INFO("Initializing OSC Remote control"); | |||
oscServer = lo_server_new_with_proto(REMOTE_HOST_PORT, LO_UDP, osc_error_handler); | |||
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); | |||
lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this); | |||
lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this); | |||
lo_server_add_method(oscServer, "/screenshot", "b", osc_screenshot_handler, this); | |||
lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr); | |||
startThread(); | |||
#else | |||
INFO("OSC Remote control is not enabled in this build"); | |||
#endif | |||
} | |||
Initializer::~Initializer() | |||
{ | |||
using namespace rack; | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
if (oscServer != nullptr) | |||
{ | |||
stopThread(5000); | |||
lo_server_del_method(oscServer, nullptr, nullptr); | |||
lo_server_free(oscServer); | |||
oscServer = nullptr; | |||
} | |||
#endif | |||
INFO("Clearing asset paths"); | |||
asset::bundlePath.clear(); | |||
asset::systemDir.clear(); | |||
asset::userDir.clear(); | |||
INFO("Destroying plugins"); | |||
plugin::destroyStaticPlugins(); | |||
INFO("Destroying colourized assets"); | |||
asset::destroy(); | |||
INFO("Destroying settings"); | |||
settings::destroy(); | |||
INFO("Destroying logger"); | |||
logger::destroy(); | |||
} | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
void Initializer::run() | |||
{ | |||
INFO("OSC Thread Listening for remote commands"); | |||
while (! shouldThreadExit()) | |||
{ | |||
d_msleep(200); | |||
while (lo_server_recv_noblock(oscServer, 0) != 0) {} | |||
} | |||
INFO("OSC Thread Closed"); | |||
} | |||
#endif | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
@@ -15,14 +15,17 @@ | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#include <string> | |||
#pragma once | |||
#include "DistrhoUtils.hpp" | |||
#include <string> | |||
#ifdef HAVE_LIBLO | |||
// # define REMOTE_HOST "localhost" | |||
# define REMOTE_HOST "192.168.51.1" | |||
# define REMOTE_HOST_PORT "2228" | |||
# include "extra/Thread.hpp" | |||
#endif | |||
#ifdef DISTRHO_OS_WASM | |||
@@ -35,6 +38,8 @@ | |||
extern const std::string CARDINAL_VERSION; | |||
// ----------------------------------------------------------------------------------------------------------- | |||
namespace rack { | |||
namespace ui { | |||
@@ -65,6 +70,8 @@ extern char* patchStorageSlug; | |||
} // namespace rack | |||
// ----------------------------------------------------------------------------------------------------------- | |||
namespace patchUtils { | |||
void loadDialog(); | |||
@@ -86,3 +93,37 @@ void deployToRemote(); | |||
void sendScreenshotToRemote(const char* screenshot); | |||
} // namespace patchUtils | |||
// ----------------------------------------------------------------------------------------------------------- | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
# define CARDINAL_INIT_OSC_THREAD | |||
#endif | |||
START_NAMESPACE_DISTRHO | |||
class CardinalBasePlugin; | |||
class CardinalBaseUI; | |||
struct Initializer | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
: public Thread | |||
#endif | |||
{ | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
lo_server oscServer = nullptr; | |||
CardinalBasePlugin* oscPlugin = nullptr; | |||
#endif | |||
std::string templatePath; | |||
std::string factoryTemplatePath; | |||
Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui); | |||
~Initializer(); | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
void run() override; | |||
#endif | |||
}; | |||
END_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------------------------------------------- |
@@ -31,8 +31,8 @@ | |||
#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#mini" | |||
#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#mini" | |||
#define DISTRHO_PLUGIN_NAME "Cardinal FX" | |||
#define DISTRHO_PLUGIN_LABEL "CardinalFX" | |||
#define DISTRHO_PLUGIN_NAME "Cardinal Mini" | |||
#define DISTRHO_PLUGIN_LABEL "CardinalMini" | |||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||
#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | |||
@@ -15,7 +15,6 @@ | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#include <asset.hpp> | |||
#include <library.hpp> | |||
#include <midi.hpp> | |||
#include <patch.hpp> | |||
@@ -24,7 +23,6 @@ | |||
#include <settings.hpp> | |||
#include <system.hpp> | |||
#include <app/Browser.hpp> | |||
#include <app/Scene.hpp> | |||
#include <engine/Engine.hpp> | |||
#include <ui/common.hpp> | |||
@@ -52,16 +50,6 @@ | |||
# include "extra/SharedResourcePointer.hpp" | |||
#endif | |||
#if CARDINAL_VARIANT_FX | |||
# define CARDINAL_TEMPLATE_NAME "init/fx.vcv" | |||
#elif CARDINAL_VARIANT_NATIVE | |||
# define CARDINAL_TEMPLATE_NAME "init/native.vcv" | |||
#elif CARDINAL_VARIANT_SYNTH | |||
# define CARDINAL_TEMPLATE_NAME "init/synth.vcv" | |||
#else | |||
# define CARDINAL_TEMPLATE_NAME "init/main.vcv" | |||
#endif | |||
static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment | |||
#ifndef HEADLESS | |||
@@ -76,17 +64,9 @@ static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount; | |||
extern const std::string CARDINAL_VERSION; | |||
namespace rack { | |||
namespace asset { | |||
std::string patchesPath(); | |||
void destroy(); | |||
} | |||
namespace engine { | |||
void Engine_setAboutToClose(Engine*); | |||
} | |||
namespace plugin { | |||
void initStaticPlugins(); | |||
void destroyStaticPlugins(); | |||
} | |||
} | |||
START_NAMESPACE_DISTRHO | |||
@@ -98,6 +78,10 @@ bool d_isDiffHigherThanLimit(const T& v1, const T& v2, const T& limit) | |||
return v1 != v2 ? (v1 > v2 ? v1 - v2 : v2 - v1) > limit : false; | |||
} | |||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
const char* UI::getBundlePath() const noexcept { return nullptr; } | |||
#endif | |||
// ----------------------------------------------------------------------------------------------------------- | |||
#ifdef DISTRHO_OS_WASM | |||
@@ -143,288 +127,6 @@ static char* getPatchStorageSlug() { | |||
// ----------------------------------------------------------------------------------------------------------- | |||
struct Initializer | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
: public Thread | |||
#endif | |||
{ | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
lo_server oscServer = nullptr; | |||
CardinalBasePlugin* oscPlugin = nullptr; | |||
#endif | |||
std::string templatePath; | |||
std::string factoryTemplatePath; | |||
Initializer(const CardinalBasePlugin* const plugin) | |||
{ | |||
using namespace rack; | |||
#ifdef DISTRHO_OS_WASM | |||
settings::allowCursorLock = true; | |||
#else | |||
settings::allowCursorLock = false; | |||
#endif | |||
settings::autoCheckUpdates = false; | |||
settings::autosaveInterval = 0; | |||
settings::devMode = true; | |||
settings::isPlugin = true; | |||
settings::skipLoadOnLaunch = true; | |||
settings::showTipsOnLaunch = false; | |||
settings::windowPos = math::Vec(0, 0); | |||
#ifdef HEADLESS | |||
settings::headless = true; | |||
#endif | |||
// copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 | |||
settings::cableColors = { | |||
color::fromHexString("#ff5252"), | |||
color::fromHexString("#ff9352"), | |||
color::fromHexString("#ffd452"), | |||
color::fromHexString("#e8ff52"), | |||
color::fromHexString("#a8ff52"), | |||
color::fromHexString("#67ff52"), | |||
color::fromHexString("#52ff7d"), | |||
color::fromHexString("#52ffbe"), | |||
color::fromHexString("#52ffff"), | |||
color::fromHexString("#52beff"), | |||
color::fromHexString("#527dff"), | |||
color::fromHexString("#6752ff"), | |||
color::fromHexString("#a852ff"), | |||
color::fromHexString("#e952ff"), | |||
color::fromHexString("#ff52d4"), | |||
color::fromHexString("#ff5293"), | |||
}; | |||
system::init(); | |||
logger::init(); | |||
random::init(); | |||
ui::init(); | |||
if (asset::systemDir.empty()) | |||
{ | |||
if (const char* const bundlePath = plugin->getBundlePath()) | |||
{ | |||
if (const char* const resourcePath = getResourcePath(bundlePath)) | |||
{ | |||
asset::systemDir = resourcePath; | |||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||
} | |||
} | |||
if (asset::systemDir.empty() || ! system::exists(asset::systemDir) || ! system::exists(asset::bundlePath)) | |||
{ | |||
#ifdef CARDINAL_PLUGIN_SOURCE_DIR | |||
// Make system dir point to source code location as fallback | |||
asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; | |||
asset::bundlePath.clear(); | |||
// If source code dir does not exist use install target prefix as system dir | |||
if (!system::exists(system::join(asset::systemDir, "res"))) | |||
#endif | |||
{ | |||
#if defined(DISTRHO_OS_WASM) | |||
asset::systemDir = "/resources"; | |||
#elif defined(ARCH_MAC) | |||
asset::systemDir = "/Library/Application Support/Cardinal"; | |||
#elif defined(ARCH_WIN) | |||
const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); | |||
if (! commonprogfiles.empty()) | |||
asset::systemDir = system::join(commonprogfiles, "Cardinal"); | |||
#else | |||
asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | |||
#endif | |||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||
} | |||
} | |||
asset::userDir = asset::systemDir; | |||
} | |||
const std::string patchesPath = asset::patchesPath(); | |||
#ifdef DISTRHO_OS_WASM | |||
templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); | |||
#else | |||
templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||
#endif | |||
factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||
// Log environment | |||
INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); | |||
INFO("%s", system::getOperatingSystemInfo().c_str()); | |||
INFO("Binary filename: %s", getBinaryFilename()); | |||
INFO("Bundle path: %s", plugin->getBundlePath()); | |||
INFO("System directory: %s", asset::systemDir.c_str()); | |||
INFO("User directory: %s", asset::userDir.c_str()); | |||
INFO("Template patch: %s", templatePath.c_str()); | |||
INFO("System template patch: %s", factoryTemplatePath.c_str()); | |||
// Report to user if something is wrong with the installation | |||
if (asset::systemDir.empty()) | |||
{ | |||
d_stderr2("Failed to locate Cardinal plugin bundle.\n" | |||
"Install Cardinal with its bundle folder intact and try again."); | |||
} | |||
else if (! system::exists(asset::systemDir)) | |||
{ | |||
d_stderr2("System directory \"%s\" does not exist.\n" | |||
"Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); | |||
} | |||
INFO("Initializing plugins"); | |||
plugin::initStaticPlugins(); | |||
INFO("Initializing plugin browser DB"); | |||
app::browserInit(); | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
INFO("Initializing OSC Remote control"); | |||
oscServer = lo_server_new_with_proto(REMOTE_HOST_PORT, LO_UDP, osc_error_handler); | |||
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); | |||
lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this); | |||
lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this); | |||
lo_server_add_method(oscServer, "/screenshot", "b", osc_screenshot_handler, this); | |||
lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr); | |||
startThread(); | |||
#elif defined(HEADLESS) | |||
INFO("OSC Remote control is not enabled in this build"); | |||
#endif | |||
} | |||
~Initializer() | |||
{ | |||
using namespace rack; | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
if (oscServer != nullptr) | |||
{ | |||
stopThread(5000); | |||
lo_server_del_method(oscServer, nullptr, nullptr); | |||
lo_server_free(oscServer); | |||
oscServer = nullptr; | |||
} | |||
#endif | |||
INFO("Clearing asset paths"); | |||
asset::bundlePath.clear(); | |||
asset::systemDir.clear(); | |||
asset::userDir.clear(); | |||
INFO("Destroying plugins"); | |||
plugin::destroyStaticPlugins(); | |||
INFO("Destroying colourized assets"); | |||
asset::destroy(); | |||
INFO("Destroying settings"); | |||
settings::destroy(); | |||
INFO("Destroying logger"); | |||
logger::destroy(); | |||
} | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
void run() override | |||
{ | |||
INFO("OSC Thread Listening for remote commands"); | |||
while (! shouldThreadExit()) | |||
{ | |||
d_msleep(200); | |||
while (lo_server_recv_noblock(oscServer, 0) != 0) {} | |||
} | |||
INFO("OSC Thread Closed"); | |||
} | |||
static void osc_error_handler(int num, const char* msg, const char* path) | |||
{ | |||
d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path); | |||
} | |||
static int osc_fallback_handler(const char* const path, const char* const types, lo_arg**, int, lo_message, void*) | |||
{ | |||
d_stderr("Cardinal OSC unhandled message \"%s\" with types \"%s\"", path, types); | |||
return 0; | |||
} | |||
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self) | |||
{ | |||
d_stdout("osc_hello_handler()"); | |||
const lo_address source = lo_message_get_source(m); | |||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); | |||
return 0; | |||
} | |||
static int osc_load_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||
{ | |||
d_stdout("osc_load_handler()"); | |||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||
const int32_t size = argv[0]->blob.size; | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||
bool ok = false; | |||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||
{ | |||
CardinalPluginContext* const context = plugin->context; | |||
std::vector<uint8_t> data(size); | |||
std::memcpy(data.data(), blob, size); | |||
rack::contextSet(context); | |||
rack::system::removeRecursively(context->patch->autosavePath); | |||
rack::system::createDirectories(context->patch->autosavePath); | |||
try { | |||
rack::system::unarchiveToDirectory(data, context->patch->autosavePath); | |||
context->patch->loadAutosave(); | |||
ok = true; | |||
} | |||
catch (rack::Exception& e) { | |||
WARN("%s", e.what()); | |||
} | |||
rack::contextSet(nullptr); | |||
} | |||
const lo_address source = lo_message_get_source(m); | |||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||
LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); | |||
return 0; | |||
} | |||
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||
{ | |||
d_stdout("osc_screenshot_handler()"); | |||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||
const int32_t size = argv[0]->blob.size; | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||
bool ok = false; | |||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||
ok = plugin->updateStateValue("screenshot", String::asBase64(blob, size).buffer()); | |||
const lo_address source = lo_message_get_source(m); | |||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||
LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); | |||
return 0; | |||
} | |||
#endif | |||
}; | |||
// ----------------------------------------------------------------------------------------------------------- | |||
struct ScopedContext { | |||
ScopedContext(const CardinalBasePlugin* const plugin) | |||
{ | |||
@@ -479,9 +181,9 @@ public: | |||
CardinalPlugin() | |||
: CardinalBasePlugin(kModuleParameters + kWindowParameterCount + 1, 0, kCardinalStateCount), | |||
#ifdef DISTRHO_OS_WASM | |||
fInitializer(new Initializer(this)), | |||
fInitializer(new Initializer(this, static_cast<const CardinalBaseUI*>(nullptr))), | |||
#else | |||
fInitializer(this), | |||
fInitializer(this, static_cast<const CardinalBaseUI*>(nullptr)), | |||
#endif | |||
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
fAudioBufferCopy(nullptr), | |||
@@ -571,14 +273,14 @@ public: | |||
context->patch->templatePath = context->patch->factoryTemplatePath; | |||
} | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
fInitializer->oscPlugin = this; | |||
#endif | |||
} | |||
~CardinalPlugin() override | |||
{ | |||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
#ifdef CARDINAL_INIT_OSC_THREAD | |||
fInitializer->oscPlugin = nullptr; | |||
#endif | |||
@@ -39,7 +39,6 @@ | |||
# include <ui/Label.hpp> | |||
# include <ui/MenuOverlay.hpp> | |||
# include <ui/SequentialLayout.hpp> | |||
# include "CardinalCommon.hpp" | |||
# include <emscripten/emscripten.h> | |||
#endif | |||
@@ -47,15 +46,27 @@ | |||
# undef DEBUG | |||
#endif | |||
#include <Application.hpp> | |||
#include "Application.hpp" | |||
#include "AsyncDialog.hpp" | |||
#include "CardinalCommon.hpp" | |||
#include "PluginContext.hpp" | |||
#include "WindowParameters.hpp" | |||
#ifndef DISTRHO_OS_WASM | |||
# include "extra/SharedResourcePointer.hpp" | |||
#endif | |||
#ifndef HEADLESS | |||
# include "extra/ScopedValueSetter.hpp" | |||
#endif | |||
namespace rack { | |||
namespace app { | |||
widget::Widget* createMenuBar(bool isStandalone); | |||
} | |||
namespace engine { | |||
void Engine_setAboutToClose(Engine*); | |||
} | |||
namespace window { | |||
void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui); | |||
void WindowSetMods(Window* window, int mods); | |||
@@ -65,7 +76,14 @@ namespace window { | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------------------------------------------- | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
const char* Plugin::getBundlePath() const noexcept { return nullptr; } | |||
bool Plugin::writeMidiEvent(const MidiEvent&) noexcept { return false; } | |||
#endif | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
#ifdef DISTRHO_OS_WASM | |||
struct WasmWelcomeDialog : rack::widget::OpaqueWidget | |||
@@ -268,6 +286,15 @@ static void downloadRemotePatchSucceeded(const char* const filename) | |||
class CardinalUI : public CardinalBaseUI, | |||
public WindowParametersCallback | |||
{ | |||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
#ifdef DISTRHO_OS_WASM | |||
ScopedPointer<Initializer> fInitializer; | |||
#else | |||
SharedResourcePointer<Initializer> fInitializer; | |||
#endif | |||
std::string fAutosavePath; | |||
#endif | |||
rack::math::Vec lastMousePos; | |||
WindowParameters windowParameters; | |||
int rateLimitStep = 0; | |||
@@ -305,8 +332,65 @@ class CardinalUI : public CardinalBaseUI, | |||
public: | |||
CardinalUI() | |||
: CardinalBaseUI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT) | |||
: CardinalBaseUI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT), | |||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
#ifdef DISTRHO_OS_WASM | |||
fInitializer(new Initializer(static_cast<const CardinalBasePlugin*>(nullptr), this)), | |||
#else | |||
fInitializer(static_cast<const CardinalBasePlugin*>(nullptr), this), | |||
#endif | |||
#endif | |||
lastMousePos() | |||
{ | |||
rack::contextSet(context); | |||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
// create unique temporary path for this instance | |||
try { | |||
char uidBuf[24]; | |||
const std::string tmp = rack::system::getTempDirectory(); | |||
for (int i=1;; ++i) | |||
{ | |||
std::snprintf(uidBuf, sizeof(uidBuf), "Cardinal.%04d", i); | |||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||
if (! rack::system::exists(trypath)) | |||
{ | |||
if (rack::system::createDirectories(trypath)) | |||
fAutosavePath = trypath; | |||
break; | |||
} | |||
} | |||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||
const float sampleRate = getSampleRate(); | |||
rack::settings::sampleRate = sampleRate; | |||
context->bufferSize = 128; | |||
context->sampleRate = sampleRate; | |||
context->engine = new rack::engine::Engine; | |||
context->engine->setSampleRate(sampleRate); | |||
context->history = new rack::history::State; | |||
context->patch = new rack::patch::Manager; | |||
context->patch->autosavePath = fAutosavePath; | |||
context->patch->templatePath = fInitializer->templatePath; | |||
context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath; | |||
context->event = new rack::widget::EventState; | |||
context->scene = new rack::app::Scene; | |||
context->event->rootWidget = context->scene; | |||
context->window = new rack::window::Window; | |||
context->patch->loadTemplate(); | |||
context->scene->rackScroll->reset(); | |||
// swap to factory template after first load | |||
context->patch->templatePath = context->patch->factoryTemplatePath; | |||
#endif | |||
Window& window(getWindow()); | |||
window.setIgnoringKeyRepeat(true); | |||
@@ -319,8 +403,6 @@ public: | |||
if (scaleFactor != 1.0) | |||
setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | |||
rack::contextSet(context); | |||
rack::window::WindowSetPluginUI(context->window, this); | |||
if (rack::widget::Widget* const menuBar = context->scene->menuBar) | |||
@@ -408,6 +490,23 @@ public: | |||
rack::window::WindowSetPluginUI(context->window, nullptr); | |||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
{ | |||
const ScopedContext sc(this); | |||
context->patch->clear(); | |||
// do a little dance to prevent context scene deletion from saving to temp dir | |||
#ifndef HEADLESS | |||
const ScopedValueSetter<bool> svs(rack::settings::headless, true); | |||
#endif | |||
Engine_setAboutToClose(context->engine); | |||
delete context; | |||
} | |||
if (! fAutosavePath.empty()) | |||
rack::system::removeRecursively(fAutosavePath); | |||
#endif | |||
rack::contextSet(nullptr); | |||
} | |||
@@ -201,8 +201,10 @@ endif | |||
# -------------------------------------------------------------- | |||
# Setup resources | |||
CORE_RESOURCES = patches | |||
CORE_RESOURCES += $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) | |||
CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) | |||
# ifneq ($(CARDINAL_VARIANT),mini) | |||
CORE_RESOURCES += patches | |||
# endif | |||
LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) | |||
VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) | |||
@@ -243,15 +245,19 @@ endif | |||
# -------------------------------------------------------------- | |||
# mini variant UI | |||
# ifeq ($(CARDINAL_VARIANT),mini) | |||
# ifneq ($(HEADLESS)$(MOD_BUILD),true) | |||
# FILES_UI = CardinalUI.cpp | |||
# FILES_UI += glfw.cpp | |||
# FILES_UI += Window.cpp | |||
# EXTRA_UI_DEPENDENCIES = $(subst -headless,,$(EXTRA_DSP_DEPENDENCIES)) | |||
# EXTRA_UI_LIBS = $(subst -headless,,$(EXTRA_DSP_LIBS)) | |||
# endif | |||
# endif | |||
ifeq ($(CARDINAL_VARIANT),mini) | |||
ifneq ($(HEADLESS)$(MOD_BUILD),true) | |||
FILES_UI = CardinalUI.cpp | |||
FILES_UI += CardinalCommon.cpp | |||
FILES_UI += common.cpp | |||
FILES_UI += glfw.cpp | |||
FILES_UI += Window.cpp | |||
EXTRA_UI_DEPENDENCIES = $(subst -headless,,$(EXTRA_DSP_DEPENDENCIES)) | |||
EXTRA_UI_LIBS = -Wl,--start-group | |||
EXTRA_UI_LIBS += $(subst -headless,,$(EXTRA_DSP_LIBS)) | |||
EXTRA_UI_LIBS += -Wl,--end-group | |||
endif | |||
endif | |||
# -------------------------------------------------------------- | |||
# Do some magic | |||
@@ -467,6 +473,7 @@ endif | |||
all: $(TARGETS) | |||
lv2: $(LV2_RESOURCES) | |||
lv2_sep: $(LV2_RESOURCES) | |||
vst2: $(VST2_RESOURCES) | |||
vst3: $(VST3_RESOURCES) | |||
clap: $(CLAP_RESOURCES) | |||
@@ -189,9 +189,6 @@ public: | |||
context->tlw = nullptr; | |||
context->ui = nullptr; | |||
#if !DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
delete context; | |||
#endif | |||
} | |||
}; | |||
#endif | |||
@@ -107,6 +107,13 @@ public: | |||
initialise_variant<T>(variant); | |||
} | |||
template<class T1, class T2> | |||
SharedResourcePointer(const T1* const v1, const T2* const v2) | |||
: sharedObject(nullptr) | |||
{ | |||
initialise_variant2<T1, T2>(v1, v2); | |||
} | |||
SharedResourcePointer (const SharedResourcePointer&) | |||
: sharedObject(nullptr) | |||
{ | |||
@@ -179,6 +186,18 @@ private: | |||
sharedObject = holder.sharedInstance; | |||
} | |||
template<class T1, class T2> | |||
void initialise_variant2(const T1* const v1, const T2* const v2) | |||
{ | |||
SharedObjectHolder& holder = getSharedObjectHolder(); | |||
const SpinLock::ScopedLockType sl (holder.lock); | |||
if (++(holder.refCount) == 1) | |||
holder.sharedInstance = new SharedObjectType(v1, v2); | |||
sharedObject = holder.sharedInstance; | |||
} | |||
// There's no need to assign to a SharedResourcePointer because every | |||
// instance of the class is exactly the same! | |||
SharedResourcePointer& operator= (const SharedResourcePointer&) = delete; | |||
@@ -56,6 +56,7 @@ | |||
#include "Application.hpp" | |||
#include "extra/String.hpp" | |||
#include "../CardinalCommon.hpp" | |||
#include "../PluginContext.hpp" | |||
#include "../WindowParameters.hpp" | |||
#ifndef DGL_NO_SHARED_RESOURCES | |||
@@ -148,12 +149,14 @@ struct Window::Internal { | |||
DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; | |||
DISTRHO_NAMESPACE::WindowParameters params; | |||
DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
DGL_NAMESPACE::Application hiddenApp; | |||
DGL_NAMESPACE::Window hiddenWindow; | |||
NVGcontext* r_vg = nullptr; | |||
NVGcontext* r_fbVg = nullptr; | |||
NVGcontext* o_vg = nullptr; | |||
NVGcontext* o_fbVg = nullptr; | |||
#endif | |||
math::Vec size = WINDOW_SIZE_MIN; | |||
@@ -176,12 +179,16 @@ struct Window::Internal { | |||
int fbCount = 0; | |||
Internal() | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
: hiddenApp(false), | |||
hiddenWindow(hiddenApp) | |||
{ | |||
hiddenWindow.setIgnoringKeyRepeat(true); | |||
hiddenApp.idle(); | |||
} | |||
#else | |||
{} | |||
#endif | |||
}; | |||
@@ -203,12 +210,17 @@ static int loadFallbackFont(NVGcontext* const vg) | |||
Window::Window() { | |||
internal = new Internal; | |||
DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||
// Set up NanoVG | |||
const int nvgFlags = NVG_ANTIALIAS; | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||
vg = nvgCreateGL(nvgFlags); | |||
#else | |||
vg = static_cast<CardinalPluginContext*>(APP)->tlw->getContext(); | |||
#endif | |||
DISTRHO_SAFE_ASSERT_RETURN(vg != nullptr,); | |||
#ifdef NANOVG_GLES2 | |||
fbVg = nvgCreateSharedGLES2(vg, nvgFlags); | |||
#else | |||
@@ -268,6 +280,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||
window->internal->tlw = tlw; | |||
window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
// Set up NanoVG | |||
window->internal->r_vg = tlw->getContext(); | |||
#ifdef NANOVG_GLES2 | |||
@@ -299,6 +312,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||
image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | |||
NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
} | |||
#endif | |||
// Init settings | |||
WindowParametersRestore(window); | |||
@@ -311,6 +325,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||
widget::Widget::ContextDestroyEvent e; | |||
APP->scene->onContextDestroy(e); | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
// swap contexts | |||
window->uiFont->vg = window->internal->o_vg; | |||
window->vg = window->internal->o_vg; | |||
@@ -338,6 +353,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||
nvgDeleteGLES2(window->internal->r_fbVg); | |||
#else | |||
nvgDeleteGL2(window->internal->r_fbVg); | |||
#endif | |||
#endif | |||
window->internal->tlw = nullptr; | |||
@@ -375,6 +391,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
window->internal->ui = ui; | |||
window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
// Set up NanoVG | |||
window->internal->r_vg = ui->getContext(); | |||
#ifdef NANOVG_GLES2 | |||
@@ -406,6 +423,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | |||
NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
} | |||
#endif | |||
// Init settings | |||
WindowParametersRestore(window); | |||
@@ -418,6 +436,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
widget::Widget::ContextDestroyEvent e; | |||
APP->scene->onContextDestroy(e); | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
// swap contexts | |||
window->uiFont->vg = window->internal->o_vg; | |||
window->vg = window->internal->o_vg; | |||
@@ -445,6 +464,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
nvgDeleteGLES2(window->internal->r_fbVg); | |||
#else | |||
nvgDeleteGL2(window->internal->r_fbVg); | |||
#endif | |||
#endif | |||
window->internal->tlw = nullptr; | |||
@@ -460,9 +480,11 @@ void WindowSetMods(Window* const window, const int mods) | |||
Window::~Window() { | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||
internal->hiddenWindow.close(); | |||
internal->hiddenApp.idle(); | |||
#endif | |||
// Fonts and Images in the cache must be deleted before the NanoVG context is deleted | |||
internal->fontCache.clear(); | |||
@@ -470,12 +492,20 @@ Window::~Window() { | |||
if (vg != nullptr) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
#if defined NANOVG_GLES2 | |||
nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | |||
nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); | |||
#else | |||
nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | |||
nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); | |||
#endif | |||
#else | |||
#if defined NANOVG_GLES2 | |||
nvgDeleteGLES2(fbVg); | |||
#else | |||
nvgDeleteGL2(fbVg); | |||
#endif | |||
#endif | |||
} | |||
} | |||