@@ -32,6 +32,8 @@ struct FramebufferWidget : Widget { | |||
NVGLUframebuffer* getFramebuffer(); | |||
math::Vec getFramebufferSize(); | |||
void setScale(math::Vec scale); | |||
void onContextCreate(const ContextCreateEvent& e) override; | |||
void onContextDestroy(const ContextDestroyEvent& e) override; | |||
}; | |||
@@ -452,13 +452,33 @@ struct Widget : WeakBase { | |||
virtual void onHide(const HideEvent& e) { | |||
recurseEvent(&Widget::onHide, e); | |||
} | |||
/** Occurs after the Window, OpenGL context, and Nanovg are created. | |||
Recurses. | |||
*/ | |||
struct ContextCreateEvent : BaseEvent { | |||
NVGcontext* vg; | |||
}; | |||
virtual void onContextCreate(const ContextCreateEvent& e) { | |||
recurseEvent(&Widget::onContextCreate, e); | |||
} | |||
/** Occurs before the Window, OpenGL context, and Nanovg are destroyed. | |||
Recurses. | |||
*/ | |||
struct ContextDestroyEvent : BaseEvent { | |||
NVGcontext* vg; | |||
}; | |||
virtual void onContextDestroy(const ContextDestroyEvent& e) { | |||
recurseEvent(&Widget::onContextDestroy, e); | |||
} | |||
}; | |||
} // namespace widget | |||
/** Deprecated Rack v1 event namespace. | |||
Use `FooEvent` instead of `event::Foo` in new code. | |||
Use `FooEvent` (defined in widget::Widget) instead of `event::Foo` in new code. | |||
*/ | |||
namespace event { | |||
using Base = widget::BaseEvent; | |||
@@ -50,7 +50,7 @@ void FramebufferWidget::setDirty(bool dirty) { | |||
void FramebufferWidget::onDirty(const DirtyEvent& e) { | |||
dirty = true; | |||
setDirty(); | |||
Widget::onDirty(e); | |||
} | |||
@@ -71,7 +71,7 @@ void FramebufferWidget::step() { | |||
return; | |||
// In case we fail drawing the framebuffer, don't try again the next frame, so reset `dirty` here. | |||
dirty = false; | |||
setDirty(false); | |||
NVGcontext* vg = APP->window->vg; | |||
internal->fbScale = internal->scale; | |||
@@ -186,12 +186,12 @@ void FramebufferWidget::draw(const DrawArgs& args) { | |||
if (dirtyOnSubpixelChange && !(math::isNear(internal->offsetF.x, internal->fbOffsetF.x, 0.01f) && math::isNear(internal->offsetF.y, internal->fbOffsetF.y, 0.01f))) { | |||
// If drawing to a new subpixel location, rerender in the next frame. | |||
// DEBUG("%p dirty subpixel", this); | |||
dirty = true; | |||
setDirty(); | |||
} | |||
if (!internal->scale.equals(internal->fbScale)) { | |||
// If rescaled, rerender in the next frame. | |||
// DEBUG("%p dirty scale", this); | |||
dirty = true; | |||
setDirty(); | |||
} | |||
math::Vec scaleRatio = math::Vec(1, 1); | |||
@@ -285,5 +285,18 @@ void FramebufferWidget::setScale(math::Vec scale) { | |||
} | |||
void FramebufferWidget::onContextCreate(const ContextCreateEvent& e) { | |||
setDirty(); | |||
Widget::onContextCreate(e); | |||
} | |||
void FramebufferWidget::onContextDestroy(const ContextDestroyEvent& e) { | |||
if (internal->fb) | |||
nvgluDeleteFramebuffer(internal->fb); | |||
Widget::onContextDestroy(e); | |||
} | |||
} // namespace widget | |||
} // namespace rack |
@@ -327,6 +327,11 @@ Window::Window() { | |||
// Load default Blendish font | |||
uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); | |||
bndSetFont(uiFont->handle); | |||
if (APP->scene) { | |||
widget::Widget::ContextCreateEvent e; | |||
APP->scene->onContextCreate(e); | |||
} | |||
} | |||
@@ -344,6 +349,11 @@ Window::~Window() { | |||
settings::windowPos = math::Vec(winX, winY); | |||
} | |||
if (APP->scene) { | |||
widget::Widget::ContextDestroyEvent e; | |||
APP->scene->onContextDestroy(e); | |||
} | |||
#if defined NANOVG_GL2 | |||
nvgDeleteGL2(vg); | |||
#elif defined NANOVG_GL3 | |||
@@ -422,30 +432,32 @@ void Window::step() { | |||
glfwGetWindowSize(win, &winWidth, &winHeight); | |||
windowRatio = (float)fbWidth / winWidth; | |||
// DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); | |||
// Resize scene | |||
APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); | |||
// Step scene | |||
APP->scene->step(); | |||
// Render scene | |||
bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); | |||
if (visible) { | |||
// Update and render | |||
nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); | |||
nvgScale(vg, pixelRatio, pixelRatio); | |||
// Draw scene | |||
widget::Widget::DrawArgs args; | |||
args.vg = vg; | |||
args.clipBox = APP->scene->box.zeroPos(); | |||
APP->scene->draw(args); | |||
glViewport(0, 0, fbWidth, fbHeight); | |||
glClearColor(0.0, 0.0, 0.0, 1.0); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||
nvgEndFrame(vg); | |||
if (APP->scene) { | |||
// DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); | |||
// Resize scene | |||
APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); | |||
// Step scene | |||
APP->scene->step(); | |||
// Render scene | |||
bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); | |||
if (visible) { | |||
// Update and render | |||
nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); | |||
nvgScale(vg, pixelRatio, pixelRatio); | |||
// Draw scene | |||
widget::Widget::DrawArgs args; | |||
args.vg = vg; | |||
args.clipBox = APP->scene->box.zeroPos(); | |||
APP->scene->draw(args); | |||
glViewport(0, 0, fbWidth, fbHeight); | |||
glClearColor(0.0, 0.0, 0.0, 1.0); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||
nvgEndFrame(vg); | |||
} | |||
} | |||
glfwSwapBuffers(win); | |||
@@ -223,6 +223,12 @@ int main(int argc, char* argv[]) { | |||
INFO("Running window"); | |||
APP->window->run(); | |||
INFO("Stopped window"); | |||
delete APP->window; | |||
APP->window = NULL; | |||
INFO("Re-creating window"); | |||
APP->window = new Window; | |||
APP->window->run(); | |||
} | |||
// Destroy context | |||