<commit_before>#include "widget/FramebufferWidget.hpp"
#include "app.hpp"


namespace rack {
namespace widget {


FramebufferWidget::FramebufferWidget() {
	oversample = 1.0;
}

FramebufferWidget::~FramebufferWidget() {
	if (fb)
		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();

	// Render to framebuffer
	if (dirty) {
		dirty = false;

		fbScale = scale;
		// World coordinates, in range [0, 1)
		fbOffset = offset.minus(offsetI);

		math::Rect localBox;
		if (children.empty()) {
			localBox = box.zeroPos();
		}
		else {
			localBox = getChildrenBoundingBox();
		}

		// DEBUG("%g %g %g %g, %g %g, %g %g", RECT_ARGS(localBox), VEC_ARGS(fbOffset), VEC_ARGS(scale));
		// 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();
		fbBox = math::Rect::fromMinMax(min, max);
		// DEBUG("%g %g %g %g", RECT_ARGS(fbBox));

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

		if (!fb || !newFbSize.isEqual(fbSize)) {
			fbSize = newFbSize;
			// Delete old framebuffer
			if (fb)
				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);
		}

		if (!fb)
			return;

		nvgluBindFramebuffer(fb);
		drawFramebuffer();
		nvgluBindFramebuffer(NULL);
	}

	if (!fb)
		return;

	// Draw framebuffer image, using world coordinates
	nvgSave(args.vg);
	nvgResetTransform(args.vg);

	nvgBeginPath(args.vg);
	nvgRect(args.vg,
		offsetI.x + fbBox.pos.x,
		offsetI.y + fbBox.pos.y,
		fbBox.size.x, fbBox.size.y);
	NVGpaint paint = nvgImagePattern(args.vg,
		offsetI.x + fbBox.pos.x,
		offsetI.y + fbBox.pos.y,
		fbBox.size.x, fbBox.size.y,
		0.0, fb->image, 1.0);
	nvgFillPaint(args.vg, paint);
	nvgFill(args.vg);

	// For debugging the bounding box of the framebuffer
	// nvgStrokeWidth(args.vg, 2.0);
	// nvgStrokeColor(args.vg, nvgRGBAf(1, 1, 0, 0.5));
	// nvgStroke(args.vg);

	nvgRestore(args.vg);
}

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

	float pixelRatio = fbSize.x / fbBox.size.x;
	nvgBeginFrame(vg, fbBox.size.x, fbBox.size.y, pixelRatio);

	// Use local scaling
	nvgTranslate(vg, -fbBox.pos.x, -fbBox.pos.y);
	nvgTranslate(vg, fbOffset.x, fbOffset.y);
	nvgScale(vg, fbScale.x, fbScale.y);

	DrawArgs args;
	args.vg = vg;
	Widget::draw(args);

	glViewport(0.0, 0.0, fbSize.x, fbSize.y);
	glClearColor(0.0, 0.0, 0.0, 0.0);
	// glClearColor(0.0, 1.0, 1.0, 0.5);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	nvgEndFrame(vg);
}

int FramebufferWidget::getImageHandle() {
	if (!fb)<commit_msg>Fix FramebufferWidget call to drawFramebuffer().<commit_after>#include "widget/FramebufferWidget.hpp"
#include "app.hpp"


namespace rack {
namespace widget {


FramebufferWidget::FramebufferWidget() {
	oversample = 1.0;
}

FramebufferWidget::~FramebufferWidget() {
	if (fb)
		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();

	// Render to framebuffer
	if (dirty) {
		dirty = false;

		fbScale = scale;
		// World coordinates, in range [0, 1)
		fbOffset = offset.minus(offsetI);

		math::Rect localBox;
		if (children.empty()) {
			localBox = box.zeroPos();
		}
		else {
			localBox = getChildrenBoundingBox();
		}

		// DEBUG("%g %g %g %g, %g %g, %g %g", RECT_ARGS(localBox), VEC_ARGS(fbOffset), VEC_ARGS(scale));
		// 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();
		fbBox = math::Rect::fromMinMax(min, max);
		// DEBUG("%g %g %g %g", RECT_ARGS(fbBox));

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

		if (!fb || !newFbSize.isEqual(fbSize)) {
			fbSize = newFbSize;
			// Delete old framebuffer
			if (fb)
				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);
		}

		if (!fb)
			return;

		nvgluBindFramebuffer(fb);
		drawFramebuffer();
		nvgluBindFramebuffer(NULL);
	}

	if (!fb)
		return;

	// Draw framebuffer image, using world coordinates
	nvgSave(args.vg);
	nvgResetTransform(args.vg);

	nvgBeginPath(args.vg);
	nvgRect(args.vg,
		offsetI.x + fbBox.pos.x,
		offsetI.y + fbBox.pos.y,
		fbBox.size.x, fbBox.size.y);
	NVGpaint paint = nvgImagePattern(args.vg,
		offsetI.x + fbBox.pos.x,
		offsetI.y + fbBox.pos.y,
		fbBox.size.x, fbBox.size.y,
		0.0, fb->image, 1.0);
	nvgFillPaint(args.vg, paint);
	nvgFill(args.vg);

	// For debugging the bounding box of the framebuffer
	// nvgStrokeWidth(args.vg, 2.0);
	// nvgStrokeColor(args.vg, nvgRGBAf(1, 1, 0, 0.5));
	// nvgStroke(args.vg);

	nvgRestore(args.vg);
}

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

	float pixelRatio = fbSize.x / fbBox.size.x;
	nvgBeginFrame(vg, fbBox.size.x, fbBox.size.y, pixelRatio);

	// Use local scaling
	nvgTranslate(vg, -fbBox.pos.x, -fbBox.pos.y);
	nvgTranslate(vg, fbOffset.x, fbOffset.y);
	nvgScale(vg, fbScale.x, fbScale.y);

	DrawArgs args;
	args.vg = vg;
	args.clipBox = box.zeroPos();
	Widget::draw(args);

	glViewport(0.0, 0.0, fbSize.x, fbSize.y);
	glClearColor(0.0, 0.0, 0.0, 0.0);
	// glClearColor(0.0, 1.0, 1.0, 0.5);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	nvgEndFrame(vg);
}

int FramebufferWidget::getImageHandle() {
	if (!fb)
{'fraction_non_alphanumeric': 0.1591296928327645, 'fraction_numerical': 0.012798634812286689, 'mean_word_length': 4.186578171091446, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '225039', 'n_tokens_mistral': 2988, 'n_tokens_neox': 2696, 'n_words': 579}