| @@ -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; | |||
| } | |||