@@ -14,5 +14,6 @@ void guiCursorUnlock(); | |||||
extern NVGcontext *gVg; | extern NVGcontext *gVg; | ||||
extern std::shared_ptr<Font> gGuiFont; | extern std::shared_ptr<Font> gGuiFont; | ||||
extern float gPixelRatio; | |||||
} // namespace rack | } // namespace rack |
@@ -23,6 +23,7 @@ namespace rack { | |||||
static GLFWwindow *window = NULL; | static GLFWwindow *window = NULL; | ||||
std::shared_ptr<Font> gGuiFont; | std::shared_ptr<Font> gGuiFont; | ||||
NVGcontext *gVg = NULL; | NVGcontext *gVg = NULL; | ||||
float gPixelRatio = 0.0; | |||||
void windowSizeCallback(GLFWwindow* window, int width, int height) { | void windowSizeCallback(GLFWwindow* window, int width, int height) { | ||||
@@ -136,6 +137,7 @@ static int lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight; | |||||
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { | void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { | ||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) { | if (action == GLFW_PRESS || action == GLFW_REPEAT) { | ||||
if (key == GLFW_KEY_F11 || key == GLFW_KEY_ESCAPE) { | if (key == GLFW_KEY_F11 || key == GLFW_KEY_ESCAPE) { | ||||
/* | |||||
// Toggle fullscreen | // Toggle fullscreen | ||||
GLFWmonitor *monitor = glfwGetWindowMonitor(window); | GLFWmonitor *monitor = glfwGetWindowMonitor(window); | ||||
if (monitor) { | if (monitor) { | ||||
@@ -151,6 +153,7 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods | |||||
const GLFWvidmode *mode = glfwGetVideoMode(monitor); | const GLFWvidmode *mode = glfwGetVideoMode(monitor); | ||||
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | ||||
} | } | ||||
*/ | |||||
} | } | ||||
else { | else { | ||||
if (gSelectedWidget) { | if (gSelectedWidget) { | ||||
@@ -163,16 +166,20 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods | |||||
void renderGui() { | void renderGui() { | ||||
int width, height; | int width, height; | ||||
glfwGetFramebufferSize(window, &width, &height); | glfwGetFramebufferSize(window, &width, &height); | ||||
// glfwGetWindowSize(window, &width, &height); | |||||
int windowWidth, windowHeight; | |||||
glfwGetWindowSize(window, &windowWidth, &windowHeight); | |||||
gPixelRatio = (float)width / windowWidth; | |||||
// Update and render | // Update and render | ||||
glViewport(0, 0, width, height); | glViewport(0, 0, width, height); | ||||
glClearColor(0.0, 0.0, 0.0, 1.0); | glClearColor(0.0, 0.0, 0.0, 1.0); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | ||||
nvgBeginFrame(gVg, width, height, 1.0); | |||||
nvgBeginFrame(gVg, width, height, gPixelRatio); | |||||
nvgSave(gVg); | nvgSave(gVg); | ||||
nvgReset(gVg); | |||||
nvgScale(gVg, gPixelRatio, gPixelRatio); | |||||
gScene->draw(gVg); | gScene->draw(gVg); | ||||
nvgRestore(gVg); | nvgRestore(gVg); | ||||
@@ -220,7 +227,7 @@ void guiInit() { | |||||
// GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. | // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. | ||||
glGetError(); | glGetError(); | ||||
glfwSetWindowSizeLimits(window, 240, 160, GLFW_DONT_CARE, GLFW_DONT_CARE); | |||||
glfwSetWindowSizeLimits(window, 640, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); | |||||
// Set up NanoVG | // Set up NanoVG | ||||
gVg = nvgCreateGL2(NVG_ANTIALIAS); | gVg = nvgCreateGL2(NVG_ANTIALIAS); | ||||
@@ -10,6 +10,7 @@ namespace rack { | |||||
struct FramebufferWidget::Internal { | struct FramebufferWidget::Internal { | ||||
NVGLUframebuffer *fb = NULL; | NVGLUframebuffer *fb = NULL; | ||||
Rect box; | |||||
~Internal() { | ~Internal() { | ||||
setFramebuffer(NULL); | setFramebuffer(NULL); | ||||
@@ -21,6 +22,7 @@ struct FramebufferWidget::Internal { | |||||
} | } | ||||
}; | }; | ||||
FramebufferWidget::FramebufferWidget() { | FramebufferWidget::FramebufferWidget() { | ||||
internal = new Internal(); | internal = new Internal(); | ||||
} | } | ||||
@@ -35,7 +37,9 @@ void FramebufferWidget::step() { | |||||
// Render the scene to the framebuffer if dirty | // Render the scene to the framebuffer if dirty | ||||
if (dirty) { | if (dirty) { | ||||
Vec fbSize = box.size.plus(padding.mult(2)); | |||||
internal->box.pos = padding.neg(); | |||||
internal->box.size = box.size.plus(padding.mult(2)); | |||||
Vec fbSize = internal->box.size.mult(gPixelRatio); | |||||
assert(fbSize.isFinite()); | assert(fbSize.isFinite()); | ||||
internal->setFramebuffer(NULL); | internal->setFramebuffer(NULL); | ||||
@@ -44,14 +48,13 @@ void FramebufferWidget::step() { | |||||
return; | return; | ||||
internal->setFramebuffer(fb); | 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); | nvgluBindFramebuffer(fb); | ||||
glViewport(0.0, 0.0, fbSize.x, fbSize.y); | glViewport(0.0, 0.0, fbSize.x, fbSize.y); | ||||
glClearColor(0.0, 0.0, 0.0, 0.0); | glClearColor(0.0, 0.0, 0.0, 0.0); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | ||||
nvgBeginFrame(gVg, fbSize.x, fbSize.y, pixelRatio); | |||||
nvgBeginFrame(gVg, fbSize.x, fbSize.y, gPixelRatio); | |||||
nvgScale(gVg, gPixelRatio, gPixelRatio); | |||||
nvgTranslate(gVg, padding.x, padding.y); | nvgTranslate(gVg, padding.x, padding.y); | ||||
Widget::draw(gVg); | Widget::draw(gVg); | ||||
@@ -67,14 +70,13 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||||
return; | return; | ||||
// Draw framebuffer image | // Draw framebuffer image | ||||
int width, height; | |||||
nvgImageSize(vg, internal->fb->image, &width, &height); | |||||
nvgBeginPath(vg); | nvgBeginPath(vg); | ||||
nvgRect(vg, -padding.x, -padding.y, width, height); | |||||
NVGpaint paint = nvgImagePattern(vg, -padding.x, -padding.y, width, height, 0.0, internal->fb->image, 1.0); | |||||
nvgRect(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y); | |||||
NVGpaint paint = nvgImagePattern(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y, 0.0, internal->fb->image, 1.0); | |||||
nvgFillPaint(vg, paint); | nvgFillPaint(vg, paint); | ||||
nvgFill(vg); | nvgFill(vg); | ||||
// For debugging bounding box of framebuffer image | |||||
// nvgFillColor(vg, nvgRGBA(255, 0, 0, 64)); | // nvgFillColor(vg, nvgRGBA(255, 0, 0, 64)); | ||||
// nvgFill(vg); | // nvgFill(vg); | ||||
} | } | ||||