#include "widgets.hpp" #include "gui.hpp" #include #include "../ext/nanovg/src/nanovg_gl.h" #include "../ext/nanovg/src/nanovg_gl_utils.h" namespace rack { struct FramebufferWidget::Internal { NVGLUframebuffer *fb = NULL; Vec offset; ~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() { if (children.empty()) return; // Step children before rendering Widget::step(); // Render the scene to the framebuffer if dirty if (dirty) { Rect childrenBox = getChildrenBoundingBox(); assert(childrenBox.size.isFinite()); int width = ceilf(childrenBox.size.x) + 2*margin; int height = ceilf(childrenBox.size.y) + 2*margin; internal->offset = childrenBox.pos.minus(Vec(margin, margin)); internal->setFramebuffer(NULL); NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, width, height, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); if (!fb) return; internal->setFramebuffer(fb); // TODO Support screens with pixelRatio != 1.0 (e.g. Retina) by using the actual size of the framebuffer, etc. const float pixelRatio = 1.0; nvgluBindFramebuffer(fb); glViewport(0.0, 0.0, width, height); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); nvgBeginFrame(gVg, width, height, pixelRatio); nvgTranslate(gVg, -internal->offset.x, -internal->offset.y); Widget::draw(gVg); nvgEndFrame(gVg); nvgluBindFramebuffer(NULL); dirty = false; } } void FramebufferWidget::draw(NVGcontext *vg) { if (!internal->fb) return; // Draw framebuffer image int width, height; nvgImageSize(vg, internal->fb->image, &width, &height); nvgBeginPath(vg); nvgRect(vg, internal->offset.x, internal->offset.y, width, height); NVGpaint paint = nvgImagePattern(vg, internal->offset.x, internal->offset.y, width, height, 0.0, internal->fb->image, 1.0); nvgFillPaint(vg, paint); nvgFill(vg); // nvgFillColor(vg, nvgRGBA(255, 0, 0, 64)); // nvgFill(vg); } } // namespace rack