diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ff00eeb..0616215 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -732,12 +732,12 @@ jobs: run: | source ~/PawPawBuilds/emsdk/emsdk_env.sh ./deps/PawPaw/bootstrap-cardinal.sh wasm && ./deps/PawPaw/.cleanup.sh wasm - #- name: Build wasm cross-compiled - #run: | - #source ~/PawPawBuilds/emsdk/emsdk_env.sh - #pushd deps/PawPaw; source local.env wasm; popd - #make features - #make CIBUILD=true NOOPT=true -j $(nproc) + - name: Build wasm cross-compiled + run: | + source ~/PawPawBuilds/emsdk/emsdk_env.sh + pushd deps/PawPaw; source local.env wasm; popd + make features + make CIBUILD=true NOOPT=true USING_GLES2=true -j $(nproc) - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true id: slug1 @@ -749,23 +749,23 @@ jobs: - name: Set sha8 id: slug run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - #- name: Pack binaries - #run: | - #cd bin; zip -r -9 ../${{ github.event.repository.name }}-wasm-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.zip $(ls *.html *.data *.js *.wasm) - #- uses: actions/upload-artifact@v2 - #with: - #name: ${{ github.event.repository.name }}-wasm-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - #path: | - #*.zip - #- uses: softprops/action-gh-release@v1 - #if: startsWith(github.ref, 'refs/tags/') - #with: - #tag_name: ${{ github.ref_name }} - #name: ${{ github.ref_name }} - #draft: false - #prerelease: false - #files: | - #*.zip + - name: Pack binaries + run: | + cd bin; zip -r -9 ../${{ github.event.repository.name }}-wasm-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.zip $(ls *.html *.data *.js *.wasm) + - uses: actions/upload-artifact@v2 + with: + name: ${{ github.event.repository.name }}-wasm-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + path: | + *.zip + - uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + tag_name: ${{ github.ref_name }} + name: ${{ github.ref_name }} + draft: false + prerelease: false + files: | + *.zip win32: runs-on: ubuntu-20.04 diff --git a/src/Makefile b/src/Makefile index 5c2c9eb..f575c33 100644 --- a/src/Makefile +++ b/src/Makefile @@ -136,6 +136,7 @@ RACK_FILES += override/plugin.cpp RACK_FILES += override/Engine.cpp RACK_FILES += override/MenuBar.cpp RACK_FILES += override/Model.cpp +RACK_FILES += override/OpenGlWidget.cpp RACK_FILES += override/Scene.cpp RACK_FILES += Rack/dep/pffft/pffft.c @@ -164,6 +165,7 @@ IGNORED_FILES += Rack/src/app/TipWindow.cpp IGNORED_FILES += Rack/src/dsp/minblep.cpp IGNORED_FILES += Rack/src/engine/Engine.cpp IGNORED_FILES += Rack/src/plugin/Model.cpp +IGNORED_FILES += Rack/src/widget/OpenGlWidget.cpp IGNORED_FILES += Rack/src/window/Window.cpp IGNORED_FILES += $(wildcard Rack/src/core/*.cpp) diff --git a/src/override/.generate-diffs.sh b/src/override/.generate-diffs.sh index 68b2646..887e293 100755 --- a/src/override/.generate-diffs.sh +++ b/src/override/.generate-diffs.sh @@ -10,4 +10,5 @@ diff -U3 ../Rack/src/app/MenuBar.cpp MenuBar.cpp > diffs/MenuBar.cpp.diff diff -U3 ../Rack/src/app/Scene.cpp Scene.cpp > diffs/Scene.cpp.diff diff -U3 ../Rack/src/engine/Engine.cpp Engine.cpp > diffs/Engine.cpp.diff diff -U3 ../Rack/src/plugin/Model.cpp Model.cpp > diffs/Model.cpp.diff +diff -U3 ../Rack/src/widget/OpenGlWidget.cpp OpenGlWidget.cpp > diffs/OpenGlWidget.cpp.diff diff -U3 ../Rack/src/window/Window.cpp Window.cpp > diffs/Window.cpp.diff diff --git a/src/override/OpenGlWidget.cpp b/src/override/OpenGlWidget.cpp new file mode 100644 index 0000000..a8aad19 --- /dev/null +++ b/src/override/OpenGlWidget.cpp @@ -0,0 +1,48 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * 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 any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +/** + * This file is an edited version of VCVRack's OpenGlWidget.cpp + * Copyright (C) 2016-2021 VCV. + * + * 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. + */ + +#include +#include + + +namespace rack { +namespace widget { + + +void OpenGlWidget::step() { + // Render every frame + dirty = true; + FramebufferWidget::step(); +} + + +void OpenGlWidget::drawFramebuffer() { +} + + +} // namespace widget +} // namespace rack diff --git a/src/override/diffs/Engine.cpp.diff b/src/override/diffs/Engine.cpp.diff index adc19eb..7a58e95 100644 --- a/src/override/diffs/Engine.cpp.diff +++ b/src/override/diffs/Engine.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/engine/Engine.cpp 2022-06-04 19:14:19.947414815 +0100 -+++ Engine.cpp 2022-06-27 19:37:11.048290788 +0100 +--- ../Rack/src/engine/Engine.cpp 2022-04-11 20:05:02.011283836 +0100 ++++ Engine.cpp 2022-06-29 01:30:02.024102120 +0100 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin diff --git a/src/override/diffs/MenuBar.cpp.diff b/src/override/diffs/MenuBar.cpp.diff index c08d090..5a32860 100644 --- a/src/override/diffs/MenuBar.cpp.diff +++ b/src/override/diffs/MenuBar.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/app/MenuBar.cpp 2022-07-07 00:16:13.700491991 +0100 -+++ MenuBar.cpp 2022-07-08 12:33:18.481979775 +0100 +--- ../Rack/src/app/MenuBar.cpp 2022-07-12 09:46:20.716165650 +0100 ++++ MenuBar.cpp 2022-07-12 09:45:31.518663160 +0100 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin @@ -36,15 +36,19 @@ #include #include #include -@@ -25,8 +50,17 @@ +@@ -25,8 +50,21 @@ #include #include ++#include "../CardinalCommon.hpp" ++ +#ifdef HAVE_LIBLO +# include +#endif + -+#include "../CardinalCommon.hpp" ++#ifdef DISTRHO_OS_WASM ++# include "DistrhoStandaloneUtils.hpp" ++#endif namespace rack { +namespace asset { @@ -54,7 +58,7 @@ namespace app { namespace menuBar { -@@ -48,79 +82,135 @@ +@@ -48,79 +86,140 @@ }; @@ -99,8 +103,14 @@ menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { +- menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { - APP->patch->loadTemplateDialog(); ++#ifndef DISTRHO_OS_WASM ++ const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; ++#else ++ const char* const NewShortcut = ""; ++#endif ++ menu->addChild(createMenuItem("New", NewShortcut, []() { + patchUtils::loadTemplateDialog(); })); @@ -162,7 +172,7 @@ - })); +#ifdef HAVE_LIBLO + menu->addChild(new ui::MenuSeparator); - ++ + if (patchUtils::isRemoteConnected()) { + menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { + patchUtils::deployToRemote(); @@ -179,7 +189,7 @@ + })); + } +#endif -+ + +#ifndef DISTRHO_OS_WASM menu->addChild(new ui::MenuSeparator); @@ -231,7 +241,7 @@ } }; -@@ -166,7 +256,7 @@ +@@ -166,7 +265,7 @@ menu->addChild(new ui::MenuSeparator); @@ -240,7 +250,7 @@ } }; -@@ -256,7 +346,7 @@ +@@ -256,7 +355,7 @@ return settings::cableTension; } float getDefaultValue() override { @@ -249,7 +259,7 @@ } float getDisplayValue() override { return getValue() * 100; -@@ -399,28 +489,6 @@ +@@ -399,28 +498,6 @@ menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); @@ -278,7 +288,7 @@ menu->addChild(createMenuLabel("Appearance")); menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); -@@ -446,9 +514,16 @@ +@@ -446,9 +523,18 @@ menu->addChild(haloBrightnessSlider); menu->addChild(new ui::MenuSeparator); @@ -291,12 +301,13 @@ + menu->addChild(new ui::MenuSeparator); menu->addChild(createMenuLabel("Parameters")); -- menu->addChild(createBoolPtrMenuItem("Lock cursor while dragging", "", &settings::allowCursorLock)); -+ // menu->addChild(createBoolPtrMenuItem("Lock cursor while dragging", "", &settings::allowCursorLock)); ++#ifdef DISTRHO_OS_WASM + menu->addChild(createBoolPtrMenuItem("Lock cursor while dragging", "", &settings::allowCursorLock)); ++#endif static const std::vector knobModeLabels = { "Linear", -@@ -473,11 +548,24 @@ +@@ -473,11 +559,34 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(new ui::MenuSeparator); @@ -304,9 +315,19 @@ + menu->addChild(createMenuLabel("Window")); - menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); -+ menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); ++#ifdef DISTRHO_OS_WASM ++ const bool fullscreen = APP->window->isFullScreen(); ++ std::string fullscreenText = "F11"; ++ if (fullscreen) ++ fullscreenText += " " CHECKMARK_STRING; ++ menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { ++ APP->window->setFullScreen(!fullscreen); ++ })); ++#endif - menu->addChild(createBoolPtrMenuItem("Auto-squeeze algorithm (experimental)", "", &settings::squeezeModules)); ++ menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); ++ + static const std::vector rateLimitLabels = { + "None", + "2x", @@ -324,7 +345,7 @@ } }; -@@ -487,47 +575,6 @@ +@@ -487,47 +596,6 @@ //////////////////// @@ -372,11 +393,10 @@ struct EngineButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); -@@ -540,269 +587,6 @@ - menu->addChild(createMenuItem("Performance meters", cpuMeterText, [=]() { +@@ -541,268 +609,42 @@ settings::cpuMeter ^= true; })); -- + - menu->addChild(createMenuItem("Sample rate", RIGHT_ARROW)); - - menu->addChild(createSubmenuItem("Threads", string::f("%d", settings::threadCount), [=](ui::Menu* menu) { @@ -558,7 +578,16 @@ - else if (!library::isLoggedIn()) { - addChild(createMenuItem("Register VCV account", "", [=]() { - system::openBrowser("https://vcvrack.com/login"); -- })); ++#ifdef DISTRHO_OS_WASM ++ if (supportsAudioInput()) { ++ const bool enabled = isAudioInputEnabled(); ++ std::string text = "Enable Audio Input"; ++ if (enabled) ++ text += " " CHECKMARK_STRING; ++ menu->addChild(createMenuItem(text, "", [enabled]() { ++ if (!enabled) ++ requestAudioInput(); + })); - - ui::TextField* emailField = new ui::TextField; - emailField->placeholder = "Email"; @@ -577,15 +606,23 @@ - logInItem->passwordField = passwordField; - passwordField->logInItem = logInItem; - addChild(logInItem); -- } + } - else { - addChild(createMenuItem("Log out", "", [=]() { - library::logOut(); - })); -- + - addChild(createMenuItem("Browse VCV Library", "", [=]() { - system::openBrowser("https://library.vcvrack.com/"); -- })); ++ if (supportsMIDI()) { ++ const bool enabled = isMIDIEnabled(); ++ std::string text = "Enable MIDI"; ++ if (enabled) ++ text += " " CHECKMARK_STRING; ++ menu->addChild(createMenuItem(text, "", [enabled]() { ++ if (!enabled) ++ requestMIDI(); + })); - - SyncUpdatesItem* syncItem = new SyncUpdatesItem; - syncItem->text = "Update all"; @@ -601,11 +638,11 @@ - addChild(updateItem); - } - } -- } + } - } -}; - -- + -struct LibraryButton : MenuButton { - NotificationIcon* notification; - @@ -636,13 +673,25 @@ - if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "All plugins have been downloaded. Close and re-launch Rack to load new updates.")) { - APP->window->close(); - } -- } ++ if (supportsBufferSizeChanges()) { ++ static const std::vector bufferSizes = {256, 512, 1024, 2048, 4096, 8192, 16384}; ++ const uint32_t currentBufferSize = getBufferSize(); ++ menu->addChild(createSubmenuItem("Buffer Size", std::to_string(currentBufferSize), [=](ui::Menu* menu) { ++ for (uint32_t bufferSize : bufferSizes) { ++ menu->addChild(createCheckMenuItem(std::to_string(bufferSize), "", ++ [=]() {return currentBufferSize == bufferSize;}, ++ [=]() {requestBufferSizeChange(bufferSize);} ++ )); ++ } ++ })); + } - - MenuButton::step(); ++#endif } }; -@@ -813,65 +597,23 @@ +@@ -813,65 +655,23 @@ struct HelpButton : MenuButton { @@ -714,18 +763,18 @@ } }; -@@ -921,7 +663,9 @@ +@@ -921,7 +721,9 @@ struct MenuBar : widget::OpaqueWidget { MeterLabel* meterLabel; - MenuBar() { + MenuBar(const bool isStandalone) + : widget::OpaqueWidget() -+ { ++ { const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; -@@ -930,7 +674,7 @@ +@@ -930,7 +732,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); @@ -734,7 +783,7 @@ fileButton->text = "File"; layout->addChild(fileButton); -@@ -946,10 +690,6 @@ +@@ -946,10 +748,6 @@ engineButton->text = "Engine"; layout->addChild(engineButton); @@ -745,7 +794,7 @@ HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; layout->addChild(helpButton); -@@ -984,7 +724,11 @@ +@@ -984,7 +782,11 @@ widget::Widget* createMenuBar() { diff --git a/src/override/diffs/Model.cpp.diff b/src/override/diffs/Model.cpp.diff index 69df973..b1f5617 100644 --- a/src/override/diffs/Model.cpp.diff +++ b/src/override/diffs/Model.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/plugin/Model.cpp 2022-07-07 00:16:13.701492001 +0100 -+++ Model.cpp 2022-07-05 16:34:56.679860788 +0100 +--- ../Rack/src/plugin/Model.cpp 2022-07-12 09:46:20.716165650 +0100 ++++ Model.cpp 2022-07-06 16:19:37.977002863 +0100 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin diff --git a/src/override/diffs/OpenGlWidget.cpp.diff b/src/override/diffs/OpenGlWidget.cpp.diff new file mode 100644 index 0000000..1ada3cd --- /dev/null +++ b/src/override/diffs/OpenGlWidget.cpp.diff @@ -0,0 +1,57 @@ +--- ../Rack/src/widget/OpenGlWidget.cpp 2022-04-11 20:05:02.023283713 +0100 ++++ OpenGlWidget.cpp 2022-07-14 01:14:57.028367786 +0100 +@@ -1,3 +1,30 @@ ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2022 Filipe Coelho ++ * ++ * 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 any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's OpenGlWidget.cpp ++ * Copyright (C) 2016-2021 VCV. ++ * ++ * 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. ++ */ ++ + #include + #include + +@@ -14,23 +41,6 @@ + + + void OpenGlWidget::drawFramebuffer() { +- math::Vec fbSize = getFramebufferSize(); +- glViewport(0.0, 0.0, fbSize.x, fbSize.y); +- glClearColor(0.0, 0.0, 0.0, 1.0); +- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +- +- glMatrixMode(GL_PROJECTION); +- glLoadIdentity(); +- glOrtho(0.0, fbSize.x, 0.0, fbSize.y, -1.0, 1.0); +- +- glBegin(GL_TRIANGLES); +- glColor3f(1, 0, 0); +- glVertex3f(0, 0, 0); +- glColor3f(0, 1, 0); +- glVertex3f(fbSize.x, 0, 0); +- glColor3f(0, 0, 1); +- glVertex3f(0, fbSize.y, 0); +- glEnd(); + } + + diff --git a/src/override/diffs/Scene.cpp.diff b/src/override/diffs/Scene.cpp.diff index e3591d4..3d338e9 100644 --- a/src/override/diffs/Scene.cpp.diff +++ b/src/override/diffs/Scene.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/app/Scene.cpp 2022-06-04 19:14:19.947414815 +0100 -+++ Scene.cpp 2022-07-06 09:36:54.421492710 +0100 +--- ../Rack/src/app/Scene.cpp 2022-04-11 20:05:02.007283878 +0100 ++++ Scene.cpp 2022-07-12 09:45:31.518663160 +0100 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin @@ -269,7 +269,7 @@ e.consume(this); } if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -220,22 +335,29 @@ +@@ -220,24 +335,37 @@ APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); e.consume(this); } @@ -291,10 +291,6 @@ settings::cpuMeter ^= true; e.consume(this); } -- if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { -- APP->window->setFullScreen(!APP->window->isFullScreen()); -- // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. -- // menuBar->hide(); + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { + patchUtils::deployToRemote(); + window::generateScreenshot(); @@ -302,10 +298,20 @@ + } + if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { + window::generateScreenshot(); ++ e.consume(this); ++ } ++#ifdef DISTRHO_OS_WASM + if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { + APP->window->setFullScreen(!APP->window->isFullScreen()); +- // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. +- // menuBar->hide(); e.consume(this); } ++#endif -@@ -326,13 +448,6 @@ + // Module selections + if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { +@@ -326,13 +454,6 @@ // Key commands that can be overridden by children if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { @@ -319,7 +325,7 @@ if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { rack->pasteClipboardAction(); e.consume(this); -@@ -351,7 +466,7 @@ +@@ -351,7 +472,7 @@ std::string extension = system::getExtension(path); if (extension == ".vcv") { @@ -328,7 +334,7 @@ e.consume(this); return; } -@@ -368,3 +483,94 @@ +@@ -368,3 +489,94 @@ } // namespace app } // namespace rack diff --git a/src/override/diffs/Window.cpp.diff b/src/override/diffs/Window.cpp.diff index c6a8b19..2082672 100644 --- a/src/override/diffs/Window.cpp.diff +++ b/src/override/diffs/Window.cpp.diff @@ -1,6 +1,6 @@ ---- ../Rack/src/window/Window.cpp 2022-06-04 19:14:19.951414839 +0100 -+++ Window.cpp 2022-07-08 12:18:51.634824005 +0100 -@@ -1,33 +1,83 @@ +--- ../Rack/src/window/Window.cpp 2022-04-11 20:05:02.023283713 +0100 ++++ Window.cpp 2022-07-12 09:45:31.518663160 +0100 +@@ -1,33 +1,87 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho @@ -75,6 +75,10 @@ + +#ifndef DGL_NO_SHARED_RESOURCES +# include "src/Resources.hpp" ++#endif ++ ++#ifdef DISTRHO_OS_WASM ++# include +#endif namespace rack { @@ -97,7 +101,7 @@ Font::~Font() { -@@ -42,9 +92,8 @@ +@@ -42,9 +96,8 @@ // Transfer ownership of font data to font object uint8_t* data = system::readFile(filename, &size); // Don't use nvgCreateFont because it doesn't properly handle UTF-8 filenames on Windows. @@ -108,7 +112,7 @@ throw Exception("Failed to load font %s", filename.c_str()); } INFO("Loaded font %s", filename.c_str()); -@@ -79,375 +128,317 @@ +@@ -79,375 +132,325 @@ } @@ -167,7 +171,11 @@ + + Internal() + : hiddenApp(false), -+ hiddenWindow(hiddenApp) { hiddenApp.idle(); } ++ hiddenWindow(hiddenApp) ++ { ++ hiddenWindow.setIgnoringKeyRepeat(true); ++ hiddenApp.idle(); ++ } }; @@ -239,6 +247,18 @@ - APP->event->handleButton(APP->window->internal->lastMousePos, button, action, mods); -} +- +- +-static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { +- contextSet((Context*) glfwGetWindowUserPointer(win)); +- math::Vec mousePos = math::Vec(xpos, ypos).div(APP->window->pixelRatio / APP->window->windowRatio).round(); +- math::Vec mouseDelta = mousePos.minus(APP->window->internal->lastMousePos); +- +- // Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. +- if (APP->window->internal->ignoreNextMouseDelta) { +- APP->window->internal->ignoreNextMouseDelta = false; +- mouseDelta = math::Vec(); +- } + // Load default Blendish font +#ifndef DGL_NO_SHARED_RESOURCES + uiFont = std::make_shared(); @@ -255,14 +275,30 @@ + uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); +#endif +- int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); +- (void) cursorMode; + if (uiFont != nullptr) + bndSetFont(uiFont->handle); + +-#if defined ARCH_MAC +- // Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own. +- // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. +- if (cursorMode == GLFW_CURSOR_HIDDEN) { +- // CGSetLocalEventsSuppressionInterval(0.0); +- glfwSetCursorPos(win, APP->window->internal->lastMousePos.x, APP->window->internal->lastMousePos.y); +- CGAssociateMouseAndMouseCursorPosition(true); +- mousePos = APP->window->internal->lastMousePos; +- } +- // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window +- glfwSetCursor(win, NULL); ++#ifdef DISTRHO_OS_WASM ++ emscripten_lock_orientation(EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY); + #endif +} --static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { -- contextSet((Context*) glfwGetWindowUserPointer(win)); -- math::Vec mousePos = math::Vec(xpos, ypos).div(APP->window->pixelRatio / APP->window->windowRatio).round(); -- math::Vec mouseDelta = mousePos.minus(APP->window->internal->lastMousePos); +- APP->window->internal->lastMousePos = mousePos; +- +- APP->event->handleHover(mousePos, mouseDelta); +void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) +{ + if (ui != nullptr) @@ -284,11 +320,12 @@ + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); +#endif -- // Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. -- if (APP->window->internal->ignoreNextMouseDelta) { -- APP->window->internal->ignoreNextMouseDelta = false; -- mouseDelta = math::Vec(); -- } +- // Keyboard/mouse MIDI driver +- int width, height; +- glfwGetWindowSize(win, &width, &height); +- math::Vec scaledPos(xpos / width, ypos / height); +- keyboard::mouseMove(scaledPos); +-} + // swap contexts + window->internal->o_vg = window->vg; + window->internal->o_fbVg = window->fbVg; @@ -313,40 +350,22 @@ + NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); + } -- int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); -- (void) cursorMode; + // Init settings + WindowParametersRestore(window); --#if defined ARCH_MAC -- // Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own. -- // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. -- if (cursorMode == GLFW_CURSOR_HIDDEN) { -- // CGSetLocalEventsSuppressionInterval(0.0); -- glfwSetCursorPos(win, APP->window->internal->lastMousePos.x, APP->window->internal->lastMousePos.y); -- CGAssociateMouseAndMouseCursorPosition(true); -- mousePos = APP->window->internal->lastMousePos; +-static void cursorEnterCallback(GLFWwindow* win, int entered) { +- contextSet((Context*) glfwGetWindowUserPointer(win)); +- if (!entered) { +- APP->event->handleLeave(); + widget::Widget::ContextCreateEvent e; + APP->scene->onContextCreate(e); } -- // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window -- glfwSetCursor(win, NULL); --#endif -- -- APP->window->internal->lastMousePos = mousePos; -- -- APP->event->handleHover(mousePos, mouseDelta); +-} + else + { + widget::Widget::ContextDestroyEvent e; + APP->scene->onContextDestroy(e); -- // Keyboard/mouse MIDI driver -- int width, height; -- glfwGetWindowSize(win, &width, &height); -- math::Vec scaledPos(xpos / width, ypos / height); -- keyboard::mouseMove(scaledPos); --} + // swap contexts + window->uiFont->vg = window->internal->o_vg; + window->vg = window->internal->o_vg; @@ -370,31 +389,46 @@ + image.second->ohandle = -1; + } -+#if defined NANOVG_GLES2 -+ nvgDeleteGLES2(window->internal->r_fbVg); -+#else -+ nvgDeleteGL2(window->internal->r_fbVg); -+#endif - --static void cursorEnterCallback(GLFWwindow* win, int entered) { -- contextSet((Context*) glfwGetWindowUserPointer(win)); -- if (!entered) { -- APP->event->handleLeave(); -+ window->internal->ui = nullptr; -+ window->internal->callback = nullptr; - } - } - -+void WindowSetMods(Window* const window, const int mods) -+{ -+ window->internal->mods = mods; -+} - -static void scrollCallback(GLFWwindow* win, double x, double y) { - contextSet((Context*) glfwGetWindowUserPointer(win)); - math::Vec scrollDelta = math::Vec(x, y); -#if defined ARCH_MAC - scrollDelta = scrollDelta.mult(10.0); ++#if defined NANOVG_GLES2 ++ nvgDeleteGLES2(window->internal->r_fbVg); + #else +- scrollDelta = scrollDelta.mult(50.0); ++ nvgDeleteGL2(window->internal->r_fbVg); + #endif + +- APP->event->handleScroll(APP->window->internal->lastMousePos, scrollDelta); ++ window->internal->ui = nullptr; ++ window->internal->callback = nullptr; ++ } + } + +- +-static void charCallback(GLFWwindow* win, unsigned int codepoint) { +- contextSet((Context*) glfwGetWindowUserPointer(win)); +- if (APP->event->handleText(APP->window->internal->lastMousePos, codepoint)) +- return; ++void WindowSetMods(Window* const window, const int mods) ++{ ++ window->internal->mods = mods; + } + +- +-static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { +- contextSet((Context*) glfwGetWindowUserPointer(win)); +- if (APP->event->handleKey(APP->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); +Window::~Window() { + { + DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); @@ -408,47 +442,14 @@ +#if defined NANOVG_GLES2 + nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); + nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); - #else -- scrollDelta = scrollDelta.mult(50.0); ++#else + nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); + nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); - #endif -+ } - -- APP->event->handleScroll(APP->window->internal->lastMousePos, scrollDelta); -+ delete internal; - } - - --static void charCallback(GLFWwindow* win, unsigned int codepoint) { -- contextSet((Context*) glfwGetWindowUserPointer(win)); -- if (APP->event->handleText(APP->window->internal->lastMousePos, codepoint)) -- return; -+math::Vec Window::getSize() { -+ return internal->size; - } - - --static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { -- contextSet((Context*) glfwGetWindowUserPointer(win)); -- if (APP->event->handleKey(APP->window->internal->lastMousePos, key, scancode, action, mods)) -- return; -+void Window::setSize(math::Vec size) { -+ size = size.max(WINDOW_SIZE_MIN); -+ internal->size = size; - -- // Keyboard/mouse MIDI driver -- if (action == GLFW_PRESS && (mods & RACK_MOD_MASK) == 0) { -- keyboard::press(key); -- } -- if (action == GLFW_RELEASE) { -- keyboard::release(key); -- } -+ if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) -+ ui->setSize(internal->size.x, internal->size.y); - } - ++#endif + } +-} - + -static void dropCallback(GLFWwindow* win, int count, const char** paths) { - contextSet((Context*) glfwGetWindowUserPointer(win)); - std::vector pathsVec; @@ -456,23 +457,24 @@ - pathsVec.push_back(paths[i]); - } - APP->event->handleDrop(APP->window->internal->lastMousePos, pathsVec); -+void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { -+ size = size.max(WINDOW_SIZE_MIN); -+ window->internal->size = size; ++ delete internal; } -static void errorCallback(int error, const char* description) { - WARN("GLFW error %d: %s", error, description); -+void Window::run() { -+ internal->frame = 0; ++math::Vec Window::getSize() { ++ return internal->size; } -Window::Window() { - internal = new Internal; - int err; -- ++void Window::setSize(math::Vec size) { ++ size = size.max(WINDOW_SIZE_MIN); ++ internal->size = size; + - // Set window hints -#if defined NANOVG_GL2 - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); @@ -553,10 +555,17 @@ - const GLubyte* version = glGetString(GL_VERSION); - INFO("Renderer: %s %s", vendor, renderer); - INFO("OpenGL: %s", version); -- ++ if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) ++ ui->setSize(internal->size.x, internal->size.y); ++} + - // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. - glGetError(); -- ++void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { ++ size = size.max(WINDOW_SIZE_MIN); ++ window->internal->size = size; ++} + - // Set up NanoVG - int nvgFlags = NVG_ANTIALIAS; -#if defined NANOVG_GL2 @@ -571,7 +580,7 @@ - osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize NanoVG. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed."); - throw Exception("Could not initialize NanoVG"); - } -- + - // Load default Blendish font - uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); - bndSetFont(uiFont->handle); @@ -579,6 +588,16 @@ - if (APP->scene) { - widget::Widget::ContextCreateEvent e; - APP->scene->onContextCreate(e); +- } ++void Window::run() { ++ internal->frame = 0; + } + + +-Window::~Window() { +- if (APP->scene) { +- widget::Widget::ContextDestroyEvent e; +- APP->scene->onContextDestroy(e); +#ifndef DGL_USE_GLES +static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { + for (int y = 0; y < height / 2; y++) { @@ -588,13 +607,33 @@ + std::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); + std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); } +- +- // Fonts and Images in the cache must be deleted before the NanoVG context is deleted +- internal->fontCache.clear(); +- internal->imageCache.clear(); +- +- // nvgDeleteClone(fbVg); +- +-#if defined NANOVG_GL2 +- nvgDeleteGL2(vg); +- nvgDeleteGL2(fbVg); +-#elif defined NANOVG_GL3 +- nvgDeleteGL3(vg); +-#elif defined NANOVG_GLES2 +- nvgDeleteGLES2(vg); +-#endif +- +- glfwDestroyWindow(win); +- delete internal; } --Window::~Window() { -- if (APP->scene) { -- widget::Widget::ContextDestroyEvent e; -- APP->scene->onContextDestroy(e); +-math::Vec Window::getSize() { +- int width, height; +- glfwGetWindowSize(win, &width, &height); +- return math::Vec(width, height); +-} +- +#ifdef STBI_WRITE_NO_STDIO +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { + int targetWidth = width; @@ -621,42 +660,15 @@ + const int xs = static_cast(x * scale); + std::memmove(pixels + (width * y + x) * 3, pixels + (width * ys + xs) * 3, 3); + } - } ++ } -- // Fonts and Images in the cache must be deleted before the NanoVG context is deleted -- internal->fontCache.clear(); -- internal->imageCache.clear(); -- -- // nvgDeleteClone(fbVg); -- --#if defined NANOVG_GL2 -- nvgDeleteGL2(vg); -- nvgDeleteGL2(fbVg); --#elif defined NANOVG_GL3 -- nvgDeleteGL3(vg); --#elif defined NANOVG_GLES2 -- nvgDeleteGLES2(vg); --#endif -- -- glfwDestroyWindow(win); -- delete internal; +-void Window::setSize(math::Vec size) { +- size = size.max(WINDOW_SIZE_MIN); +- glfwSetWindowSize(win, size.x, size.y); + width = targetWidth; + height = targetHeight; } -- --math::Vec Window::getSize() { -- int width, height; -- glfwGetWindowSize(win, &width, &height); -- return math::Vec(width, height); --} -- -- --void Window::setSize(math::Vec size) { -- size = size.max(WINDOW_SIZE_MIN); -- glfwSetWindowSize(win, size.x, size.y); --} -- - -void Window::run() { - internal->frame = 0; @@ -717,7 +729,7 @@ if (APP->patch->path != "") { windowTitle += " - "; if (!APP->history->isSaved()) -@@ -455,243 +446,159 @@ +@@ -455,246 +458,189 @@ windowTitle += system::getFilename(APP->patch->path); } if (windowTitle != internal->lastWindowTitle) { @@ -856,7 +868,7 @@ +#ifdef STBI_WRITE_NO_STDIO + Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); + stbi_write_png_to_func(Window__writeImagePNG, internal->ui, -+ winWidth, winHeight, depth, pixelsWithOffset, stride); ++ winWidth, winHeight, depth, pixelsWithOffset, stride); +#else + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); +#endif @@ -876,10 +888,6 @@ + delete[] pixels; } +#endif -+} -+ -+ -+void Window::activateContext() { } @@ -948,7 +956,7 @@ - nvgImageSize(vg, fbw->getImageHandle(), &width, &height); - uint8_t* pixels = new uint8_t[height * width * 4]; - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -+void Window::screenshot(const std::string&) { ++void Window::activateContext() { +} - // Write pixels to PNG @@ -961,6 +969,10 @@ - delete fbw; - } - } ++void Window::screenshot(const std::string&) { ++} ++ ++ +void Window::screenshotModules(const std::string&, float) { } @@ -974,29 +986,39 @@ void Window::cursorLock() { -- if (!settings::allowCursorLock) -- return; -- ++#ifdef DISTRHO_OS_WASM + if (!settings::allowCursorLock) + return; + -#if defined ARCH_MAC - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); -#else - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); --#endif ++ emscripten_request_pointerlock(internal->ui->getWindow().getApp().getClassName(), false); + #endif - internal->ignoreNextMouseDelta = true; } void Window::cursorUnlock() { -- if (!settings::allowCursorLock) -- return; -- ++#ifdef DISTRHO_OS_WASM + if (!settings::allowCursorLock) + return; + - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - internal->ignoreNextMouseDelta = true; ++ emscripten_exit_pointerlock(); ++#endif } bool Window::isCursorLocked() { - return glfwGetInputMode(win, GLFW_CURSOR) != GLFW_CURSOR_NORMAL; ++#ifdef DISTRHO_OS_WASM ++ EmscriptenPointerlockChangeEvent status; ++ if (emscripten_get_pointerlock_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) ++ return status.isActive; ++#endif + return false; } @@ -1027,22 +1049,36 @@ - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); - } -+void Window::setFullScreen(bool) { ++void Window::setFullScreen(const bool fullscreen) { ++#ifdef DISTRHO_OS_WASM ++ if (fullscreen) ++ emscripten_request_fullscreen(internal->ui->getWindow().getApp().getClassName(), false); ++ else ++ emscripten_exit_fullscreen(); ++#endif } bool Window::isFullScreen() { - GLFWmonitor* monitor = glfwGetWindowMonitor(win); - return monitor != NULL; -+#if defined(CARDINAL_TRANSPARENT_SCREENSHOTS) && !defined(DGL_USE_GLES) ++#ifdef DISTRHO_OS_WASM ++ EmscriptenFullscreenChangeEvent status; ++ if (emscripten_get_fullscreen_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) ++ return status.isFullscreen; ++ return false; ++#elif defined(CARDINAL_TRANSPARENT_SCREENSHOTS) && !defined(DGL_USE_GLES) + return internal->generateScreenshotStep != kScreenshotStepNone; +#else + return false; +#endif } - -@@ -722,14 +629,15 @@ +- + double Window::getMonitorRefreshRate() { + return internal->monitorRefreshRate; + } +@@ -722,14 +668,15 @@ return pair->second; // Load font @@ -1061,7 +1097,7 @@ } internal->fontCache[filename] = font; return font; -@@ -742,14 +650,15 @@ +@@ -742,14 +689,15 @@ return pair->second; // Load image @@ -1080,7 +1116,7 @@ } internal->imageCache[filename] = image; return image; -@@ -766,28 +675,156 @@ +@@ -766,28 +714,156 @@ } diff --git a/src/override/diffs/blendish.c.diff b/src/override/diffs/blendish.c.diff index feb7536..69f860a 100644 --- a/src/override/diffs/blendish.c.diff +++ b/src/override/diffs/blendish.c.diff @@ -1,5 +1,5 @@ ---- ../Rack/dep/oui-blendish/blendish.c 2022-06-04 19:14:37.919525628 +0100 -+++ blendish.c 2022-06-04 19:10:13.504951454 +0100 +--- ../Rack/dep/oui-blendish/blendish.c 2022-04-11 20:05:39.202902589 +0100 ++++ blendish.c 2022-04-11 19:51:05.409742542 +0100 @@ -61,7 +61,7 @@ } diff --git a/src/override/diffs/common.cpp.diff b/src/override/diffs/common.cpp.diff index 6f8995d..78d1a3d 100644 --- a/src/override/diffs/common.cpp.diff +++ b/src/override/diffs/common.cpp.diff @@ -1,6 +1,6 @@ ---- ../Rack/src/common.cpp 2022-06-04 19:14:19.947414815 +0100 -+++ common.cpp 2022-07-07 00:16:54.680919544 +0100 -@@ -1,11 +1,45 @@ +--- ../Rack/src/common.cpp 2022-04-11 20:05:02.007283878 +0100 ++++ common.cpp 2022-07-12 09:45:31.518663160 +0100 +@@ -1,33 +1,77 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho @@ -37,7 +37,8 @@ + +#include "DistrhoPluginUtils.hpp" - #if defined ARCH_WIN +-#if defined ARCH_WIN ++#if defined(ARCH_WIN) #include FILE* fopen_u8(const char* filename, const char* mode) { @@ -46,7 +47,17 @@ return _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str()); } -@@ -14,20 +48,21 @@ ++#elif defined(DISTRHO_OS_WASM) ++#include ++#undef fopen ++ ++FILE* fopen_wasm(const char* filename, const char* mode) { ++ chmod(filename, 0777); ++ return std::fopen(filename, mode); ++} ++ + #endif + namespace rack { diff --git a/src/override/diffs/context.cpp.diff b/src/override/diffs/context.cpp.diff index 52f3e6e..875e354 100644 --- a/src/override/diffs/context.cpp.diff +++ b/src/override/diffs/context.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/context.cpp 2022-06-04 19:14:19.947414815 +0100 -+++ context.cpp 2022-06-04 19:10:13.504951454 +0100 +--- ../Rack/src/context.cpp 2022-04-11 20:05:02.007283878 +0100 ++++ context.cpp 2022-04-11 19:51:05.409742542 +0100 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin diff --git a/src/override/diffs/plugin.cpp.diff b/src/override/diffs/plugin.cpp.diff index 82b395a..6e8392e 100644 --- a/src/override/diffs/plugin.cpp.diff +++ b/src/override/diffs/plugin.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/plugin.cpp 2022-07-07 00:16:13.701492001 +0100 -+++ plugin.cpp 2022-06-04 19:10:13.508951513 +0100 +--- ../Rack/src/plugin.cpp 2022-07-12 09:46:20.716165650 +0100 ++++ plugin.cpp 2022-05-27 23:15:35.681273727 +0100 @@ -1,342 +1,41 @@ -#include -#include