Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
@@ -29,6 +29,12 @@ | |||
// ----------------------------------------------------------------------------------------------------------- | |||
// from PluginContext.hpp | |||
#ifndef HEADLESS | |||
START_NAMESPACE_DGL | |||
class NanoTopLevelWidget; | |||
END_NAMESPACE_DGL | |||
#endif | |||
START_NAMESPACE_DISTRHO | |||
static constexpr const uint32_t kModuleParameters = 24; | |||
@@ -68,6 +74,7 @@ struct CardinalPluginContext : rack::Context { | |||
uint32_t midiEventCount; | |||
Plugin* const plugin; | |||
#ifndef HEADLESS | |||
DGL_NAMESPACE::NanoTopLevelWidget* tlw; | |||
UI* ui; | |||
#endif | |||
CardinalPluginContext(Plugin* const p); | |||
@@ -59,6 +59,115 @@ | |||
const std::string CARDINAL_VERSION = "22.12"; | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------------------------------------------- | |||
void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(pcontext->ui != nullptr,); | |||
if (started) | |||
{ | |||
pcontext->ui->editParameter(index, true); | |||
pcontext->ui->setParameterValue(index, pcontext->parameters[index]); | |||
} | |||
else | |||
{ | |||
pcontext->ui->editParameter(index, false); | |||
} | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb) const | |||
{ | |||
if (ui == nullptr) | |||
return false; | |||
ui->addIdleCallback(cb); | |||
return true; | |||
} | |||
void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb) const | |||
{ | |||
if (ui == nullptr) | |||
return; | |||
ui->removeIdleCallback(cb); | |||
} | |||
void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) | |||
{ | |||
if (bypassed) | |||
return; | |||
const size_t size = message.bytes.size(); | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | |||
DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); | |||
MidiEvent event; | |||
event.frame = message.frame; | |||
switch (message.bytes[0] & 0xF0) | |||
{ | |||
case 0x80: | |||
case 0x90: | |||
case 0xA0: | |||
case 0xB0: | |||
case 0xE0: | |||
event.size = 3; | |||
break; | |||
case 0xC0: | |||
case 0xD0: | |||
event.size = 2; | |||
break; | |||
case 0xF0: | |||
switch (message.bytes[0] & 0x0F) | |||
{ | |||
case 0x0: | |||
case 0x4: | |||
case 0x5: | |||
case 0x7: | |||
case 0x9: | |||
case 0xD: | |||
// unsupported | |||
return; | |||
case 0x1: | |||
case 0x2: | |||
case 0x3: | |||
case 0xE: | |||
event.size = 3; | |||
break; | |||
case 0x6: | |||
case 0x8: | |||
case 0xA: | |||
case 0xB: | |||
case 0xC: | |||
case 0xF: | |||
event.size = 1; | |||
break; | |||
} | |||
break; | |||
default: | |||
// invalid | |||
return; | |||
} | |||
DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); | |||
std::memcpy(event.data, message.bytes.data(), event.size); | |||
if (channel != 0 && event.data[0] < 0xF0) | |||
event.data[0] |= channel & 0x0F; | |||
plugin->writeMidiEvent(event); | |||
} | |||
END_NAMESPACE_DISTRHO | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
namespace rack { | |||
bool isStandalone() | |||
@@ -118,6 +227,8 @@ std::string homeDir() | |||
} // namespace rack | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
namespace patchUtils | |||
{ | |||
@@ -289,6 +400,8 @@ void openBrowser(const std::string& url) | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
void async_dialog_filebrowser(const bool saving, | |||
const char* const defaultName, | |||
const char* const startDir, | |||
@@ -430,75 +430,6 @@ struct Initializer | |||
// ----------------------------------------------------------------------------------------------------------- | |||
void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) | |||
{ | |||
if (bypassed) | |||
return; | |||
const size_t size = message.bytes.size(); | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | |||
DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); | |||
MidiEvent event; | |||
event.frame = message.frame; | |||
switch (message.bytes[0] & 0xF0) | |||
{ | |||
case 0x80: | |||
case 0x90: | |||
case 0xA0: | |||
case 0xB0: | |||
case 0xE0: | |||
event.size = 3; | |||
break; | |||
case 0xC0: | |||
case 0xD0: | |||
event.size = 2; | |||
break; | |||
case 0xF0: | |||
switch (message.bytes[0] & 0x0F) | |||
{ | |||
case 0x0: | |||
case 0x4: | |||
case 0x5: | |||
case 0x7: | |||
case 0x9: | |||
case 0xD: | |||
// unsupported | |||
return; | |||
case 0x1: | |||
case 0x2: | |||
case 0x3: | |||
case 0xE: | |||
event.size = 3; | |||
break; | |||
case 0x6: | |||
case 0x8: | |||
case 0xA: | |||
case 0xB: | |||
case 0xC: | |||
case 0xF: | |||
event.size = 1; | |||
break; | |||
} | |||
break; | |||
default: | |||
// invalid | |||
return; | |||
} | |||
DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); | |||
std::memcpy(event.data, message.bytes.data(), event.size); | |||
if (channel != 0 && event.data[0] < 0xF0) | |||
event.data[0] |= channel & 0x0F; | |||
plugin->writeMidiEvent(event); | |||
} | |||
// ----------------------------------------------------------------------------------------------------------- | |||
struct ScopedContext { | |||
ScopedContext(const CardinalBasePlugin* const plugin) | |||
{ | |||
@@ -1393,6 +1324,6 @@ Plugin* createPlugin() | |||
return new CardinalPlugin(); | |||
} | |||
// ----------------------------------------------------------------------------------------------------------- | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -7,8 +7,11 @@ | |||
# -------------------------------------------------------------- | |||
# Carla stuff | |||
CWD = ../../carla/source | |||
ifneq ($(STATIC_BUILD),true) | |||
STATIC_PLUGIN_TARGET = true | |||
CWD = ../../carla/source | |||
include $(CWD)/Makefile.deps.mk | |||
CARLA_BUILD_DIR = ../../carla/build | |||
@@ -23,7 +26,9 @@ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_engine_ | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_plugin.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/native-plugins.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/audio_decoder.a | |||
ifneq ($(WASM),true) | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/jackbridge.min.a | |||
endif | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/lilv.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/rtmempool.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/sfzero.a | |||
@@ -31,10 +36,17 @@ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/water.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/ysfx.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/zita-resampler.a | |||
endif # STATIC_BUILD | |||
# -------------------------------------------------------------- | |||
# Import base definitions | |||
DISTRHO_NAMESPACE = CardinalDISTRHO | |||
DGL_NAMESPACE = CardinalDGL | |||
NVG_DISABLE_SKIPPING_WHITESPACE = true | |||
NVG_FONT_TEXTURE_FLAGS = NVG_IMAGE_NEAREST | |||
USE_NANOVG_FBO = true | |||
WASM_EXCEPTIONS = true | |||
include ../../dpf/Makefile.base.mk | |||
# -------------------------------------------------------------- | |||
@@ -57,7 +69,11 @@ endif | |||
# -------------------------------------------------------------- | |||
# Extra libraries to link against | |||
ifeq ($(NOPLUGINS),true) | |||
RACK_EXTRA_LIBS = ../../plugins/noplugins.a | |||
else | |||
RACK_EXTRA_LIBS = ../../plugins/plugins.a | |||
endif | |||
RACK_EXTRA_LIBS += ../rack.a | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libquickjs.a | |||
@@ -74,22 +90,51 @@ RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libzstd.a | |||
endif | |||
# -------------------------------------------------------------- | |||
# surgext libraries | |||
ifneq ($(NOPLUGINS),true) | |||
SURGE_DEP_PATH = $(abspath ../../deps/surge-build) | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libsurge-common.a | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libjuce_dsp_rack_sub.a | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/airwindows/libairwindows.a | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/eurorack/libeurorack.a | |||
ifeq ($(DEBUG),true) | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmtd.a | |||
else | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmt.a | |||
endif | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sqlite-3.23.3/libsqlite.a | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libsst-plugininfra.a | |||
ifneq ($(WINDOWS),true) | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/filesystem/libfilesystem.a | |||
endif | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/strnatcmp/libstrnatcmp.a | |||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/tinyxml/libtinyxml.a | |||
endif | |||
# -------------------------------------------------------------- | |||
# FIXME | |||
ifeq ($(CIBUILD)$(WASM),truetrue) | |||
ifneq ($(STATIC_BUILD),true) | |||
STATIC_CARLA_PLUGIN_LIBS = -lsndfile -lopus -lFLAC -lvorbisenc -lvorbis -logg -lm | |||
endif | |||
endif | |||
EXTRA_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) | |||
EXTRA_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) | |||
ifeq ($(shell pkg-config --exists fftw3f && echo true),true) | |||
ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) | |||
EXTRA_DEPENDENCIES += ../../deps/aubio/libaubio.a | |||
EXTRA_LIBS += ../../deps/aubio/libaubio.a | |||
EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs fftw3f) | |||
endif | |||
# -------------------------------------------------------------- | |||
# Extra flags for liblo | |||
BASE_FLAGS += -DHAVE_LIBLO | |||
BASE_FLAGS += $(LIBLO_FLAGS) | |||
LINK_FLAGS += $(LIBLO_LIBS) | |||
ifneq ($(NOPLUGINS),true) | |||
ifeq ($(MACOS),true) | |||
EXTRA_LIBS += -framework Accelerate | |||
endif | |||
endif | |||
# -------------------------------------------------------------- | |||
# Extra flags for VCV stuff | |||
@@ -106,11 +151,11 @@ BASE_FLAGS += -DPRIVATE= | |||
BASE_FLAGS += -I.. | |||
BASE_FLAGS += -I../../dpf/dgl/src/nanovg | |||
BASE_FLAGS += -I../../include | |||
BASE_FLAGS += -I../../include/neon-compat | |||
BASE_FLAGS += -I../../include/simd-compat | |||
BASE_FLAGS += -I../Rack/include | |||
ifeq ($(SYSDEPS),true) | |||
BASE_FLAGS += -DCARDINAL_SYSDEPS | |||
BASE_FLAGS += $(shell pkg-config --cflags jansson libarchive samplerate speexdsp) | |||
BASE_FLAGS += $(shell $(PKG_CONFIG) --cflags jansson libarchive samplerate speexdsp) | |||
else | |||
BASE_FLAGS += -DZSTDLIB_VISIBILITY= | |||
BASE_FLAGS += -I../Rack/dep/include | |||
@@ -119,41 +164,98 @@ BASE_FLAGS += -I../Rack/dep/glfw/include | |||
BASE_FLAGS += -I../Rack/dep/nanosvg/src | |||
BASE_FLAGS += -I../Rack/dep/oui-blendish | |||
ifeq ($(WASM),true) | |||
BASE_FLAGS += -DNANOVG_GLES2=1 | |||
BASE_FLAGS += -msse -msse2 -msse3 -msimd128 | |||
else ifneq ($(HAIKU),true) | |||
ifeq ($(HEADLESS),true) | |||
BASE_FLAGS += -DHEADLESS | |||
endif | |||
ifeq ($(MOD_BUILD),true) | |||
BASE_FLAGS += -DDISTRHO_PLUGIN_USES_MODGUI=1 -DDISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE=0xffff | |||
endif | |||
ifneq ($(WASM),true) | |||
ifneq ($(HAIKU),true) | |||
BASE_FLAGS += -pthread | |||
endif | |||
endif | |||
ifeq ($(WINDOWS),true) | |||
BASE_FLAGS += -D_USE_MATH_DEFINES | |||
BASE_FLAGS += -DWIN32_LEAN_AND_MEAN | |||
BASE_FLAGS += -D_WIN32_WINNT=0x0600 | |||
BASE_FLAGS += -I../../include/mingw-compat | |||
BASE_FLAGS += -I../../include/mingw-std-threads | |||
endif | |||
ifeq ($(USE_GLES2),true) | |||
BASE_FLAGS += -DNANOVG_GLES2_FORCED | |||
else ifeq ($(USE_GLES3),true) | |||
BASE_FLAGS += -DNANOVG_GLES3_FORCED | |||
endif | |||
BUILD_C_FLAGS += -std=gnu11 | |||
BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing | |||
BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing | |||
ifneq ($(MACOS),true) | |||
BUILD_CXX_FLAGS += -faligned-new -Wno-abi | |||
ifeq ($(MOD_BUILD),true) | |||
BUILD_CXX_FLAGS += -std=gnu++17 | |||
endif | |||
endif | |||
# Rack code is not tested for this flag, unset it | |||
BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | |||
# Ignore bad behaviour from Rack API | |||
BUILD_CXX_FLAGS += -Wno-format-security | |||
# -------------------------------------------------------------- | |||
# FIXME lots of warnings from VCV side | |||
BASE_FLAGS += -Wno-unused-parameter | |||
BASE_FLAGS += -Wno-unused-variable | |||
# -------------------------------------------------------------- | |||
# extra linker flags | |||
ifeq ($(HAIKU),true) | |||
ifeq ($(WASM),true) | |||
ifneq ($(STATIC_BUILD),true) | |||
LINK_FLAGS += --use-preload-plugins | |||
LINK_FLAGS += --preload-file=./jsfx | |||
LINK_FLAGS += --preload-file=./lv2 | |||
endif | |||
LINK_FLAGS += --preload-file=../../bin/CardinalNative.lv2/resources@/resources | |||
LINK_FLAGS += --use-preload-cache | |||
ifneq ($(NOPLUGINS),true) | |||
SYMLINKED_DIRS_RESOURCES = | |||
# find . -type l | grep -v svg | grep -v ttf | grep -v art | grep -v json | grep -v png | grep -v otf | sort | |||
SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/chopin | |||
SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/debussy | |||
SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/goldberg | |||
SYMLINKED_DIRS_RESOURCES += cf/playeroscs | |||
SYMLINKED_DIRS_RESOURCES += DrumKit/res/samples | |||
SYMLINKED_DIRS_RESOURCES += Fundamental/presets | |||
SYMLINKED_DIRS_RESOURCES += GrandeModular/presets | |||
SYMLINKED_DIRS_RESOURCES += LyraeModules/presets | |||
SYMLINKED_DIRS_RESOURCES += Meander/res | |||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/presets | |||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityPresets | |||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityShapes | |||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldPresets | |||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldShapes | |||
SYMLINKED_DIRS_RESOURCES += Mog/res | |||
SYMLINKED_DIRS_RESOURCES += nonlinearcircuits/res | |||
SYMLINKED_DIRS_RESOURCES += Orbits/presets | |||
SYMLINKED_DIRS_RESOURCES += stoermelder-packone/presets | |||
SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/fx_presets | |||
SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/wavetables | |||
SYMLINKED_DIRS_RESOURCES += surgext/patches | |||
SYMLINKED_DIRS_RESOURCES += surgext/presets | |||
LINK_FLAGS += $(foreach d,$(SYMLINKED_DIRS_RESOURCES),--preload-file=../../bin/CardinalNative.lv2/resources/$(d)@/resources/$(d)) | |||
endif | |||
LINK_FLAGS += -sALLOW_MEMORY_GROWTH | |||
LINK_FLAGS += -sINITIAL_MEMORY=64Mb | |||
LINK_FLAGS += -sLZ4=1 | |||
LINK_FLAGS += --shell-file=../emscripten/shell.html | |||
LINK_FLAGS += -O3 | |||
else ifeq ($(HAIKU),true) | |||
LINK_FLAGS += -lpthread | |||
else | |||
LINK_FLAGS += -pthread | |||
@@ -181,7 +283,7 @@ EXTRA_LIBS += -lws2_32 -lwinmm | |||
endif | |||
ifeq ($(SYSDEPS),true) | |||
EXTRA_LIBS += $(shell pkg-config --libs jansson libarchive samplerate speexdsp) | |||
EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs jansson libarchive samplerate speexdsp) | |||
endif | |||
ifeq ($(WITH_LTO),true) | |||
@@ -193,6 +295,13 @@ LINK_FLAGS += -Wno-stringop-overflow | |||
endif | |||
endif | |||
# -------------------------------------------------------------- | |||
# Extra flags for liblo | |||
BASE_FLAGS += -DHAVE_LIBLO | |||
BASE_FLAGS += $(LIBLO_FLAGS) | |||
LINK_FLAGS += $(LIBLO_LIBS) | |||
# -------------------------------------------------------------- | |||
# fallback path to resource files | |||
@@ -17,7 +17,7 @@ | |||
#include "RemoteUI.hpp" | |||
// #include <asset.hpp> | |||
#include <asset.hpp> | |||
// #include <random.hpp> | |||
#include <patch.hpp> | |||
#include <settings.hpp> | |||
@@ -26,66 +26,293 @@ | |||
#include <app/Scene.hpp> | |||
#include <engine/Engine.hpp> | |||
#include "AsyncDialog.hpp" | |||
#include "WindowParameters.hpp" | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
namespace rack { | |||
namespace app { | |||
widget::Widget* createMenuBar(bool isStandalone); | |||
} | |||
namespace window { | |||
void WindowSetPluginRemote(Window* window, NanoTopLevelWidget* tlw); | |||
void WindowSetMods(Window* window, int mods); | |||
void WindowSetInternalSize(rack::window::Window* window, math::Vec size); | |||
} | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CardinalRemoteUI::CardinalRemoteUI(Window& window, const std::string& templatePath) | |||
: NanoTopLevelWidget(window), | |||
context(nullptr) | |||
: NanoTopLevelWidget(window) | |||
{ | |||
// create unique temporary path for this instance | |||
try { | |||
char uidBuf[24]; | |||
const std::string tmp = rack::system::getTempDirectory(); | |||
CardinalPluginContext& context(*static_cast<CardinalPluginContext*>(rack::contextGet())); | |||
context.nativeWindowId = getWindow().getNativeWindowHandle(); | |||
context.tlw = this; | |||
for (int i=1;; ++i) | |||
{ | |||
std::snprintf(uidBuf, sizeof(uidBuf), "CardinalRemote.%04d", i); | |||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||
if (! rack::system::exists(trypath)) | |||
{ | |||
if (rack::system::createDirectories(trypath)) | |||
autosavePath = trypath; | |||
break; | |||
} | |||
} | |||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||
window.setIgnoringKeyRepeat(true); | |||
context.nativeWindowId = window.getNativeWindowHandle(); | |||
rack::contextSet(&context); | |||
const double scaleFactor = getScaleFactor(); | |||
context.bufferSize = 512; | |||
rack::settings::sampleRate = context.sampleRate = 48000; | |||
setGeometryConstraints(648 * scaleFactor, 538 * scaleFactor); | |||
context.engine = new rack::engine::Engine; | |||
context.engine->setSampleRate(context.sampleRate); | |||
if (scaleFactor != 1.0) | |||
setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | |||
context.history = new rack::history::State; | |||
context.patch = new rack::patch::Manager; | |||
context.patch->autosavePath = autosavePath; | |||
context.patch->templatePath = templatePath; | |||
rack::window::WindowSetPluginRemote(context.window, this); | |||
context.event = new rack::widget::EventState; | |||
context.scene = new rack::app::Scene; | |||
context.event->rootWidget = context.scene; | |||
context.window = new rack::window::Window; | |||
if (rack::widget::Widget* const menuBar = context.scene->menuBar) | |||
{ | |||
context.scene->removeChild(menuBar); | |||
delete menuBar; | |||
} | |||
context.patch->loadTemplate(); | |||
context.scene->rackScroll->reset(); | |||
context.scene->menuBar = rack::app::createMenuBar(true); | |||
context.scene->addChildBelow(context.scene->menuBar, context.scene->rackScroll); | |||
context.nativeWindowId = getWindow().getNativeWindowHandle(); | |||
// hide "Browse VCV Library" button | |||
rack::widget::Widget* const browser = context.scene->browser->children.back(); | |||
rack::widget::Widget* const headerLayout = browser->children.front(); | |||
rack::widget::Widget* const libraryButton = headerLayout->children.back(); | |||
libraryButton->hide(); | |||
// Report to user if something is wrong with the installation | |||
std::string errorMessage; | |||
if (rack::asset::systemDir.empty()) | |||
{ | |||
errorMessage = "Failed to locate Cardinal plugin bundle.\n" | |||
"Install Cardinal with its plugin bundle folder intact and try again."; | |||
} | |||
else if (! rack::system::exists(rack::asset::systemDir)) | |||
{ | |||
errorMessage = rack::string::f("System directory \"%s\" does not exist. " | |||
"Make sure Cardinal was downloaded and installed correctly.", | |||
rack::asset::systemDir.c_str()); | |||
} | |||
if (! errorMessage.empty()) | |||
{ | |||
static bool shown = false; | |||
if (! shown) | |||
{ | |||
shown = true; | |||
asyncDialog::create(errorMessage.c_str()); | |||
} | |||
} | |||
context.window->step(); | |||
// WindowParametersSetCallback(context.window, this); | |||
} | |||
CardinalRemoteUI::~CardinalRemoteUI() | |||
{ | |||
rack::contextSet(&context); | |||
CardinalPluginContext& context(*static_cast<CardinalPluginContext*>(rack::contextGet())); | |||
context.nativeWindowId = 0; | |||
context.patch->clear(); | |||
if (! autosavePath.empty()) | |||
rack::system::removeRecursively(autosavePath); | |||
} | |||
void CardinalRemoteUI::onNanoDisplay() | |||
{ | |||
rack::contextSet(&context); | |||
CardinalPluginContext& context(*static_cast<CardinalPluginContext*>(rack::contextGet())); | |||
context.window->step(); | |||
// TODO | |||
repaint(); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
static int glfwMods(const uint mod) noexcept | |||
{ | |||
int mods = 0; | |||
if (mod & kModifierControl) | |||
mods |= GLFW_MOD_CONTROL; | |||
if (mod & kModifierShift) | |||
mods |= GLFW_MOD_SHIFT; | |||
if (mod & kModifierAlt) | |||
mods |= GLFW_MOD_ALT; | |||
if (mod & kModifierSuper) | |||
mods |= GLFW_MOD_SUPER; | |||
/* | |||
if (glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) | |||
mods |= GLFW_MOD_SHIFT; | |||
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) | |||
mods |= GLFW_MOD_CONTROL; | |||
if (glfwGetKey(win, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS) | |||
mods |= GLFW_MOD_ALT; | |||
if (glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS) | |||
mods |= GLFW_MOD_SUPER; | |||
*/ | |||
return mods; | |||
} | |||
bool CardinalRemoteUI::onMouse(const MouseEvent& ev) | |||
{ | |||
if (ev.press) | |||
getWindow().focus(); | |||
const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; | |||
int mods = glfwMods(ev.mod); | |||
int button; | |||
switch (ev.button) | |||
{ | |||
case 1: button = GLFW_MOUSE_BUTTON_LEFT; break; | |||
case 2: button = GLFW_MOUSE_BUTTON_RIGHT; break; | |||
case 3: button = GLFW_MOUSE_BUTTON_MIDDLE; break; | |||
default: | |||
button = ev.button; | |||
break; | |||
} | |||
#ifdef DISTRHO_OS_MAC | |||
// Remap Ctrl-left click to right click on macOS | |||
if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == GLFW_MOD_CONTROL) { | |||
button = GLFW_MOUSE_BUTTON_RIGHT; | |||
mods &= ~GLFW_MOD_CONTROL; | |||
} | |||
// Remap Ctrl-shift-left click to middle click on macOS | |||
if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) { | |||
button = GLFW_MOUSE_BUTTON_MIDDLE; | |||
mods &= ~(GLFW_MOD_CONTROL | GLFW_MOD_SHIFT); | |||
} | |||
#endif | |||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||
return context->event->handleButton(lastMousePos, button, action, mods); | |||
} | |||
bool CardinalRemoteUI::onMotion(const MotionEvent& ev) | |||
{ | |||
const rack::math::Vec mousePos = rack::math::Vec(ev.pos.getX(), ev.pos.getY()).div(getScaleFactor()).round(); | |||
const rack::math::Vec mouseDelta = mousePos.minus(lastMousePos); | |||
lastMousePos = mousePos; | |||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||
return context->event->handleHover(mousePos, mouseDelta); | |||
} | |||
bool CardinalRemoteUI::onScroll(const ScrollEvent& ev) | |||
{ | |||
rack::math::Vec scrollDelta = rack::math::Vec(ev.delta.getX(), ev.delta.getY()); | |||
#ifndef DISTRHO_OS_MAC | |||
scrollDelta = scrollDelta.mult(50.0); | |||
#endif | |||
const int mods = glfwMods(ev.mod); | |||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||
return context->event->handleScroll(lastMousePos, scrollDelta); | |||
} | |||
bool CardinalRemoteUI::onCharacterInput(const CharacterInputEvent& ev) | |||
{ | |||
if (ev.character < ' ' || ev.character >= kKeyDelete) | |||
return false; | |||
const int mods = glfwMods(ev.mod); | |||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||
return context->event->handleText(lastMousePos, ev.character); | |||
} | |||
bool CardinalRemoteUI::onKeyboard(const KeyboardEvent& ev) | |||
{ | |||
const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; | |||
const int mods = glfwMods(ev.mod); | |||
/* These are unsupported in pugl right now | |||
#define GLFW_KEY_KP_0 320 | |||
#define GLFW_KEY_KP_1 321 | |||
#define GLFW_KEY_KP_2 322 | |||
#define GLFW_KEY_KP_3 323 | |||
#define GLFW_KEY_KP_4 324 | |||
#define GLFW_KEY_KP_5 325 | |||
#define GLFW_KEY_KP_6 326 | |||
#define GLFW_KEY_KP_7 327 | |||
#define GLFW_KEY_KP_8 328 | |||
#define GLFW_KEY_KP_9 329 | |||
#define GLFW_KEY_KP_DECIMAL 330 | |||
#define GLFW_KEY_KP_DIVIDE 331 | |||
#define GLFW_KEY_KP_MULTIPLY 332 | |||
#define GLFW_KEY_KP_SUBTRACT 333 | |||
#define GLFW_KEY_KP_ADD 334 | |||
#define GLFW_KEY_KP_ENTER 335 | |||
#define GLFW_KEY_KP_EQUAL 336 | |||
*/ | |||
int key; | |||
switch (ev.key) | |||
{ | |||
case '\r': key = GLFW_KEY_ENTER; break; | |||
case '\t': key = GLFW_KEY_TAB; break; | |||
case kKeyBackspace: key = GLFW_KEY_BACKSPACE; break; | |||
case kKeyEscape: key = GLFW_KEY_ESCAPE; break; | |||
case kKeyDelete: key = GLFW_KEY_DELETE; break; | |||
case kKeyF1: key = GLFW_KEY_F1; break; | |||
case kKeyF2: key = GLFW_KEY_F2; break; | |||
case kKeyF3: key = GLFW_KEY_F3; break; | |||
case kKeyF4: key = GLFW_KEY_F4; break; | |||
case kKeyF5: key = GLFW_KEY_F5; break; | |||
case kKeyF6: key = GLFW_KEY_F6; break; | |||
case kKeyF7: key = GLFW_KEY_F7; break; | |||
case kKeyF8: key = GLFW_KEY_F8; break; | |||
case kKeyF9: key = GLFW_KEY_F9; break; | |||
case kKeyF10: key = GLFW_KEY_F10; break; | |||
case kKeyF11: key = GLFW_KEY_F11; break; | |||
case kKeyF12: key = GLFW_KEY_F12; break; | |||
case kKeyLeft: key = GLFW_KEY_LEFT; break; | |||
case kKeyUp: key = GLFW_KEY_UP; break; | |||
case kKeyRight: key = GLFW_KEY_RIGHT; break; | |||
case kKeyDown: key = GLFW_KEY_DOWN; break; | |||
case kKeyPageUp: key = GLFW_KEY_PAGE_UP; break; | |||
case kKeyPageDown: key = GLFW_KEY_PAGE_DOWN; break; | |||
case kKeyHome: key = GLFW_KEY_HOME; break; | |||
case kKeyEnd: key = GLFW_KEY_END; break; | |||
case kKeyInsert: key = GLFW_KEY_INSERT; break; | |||
case kKeyShiftL: key = GLFW_KEY_LEFT_SHIFT; break; | |||
case kKeyShiftR: key = GLFW_KEY_RIGHT_SHIFT; break; | |||
case kKeyControlL: key = GLFW_KEY_LEFT_CONTROL; break; | |||
case kKeyControlR: key = GLFW_KEY_RIGHT_CONTROL; break; | |||
case kKeyAltL: key = GLFW_KEY_LEFT_ALT; break; | |||
case kKeyAltR: key = GLFW_KEY_RIGHT_ALT; break; | |||
case kKeySuperL: key = GLFW_KEY_LEFT_SUPER; break; | |||
case kKeySuperR: key = GLFW_KEY_RIGHT_SUPER; break; | |||
case kKeyMenu: key = GLFW_KEY_MENU; break; | |||
case kKeyCapsLock: key = GLFW_KEY_CAPS_LOCK; break; | |||
case kKeyScrollLock: key = GLFW_KEY_SCROLL_LOCK; break; | |||
case kKeyNumLock: key = GLFW_KEY_NUM_LOCK; break; | |||
case kKeyPrintScreen: key = GLFW_KEY_PRINT_SCREEN; break; | |||
case kKeyPause: key = GLFW_KEY_PAUSE; break; | |||
default: | |||
// glfw expects uppercase | |||
if (ev.key >= 'a' && ev.key <= 'z') | |||
key = ev.key - ('a' - 'A'); | |||
else | |||
key = ev.key; | |||
break; | |||
} | |||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||
return context->event->handleKey(lastMousePos, key, ev.keycode, action, mods); | |||
} | |||
void CardinalRemoteUI::onResize(const ResizeEvent& ev) | |||
{ | |||
NanoTopLevelWidget::onResize(ev); | |||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||
if (context->window != nullptr) | |||
WindowSetInternalSize(context->window, rack::math::Vec(ev.size.getWidth(), ev.size.getHeight())); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -20,10 +20,11 @@ | |||
#include "NanoVG.hpp" | |||
#include "PluginContext.hpp" | |||
#include <app/common.hpp> | |||
class CardinalRemoteUI : public NanoTopLevelWidget | |||
{ | |||
CardinalPluginContext context; | |||
std::string autosavePath; | |||
rack::math::Vec lastMousePos; | |||
public: | |||
explicit CardinalRemoteUI(Window& window, const std::string& templatePath); | |||
@@ -31,6 +32,12 @@ public: | |||
protected: | |||
void onNanoDisplay() override; | |||
bool onMouse(const MouseEvent& ev) override; | |||
bool onMotion(const MotionEvent& ev) override; | |||
bool onScroll(const ScrollEvent& ev) override; | |||
bool onCharacterInput(const CharacterInputEvent& ev) override; | |||
bool onKeyboard(const KeyboardEvent& ev) override; | |||
void onResize(const ResizeEvent& ev) override; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalRemoteUI) | |||
}; |
@@ -20,13 +20,19 @@ | |||
#include "RemoteUI.hpp" | |||
#include <asset.hpp> | |||
#include <patch.hpp> | |||
#include <random.hpp> | |||
#include <settings.hpp> | |||
#include <system.hpp> | |||
#include <app/Browser.hpp> | |||
#include <app/Scene.hpp> | |||
#include <engine/Engine.hpp> | |||
#include <ui/common.hpp> | |||
#include "PluginContext.hpp" | |||
namespace rack { | |||
namespace plugin { | |||
void initStaticPlugins(); | |||
@@ -34,6 +40,26 @@ namespace plugin { | |||
} | |||
} | |||
START_NAMESPACE_DISTRHO | |||
bool isUsingNativeAudio() noexcept { return false; } | |||
bool supportsAudioInput() { return false; } | |||
bool supportsBufferSizeChanges() { return false; } | |||
bool supportsMIDI() { return false; } | |||
bool isAudioInputEnabled() { return false; } | |||
bool isMIDIEnabled() { return false; } | |||
uint getBufferSize() { return 0; } | |||
bool requestAudioInput() { return false; } | |||
bool requestBufferSizeChange(uint) { return false; } | |||
bool requestMIDI() { return false; } | |||
const char* getPluginFormatName() noexcept { return "Remote"; } | |||
uint32_t Plugin::getBufferSize() const noexcept { return 128; } | |||
double Plugin::getSampleRate() const noexcept { return 48000; } | |||
bool Plugin::writeMidiEvent(const MidiEvent&) noexcept { return false; } | |||
END_NAMESPACE_DISTRHO | |||
int main(const int argc, const char* argv[]) | |||
{ | |||
using namespace rack; | |||
@@ -42,7 +68,6 @@ int main(const int argc, const char* argv[]) | |||
settings::autoCheckUpdates = false; | |||
settings::autosaveInterval = 0; | |||
settings::devMode = true; | |||
settings::discordUpdateActivity = false; | |||
settings::isPlugin = true; | |||
settings::skipLoadOnLaunch = true; | |||
settings::showTipsOnLaunch = false; | |||
@@ -131,17 +156,68 @@ int main(const int argc, const char* argv[]) | |||
INFO("Initializing plugin browser DB"); | |||
app::browserInit(); | |||
// create unique temporary path for this instance | |||
std::string autosavePath; | |||
try { | |||
char uidBuf[24]; | |||
const std::string tmp = rack::system::getTempDirectory(); | |||
for (int i=1;; ++i) | |||
{ | |||
std::snprintf(uidBuf, sizeof(uidBuf), "CardinalRemote.%04d", i); | |||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||
if (! rack::system::exists(trypath)) | |||
{ | |||
if (rack::system::createDirectories(trypath)) | |||
autosavePath = trypath; | |||
break; | |||
} | |||
} | |||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||
CardinalPluginContext context(nullptr); | |||
rack::contextSet(&context); | |||
context.bufferSize = 512; | |||
rack::settings::sampleRate = context.sampleRate = 48000; | |||
context.engine = new rack::engine::Engine; | |||
context.engine->setSampleRate(context.sampleRate); | |||
context.history = new rack::history::State; | |||
context.patch = new rack::patch::Manager; | |||
context.patch->autosavePath = autosavePath; | |||
context.patch->templatePath = templatePath; | |||
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(); | |||
Application app; | |||
Window win(app); | |||
win.setResizable(true); | |||
win.setTitle("CardinalRemote"); | |||
ScopedPointer<CardinalRemoteUI> remoteUI; | |||
{ | |||
const Window::ScopedGraphicsContext sgc(win); | |||
remoteUI = new CardinalRemoteUI(win, templatePath); | |||
} | |||
win.show(); | |||
app.exec(); | |||
context.patch->clear(); | |||
if (! autosavePath.empty()) | |||
rack::system::removeRecursively(autosavePath); | |||
INFO("Clearing asset paths"); | |||
asset::bundlePath.clear(); | |||
asset::systemDir.clear(); | |||
@@ -67,40 +67,6 @@ START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------------------------------------------- | |||
bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb) const | |||
{ | |||
if (ui == nullptr) | |||
return false; | |||
ui->addIdleCallback(cb); | |||
return true; | |||
} | |||
void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb) const | |||
{ | |||
if (ui == nullptr) | |||
return; | |||
ui->removeIdleCallback(cb); | |||
} | |||
void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(pcontext->ui != nullptr,); | |||
if (started) | |||
{ | |||
pcontext->ui->editParameter(index, true); | |||
pcontext->ui->setParameterValue(index, pcontext->parameters[index]); | |||
} | |||
else | |||
{ | |||
pcontext->ui->editParameter(index, false); | |||
} | |||
} | |||
// ----------------------------------------------------------------------------------------------------------- | |||
#ifdef DISTRHO_OS_WASM | |||
struct WasmWelcomeDialog : rack::widget::OpaqueWidget | |||
{ | |||
@@ -64,13 +64,14 @@ struct CardinalPluginContext : rack::Context { | |||
uint32_t midiEventCount; | |||
Plugin* const plugin; | |||
#ifndef HEADLESS | |||
NanoTopLevelWidget* tlw; | |||
UI* ui; | |||
#endif | |||
CardinalPluginContext(Plugin* const p) | |||
: bufferSize(p->getBufferSize()), | |||
: bufferSize(p != nullptr ? p->getBufferSize() : 0), | |||
processCounter(0), | |||
sampleRate(p->getSampleRate()), | |||
sampleRate(p != nullptr ? p->getSampleRate() : 0.0), | |||
#if CARDINAL_VARIANT_MAIN | |||
variant(kCardinalVariantMain), | |||
#elif CARDINAL_VARIANT_FX | |||
@@ -105,6 +106,7 @@ struct CardinalPluginContext : rack::Context { | |||
midiEventCount(0), | |||
plugin(p) | |||
#ifndef HEADLESS | |||
, tlw(nullptr) | |||
, ui(nullptr) | |||
#endif | |||
{ | |||
@@ -169,6 +171,7 @@ public: | |||
filebrowseraction(), | |||
filebrowserhandle(nullptr) | |||
{ | |||
context->tlw = this; | |||
context->ui = this; | |||
} | |||
@@ -177,6 +180,7 @@ public: | |||
if (filebrowserhandle != nullptr) | |||
fileBrowserClose(filebrowserhandle); | |||
context->tlw = nullptr; | |||
context->ui = nullptr; | |||
} | |||
}; | |||
@@ -30,10 +30,10 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow*) | |||
{ | |||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | |||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, nullptr); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr, nullptr); | |||
size_t dataSize; | |||
return static_cast<const char*>(context->ui->getClipboard(dataSize)); | |||
return static_cast<const char*>(context->tlw->getClipboard(dataSize)); | |||
} | |||
GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) | |||
@@ -42,9 +42,9 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) | |||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | |||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr,); | |||
context->ui->setClipboard(nullptr, text, std::strlen(text)+1); | |||
context->tlw->setClipboard(nullptr, text, std::strlen(text)+1); | |||
} | |||
GLFWAPI GLFWcursor* glfwCreateStandardCursor(const int shape) | |||
@@ -91,18 +91,18 @@ GLFWAPI void glfwSetCursor(GLFWwindow*, GLFWcursor* const cursor) | |||
{ | |||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | |||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr,); | |||
context->ui->setCursor(cursor != nullptr ? cursor->cursorId : kMouseCursorArrow); | |||
context->tlw->setCursor(cursor != nullptr ? cursor->cursorId : kMouseCursorArrow); | |||
} | |||
GLFWAPI double glfwGetTime(void) | |||
{ | |||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | |||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, 0.0); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, 0.0); | |||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr, 0.0); | |||
return context->ui->getApp().getTime(); | |||
return context->tlw->getApp().getTime(); | |||
} | |||
GLFWAPI const char* glfwGetKeyName(const int key, int) | |||
@@ -145,6 +145,7 @@ struct Window::Internal { | |||
std::string lastWindowTitle; | |||
DISTRHO_NAMESPACE::UI* ui = nullptr; | |||
DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; | |||
DISTRHO_NAMESPACE::WindowParameters params; | |||
DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; | |||
DGL_NAMESPACE::Application hiddenApp; | |||
@@ -238,6 +239,112 @@ Window::Window() { | |||
#endif | |||
} | |||
void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||
{ | |||
// if nanovg context failed, init only bare minimum | |||
if (window->vg == nullptr) | |||
{ | |||
if (tlw != nullptr) | |||
{ | |||
window->internal->tlw = tlw; | |||
window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | |||
} | |||
else | |||
{ | |||
window->internal->tlw = nullptr; | |||
window->internal->callback = nullptr; | |||
} | |||
return; | |||
} | |||
if (tlw != nullptr) | |||
{ | |||
const GLubyte* vendor = glGetString(GL_VENDOR); | |||
const GLubyte* renderer = glGetString(GL_RENDERER); | |||
const GLubyte* version = glGetString(GL_VERSION); | |||
INFO("Renderer: %s %s", vendor, renderer); | |||
INFO("OpenGL: %s", version); | |||
window->internal->tlw = tlw; | |||
window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | |||
// Set up NanoVG | |||
window->internal->r_vg = tlw->getContext(); | |||
#ifdef NANOVG_GLES2 | |||
window->internal->r_fbVg = nvgCreateSharedGLES2(window->internal->r_vg, NVG_ANTIALIAS); | |||
#else | |||
window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); | |||
#endif | |||
// swap contexts | |||
window->internal->o_vg = window->vg; | |||
window->internal->o_fbVg = window->fbVg; | |||
window->vg = window->internal->r_vg; | |||
window->fbVg = window->internal->r_fbVg; | |||
// also for fonts and images | |||
window->uiFont->vg = window->vg; | |||
window->uiFont->handle = loadFallbackFont(window->vg); | |||
for (auto& font : window->internal->fontCache) | |||
{ | |||
font.second->vg = window->vg; | |||
font.second->ohandle = font.second->handle; | |||
font.second->handle = nvgCreateFont(window->vg, | |||
font.second->ofilename.c_str(), font.second->ofilename.c_str()); | |||
} | |||
for (auto& image : window->internal->imageCache) | |||
{ | |||
image.second->vg = window->vg; | |||
image.second->ohandle = image.second->handle; | |||
image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | |||
NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
} | |||
// Init settings | |||
WindowParametersRestore(window); | |||
widget::Widget::ContextCreateEvent e; | |||
APP->scene->onContextCreate(e); | |||
} | |||
else | |||
{ | |||
widget::Widget::ContextDestroyEvent e; | |||
APP->scene->onContextDestroy(e); | |||
// swap contexts | |||
window->uiFont->vg = window->internal->o_vg; | |||
window->vg = window->internal->o_vg; | |||
window->fbVg = window->internal->o_fbVg; | |||
window->internal->o_vg = nullptr; | |||
window->internal->o_fbVg = nullptr; | |||
// also for fonts and images | |||
window->uiFont->vg = window->vg; | |||
window->uiFont->handle = loadFallbackFont(window->vg); | |||
for (auto& font : window->internal->fontCache) | |||
{ | |||
font.second->vg = window->vg; | |||
font.second->handle = font.second->ohandle; | |||
font.second->ohandle = -1; | |||
} | |||
for (auto& image : window->internal->imageCache) | |||
{ | |||
image.second->vg = window->vg; | |||
image.second->handle = image.second->ohandle; | |||
image.second->ohandle = -1; | |||
} | |||
#if defined NANOVG_GLES2 | |||
nvgDeleteGLES2(window->internal->r_fbVg); | |||
#else | |||
nvgDeleteGL2(window->internal->r_fbVg); | |||
#endif | |||
window->internal->tlw = nullptr; | |||
window->internal->callback = nullptr; | |||
} | |||
} | |||
void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
{ | |||
// if nanovg context failed, init only bare minimum | |||
@@ -264,6 +371,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
INFO("Renderer: %s %s", vendor, renderer); | |||
INFO("OpenGL: %s", version); | |||
window->internal->tlw = ui; | |||
window->internal->ui = ui; | |||
window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); | |||
@@ -339,6 +447,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||
nvgDeleteGL2(window->internal->r_fbVg); | |||
#endif | |||
window->internal->tlw = nullptr; | |||
window->internal->ui = nullptr; | |||
window->internal->callback = nullptr; | |||
} | |||
@@ -384,8 +493,8 @@ void Window::setSize(math::Vec size) { | |||
size = size.max(WINDOW_SIZE_MIN); | |||
internal->size = size; | |||
if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) | |||
ui->setSize(internal->size.x, internal->size.y); | |||
if (DGL_NAMESPACE::NanoTopLevelWidget* const tlw = internal->ui) | |||
tlw->setSize(internal->size.x, internal->size.y); | |||
} | |||
void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { | |||
@@ -453,7 +562,7 @@ static void Window__writeImagePNG(void* context, void* data, int size) { | |||
void Window::step() { | |||
DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); | |||
if (vg == nullptr) | |||
return; | |||
@@ -480,12 +589,12 @@ void Window::step() { | |||
windowTitle += system::getFilename(APP->patch->path); | |||
} | |||
if (windowTitle != internal->lastWindowTitle) { | |||
internal->ui->getWindow().setTitle(windowTitle.c_str()); | |||
internal->tlw->getWindow().setTitle(windowTitle.c_str()); | |||
internal->lastWindowTitle = windowTitle; | |||
} | |||
// Get desired pixel ratio | |||
float newPixelRatio = internal->ui->getScaleFactor(); | |||
float newPixelRatio = internal->tlw->getScaleFactor(); | |||
if (newPixelRatio != pixelRatio) { | |||
pixelRatio = newPixelRatio; | |||
APP->event->handleDirty(); | |||
@@ -504,8 +613,8 @@ void Window::step() { | |||
#endif | |||
// Get framebuffer/window ratio | |||
int winWidth = internal->ui->getWidth(); | |||
int winHeight = internal->ui->getHeight(); | |||
int winWidth = internal->tlw->getWidth(); | |||
int winHeight = internal->tlw->getHeight(); | |||
int fbWidth = winWidth;// * newPixelRatio; | |||
int fbHeight = winHeight;// * newPixelRatio; | |||
windowRatio = (float)fbWidth / winWidth; | |||
@@ -599,9 +708,9 @@ void Window::screenshotModules(const std::string&, float) { | |||
void Window::close() { | |||
DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); | |||
internal->ui->getWindow().close(); | |||
internal->tlw->getWindow().close(); | |||
} | |||
@@ -610,7 +719,7 @@ void Window::cursorLock() { | |||
if (!settings::allowCursorLock) | |||
return; | |||
emscripten_request_pointerlock(internal->ui->getWindow().getApp().getClassName(), false); | |||
emscripten_request_pointerlock(internal->tlw->getWindow().getApp().getClassName(), false); | |||
#endif | |||
} | |||
@@ -643,7 +752,7 @@ int Window::getMods() { | |||
void Window::setFullScreen(const bool fullscreen) { | |||
#ifdef DISTRHO_OS_WASM | |||
if (fullscreen) | |||
emscripten_request_fullscreen(internal->ui->getWindow().getApp().getClassName(), false); | |||
emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); | |||
else | |||
emscripten_exit_fullscreen(); | |||
#endif | |||