| @@ -732,12 +732,12 @@ jobs: | |||||
| run: | | run: | | ||||
| source ~/PawPawBuilds/emsdk/emsdk_env.sh | source ~/PawPawBuilds/emsdk/emsdk_env.sh | ||||
| ./deps/PawPaw/bootstrap-cardinal.sh wasm && ./deps/PawPaw/.cleanup.sh wasm | ./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) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| id: slug1 | id: slug1 | ||||
| @@ -749,23 +749,23 @@ jobs: | |||||
| - name: Set sha8 | - name: Set sha8 | ||||
| id: slug | id: slug | ||||
| run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" | 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: | win32: | ||||
| runs-on: ubuntu-20.04 | runs-on: ubuntu-20.04 | ||||
| @@ -136,6 +136,7 @@ RACK_FILES += override/plugin.cpp | |||||
| RACK_FILES += override/Engine.cpp | RACK_FILES += override/Engine.cpp | ||||
| RACK_FILES += override/MenuBar.cpp | RACK_FILES += override/MenuBar.cpp | ||||
| RACK_FILES += override/Model.cpp | RACK_FILES += override/Model.cpp | ||||
| RACK_FILES += override/OpenGlWidget.cpp | |||||
| RACK_FILES += override/Scene.cpp | RACK_FILES += override/Scene.cpp | ||||
| RACK_FILES += Rack/dep/pffft/pffft.c | 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/dsp/minblep.cpp | ||||
| IGNORED_FILES += Rack/src/engine/Engine.cpp | IGNORED_FILES += Rack/src/engine/Engine.cpp | ||||
| IGNORED_FILES += Rack/src/plugin/Model.cpp | IGNORED_FILES += Rack/src/plugin/Model.cpp | ||||
| IGNORED_FILES += Rack/src/widget/OpenGlWidget.cpp | |||||
| IGNORED_FILES += Rack/src/window/Window.cpp | IGNORED_FILES += Rack/src/window/Window.cpp | ||||
| IGNORED_FILES += $(wildcard Rack/src/core/*.cpp) | IGNORED_FILES += $(wildcard Rack/src/core/*.cpp) | ||||
| @@ -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/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/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/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 -U3 ../Rack/src/window/Window.cpp Window.cpp > diffs/Window.cpp.diff | ||||
| @@ -0,0 +1,48 @@ | |||||
| /* | |||||
| * DISTRHO Cardinal Plugin | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * 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 <widget/OpenGlWidget.hpp> | |||||
| #include <context.hpp> | |||||
| namespace rack { | |||||
| namespace widget { | |||||
| void OpenGlWidget::step() { | |||||
| // Render every frame | |||||
| dirty = true; | |||||
| FramebufferWidget::step(); | |||||
| } | |||||
| void OpenGlWidget::drawFramebuffer() { | |||||
| } | |||||
| } // namespace widget | |||||
| } // namespace rack | |||||
| @@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
| +/* | +/* | ||||
| + * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
| @@ -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 @@ | @@ -1,8 +1,33 @@ | ||||
| +/* | +/* | ||||
| + * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
| @@ -36,15 +36,19 @@ | |||||
| #include <app/MenuBar.hpp> | #include <app/MenuBar.hpp> | ||||
| #include <app/TipWindow.hpp> | #include <app/TipWindow.hpp> | ||||
| #include <widget/OpaqueWidget.hpp> | #include <widget/OpaqueWidget.hpp> | ||||
| @@ -25,8 +50,17 @@ | |||||
| @@ -25,8 +50,21 @@ | |||||
| #include <patch.hpp> | #include <patch.hpp> | ||||
| #include <library.hpp> | #include <library.hpp> | ||||
| +#include "../CardinalCommon.hpp" | |||||
| + | |||||
| +#ifdef HAVE_LIBLO | +#ifdef HAVE_LIBLO | ||||
| +# include <lo/lo.h> | +# include <lo/lo.h> | ||||
| +#endif | +#endif | ||||
| + | + | ||||
| +#include "../CardinalCommon.hpp" | |||||
| +#ifdef DISTRHO_OS_WASM | |||||
| +# include "DistrhoStandaloneUtils.hpp" | |||||
| +#endif | |||||
| namespace rack { | namespace rack { | ||||
| +namespace asset { | +namespace asset { | ||||
| @@ -54,7 +58,7 @@ | |||||
| namespace app { | namespace app { | ||||
| namespace menuBar { | namespace menuBar { | ||||
| @@ -48,79 +82,135 @@ | |||||
| @@ -48,79 +86,140 @@ | |||||
| }; | }; | ||||
| @@ -99,8 +103,14 @@ | |||||
| menu->cornerFlags = BND_CORNER_TOP; | menu->cornerFlags = BND_CORNER_TOP; | ||||
| menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | 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(); | - 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(); | + patchUtils::loadTemplateDialog(); | ||||
| })); | })); | ||||
| @@ -162,7 +172,7 @@ | |||||
| - })); | - })); | ||||
| +#ifdef HAVE_LIBLO | +#ifdef HAVE_LIBLO | ||||
| + menu->addChild(new ui::MenuSeparator); | + menu->addChild(new ui::MenuSeparator); | ||||
| + | |||||
| + if (patchUtils::isRemoteConnected()) { | + if (patchUtils::isRemoteConnected()) { | ||||
| + menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { | + menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { | ||||
| + patchUtils::deployToRemote(); | + patchUtils::deployToRemote(); | ||||
| @@ -179,7 +189,7 @@ | |||||
| + })); | + })); | ||||
| + } | + } | ||||
| +#endif | +#endif | ||||
| + | |||||
| +#ifndef DISTRHO_OS_WASM | +#ifndef DISTRHO_OS_WASM | ||||
| menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
| @@ -231,7 +241,7 @@ | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -166,7 +256,7 @@ | |||||
| @@ -166,7 +265,7 @@ | |||||
| menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
| @@ -240,7 +250,7 @@ | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -256,7 +346,7 @@ | |||||
| @@ -256,7 +355,7 @@ | |||||
| return settings::cableTension; | return settings::cableTension; | ||||
| } | } | ||||
| float getDefaultValue() override { | float getDefaultValue() override { | ||||
| @@ -249,7 +259,7 @@ | |||||
| } | } | ||||
| float getDisplayValue() override { | float getDisplayValue() override { | ||||
| return getValue() * 100; | return getValue() * 100; | ||||
| @@ -399,28 +489,6 @@ | |||||
| @@ -399,28 +498,6 @@ | |||||
| menu->cornerFlags = BND_CORNER_TOP; | menu->cornerFlags = BND_CORNER_TOP; | ||||
| menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | ||||
| @@ -278,7 +288,7 @@ | |||||
| menu->addChild(createMenuLabel("Appearance")); | menu->addChild(createMenuLabel("Appearance")); | ||||
| menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); | menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); | ||||
| @@ -446,9 +514,16 @@ | |||||
| @@ -446,9 +523,18 @@ | |||||
| menu->addChild(haloBrightnessSlider); | menu->addChild(haloBrightnessSlider); | ||||
| menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
| @@ -291,12 +301,13 @@ | |||||
| + menu->addChild(new ui::MenuSeparator); | + menu->addChild(new ui::MenuSeparator); | ||||
| menu->addChild(createMenuLabel("Parameters")); | 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<std::string> knobModeLabels = { | static const std::vector<std::string> knobModeLabels = { | ||||
| "Linear", | "Linear", | ||||
| @@ -473,11 +548,24 @@ | |||||
| @@ -473,11 +559,34 @@ | |||||
| menu->addChild(knobScrollSensitivitySlider); | menu->addChild(knobScrollSensitivitySlider); | ||||
| menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
| @@ -304,9 +315,19 @@ | |||||
| + menu->addChild(createMenuLabel("Window")); | + menu->addChild(createMenuLabel("Window")); | ||||
| - menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); | - 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("Auto-squeeze algorithm (experimental)", "", &settings::squeezeModules)); | ||||
| + menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); | |||||
| + | |||||
| + static const std::vector<std::string> rateLimitLabels = { | + static const std::vector<std::string> rateLimitLabels = { | ||||
| + "None", | + "None", | ||||
| + "2x", | + "2x", | ||||
| @@ -324,7 +345,7 @@ | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -487,47 +575,6 @@ | |||||
| @@ -487,47 +596,6 @@ | |||||
| //////////////////// | //////////////////// | ||||
| @@ -372,11 +393,10 @@ | |||||
| struct EngineButton : MenuButton { | struct EngineButton : MenuButton { | ||||
| void onAction(const ActionEvent& e) override { | void onAction(const ActionEvent& e) override { | ||||
| ui::Menu* menu = createMenu(); | ui::Menu* menu = createMenu(); | ||||
| @@ -540,269 +587,6 @@ | |||||
| menu->addChild(createMenuItem("Performance meters", cpuMeterText, [=]() { | |||||
| @@ -541,268 +609,42 @@ | |||||
| settings::cpuMeter ^= true; | settings::cpuMeter ^= true; | ||||
| })); | })); | ||||
| - | |||||
| - menu->addChild(createMenuItem<SampleRateItem>("Sample rate", RIGHT_ARROW)); | - menu->addChild(createMenuItem<SampleRateItem>("Sample rate", RIGHT_ARROW)); | ||||
| - | - | ||||
| - menu->addChild(createSubmenuItem("Threads", string::f("%d", settings::threadCount), [=](ui::Menu* menu) { | - menu->addChild(createSubmenuItem("Threads", string::f("%d", settings::threadCount), [=](ui::Menu* menu) { | ||||
| @@ -558,7 +578,16 @@ | |||||
| - else if (!library::isLoggedIn()) { | - else if (!library::isLoggedIn()) { | ||||
| - addChild(createMenuItem("Register VCV account", "", [=]() { | - addChild(createMenuItem("Register VCV account", "", [=]() { | ||||
| - system::openBrowser("https://vcvrack.com/login"); | - 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; | - ui::TextField* emailField = new ui::TextField; | ||||
| - emailField->placeholder = "Email"; | - emailField->placeholder = "Email"; | ||||
| @@ -577,15 +606,23 @@ | |||||
| - logInItem->passwordField = passwordField; | - logInItem->passwordField = passwordField; | ||||
| - passwordField->logInItem = logInItem; | - passwordField->logInItem = logInItem; | ||||
| - addChild(logInItem); | - addChild(logInItem); | ||||
| - } | |||||
| } | |||||
| - else { | - else { | ||||
| - addChild(createMenuItem("Log out", "", [=]() { | - addChild(createMenuItem("Log out", "", [=]() { | ||||
| - library::logOut(); | - library::logOut(); | ||||
| - })); | - })); | ||||
| - | |||||
| - addChild(createMenuItem("Browse VCV Library", "", [=]() { | - addChild(createMenuItem("Browse VCV Library", "", [=]() { | ||||
| - system::openBrowser("https://library.vcvrack.com/"); | - 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; | - SyncUpdatesItem* syncItem = new SyncUpdatesItem; | ||||
| - syncItem->text = "Update all"; | - syncItem->text = "Update all"; | ||||
| @@ -601,11 +638,11 @@ | |||||
| - addChild(updateItem); | - addChild(updateItem); | ||||
| - } | - } | ||||
| - } | - } | ||||
| - } | |||||
| } | |||||
| - } | - } | ||||
| -}; | -}; | ||||
| - | - | ||||
| - | |||||
| -struct LibraryButton : MenuButton { | -struct LibraryButton : MenuButton { | ||||
| - NotificationIcon* notification; | - 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.")) { | - 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(); | - APP->window->close(); | ||||
| - } | - } | ||||
| - } | |||||
| + if (supportsBufferSizeChanges()) { | |||||
| + static const std::vector<uint32_t> 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(); | - MenuButton::step(); | ||||
| +#endif | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -813,65 +597,23 @@ | |||||
| @@ -813,65 +655,23 @@ | |||||
| struct HelpButton : MenuButton { | struct HelpButton : MenuButton { | ||||
| @@ -714,18 +763,18 @@ | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -921,7 +663,9 @@ | |||||
| @@ -921,7 +721,9 @@ | |||||
| struct MenuBar : widget::OpaqueWidget { | struct MenuBar : widget::OpaqueWidget { | ||||
| MeterLabel* meterLabel; | MeterLabel* meterLabel; | ||||
| - MenuBar() { | - MenuBar() { | ||||
| + MenuBar(const bool isStandalone) | + MenuBar(const bool isStandalone) | ||||
| + : widget::OpaqueWidget() | + : widget::OpaqueWidget() | ||||
| + { | |||||
| + { | |||||
| const float margin = 5; | const float margin = 5; | ||||
| box.size.y = BND_WIDGET_HEIGHT + 2 * margin; | box.size.y = BND_WIDGET_HEIGHT + 2 * margin; | ||||
| @@ -930,7 +674,7 @@ | |||||
| @@ -930,7 +732,7 @@ | |||||
| layout->spacing = math::Vec(0, 0); | layout->spacing = math::Vec(0, 0); | ||||
| addChild(layout); | addChild(layout); | ||||
| @@ -734,7 +783,7 @@ | |||||
| fileButton->text = "File"; | fileButton->text = "File"; | ||||
| layout->addChild(fileButton); | layout->addChild(fileButton); | ||||
| @@ -946,10 +690,6 @@ | |||||
| @@ -946,10 +748,6 @@ | |||||
| engineButton->text = "Engine"; | engineButton->text = "Engine"; | ||||
| layout->addChild(engineButton); | layout->addChild(engineButton); | ||||
| @@ -745,7 +794,7 @@ | |||||
| HelpButton* helpButton = new HelpButton; | HelpButton* helpButton = new HelpButton; | ||||
| helpButton->text = "Help"; | helpButton->text = "Help"; | ||||
| layout->addChild(helpButton); | layout->addChild(helpButton); | ||||
| @@ -984,7 +724,11 @@ | |||||
| @@ -984,7 +782,11 @@ | |||||
| widget::Widget* createMenuBar() { | widget::Widget* createMenuBar() { | ||||
| @@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
| +/* | +/* | ||||
| + * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
| @@ -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 <falktx@falktx.com> | |||||
| + * | |||||
| + * 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 <widget/OpenGlWidget.hpp> | |||||
| #include <context.hpp> | |||||
| @@ -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(); | |||||
| } | |||||
| @@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
| +/* | +/* | ||||
| + * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
| @@ -269,7 +269,7 @@ | |||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | 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)); | APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| @@ -291,10 +291,6 @@ | |||||
| settings::cpuMeter ^= true; | settings::cpuMeter ^= true; | ||||
| e.consume(this); | 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) { | + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
| + patchUtils::deployToRemote(); | + patchUtils::deployToRemote(); | ||||
| + window::generateScreenshot(); | + window::generateScreenshot(); | ||||
| @@ -302,10 +298,20 @@ | |||||
| + } | + } | ||||
| + if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { | + if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
| + window::generateScreenshot(); | + 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); | 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 | // Key commands that can be overridden by children | ||||
| if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | 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) { | if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
| rack->pasteClipboardAction(); | rack->pasteClipboardAction(); | ||||
| e.consume(this); | e.consume(this); | ||||
| @@ -351,7 +466,7 @@ | |||||
| @@ -351,7 +472,7 @@ | |||||
| std::string extension = system::getExtension(path); | std::string extension = system::getExtension(path); | ||||
| if (extension == ".vcv") { | if (extension == ".vcv") { | ||||
| @@ -328,7 +334,7 @@ | |||||
| e.consume(this); | e.consume(this); | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -368,3 +483,94 @@ | |||||
| @@ -368,3 +489,94 @@ | |||||
| } // namespace app | } // namespace app | ||||
| } // namespace rack | } // namespace rack | ||||
| @@ -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 | + * DISTRHO Cardinal Plugin | ||||
| + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | ||||
| @@ -75,6 +75,10 @@ | |||||
| + | + | ||||
| +#ifndef DGL_NO_SHARED_RESOURCES | +#ifndef DGL_NO_SHARED_RESOURCES | ||||
| +# include "src/Resources.hpp" | +# include "src/Resources.hpp" | ||||
| +#endif | |||||
| + | |||||
| +#ifdef DISTRHO_OS_WASM | |||||
| +# include <emscripten/html5.h> | |||||
| +#endif | +#endif | ||||
| namespace rack { | namespace rack { | ||||
| @@ -97,7 +101,7 @@ | |||||
| Font::~Font() { | Font::~Font() { | ||||
| @@ -42,9 +92,8 @@ | |||||
| @@ -42,9 +96,8 @@ | |||||
| // Transfer ownership of font data to font object | // Transfer ownership of font data to font object | ||||
| uint8_t* data = system::readFile(filename, &size); | uint8_t* data = system::readFile(filename, &size); | ||||
| // Don't use nvgCreateFont because it doesn't properly handle UTF-8 filenames on Windows. | // 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()); | throw Exception("Failed to load font %s", filename.c_str()); | ||||
| } | } | ||||
| INFO("Loaded 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() | + Internal() | ||||
| + : hiddenApp(false), | + : 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); | - 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 | + // Load default Blendish font | ||||
| +#ifndef DGL_NO_SHARED_RESOURCES | +#ifndef DGL_NO_SHARED_RESOURCES | ||||
| + uiFont = std::make_shared<Font>(); | + uiFont = std::make_shared<Font>(); | ||||
| @@ -255,14 +275,30 @@ | |||||
| + uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); | + uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); | ||||
| +#endif | +#endif | ||||
| - int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); | |||||
| - (void) cursorMode; | |||||
| + if (uiFont != nullptr) | + if (uiFont != nullptr) | ||||
| + bndSetFont(uiFont->handle); | + 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) | +void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | ||||
| +{ | +{ | ||||
| + if (ui != nullptr) | + if (ui != nullptr) | ||||
| @@ -284,11 +320,12 @@ | |||||
| + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); | + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); | ||||
| +#endif | +#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 | + // swap contexts | ||||
| + window->internal->o_vg = window->vg; | + window->internal->o_vg = window->vg; | ||||
| + window->internal->o_fbVg = window->fbVg; | + window->internal->o_fbVg = window->fbVg; | ||||
| @@ -313,40 +350,22 @@ | |||||
| + NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | + NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | ||||
| + } | + } | ||||
| - int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); | |||||
| - (void) cursorMode; | |||||
| + // Init settings | + // Init settings | ||||
| + WindowParametersRestore(window); | + 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; | + widget::Widget::ContextCreateEvent e; | ||||
| + APP->scene->onContextCreate(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 | + else | ||||
| + { | + { | ||||
| + widget::Widget::ContextDestroyEvent e; | + widget::Widget::ContextDestroyEvent e; | ||||
| + APP->scene->onContextDestroy(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 | + // swap contexts | ||||
| + window->uiFont->vg = window->internal->o_vg; | + window->uiFont->vg = window->internal->o_vg; | ||||
| + window->vg = window->internal->o_vg; | + window->vg = window->internal->o_vg; | ||||
| @@ -370,85 +389,67 @@ | |||||
| + image.second->ohandle = -1; | + 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) { | -static void scrollCallback(GLFWwindow* win, double x, double y) { | ||||
| - contextSet((Context*) glfwGetWindowUserPointer(win)); | - contextSet((Context*) glfwGetWindowUserPointer(win)); | ||||
| - math::Vec scrollDelta = math::Vec(x, y); | - math::Vec scrollDelta = math::Vec(x, y); | ||||
| -#if defined ARCH_MAC | -#if defined ARCH_MAC | ||||
| - scrollDelta = scrollDelta.mult(10.0); | - scrollDelta = scrollDelta.mult(10.0); | ||||
| +Window::~Window() { | |||||
| + { | |||||
| + DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||||
| + internal->hiddenWindow.close(); | |||||
| + internal->hiddenApp.idle(); | |||||
| + | |||||
| + // Fonts and Images in the cache must be deleted before the NanoVG context is deleted | |||||
| + internal->fontCache.clear(); | |||||
| + internal->imageCache.clear(); | |||||
| + | |||||
| +#if defined NANOVG_GLES2 | +#if defined NANOVG_GLES2 | ||||
| + nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | |||||
| + nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); | |||||
| + nvgDeleteGLES2(window->internal->r_fbVg); | |||||
| #else | #else | ||||
| - scrollDelta = scrollDelta.mult(50.0); | - scrollDelta = scrollDelta.mult(50.0); | ||||
| + nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | |||||
| + nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); | |||||
| + nvgDeleteGL2(window->internal->r_fbVg); | |||||
| #endif | #endif | ||||
| + } | |||||
| - APP->event->handleScroll(APP->window->internal->lastMousePos, scrollDelta); | - APP->event->handleScroll(APP->window->internal->lastMousePos, scrollDelta); | ||||
| + delete internal; | |||||
| + window->internal->ui = nullptr; | |||||
| + window->internal->callback = nullptr; | |||||
| + } | |||||
| } | } | ||||
| - | |||||
| -static void charCallback(GLFWwindow* win, unsigned int codepoint) { | -static void charCallback(GLFWwindow* win, unsigned int codepoint) { | ||||
| - contextSet((Context*) glfwGetWindowUserPointer(win)); | - contextSet((Context*) glfwGetWindowUserPointer(win)); | ||||
| - if (APP->event->handleText(APP->window->internal->lastMousePos, codepoint)) | - if (APP->event->handleText(APP->window->internal->lastMousePos, codepoint)) | ||||
| - return; | - return; | ||||
| +math::Vec Window::getSize() { | |||||
| + return internal->size; | |||||
| +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) { | -static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { | ||||
| - contextSet((Context*) glfwGetWindowUserPointer(win)); | - contextSet((Context*) glfwGetWindowUserPointer(win)); | ||||
| - if (APP->event->handleKey(APP->window->internal->lastMousePos, key, scancode, action, mods)) | - if (APP->event->handleKey(APP->window->internal->lastMousePos, key, scancode, action, mods)) | ||||
| - return; | - return; | ||||
| +void Window::setSize(math::Vec size) { | |||||
| + size = size.max(WINDOW_SIZE_MIN); | |||||
| + internal->size = size; | |||||
| - | |||||
| - // Keyboard/mouse MIDI driver | - // Keyboard/mouse MIDI driver | ||||
| - if (action == GLFW_PRESS && (mods & RACK_MOD_MASK) == 0) { | - if (action == GLFW_PRESS && (mods & RACK_MOD_MASK) == 0) { | ||||
| - keyboard::press(key); | - keyboard::press(key); | ||||
| - } | - } | ||||
| - if (action == GLFW_RELEASE) { | - if (action == GLFW_RELEASE) { | ||||
| - keyboard::release(key); | - keyboard::release(key); | ||||
| - } | |||||
| + if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) | |||||
| + ui->setSize(internal->size.x, internal->size.y); | |||||
| } | |||||
| +Window::~Window() { | |||||
| + { | |||||
| + DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||||
| + internal->hiddenWindow.close(); | |||||
| + internal->hiddenApp.idle(); | |||||
| + | |||||
| + // Fonts and Images in the cache must be deleted before the NanoVG context is deleted | |||||
| + internal->fontCache.clear(); | |||||
| + internal->imageCache.clear(); | |||||
| + | |||||
| +#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 | |||||
| } | |||||
| -} | |||||
| - | - | ||||
| -static void dropCallback(GLFWwindow* win, int count, const char** paths) { | -static void dropCallback(GLFWwindow* win, int count, const char** paths) { | ||||
| - contextSet((Context*) glfwGetWindowUserPointer(win)); | - contextSet((Context*) glfwGetWindowUserPointer(win)); | ||||
| - std::vector<std::string> pathsVec; | - std::vector<std::string> pathsVec; | ||||
| @@ -456,23 +457,24 @@ | |||||
| - pathsVec.push_back(paths[i]); | - pathsVec.push_back(paths[i]); | ||||
| - } | - } | ||||
| - APP->event->handleDrop(APP->window->internal->lastMousePos, pathsVec); | - 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) { | -static void errorCallback(int error, const char* description) { | ||||
| - WARN("GLFW error %d: %s", error, description); | - WARN("GLFW error %d: %s", error, description); | ||||
| +void Window::run() { | |||||
| + internal->frame = 0; | |||||
| +math::Vec Window::getSize() { | |||||
| + return internal->size; | |||||
| } | } | ||||
| -Window::Window() { | -Window::Window() { | ||||
| - internal = new Internal; | - internal = new Internal; | ||||
| - int err; | - int err; | ||||
| - | |||||
| +void Window::setSize(math::Vec size) { | |||||
| + size = size.max(WINDOW_SIZE_MIN); | |||||
| + internal->size = size; | |||||
| - // Set window hints | - // Set window hints | ||||
| -#if defined NANOVG_GL2 | -#if defined NANOVG_GL2 | ||||
| - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | ||||
| @@ -553,10 +555,17 @@ | |||||
| - const GLubyte* version = glGetString(GL_VERSION); | - const GLubyte* version = glGetString(GL_VERSION); | ||||
| - INFO("Renderer: %s %s", vendor, renderer); | - INFO("Renderer: %s %s", vendor, renderer); | ||||
| - INFO("OpenGL: %s", version); | - 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. | - // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. | ||||
| - glGetError(); | - glGetError(); | ||||
| - | |||||
| +void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { | |||||
| + size = size.max(WINDOW_SIZE_MIN); | |||||
| + window->internal->size = size; | |||||
| +} | |||||
| - // Set up NanoVG | - // Set up NanoVG | ||||
| - int nvgFlags = NVG_ANTIALIAS; | - int nvgFlags = NVG_ANTIALIAS; | ||||
| -#if defined NANOVG_GL2 | -#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."); | - 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"); | - throw Exception("Could not initialize NanoVG"); | ||||
| - } | - } | ||||
| - | |||||
| - // Load default Blendish font | - // Load default Blendish font | ||||
| - uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); | - uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); | ||||
| - bndSetFont(uiFont->handle); | - bndSetFont(uiFont->handle); | ||||
| @@ -579,6 +588,16 @@ | |||||
| - if (APP->scene) { | - if (APP->scene) { | ||||
| - widget::Widget::ContextCreateEvent e; | - widget::Widget::ContextCreateEvent e; | ||||
| - APP->scene->onContextCreate(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 | +#ifndef DGL_USE_GLES | ||||
| +static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { | +static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { | ||||
| + for (int y = 0; y < height / 2; y++) { | + 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::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); | ||||
| + std::memcpy(&pixels[flipY * width * depth], tmp, 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 | +#ifdef STBI_WRITE_NO_STDIO | ||||
| +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { | +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { | ||||
| + int targetWidth = width; | + int targetWidth = width; | ||||
| @@ -621,42 +660,15 @@ | |||||
| + const int xs = static_cast<int>(x * scale); | + const int xs = static_cast<int>(x * scale); | ||||
| + std::memmove(pixels + (width * y + x) * 3, pixels + (width * ys + xs) * 3, 3); | + 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; | + width = targetWidth; | ||||
| + height = targetHeight; | + 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() { | -void Window::run() { | ||||
| - internal->frame = 0; | - internal->frame = 0; | ||||
| @@ -717,7 +729,7 @@ | |||||
| if (APP->patch->path != "") { | if (APP->patch->path != "") { | ||||
| windowTitle += " - "; | windowTitle += " - "; | ||||
| if (!APP->history->isSaved()) | if (!APP->history->isSaved()) | ||||
| @@ -455,243 +446,159 @@ | |||||
| @@ -455,246 +458,189 @@ | |||||
| windowTitle += system::getFilename(APP->patch->path); | windowTitle += system::getFilename(APP->patch->path); | ||||
| } | } | ||||
| if (windowTitle != internal->lastWindowTitle) { | if (windowTitle != internal->lastWindowTitle) { | ||||
| @@ -856,7 +868,7 @@ | |||||
| +#ifdef STBI_WRITE_NO_STDIO | +#ifdef STBI_WRITE_NO_STDIO | ||||
| + Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); | + Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); | ||||
| + stbi_write_png_to_func(Window__writeImagePNG, internal->ui, | + stbi_write_png_to_func(Window__writeImagePNG, internal->ui, | ||||
| + winWidth, winHeight, depth, pixelsWithOffset, stride); | |||||
| + winWidth, winHeight, depth, pixelsWithOffset, stride); | |||||
| +#else | +#else | ||||
| + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); | + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); | ||||
| +#endif | +#endif | ||||
| @@ -876,10 +888,6 @@ | |||||
| + delete[] pixels; | + delete[] pixels; | ||||
| } | } | ||||
| +#endif | +#endif | ||||
| +} | |||||
| + | |||||
| + | |||||
| +void Window::activateContext() { | |||||
| } | } | ||||
| @@ -948,7 +956,7 @@ | |||||
| - nvgImageSize(vg, fbw->getImageHandle(), &width, &height); | - nvgImageSize(vg, fbw->getImageHandle(), &width, &height); | ||||
| - uint8_t* pixels = new uint8_t[height * width * 4]; | - uint8_t* pixels = new uint8_t[height * width * 4]; | ||||
| - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||
| +void Window::screenshot(const std::string&) { | |||||
| +void Window::activateContext() { | |||||
| +} | +} | ||||
| - // Write pixels to PNG | - // Write pixels to PNG | ||||
| @@ -961,6 +969,10 @@ | |||||
| - delete fbw; | - delete fbw; | ||||
| - } | - } | ||||
| - } | - } | ||||
| +void Window::screenshot(const std::string&) { | |||||
| +} | |||||
| + | |||||
| + | |||||
| +void Window::screenshotModules(const std::string&, float) { | +void Window::screenshotModules(const std::string&, float) { | ||||
| } | } | ||||
| @@ -974,29 +986,39 @@ | |||||
| void Window::cursorLock() { | void Window::cursorLock() { | ||||
| - if (!settings::allowCursorLock) | |||||
| - return; | |||||
| - | |||||
| +#ifdef DISTRHO_OS_WASM | |||||
| if (!settings::allowCursorLock) | |||||
| return; | |||||
| -#if defined ARCH_MAC | -#if defined ARCH_MAC | ||||
| - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | ||||
| -#else | -#else | ||||
| - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | ||||
| -#endif | |||||
| + emscripten_request_pointerlock(internal->ui->getWindow().getApp().getClassName(), false); | |||||
| #endif | |||||
| - internal->ignoreNextMouseDelta = true; | - internal->ignoreNextMouseDelta = true; | ||||
| } | } | ||||
| void Window::cursorUnlock() { | void Window::cursorUnlock() { | ||||
| - if (!settings::allowCursorLock) | |||||
| - return; | |||||
| - | |||||
| +#ifdef DISTRHO_OS_WASM | |||||
| if (!settings::allowCursorLock) | |||||
| return; | |||||
| - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | ||||
| - internal->ignoreNextMouseDelta = true; | - internal->ignoreNextMouseDelta = true; | ||||
| + emscripten_exit_pointerlock(); | |||||
| +#endif | |||||
| } | } | ||||
| bool Window::isCursorLocked() { | bool Window::isCursorLocked() { | ||||
| - return glfwGetInputMode(win, GLFW_CURSOR) != GLFW_CURSOR_NORMAL; | - 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; | + return false; | ||||
| } | } | ||||
| @@ -1027,22 +1049,36 @@ | |||||
| - const GLFWvidmode* mode = glfwGetVideoMode(monitor); | - const GLFWvidmode* mode = glfwGetVideoMode(monitor); | ||||
| - glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | - 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() { | bool Window::isFullScreen() { | ||||
| - GLFWmonitor* monitor = glfwGetWindowMonitor(win); | - GLFWmonitor* monitor = glfwGetWindowMonitor(win); | ||||
| - return monitor != NULL; | - 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; | + return internal->generateScreenshotStep != kScreenshotStepNone; | ||||
| +#else | +#else | ||||
| + return false; | + return false; | ||||
| +#endif | +#endif | ||||
| } | } | ||||
| @@ -722,14 +629,15 @@ | |||||
| - | |||||
| double Window::getMonitorRefreshRate() { | |||||
| return internal->monitorRefreshRate; | |||||
| } | |||||
| @@ -722,14 +668,15 @@ | |||||
| return pair->second; | return pair->second; | ||||
| // Load font | // Load font | ||||
| @@ -1061,7 +1097,7 @@ | |||||
| } | } | ||||
| internal->fontCache[filename] = font; | internal->fontCache[filename] = font; | ||||
| return font; | return font; | ||||
| @@ -742,14 +650,15 @@ | |||||
| @@ -742,14 +689,15 @@ | |||||
| return pair->second; | return pair->second; | ||||
| // Load image | // Load image | ||||
| @@ -1080,7 +1116,7 @@ | |||||
| } | } | ||||
| internal->imageCache[filename] = image; | internal->imageCache[filename] = image; | ||||
| return image; | return image; | ||||
| @@ -766,28 +675,156 @@ | |||||
| @@ -766,28 +714,156 @@ | |||||
| } | } | ||||
| @@ -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 @@ | @@ -61,7 +61,7 @@ | ||||
| } | } | ||||
| @@ -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 | + * DISTRHO Cardinal Plugin | ||||
| + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | ||||
| @@ -37,7 +37,8 @@ | |||||
| + | + | ||||
| +#include "DistrhoPluginUtils.hpp" | +#include "DistrhoPluginUtils.hpp" | ||||
| #if defined ARCH_WIN | |||||
| -#if defined ARCH_WIN | |||||
| +#if defined(ARCH_WIN) | |||||
| #include <windows.h> | #include <windows.h> | ||||
| FILE* fopen_u8(const char* filename, const char* mode) { | 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()); | return _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str()); | ||||
| } | } | ||||
| @@ -14,20 +48,21 @@ | |||||
| +#elif defined(DISTRHO_OS_WASM) | |||||
| +#include <sys/stat.h> | |||||
| +#undef fopen | |||||
| + | |||||
| +FILE* fopen_wasm(const char* filename, const char* mode) { | |||||
| + chmod(filename, 0777); | |||||
| + return std::fopen(filename, mode); | |||||
| +} | |||||
| + | |||||
| #endif | |||||
| namespace rack { | namespace rack { | ||||
| @@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
| +/* | +/* | ||||
| + * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
| @@ -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 @@ | @@ -1,342 +1,41 @@ | ||||
| -#include <thread> | -#include <thread> | ||||
| -#include <map> | -#include <map> | ||||