Browse Source

Draw FramebufferWidgets during step() instead of draw() so we can use the same NanoVG context.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
d6f5a84178
24 changed files with 89 additions and 91 deletions
  1. +8
    -3
      include/widget/FramebufferWidget.hpp
  2. +1
    -0
      include/widget/Widget.hpp
  3. +0
    -2
      include/window.hpp
  4. +1
    -1
      src/app/LedDisplay.cpp
  5. +9
    -8
      src/app/ModuleBrowser.cpp
  6. +1
    -1
      src/app/ModuleWidget.cpp
  7. +7
    -7
      src/app/ParamWidget.cpp
  8. +3
    -1
      src/app/PortWidget.cpp
  9. +2
    -2
      src/app/RackScrollWidget.cpp
  10. +4
    -4
      src/app/RackWidget.cpp
  11. +4
    -4
      src/app/Scene.cpp
  12. +1
    -1
      src/app/SvgPanel.cpp
  13. +2
    -2
      src/app/Toolbar.cpp
  14. +1
    -1
      src/ui/List.cpp
  15. +1
    -1
      src/ui/MarginLayout.cpp
  16. +2
    -2
      src/ui/Menu.cpp
  17. +1
    -1
      src/ui/MenuItem.cpp
  18. +1
    -1
      src/ui/MenuLabel.cpp
  19. +1
    -1
      src/ui/MenuOverlay.cpp
  20. +2
    -2
      src/ui/ScrollWidget.cpp
  21. +1
    -1
      src/ui/SequentialLayout.cpp
  22. +2
    -2
      src/ui/Tooltip.cpp
  23. +34
    -26
      src/widget/FramebufferWidget.cpp
  24. +0
    -17
      src/window.cpp

+ 8
- 3
include/widget/FramebufferWidget.hpp View File

@@ -15,19 +15,24 @@ struct FramebufferWidget : Widget {
bool dirty = true;
float oversample;
NVGLUframebuffer *fb = NULL;
/** Scale relative to the world */
math::Vec scale;
/** Offset in world coordinates */
math::Vec offset;
/** Pixel dimensions of the allocated framebuffer */
math::Vec fbSize;
/** Bounding box in world coordinates of where the framebuffer should be painted
/** Bounding box in world coordinates of where the framebuffer should be painted.
Always has integer coordinates so that blitting framebuffers is pixel-perfect.
*/
math::Rect fbBox;
/** Local scale relative to the world scale */
/** Framebuffer's scale relative to the world */
math::Vec fbScale;
/** Subpixel offset of fbBox in world coordinates */
/** Framebuffer's subpixel offset relative to fbBox in world coordinates */
math::Vec fbOffset;

FramebufferWidget();
~FramebufferWidget();
void step() override;
void draw(const DrawArgs &args) override;
virtual void drawFramebuffer();
int getImageHandle();


+ 1
- 0
include/widget/Widget.hpp View File

@@ -84,6 +84,7 @@ struct Widget {
struct DrawArgs {
NVGcontext *vg;
math::Rect clipBox;
NVGLUframebuffer *fb = NULL;
};

/** Draws the widget to the NanoVG context */


+ 0
- 2
include/window.hpp View File

@@ -74,8 +74,6 @@ DEPRECATED typedef Svg SVG;
struct Window {
GLFWwindow *win = NULL;
NVGcontext *vg = NULL;
/** Secondary nanovg context for drawing to framebuffers */
NVGcontext *fbVg = NULL;
/** The scaling ratio */
float pixelRatio = 1.f;
/* The ratio between the framebuffer size and the window size reported by the OS.


+ 1
- 1
src/app/LedDisplay.cpp View File

@@ -17,7 +17,7 @@ void LedDisplay::draw(const DrawArgs &args) {
nvgFill(args.vg);

nvgScissor(args.vg, RECT_ARGS(args.clipBox));
widget::Widget::draw(args);
Widget::draw(args);
nvgResetScissor(args.vg);
}



+ 9
- 8
src/app/ModuleBrowser.cpp View File

@@ -64,11 +64,11 @@ struct BrowserOverlay : widget::OpaqueWidget {
box = parent->box.zeroPos();
// Only step if visible, since there are potentially thousands of descendants that don't need to be stepped.
if (visible)
widget::OpaqueWidget::step();
OpaqueWidget::step();
}

void onButton(const event::Button &e) override {
widget::OpaqueWidget::onButton(e);
OpaqueWidget::onButton(e);
if (e.getConsumed() != this)
return;

@@ -189,6 +189,7 @@ struct ModelBox : widget::OpaqueWidget {
if (previewWidget && ++visibleFrames >= 60) {
deletePreview();
}
OpaqueWidget::step();
}

void draw(const DrawArgs &args) override {
@@ -210,7 +211,7 @@ struct ModelBox : widget::OpaqueWidget {
nvgFill(args.vg);

nvgScissor(args.vg, RECT_ARGS(args.clipBox));
widget::OpaqueWidget::draw(args);
OpaqueWidget::draw(args);
nvgResetScissor(args.vg);

// Translucent overlay when selected
@@ -239,7 +240,7 @@ struct BrowserSearchField : ui::TextField {
void step() override {
// Steal focus when step is called
APP->event->setSelected(this);
ui::TextField::step();
TextField::step();
}
void onSelectKey(const event::SelectKey &e) override {
if (e.action == GLFW_PRESS) {
@@ -316,7 +317,7 @@ struct BrowserSidebar : widget::Widget {
tagScroll->box.size.y = (box.size.y - searchField->box.size.y) / 2;
tagScroll->box.size.x = box.size.x;
tagList->box.size.x = tagScroll->box.size.x;
widget::Widget::step();
Widget::step();
}
};

@@ -363,12 +364,12 @@ struct ModuleBrowser : widget::OpaqueWidget {
modelMargin->box.size.x = modelScroll->box.size.x;
modelMargin->box.size.y = modelContainer->getChildrenBoundingBox().size.y + 2 * modelMargin->margin.y;

widget::OpaqueWidget::step();
OpaqueWidget::step();
}

void draw(const DrawArgs &args) override {
bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, 0);
widget::Widget::draw(args);
Widget::draw(args);
}

void setSearch(const std::string &search) {
@@ -388,7 +389,7 @@ struct ModuleBrowser : widget::OpaqueWidget {


void ModelBox::onButton(const event::Button &e) {
widget::OpaqueWidget::onButton(e);
OpaqueWidget::onButton(e);
if (e.getConsumed() != this)
return;



+ 1
- 1
src/app/ModuleWidget.cpp View File

@@ -148,7 +148,7 @@ void ModuleWidget::draw(const DrawArgs &args) {
nvgGlobalAlpha(args.vg, 0.25);
}

widget::Widget::draw(args);
Widget::draw(args);

// Power meter
if (module && settings.cpuMeter) {


+ 7
- 7
src/app/ParamWidget.cpp View File

@@ -21,7 +21,7 @@ struct ParamField : ui::TextField {
void step() override {
// Keep selected
APP->event->setSelected(this);
ui::TextField::step();
TextField::step();
}

void setParamWidget(ParamWidget *paramWidget) {
@@ -54,7 +54,7 @@ struct ParamField : ui::TextField {
}

if (!e.getConsumed())
ui::TextField::onSelectKey(e);
TextField::onSelectKey(e);
}
};

@@ -73,7 +73,7 @@ struct ParamTooltip : ui::Tooltip {
}
// Position at bottom-right of parameter
box.pos = paramWidget->getAbsoluteOffset(paramWidget->box.size).round();
ui::Tooltip::step();
Tooltip::step();
}
};

@@ -82,7 +82,7 @@ struct ParamLabel : ui::MenuLabel {
ParamWidget *paramWidget;
void step() override {
text = paramWidget->paramQuantity->getString();
ui::MenuLabel::step();
MenuLabel::step();
}
};

@@ -138,11 +138,11 @@ void ParamWidget::step() {
}
}

widget::OpaqueWidget::step();
OpaqueWidget::step();
}

void ParamWidget::draw(const DrawArgs &args) {
widget::Widget::draw(args);
Widget::draw(args);

// if (paramQuantity) {
// nvgBeginPath(args.vg);
@@ -185,7 +185,7 @@ void ParamWidget::onButton(const event::Button &e) {
}

if (!e.getConsumed())
widget::OpaqueWidget::onButton(e);
OpaqueWidget::onButton(e);
}

void ParamWidget::onDoubleClick(const event::DoubleClick &e) {


+ 3
- 1
src/app/PortWidget.cpp View File

@@ -45,6 +45,8 @@ void PortWidget::step() {
values[i] = module->inputs[portId].plugLights[i].getBrightness();
}
plugLight->setBrightnesses(values);

OpaqueWidget::step();
}

void PortWidget::draw(const DrawArgs &args) {
@@ -54,7 +56,7 @@ void PortWidget::draw(const DrawArgs &args) {
if (type == OUTPUT ? cw->outputPort : cw->inputPort)
nvgGlobalAlpha(args.vg, 0.5);
}
widget::Widget::draw(args);
Widget::draw(args);
}

void PortWidget::onButton(const event::Button &e) {


+ 2
- 2
src/app/RackScrollWidget.cpp View File

@@ -24,12 +24,12 @@ void RackScrollWidget::step() {
if (pos.y >= viewport.pos.y + viewport.size.y - margin)
offset.y += speed;
}
ui::ScrollWidget::step();
ScrollWidget::step();
}


void RackScrollWidget::draw(const DrawArgs &args) {
ui::ScrollWidget::draw(args);
ScrollWidget::draw(args);
}




+ 4
- 4
src/app/RackWidget.cpp View File

@@ -55,14 +55,14 @@ struct ModuleContainer : widget::Widget {
nvgRestore(args.vg);
}

widget::Widget::draw(args);
Widget::draw(args);
}
};


struct CableContainer : widget::TransparentWidget {
void draw(const DrawArgs &args) override {
widget::Widget::draw(args);
Widget::draw(args);

// Draw cable plugs
for (widget::Widget *w : children) {
@@ -114,11 +114,11 @@ void RackWidget::step() {
rail->box.size = rails->box.size;
}

widget::Widget::step();
Widget::step();
}

void RackWidget::draw(const DrawArgs &args) {
widget::Widget::draw(args);
Widget::draw(args);
}

void RackWidget::onHover(const event::Hover &e) {


+ 4
- 4
src/app/Scene.cpp View File

@@ -51,7 +51,7 @@ void Scene::step() {
.plus(math::Vec(500, 500))
.div(zoomWidget->zoom);

widget::OpaqueWidget::step();
OpaqueWidget::step();

zoomWidget->box.size = rackWidget->box.size.mult(zoomWidget->zoom);

@@ -88,7 +88,7 @@ void Scene::step() {
}

void Scene::draw(const DrawArgs &args) {
widget::OpaqueWidget::draw(args);
OpaqueWidget::draw(args);
}

void Scene::onHoverKey(const event::HoverKey &e) {
@@ -149,7 +149,7 @@ void Scene::onHoverKey(const event::HoverKey &e) {
}

if (!e.getConsumed())
widget::OpaqueWidget::onHoverKey(e);
OpaqueWidget::onHoverKey(e);
}

void Scene::onPathDrop(const event::PathDrop &e) {
@@ -162,7 +162,7 @@ void Scene::onPathDrop(const event::PathDrop &e) {
}

if (!e.getConsumed())
widget::OpaqueWidget::onPathDrop(e);
OpaqueWidget::onPathDrop(e);
}

void Scene::runCheckVersion() {


+ 1
- 1
src/app/SvgPanel.cpp View File

@@ -20,7 +20,7 @@ void SvgPanel::step() {
// Small details draw poorly at low DPI, so oversample when drawing to the framebuffer
oversample = 2.0;
}
widget::FramebufferWidget::step();
FramebufferWidget::step();
}

void SvgPanel::setBackground(std::shared_ptr<Svg> svg) {


+ 2
- 2
src/app/Toolbar.cpp View File

@@ -25,7 +25,7 @@ namespace app {
struct MenuButton : ui::Button {
void step() override {
box.size.x = bndLabelWidth(APP->window->vg, -1, text.c_str()) + 1.0;
widget::Widget::step();
Widget::step();
}
void draw(const DrawArgs &args) override {
bndMenuItem(args.vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, text.c_str());
@@ -680,7 +680,7 @@ void Toolbar::draw(const DrawArgs &args) {
bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_ALL);
bndBevel(args.vg, 0.0, 0.0, box.size.x, box.size.y);

widget::Widget::draw(args);
Widget::draw(args);
}




+ 1
- 1
src/ui/List.cpp View File

@@ -6,7 +6,7 @@ namespace ui {


void List::step() {
widget::Widget::step();
Widget::step();

// Set positions of children
box.size.y = 0.0;


+ 1
- 1
src/ui/MarginLayout.cpp View File

@@ -7,7 +7,7 @@ namespace ui {


void MarginLayout::step() {
widget::Widget::step();
Widget::step();

math::Rect childBox = box.zeroPos().grow(margin.neg());
for (Widget *child : children) {


+ 2
- 2
src/ui/Menu.cpp View File

@@ -27,7 +27,7 @@ void Menu::setChildMenu(Menu *menu) {
}

void Menu::step() {
widget::Widget::step();
Widget::step();

// Set positions of children
box.size = math::Vec(0, 0);
@@ -51,7 +51,7 @@ void Menu::step() {

void Menu::draw(const DrawArgs &args) {
bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE);
widget::Widget::draw(args);
Widget::draw(args);
}

void Menu::onHoverScroll(const event::HoverScroll &e) {


+ 1
- 1
src/ui/MenuItem.cpp View File

@@ -34,7 +34,7 @@ void MenuItem::step() {
// HACK use APP->window->vg from the window.
// All this does is inspect the font, so it shouldn't modify APP->window->vg and should work when called from a widget::FramebufferWidget for example.
box.size.x = bndLabelWidth(APP->window->vg, -1, text.c_str()) + bndLabelWidth(APP->window->vg, -1, rightText.c_str()) + rightPadding;
widget::Widget::step();
Widget::step();
}

void MenuItem::onEnter(const event::Enter &e) {


+ 1
- 1
src/ui/MenuLabel.cpp View File

@@ -15,7 +15,7 @@ void MenuLabel::step() {
const float rightPadding = 10.0;
// HACK use APP->window->vg from the window.
box.size.x = bndLabelWidth(APP->window->vg, -1, text.c_str()) + rightPadding;
widget::Widget::step();
Widget::step();
}




+ 1
- 1
src/ui/MenuOverlay.cpp View File

@@ -14,7 +14,7 @@ void MenuOverlay::step() {
child->box = child->box.nudge(box.zeroPos());
}

widget::Widget::step();
Widget::step();
}

void MenuOverlay::onButton(const event::Button &e) {


+ 2
- 2
src/ui/ScrollWidget.cpp View File

@@ -29,12 +29,12 @@ void ScrollWidget::scrollTo(math::Rect r) {

void ScrollWidget::draw(const DrawArgs &args) {
nvgScissor(args.vg, RECT_ARGS(args.clipBox));
widget::Widget::draw(args);
Widget::draw(args);
nvgResetScissor(args.vg);
}

void ScrollWidget::step() {
widget::Widget::step();
Widget::step();

// Clamp scroll offset
math::Vec containerCorner = container->getChildrenBoundingBox().getBottomRight();


+ 1
- 1
src/ui/SequentialLayout.cpp View File

@@ -11,7 +11,7 @@ namespace ui {


void SequentialLayout::step() {
widget::Widget::step();
Widget::step();

// Sort widgets into rows (or columns if vertical)
std::vector<std::vector<widget::Widget*>> rows;


+ 2
- 2
src/ui/Tooltip.cpp View File

@@ -11,13 +11,13 @@ void Tooltip::step() {
// Wrap size to contents
box.size.x = bndLabelWidth(APP->window->vg, -1, text.c_str()) + 10.0;
box.size.y = bndLabelHeight(APP->window->vg, -1, text.c_str(), INFINITY);
widget::Widget::step();
Widget::step();
}

void Tooltip::draw(const DrawArgs &args) {
bndTooltipBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y);
bndMenuLabel(args.vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str());
widget::Widget::draw(args);
Widget::draw(args);
}




+ 34
- 26
src/widget/FramebufferWidget.cpp View File

@@ -15,31 +15,18 @@ FramebufferWidget::~FramebufferWidget() {
nvgluDeleteFramebuffer(fb);
}

void FramebufferWidget::draw(const DrawArgs &args) {
// Bypass framebuffer rendering if we're already drawing in a framebuffer
// In other words, disallow nested framebuffers. They look bad.
if (args.vg == APP->window->fbVg) {
Widget::draw(args);
return;
}

// Get world transform
float xform[6];
nvgCurrentTransform(args.vg, xform);
// Skew and rotate is not supported
assert(math::isNear(xform[1], 0.f));
assert(math::isNear(xform[2], 0.f));
// Extract scale and offset from world transform
math::Vec scale = math::Vec(xform[0], xform[3]);
math::Vec offset = math::Vec(xform[4], xform[5]);
math::Vec offsetI = offset.floor();
void FramebufferWidget::step() {
Widget::step();

// Render to framebuffer
if (dirty) {
// Render to framebuffer if dirty.
// Also check that scale has been set by `draw()` yet.
if (dirty && !scale.isZero()) {
// In case we fail drawing the framebuffer, don't try again the next frame, so reset `dirty` here.
dirty = false;

fbScale = scale;
// World coordinates, in range [0, 1)
// Get subpixel offset in range [0, 1)
math::Vec offsetI = offset.floor();
fbOffset = offset.minus(offsetI);

math::Rect localBox;
@@ -50,15 +37,16 @@ void FramebufferWidget::draw(const DrawArgs &args) {
localBox = getChildrenBoundingBox();
}

// DEBUG("%g %g %g %g, %g %g, %g %g", RECT_ARGS(localBox), VEC_ARGS(fbOffset), VEC_ARGS(scale));
// DEBUG("%g %g %g %g, %g %g, %g %g", RECT_ARGS(localBox), VEC_ARGS(fbOffset), VEC_ARGS(fbScale));
// Transform to world coordinates, then expand to nearest integer coordinates
math::Vec min = localBox.getTopLeft().mult(scale).plus(fbOffset).floor();
math::Vec max = localBox.getBottomRight().mult(scale).plus(fbOffset).ceil();
math::Vec min = localBox.getTopLeft().mult(fbScale).plus(fbOffset).floor();
math::Vec max = localBox.getBottomRight().mult(fbScale).plus(fbOffset).ceil();
fbBox = math::Rect::fromMinMax(min, max);
// DEBUG("%g %g %g %g", RECT_ARGS(fbBox));

math::Vec newFbSize = fbBox.size.mult(APP->window->pixelRatio * oversample);

// Create framebuffer if a new size is needed
if (!fb || !newFbSize.isEqual(fbSize)) {
fbSize = newFbSize;
// Delete old framebuffer
@@ -66,7 +54,7 @@ void FramebufferWidget::draw(const DrawArgs &args) {
nvgluDeleteFramebuffer(fb);
// Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context.
if (fbSize.isFinite() && !fbSize.isZero())
fb = nvgluCreateFramebuffer(args.vg, fbSize.x, fbSize.y, 0);
fb = nvgluCreateFramebuffer(APP->window->vg, fbSize.x, fbSize.y, 0);
}

if (!fb)
@@ -76,6 +64,25 @@ void FramebufferWidget::draw(const DrawArgs &args) {
drawFramebuffer();
nvgluBindFramebuffer(NULL);
}
}

void FramebufferWidget::draw(const DrawArgs &args) {
// Draw directly if already drawing in a framebuffer
if (args.fb) {
Widget::draw(args);
return;
}

// Get world transform
float xform[6];
nvgCurrentTransform(args.vg, xform);
// Skew and rotate is not supported
assert(math::isNear(xform[1], 0.f));
assert(math::isNear(xform[2], 0.f));
// Extract scale and offset from world transform
scale = math::Vec(xform[0], xform[3]);
offset = math::Vec(xform[4], xform[5]);
math::Vec offsetI = offset.floor();

if (!fb)
return;
@@ -106,7 +113,7 @@ void FramebufferWidget::draw(const DrawArgs &args) {
}

void FramebufferWidget::drawFramebuffer() {
NVGcontext *vg = APP->window->fbVg;
NVGcontext *vg = APP->window->vg;

float pixelRatio = fbSize.x / fbBox.size.x;
nvgBeginFrame(vg, fbBox.size.x, fbBox.size.y, pixelRatio);
@@ -119,6 +126,7 @@ void FramebufferWidget::drawFramebuffer() {
DrawArgs args;
args.vg = vg;
args.clipBox = box.zeroPos();
args.fb = fb;
Widget::draw(args);

glViewport(0.0, 0.0, fbSize.x, fbSize.y);


+ 0
- 17
src/window.cpp View File

@@ -275,15 +275,6 @@ Window::Window() {
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.");
exit(1);
}

#if defined NANOVG_GL2
fbVg = nvgCreateGL2(nvgFlags);
#elif defined NANOVG_GL3
fbVg = nvgCreateGL3(nvgFlags);
#elif defined NANOVG_GLES2
fbVg = nvgCreateGLES2(nvgFlags);
#endif
assert(fbVg);
}

Window::~Window() {
@@ -308,14 +299,6 @@ Window::~Window() {
nvgDeleteGLES2(vg);
#endif

#if defined NANOVG_GL2
nvgDeleteGL2(fbVg);
#elif defined NANOVG_GL3
nvgDeleteGL3(fbVg);
#elif defined NANOVG_GLES2
nvgDeleteGLES2(fbVg);
#endif

glfwDestroyWindow(win);
delete internal;
}


Loading…
Cancel
Save