@@ -6,9 +6,8 @@ namespace rack { | |||
namespace widget { | |||
/** Caches a widget's draw() result to a framebuffer so it is called less frequently. | |||
When `dirty` is true, its children will be re-rendered on the next call to step(). | |||
Events are not passed to the underlying scene. | |||
/** Caches its children's draw() result to a framebuffer image. | |||
When dirty, its children will be re-rendered on the next call to step(). | |||
*/ | |||
struct FramebufferWidget : Widget { | |||
struct Internal; | |||
@@ -82,7 +82,7 @@ struct Window { | |||
void setFullScreen(bool fullScreen); | |||
bool isFullScreen(); | |||
double getMonitorRefreshRate(); | |||
double getLastFrameTime(); | |||
double getFrameTime(); | |||
double getLastFrameDuration(); | |||
double getFrameTimeOverdue(); | |||
@@ -73,17 +73,17 @@ struct CableContainer : widget::TransparentWidget { | |||
RackWidget::RackWidget() { | |||
railFb = new widget::FramebufferWidget; | |||
railFb->box.size = math::Vec(); | |||
railFb->oversample = 1.0; | |||
// Don't redraw when the world offset of the rail FramebufferWidget changes its fractional value. | |||
railFb->dirtyOnSubpixelChange = false; | |||
{ | |||
RackRail* rail = new RackRail; | |||
rail->box.size = math::Vec(); | |||
railFb->addChild(rail); | |||
} | |||
addChild(railFb); | |||
// railFb = new widget::FramebufferWidget; | |||
// railFb->box.size = math::Vec(); | |||
// railFb->oversample = 1.0; | |||
// // Don't redraw when the world offset of the rail FramebufferWidget changes its fractional value. | |||
// railFb->dirtyOnSubpixelChange = false; | |||
// { | |||
// RackRail* rail = new RackRail; | |||
// rail->box.size = math::Vec(); | |||
// railFb->addChild(rail); | |||
// } | |||
// addChild(railFb); | |||
moduleContainer = new ModuleContainer; | |||
addChild(moduleContainer); | |||
@@ -106,16 +106,16 @@ void RackWidget::draw(const DrawArgs& args) { | |||
nvgGlobalTint(args.vg, nvgRGBAf(b, b, b, 1)); | |||
// Resize and reposition the RackRail to align on the grid. | |||
math::Rect railBox; | |||
railBox.pos = args.clipBox.pos.div(BUS_BOARD_GRID_SIZE).floor().mult(BUS_BOARD_GRID_SIZE); | |||
railBox.size = args.clipBox.size.div(BUS_BOARD_GRID_SIZE).ceil().plus(math::Vec(1, 1)).mult(BUS_BOARD_GRID_SIZE); | |||
if (!railFb->box.size.equals(railBox.size)) { | |||
railFb->dirty = true; | |||
} | |||
railFb->box = railBox; | |||
RackRail* rail = railFb->getFirstDescendantOfType<RackRail>(); | |||
rail->box.size = railFb->box.size; | |||
// math::Rect railBox; | |||
// railBox.pos = args.clipBox.pos.div(BUS_BOARD_GRID_SIZE).floor().mult(BUS_BOARD_GRID_SIZE); | |||
// railBox.size = args.clipBox.size.div(BUS_BOARD_GRID_SIZE).ceil().plus(math::Vec(1, 1)).mult(BUS_BOARD_GRID_SIZE); | |||
// if (!railFb->box.size.equals(railBox.size)) { | |||
// railFb->dirty = true; | |||
// } | |||
// railFb->box = railBox; | |||
// RackRail* rail = railFb->getFirstDescendantOfType<RackRail>(); | |||
// rail->box.size = railFb->box.size; | |||
Widget::draw(args); | |||
} | |||
@@ -111,7 +111,7 @@ void Scene::step() { | |||
// Autosave periodically | |||
if (settings::autosaveInterval > 0.0) { | |||
double time = glfwGetTime(); | |||
double time = system::getTime(); | |||
if (time - lastAutosaveTime >= settings::autosaveInterval) { | |||
lastAutosaveTime = time; | |||
APP->patch->saveAutosave(); | |||
@@ -95,10 +95,6 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
if (APP->window->getFrameTimeOverdue() > 0.0) | |||
return; | |||
// Check that scale has been set by `draw()` yet. | |||
if (scale.isZero()) | |||
return; | |||
// In case we fail drawing the framebuffer, don't try again the next frame, so reset `dirty` here. | |||
dirty = false; | |||
NVGcontext* vg = APP->window->vg; | |||
@@ -134,8 +130,8 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
} | |||
// Create a framebuffer | |||
if (internal->fbSize.isFinite() && !internal->fbSize.isZero()) { | |||
// DEBUG("Creating framebuffer of size (%f, %f)", VEC_ARGS(internal->fbSize)); | |||
internal->fb = nvgluCreateFramebuffer(vg, internal->fbSize.x, internal->fbSize.y, 0); | |||
// DEBUG("Created framebuffer of size (%f, %f)", VEC_ARGS(internal->fbSize)); | |||
} | |||
} | |||
if (!internal->fb) { | |||
@@ -143,7 +139,7 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
return; | |||
} | |||
DEBUG("Drawing to framebuffer of size (%f, %f)", VEC_ARGS(internal->fbSize)); | |||
// DEBUG("Drawing to framebuffer of size (%f, %f)", VEC_ARGS(internal->fbSize)); | |||
// Render to framebuffer | |||
if (oversample == 1.0) { | |||
@@ -156,6 +152,7 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
NVGLUframebuffer* fb = internal->fb; | |||
// If oversampling, create another framebuffer and copy it to actual size. | |||
math::Vec oversampledFbSize = internal->fbSize.mult(oversample).ceil(); | |||
// DEBUG("Creating %0.fx oversampled framebuffer of size (%f, %f)", oversample, VEC_ARGS(internal->fbSize)); | |||
NVGLUframebuffer* oversampledFb = nvgluCreateFramebuffer(fbVg, oversampledFbSize.x, oversampledFbSize.y, 0); | |||
if (!oversampledFb) { | |||
@@ -170,9 +167,8 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
internal->fb = fb; | |||
nvgluBindFramebuffer(NULL); | |||
// Use NanoVG for resizing framebuffers | |||
// Use NanoVG for copying oversampled framebuffer to normal framebuffer | |||
nvgluBindFramebuffer(internal->fb); | |||
nvgBeginFrame(fbVg, internal->fbBox.size.x, internal->fbBox.size.y, 1.0); | |||
// Draw oversampled framebuffer | |||
@@ -205,11 +201,7 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
nvgSave(args.vg); | |||
nvgResetTransform(args.vg); | |||
math::Vec scaleRatio = math::Vec(1, 1); | |||
if (!internal->fbScale.isZero() && !scale.equals(internal->fbScale)) { | |||
// Continue to draw with the last framebuffer, but stretch it to rescale. | |||
scaleRatio = scale.div(internal->fbScale); | |||
} | |||
math::Vec scaleRatio = scale.div(internal->fbScale); | |||
// DEBUG("%f %f %f %f", scaleRatio.x, scaleRatio.y, offsetF.x, offsetF.y); | |||
// DEBUG("%f %f %f %f, %f %f", RECT_ARGS(internal->fbBox), VEC_ARGS(internal->fbSize)); | |||
@@ -2,6 +2,7 @@ | |||
#include <widget/Widget.hpp> | |||
#include <context.hpp> | |||
#include <window.hpp> | |||
#include <system.hpp> | |||
namespace rack { | |||
@@ -159,7 +160,7 @@ bool EventState::handleButton(math::Vec pos, int button, int action, int mods) { | |||
if (action == GLFW_PRESS) { | |||
const double doubleClickDuration = 0.3; | |||
double clickTime = glfwGetTime(); | |||
double clickTime = system::getTime(); | |||
if (clickedWidget | |||
&& clickTime - lastClickTime <= doubleClickDuration | |||
&& lastClickedWidget == clickedWidget) { | |||
@@ -81,8 +81,8 @@ struct Window::Internal { | |||
bool ignoreNextMouseDelta = false; | |||
int frameSwapInterval = -1; | |||
double monitorRefreshRate = 0.0; | |||
double frameTime = 0.0; | |||
double lastFrameDuration = 0.0; | |||
double lastFrameTime = 0.0; | |||
math::Vec lastMousePos; | |||
@@ -387,10 +387,10 @@ void Window::run() { | |||
void Window::step() { | |||
double frameTime = glfwGetTime(); | |||
internal->lastFrameDuration = frameTime - internal->lastFrameTime; | |||
double lastFrameTime = internal->frameTime; | |||
internal->frameTime = system::getTime(); | |||
internal->lastFrameDuration = internal->frameTime - lastFrameTime; | |||
// DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); | |||
internal->lastFrameTime = frameTime; | |||
// Make event handlers and step() have a clean NanoVG context | |||
nvgReset(vg); | |||
@@ -540,7 +540,7 @@ void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { | |||
zw->addChild(mw); | |||
// HACK: Set the frame time so FramebufferWidgets are never overdue and therefore guaranteed to draw | |||
internal->lastFrameTime = INFINITY; | |||
internal->frameTime = INFINITY; | |||
// Draw to framebuffer | |||
fbw->step(); | |||
@@ -636,8 +636,8 @@ double Window::getMonitorRefreshRate() { | |||
} | |||
double Window::getLastFrameTime() { | |||
return internal->lastFrameTime; | |||
double Window::getFrameTime() { | |||
return internal->frameTime; | |||
} | |||
@@ -648,7 +648,7 @@ double Window::getLastFrameDuration() { | |||
double Window::getFrameTimeOverdue() { | |||
double desiredFrameDuration = internal->frameSwapInterval / internal->monitorRefreshRate; | |||
double frameDuration = glfwGetTime() - internal->lastFrameTime; | |||
double frameDuration = system::getTime() - internal->frameTime; | |||
return frameDuration - desiredFrameDuration; | |||
} | |||