Special trickery to allow browser preview of framebuffer panels

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2022-01-30 21:09:25 +00:00
parent da190c9bfc
commit 54bc763d0d
No known key found for this signature in database
GPG key ID: CDBAA37ABC74FBA0
9 changed files with 196 additions and 74 deletions

View file

@ -497,15 +497,7 @@ struct HostMIDICC : Module {
// --------------------------------------------------------------------------------------------------------------------
struct CardinalMIDILearnPJ301MPort : PJ301MPort {
void onDragStart(const DragStartEvent& e) override {
PJ301MPort::onDragStart(e);
}
void onDragEnd(const DragEndEvent& e) override {
PJ301MPort::onDragEnd(e);
}
};
#ifndef HEADLESS
/**
* Based on VCVRack's CcChoice as defined in src/core/plugin.hpp
* Copyright (C) 2016-2021 VCV.
@ -523,7 +515,14 @@ struct CardinalCcChoice : CardinalLedDisplayChoice {
CardinalCcChoice(HostMIDICC* const m, const int i)
: CardinalLedDisplayChoice(),
module(m),
id(i) {}
id(i)
{
// Module browser setup
if (m == nullptr)
{
text = string::f("%d", i+1);
}
}
void step() override
{
@ -691,14 +690,14 @@ struct HostMIDICCWidget : ModuleWidget {
{
const float x = startX_In + int(i / 6) * padding;
const float y = startY + int(i % 6) * padding;
addInput(createInput<CardinalMIDILearnPJ301MPort>(Vec(x, y), module, i));
addInput(createInput<PJ301MPort>(Vec(x, y), module, i));
}
for (int i=0; i<18; ++i)
{
const float x = startX_Out + int(i / 6) * padding;
const float y = startY + int(i % 6) * padding;
addOutput(createOutput<CardinalMIDILearnPJ301MPort>(Vec(x, y), module, i));
addOutput(createOutput<PJ301MPort>(Vec(x, y), module, i));
}
CCGridDisplay* const display = createWidget<CCGridDisplay>(Vec(startX_In - 3.0f, 70.0f));
@ -775,6 +774,9 @@ struct HostMIDICCWidget : ModuleWidget {
menu->addChild(outputChannelItem);
}
};
#else
typedef ModuleWidget HostMIDICCWidget;
#endif
// --------------------------------------------------------------------------------------------------------------------

View file

@ -404,15 +404,7 @@ struct HostMIDIGate : Module {
// --------------------------------------------------------------------------------------------------------------------
struct CardinalMIDILearnPJ301MPort : PJ301MPort {
void onDragStart(const DragStartEvent& e) override {
PJ301MPort::onDragStart(e);
}
void onDragEnd(const DragEndEvent& e) override {
PJ301MPort::onDragEnd(e);
}
};
#ifndef HEADLESS
/**
* Based on VCVRack's NoteChoice as defined in src/core/plugin.hpp
* Copyright (C) 2016-2021 VCV.
@ -605,14 +597,14 @@ struct HostMIDIGateWidget : ModuleWidget {
{
const float x = startX_In + int(i / 6) * padding;
const float y = startY + int(i % 6) * padding;
addInput(createInput<CardinalMIDILearnPJ301MPort>(Vec(x, y), module, i));
addInput(createInput<PJ301MPort>(Vec(x, y), module, i));
}
for (int i=0; i<18; ++i)
{
const float x = startX_Out + int(i / 6) * padding;
const float y = startY + int(i % 6) * padding;
addOutput(createOutput<CardinalMIDILearnPJ301MPort>(Vec(x, y), module, i));
addOutput(createOutput<PJ301MPort>(Vec(x, y), module, i));
}
NoteGridDisplay* const display = createWidget<NoteGridDisplay>(Vec(startX_In - 3.0f, 70.0f));
@ -696,6 +688,9 @@ struct HostMIDIGateWidget : ModuleWidget {
));
}
};
#else
typedef ModuleWidget HostMIDIGateWidget;
#endif
// --------------------------------------------------------------------------------------------------------------------

View file

@ -90,10 +90,10 @@ struct HostMIDIMap : Module {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
for (int id = 0; id < MAX_MIDI_CONTROL; ++id)
// {
// paramHandles[id].color = nvgRGB(0xff, 0xff, 0x40);
{
paramHandles[id].color = nvgRGBf(0.76f, 0.11f, 0.22f);
pcontext->engine->addParamHandle(&paramHandles[id]);
// }
}
for (int i = 0; i < MAX_MIDI_CONTROL; i++)
valueFilters[i].setTau(1 / 30.f);
@ -460,18 +460,27 @@ struct HostMIDIMap : Module {
// --------------------------------------------------------------------------------------------------------------------
struct MIDIMapChoice : CardinalLedDisplayChoice {
#ifndef HEADLESS
struct CardinalMIDIMapChoice : CardinalLedDisplayChoice {
HostMIDIMap* const module;
const int id;
int disableLearnFrames = -1;
ParamWidget* lastTouchedParam = nullptr;
MIDIMapChoice(HostMIDIMap* const m, const int i)
CardinalMIDIMapChoice(HostMIDIMap* const m, const int i)
: CardinalLedDisplayChoice(),
module(m),
id(i)
{
alignTextCenter = false;
// Module browser setup
if (m == nullptr)
{
bgColor = nvgRGB(0, 0, 0);
color.a = 0.75f;
text = "Click here to map";
}
}
void draw(const DrawArgs& args) override
@ -489,7 +498,7 @@ struct MIDIMapChoice : CardinalLedDisplayChoice {
void step() override
{
if (!module)
if (module == nullptr)
return;
// Set bgColor and selected state
@ -609,7 +618,7 @@ struct MIDIMapChoice : CardinalLedDisplayChoice {
struct HostMIDIMapDisplay : Widget {
HostMIDIMap* module;
ScrollWidget* scroll;
MIDIMapChoice* choices[MAX_MIDI_CONTROL];
CardinalMIDIMapChoice* choices[MAX_MIDI_CONTROL];
LedDisplaySeparator* separators[MAX_MIDI_CONTROL];
void drawLayer(const DrawArgs& args, int layer) override
@ -634,13 +643,15 @@ struct HostMIDIMapDisplay : Widget {
{
LedDisplaySeparator* separator = createWidget<LedDisplaySeparator>(Vec(0.0f, posY));
separator->box.size = Vec(box.size.x, 1.0f);
separator->visible = false;
scroll->container->addChild(separator);
separators[id] = separator;
}
MIDIMapChoice* const choice = new MIDIMapChoice(module, id);
CardinalMIDIMapChoice* const choice = new CardinalMIDIMapChoice(module, id);
choice->box.pos = Vec(0.0f, posY);
choice->box.size = Vec(box.size.x, 20.0f);
choice->visible = id == 0;
scroll->container->addChild(choice);
choices[id] = choice;
@ -722,6 +733,9 @@ struct HostMIDIMapWidget : ModuleWidget {
menu->addChild(inputChannelItem);
}
};
#else
typedef ModuleWidget HostMIDIMapWidget;
#endif
// --------------------------------------------------------------------------------------------------------------------

View file

@ -745,25 +745,33 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread {
: ImGuiWidget(),
module(m)
{
if (module->fCarlaHostHandle == nullptr)
{
fDrawingState = kDrawingErrorInit;
fIdleState = kIdleNothing;
fPopupError = "Ildaeil backend failed to init properly, cannot continue.";
return;
}
std::strcpy(fPluginSearchString, "Search...");
if (checkIfPluginIsLoaded())
fIdleState = kIdleInitPluginAlreadyLoaded;
if (m != nullptr)
{
if (m->fCarlaHostHandle == nullptr)
{
fDrawingState = kDrawingErrorInit;
fIdleState = kIdleNothing;
fPopupError = "Ildaeil backend failed to init properly, cannot continue.";
return;
}
module->fUI = this;
if (checkIfPluginIsLoaded())
fIdleState = kIdleInitPluginAlreadyLoaded;
m->fUI = this;
}
else
{
fDrawingState = kDrawingPluginList;
fIdleState = kIdleNothing;
}
}
~IldaeilWidget() override
{
if (module->fCarlaHostHandle != nullptr)
if (module != nullptr && module->fCarlaHostHandle != nullptr)
{
if (idleCallbackActive)
{
@ -1009,6 +1017,9 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread {
void widgetCreated()
{
if (module == nullptr)
return;
if (const CarlaHostHandle handle = module->fCarlaHostHandle)
{
const CardinalPluginContext* const pcontext = module->pcontext;
@ -1031,6 +1042,9 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread {
void widgetDestroyed()
{
if (module == nullptr)
return;
if (const CarlaHostHandle handle = module->fCarlaHostHandle)
{
const CardinalPluginContext* const pcontext = module->pcontext;
@ -1532,7 +1546,7 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread {
if (ImGui::Button("Load Plugin"))
fIdleState = kIdleLoadSelectedPlugin;
if (fPluginType != PLUGIN_INTERNAL && module->canUseBridges)
if (fPluginType != PLUGIN_INTERNAL && (module == nullptr || module->canUseBridges))
{
ImGui::SameLine();
ImGui::Checkbox("Run in bridge mode", &fPluginWillRunInBridgeMode);
@ -1657,7 +1671,7 @@ struct IldaeilModuleWidget : ModuleWidget {
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Ildaeil.svg")));
if (module != nullptr && module->pcontext != nullptr)
if (module == nullptr || module->pcontext != nullptr)
{
ildaeilWidget = new IldaeilWidget(module);
ildaeilWidget->box.pos = Vec(2 * RACK_GRID_WIDTH, 0);

View file

@ -1,6 +1,6 @@
/*
* Dear ImGui for DPF, converted to VCV
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
@ -145,7 +145,7 @@ float ImGuiWidget::getScaleFactor() const noexcept
void ImGuiWidget::onContextCreate(const ContextCreateEvent& e)
{
OpenGlWidget::onContextCreate(e);
OpenGlWidgetWithBrowserPreview::onContextCreate(e);
DISTRHO_SAFE_ASSERT_RETURN(!imData->created,);
ImGui::SetCurrentContext(imData->context);
@ -162,7 +162,7 @@ void ImGuiWidget::onContextDestroy(const ContextDestroyEvent& e)
imData->created = false;
}
OpenGlWidget::onContextDestroy(e);
OpenGlWidgetWithBrowserPreview::onContextDestroy(e);
}
void ImGuiWidget::setAsCurrentContext()
@ -307,13 +307,39 @@ void ImGuiWidget::onSelectText(const SelectTextEvent& e)
}
void ImGuiWidget::drawFramebuffer()
{
const float scaleFactor = APP->window->pixelRatio;
drawFramebufferCommon(getFramebufferSize(), scaleFactor);
}
void ImGuiWidget::drawFramebufferForBrowserPreview()
{
if (imData->created)
{
ImGui::SetCurrentContext(imData->context);
ImGui_ImplOpenGL2_Shutdown();
ImGui::DestroyContext(imData->context);
imData->created = false;
imData->fontGenerated = false;
imData->originalScaleFactor = 0.0f;
imData->scaleFactor = 0.0f;
}
imData->context = ImGui::CreateContext();
ImGui::SetCurrentContext(imData->context);
ImGui_ImplOpenGL2_Init();
imData->created = true;
drawFramebufferCommon(box.size.mult(oversample), oversample);
}
void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFactor)
{
ImGui::SetCurrentContext(imData->context);
ImGuiIO& io(ImGui::GetIO());
const math::Vec fbSize = getFramebufferSize();
const float scaleFactor = APP->window->pixelRatio;
if (d_isNotEqual(imData->scaleFactor, scaleFactor))
{
imData->scaleFactor = scaleFactor;

View file

@ -1,6 +1,6 @@
/*
* Dear ImGui for DPF, converted to VCV
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
@ -20,7 +20,7 @@
#include "plugin.hpp"
#include "DearImGui/imgui.h"
struct ImGuiWidget : OpenGlWidget {
struct ImGuiWidget : OpenGlWidgetWithBrowserPreview {
struct PrivateData;
PrivateData* const imData;
@ -50,4 +50,6 @@ protected:
private:
void drawFramebuffer() override;
void drawFramebufferForBrowserPreview() override;
void drawFramebufferCommon(const Vec& fbSize, float scaleFactor);
};

View file

@ -326,21 +326,24 @@ struct TextEditorModuleWidget : ModuleWidget {
addChild(rightHandle = new ModuleResizeHandle(module, this, true));
addChild(new ModuleResizeHandle(module, this, false));
box.size = Vec(RACK_GRID_WIDTH * (module != nullptr ? module->width : DEFAULT_WIDTH), RACK_GRID_HEIGHT);
textEditorModule = module;
textEditorWidget = new ImGuiTextEditor();
textEditorWidget->box.pos = Vec(RACK_GRID_WIDTH, 0);
textEditorWidget->box.size = Vec(box.size.x - 2 * RACK_GRID_WIDTH, box.size.y);
addChild(textEditorWidget);
if (module != nullptr)
{
box.size = Vec(RACK_GRID_WIDTH * module->width, RACK_GRID_HEIGHT);
textEditorModule = module;
textEditorWidget = new ImGuiTextEditor();
textEditorWidget->setFileWithKnownText(module->file, module->text);
textEditorWidget->setLanguageDefinition(module->lang);
textEditorWidget->box.pos = Vec(RACK_GRID_WIDTH, 0);
textEditorWidget->box.size = Vec((module->width - 2) * RACK_GRID_WIDTH, box.size.y);
addChild(textEditorWidget);
textEditorWidget->setFileWithKnownText(module->file, module->text);
module->widgetPtr = textEditorWidget;
}
else
{
box.size = Vec(RACK_GRID_WIDTH * DEFAULT_WIDTH, RACK_GRID_HEIGHT);
textEditorWidget->setLanguageDefinition(DEFAULT_LANG);
textEditorWidget->setText(DEFAULT_TEXT);
}
}

View file

@ -61,13 +61,13 @@ struct glBarsModule : Module {
};
#ifndef HEADLESS
struct glBarsRendererWidget : OpenGlWidget {
struct glBarsRendererWidget : OpenGlWidgetWithBrowserPreview {
glBarsModule* const glBars;
glBarsRendererWidget(glBarsModule* const module)
: glBars(module)
{
if (APP->window->pixelRatio < 2.0f)
if (glBars != nullptr && APP->window->pixelRatio < 2.0f)
oversample = 2.0f;
}
@ -75,22 +75,34 @@ struct glBarsRendererWidget : OpenGlWidget {
{
}
void drawLayer(const DrawArgs& args, int layer) override
void drawLayer(const DrawArgs& args, const int layer) override
{
if (layer != 1)
return;
OpenGlWidget::draw(args);
OpenGlWidgetWithBrowserPreview::draw(args);
}
void drawFramebuffer() override {
math::Vec fbSize = getFramebufferSize();
void drawFramebuffer() override
{
DISTRHO_SAFE_ASSERT_RETURN(glBars != nullptr,);
drawFramebuffer(glBars->state, getFramebufferSize());
}
void drawFramebufferForBrowserPreview() override
{
glBarsState state;
drawFramebuffer(state, box.size);
}
void drawFramebuffer(glBarsState& state, const Vec& fbSize)
{
glDisable(GL_BLEND);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glViewport(0.0, -100, fbSize.x * oversample, fbSize.y * oversample);
glViewport(0.0, -50 * oversample, fbSize.x * oversample, fbSize.y * oversample);
glFrustum(-1, 1, -1, 1, 1.5, 10);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
@ -99,7 +111,7 @@ struct glBarsRendererWidget : OpenGlWidget {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBars->state.Render();
state.Render();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
@ -107,18 +119,17 @@ struct glBarsRendererWidget : OpenGlWidget {
glEnable(GL_BLEND);
}
void step() override {
void step() override
{
OpenGlWidget::step();
oversample = APP->window->pixelRatio < 2.0f ? 2.0f : 1.0f;
if (glBars != nullptr)
oversample = APP->window->pixelRatio < 2.0f ? 2.0f : 1.0f;
}
};
struct glBarsWidget : ModuleWidget {
glBarsRendererWidget* const glBarsRenderer;
glBarsWidget(glBarsModule* const module)
: glBarsRenderer(new glBarsRendererWidget(module))
{
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/glBars.svg")));
@ -131,6 +142,7 @@ struct glBarsWidget : ModuleWidget {
addInput(createInput<PJ301MPort>(Vec(135.0f, 20.0f), module, glBarsModule::IN1_INPUT));
const float size = mm2px(127.0f);
glBarsRendererWidget* const glBarsRenderer = new glBarsRendererWidget(module);
glBarsRenderer->box.pos = Vec((box.size.x - size) * 0.5f, (box.size.y - size) * 0.5f);
glBarsRenderer->box.size = Vec(size, size);
addChild(glBarsRenderer);

View file

@ -25,6 +25,7 @@
using namespace rack;
#ifndef HEADLESS
struct CardinalLedDisplayChoice : LedDisplayChoice {
bool alignTextCenter = true;
@ -60,6 +61,59 @@ struct CardinalLedDisplayChoice : LedDisplayChoice {
}
};
struct OpenGlWidgetWithBrowserPreview : OpenGlWidget {
NVGLUframebuffer* fb = nullptr;
void draw(const DrawArgs& args) override
{
if (args.fb == nullptr)
return OpenGlWidget::draw(args);
// set oversample to current scale
float trans[6];
nvgCurrentTransform(args.vg, trans);
oversample = std::max(1.0f, trans[0]);
// recreate framebuffer
deleteFramebuffer();
fb = nvgluCreateFramebuffer(args.vg, box.size.x * oversample, box.size.y * oversample, 0);
DISTRHO_SAFE_ASSERT_RETURN(fb != nullptr,);
// draw our special framebuffer
nvgluBindFramebuffer(fb);
drawFramebufferForBrowserPreview();
// reset to regular framebuffer
nvgluBindFramebuffer(args.fb);
// render image generated by our framebuffer
nvgBeginPath(args.vg);
nvgRect(args.vg, 0.0f, 0.0f, box.size.x, box.size.y);
NVGpaint paint = nvgImagePattern(args.vg,
0.0f, 0.0f, box.size.x, box.size.y,
0.0f, fb->image, 1.0f);
nvgFillPaint(args.vg, paint);
nvgFill(args.vg);
}
void onContextDestroy(const ContextDestroyEvent& e) override
{
deleteFramebuffer();
OpenGlWidget::onContextDestroy(e);
}
void deleteFramebuffer()
{
if (fb == nullptr)
return;
nvgluDeleteFramebuffer(fb);
fb = nullptr;
}
virtual void drawFramebufferForBrowserPreview() = 0;
};
#endif
extern Plugin* pluginInstance;
extern Model* modelAudioFile;