@@ -16,6 +16,7 @@ struct Scene : widget::OpaqueWidget { | |||||
RackWidget* rack; | RackWidget* rack; | ||||
MenuBar* menuBar; | MenuBar* menuBar; | ||||
widget::Widget* moduleBrowser; | widget::Widget* moduleBrowser; | ||||
widget::Widget* frameRateWidget; | |||||
double lastAutosaveTime = 0.0; | double lastAutosaveTime = 0.0; | ||||
@@ -90,7 +90,8 @@ struct Window { | |||||
void setFullScreen(bool fullScreen); | void setFullScreen(bool fullScreen); | ||||
bool isFullScreen(); | bool isFullScreen(); | ||||
bool isFrameOverdue(); | bool isFrameOverdue(); | ||||
double getMonitorRefreshRate(); | |||||
float getMonitorRefreshRate(); | |||||
float getLastFrameRate(); | |||||
std::shared_ptr<Font> loadFont(const std::string& filename); | std::shared_ptr<Font> loadFont(const std::string& filename); | ||||
std::shared_ptr<Image> loadImage(const std::string& filename); | std::shared_ptr<Image> loadImage(const std::string& filename); | ||||
@@ -339,11 +339,11 @@ struct FrameRateItem : ui::MenuItem { | |||||
ui::Menu* menu = new ui::Menu; | ui::Menu* menu = new ui::Menu; | ||||
for (int i = 1; i <= 6; i++) { | for (int i = 1; i <= 6; i++) { | ||||
double frameRate = APP->window->getMonitorRefreshRate() / i; | |||||
float frameRate = APP->window->getMonitorRefreshRate() / i; | |||||
FrameRateValueItem* item = new FrameRateValueItem; | FrameRateValueItem* item = new FrameRateValueItem; | ||||
item->frameSwapInterval = i; | item->frameSwapInterval = i; | ||||
item->text = string::f("%.0lf Hz", frameRate); | |||||
item->text = string::f("%.0f Hz", frameRate); | |||||
item->rightText += CHECKMARK(settings::frameSwapInterval == i); | item->rightText += CHECKMARK(settings::frameSwapInterval == i); | ||||
menu->addChild(item); | menu->addChild(item); | ||||
} | } | ||||
@@ -15,6 +15,14 @@ namespace rack { | |||||
namespace app { | namespace app { | ||||
struct FrameRateWidget : widget::TransparentWidget { | |||||
void draw(const DrawArgs& args) override { | |||||
std::string text = string::f("%.2f Hz", APP->window->getLastFrameRate()); | |||||
bndLabel(args.vg, 0.0, 0.0, INFINITY, INFINITY, -1, text.c_str()); | |||||
} | |||||
}; | |||||
Scene::Scene() { | Scene::Scene() { | ||||
rackScroll = new RackScrollWidget; | rackScroll = new RackScrollWidget; | ||||
addChild(rackScroll); | addChild(rackScroll); | ||||
@@ -27,6 +35,11 @@ Scene::Scene() { | |||||
moduleBrowser = moduleBrowserCreate(); | moduleBrowser = moduleBrowserCreate(); | ||||
moduleBrowser->hide(); | moduleBrowser->hide(); | ||||
addChild(moduleBrowser); | addChild(moduleBrowser); | ||||
frameRateWidget = new FrameRateWidget; | |||||
frameRateWidget->box.size = math::Vec(80.0, 30.0); | |||||
frameRateWidget->hide(); | |||||
addChild(frameRateWidget); | |||||
} | } | ||||
Scene::~Scene() { | Scene::~Scene() { | ||||
@@ -36,6 +49,7 @@ void Scene::step() { | |||||
bool fullscreen = APP->window->isFullScreen(); | bool fullscreen = APP->window->isFullScreen(); | ||||
menuBar->visible = !fullscreen; | menuBar->visible = !fullscreen; | ||||
rackScroll->box.pos.y = menuBar->visible ? menuBar->box.size.y : 0; | rackScroll->box.pos.y = menuBar->visible ? menuBar->box.size.y : 0; | ||||
frameRateWidget->box.pos.x = box.size.x - frameRateWidget->box.size.x; | |||||
// Resize owned descendants | // Resize owned descendants | ||||
menuBar->box.size.x = box.size.x; | menuBar->box.size.x = box.size.x; | ||||
@@ -96,7 +96,8 @@ struct Window::Internal { | |||||
bool ignoreNextMouseDelta = false; | bool ignoreNextMouseDelta = false; | ||||
int frameSwapInterval = -1; | int frameSwapInterval = -1; | ||||
double monitorRefreshRate = -1; | |||||
float monitorRefreshRate = 0.f; | |||||
float lastFrameRate = 0.f; | |||||
}; | }; | ||||
@@ -329,8 +330,8 @@ void Window::run() { | |||||
frame = 0; | frame = 0; | ||||
while (!glfwWindowShouldClose(win)) { | while (!glfwWindowShouldClose(win)) { | ||||
double frameTime = glfwGetTime(); | double frameTime = glfwGetTime(); | ||||
// double frameRate = 1.0 / (frameTime - frameTimeStart); | |||||
// DEBUG("%g fps", frameRate); | |||||
internal->lastFrameRate = 1.f / float(frameTime - frameTimeStart); | |||||
// DEBUG("%.2f Hz", internal->lastFrameRate); | |||||
frameTimeStart = frameTime; | frameTimeStart = frameTime; | ||||
// Make event handlers and step() have a clean nanovg context | // Make event handlers and step() have a clean nanovg context | ||||
@@ -529,10 +530,14 @@ bool Window::isFrameOverdue() { | |||||
return frameDuration > frameDeadline; | return frameDuration > frameDeadline; | ||||
} | } | ||||
double Window::getMonitorRefreshRate() { | |||||
float Window::getMonitorRefreshRate() { | |||||
return internal->monitorRefreshRate; | return internal->monitorRefreshRate; | ||||
} | } | ||||
float Window::getLastFrameRate() { | |||||
return internal->lastFrameRate; | |||||
} | |||||
std::shared_ptr<Font> Window::loadFont(const std::string& filename) { | std::shared_ptr<Font> Window::loadFont(const std::string& filename) { | ||||
auto sp = fontCache[filename].lock(); | auto sp = fontCache[filename].lock(); | ||||
if (!sp) { | if (!sp) { | ||||