#include "widgets.hpp" #include "gui.hpp" #include #include "../ext/nanovg/src/nanovg_gl.h" #include "../ext/nanovg/src/nanovg_gl_utils.h" #include "../ext/osdialog/osdialog.h" namespace rack { struct FramebufferWidget::Internal { NVGLUframebuffer *fb = NULL; Rect box; ~Internal() { setFramebuffer(NULL); } void setFramebuffer(NVGLUframebuffer *fb) { if (this->fb) nvgluDeleteFramebuffer(this->fb); this->fb = fb; } }; FramebufferWidget::FramebufferWidget() { internal = new Internal(); } FramebufferWidget::~FramebufferWidget() { delete internal; } void FramebufferWidget::step() { // Step children before rendering Widget::step(); // Render the scene to the framebuffer if dirty if (dirty) { internal->box.pos = Vec(0, 0); internal->box.size = box.size; internal->box.size = Vec(ceilf(internal->box.size.x), ceilf(internal->box.size.y)); Vec fbSize = internal->box.size.mult(gPixelRatio * oversample); // assert(fbSize.isFinite()); // Reject zero area size if (fbSize.x <= 0.0 || fbSize.y <= 0.0) return; // Delete old one first to free up GPU memory internal->setFramebuffer(NULL); NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); if (!fb) return; internal->setFramebuffer(fb); nvgluBindFramebuffer(fb); glViewport(0.0, 0.0, fbSize.x, fbSize.y); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); nvgBeginFrame(gVg, fbSize.x, fbSize.y, gPixelRatio * oversample); nvgScale(gVg, gPixelRatio * oversample, gPixelRatio * oversample); Widget::draw(gVg); nvgEndFrame(gVg); nvgluBindFramebuffer(NULL); dirty = false; } } void FramebufferWidget::draw(NVGcontext *vg) { if (!internal->fb) { // Bypass framebuffer cache entirely // Widget::draw(vg); return; } // Draw framebuffer image nvgBeginPath(vg); nvgRect(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y); NVGpaint paint = nvgImagePattern(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y, 0.0, internal->fb->image, 1.0); nvgFillPaint(vg, paint); nvgFill(vg); // For debugging bounding box of framebuffer image // nvgFillColor(vg, nvgRGBA(255, 0, 0, 64)); // nvgFill(vg); } int FramebufferWidget::getImageHandle() { if (!internal->fb) return -1; return internal->fb->image; } } // namespace rack