mirror of https://github.com/mgba-emu/mgba.git
Qt: Add optional frame counter to OSD (closes #1728)
This commit is contained in:
parent
b512d6d455
commit
006dba7d69
1
CHANGES
1
CHANGES
|
@ -33,6 +33,7 @@ Misc:
|
|||
- Qt: Only set default controller bindings if loading fails (fixes mgba.io/i/799)
|
||||
- Qt: Save converter now supports importing GameShark Advance saves
|
||||
- Qt: Save positions of multiplayer windows (closes mgba.io/i/2128)
|
||||
- Qt: Add optional frame counter to OSD (closes mgba.io/i/1728)
|
||||
- Windows: Attach to console if present
|
||||
|
||||
0.9.3: (2021-12-17)
|
||||
|
|
|
@ -86,6 +86,7 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
|||
}
|
||||
|
||||
controller->m_resetActions.clear();
|
||||
controller->m_frameCounter = -1;
|
||||
|
||||
if (!controller->m_hwaccel) {
|
||||
context->core->setVideoBuffer(context->core, reinterpret_cast<color_t*>(controller->m_activeBuffer.data()), controller->screenDimensions().width());
|
||||
|
@ -1081,6 +1082,7 @@ void CoreController::finishFrame() {
|
|||
mCoreThreadPauseFromThread(&m_threadContext);
|
||||
}
|
||||
}
|
||||
++m_frameCounter;
|
||||
}
|
||||
updateKeys();
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ public:
|
|||
bool videoSync() const { return m_videoSync; }
|
||||
|
||||
void addFrameAction(std::function<void ()> callback);
|
||||
uint64_t frameCounter() const { return m_frameCounter; }
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
|
@ -244,6 +245,7 @@ private:
|
|||
std::unique_ptr<mCacheSet> m_cacheSet;
|
||||
std::unique_ptr<Override> m_override;
|
||||
|
||||
uint64_t m_frameCounter;
|
||||
QList<std::function<void()>> m_resetActions;
|
||||
QList<std::function<void()>> m_frameActions;
|
||||
QMutex m_actionMutex{QMutex::Recursive};
|
||||
|
|
|
@ -85,14 +85,20 @@ Display::Display(QWidget* parent)
|
|||
}
|
||||
|
||||
void Display::attach(std::shared_ptr<CoreController> controller) {
|
||||
connect(controller.get(), &CoreController::stateLoaded, this, &Display::resizeContext);
|
||||
connect(controller.get(), &CoreController::stateLoaded, this, &Display::forceDraw);
|
||||
connect(controller.get(), &CoreController::rewound, this, &Display::forceDraw);
|
||||
connect(controller.get(), &CoreController::paused, this, &Display::pauseDrawing);
|
||||
connect(controller.get(), &CoreController::unpaused, this, &Display::unpauseDrawing);
|
||||
connect(controller.get(), &CoreController::frameAvailable, this, &Display::framePosted);
|
||||
connect(controller.get(), &CoreController::statusPosted, this, &Display::showMessage);
|
||||
connect(controller.get(), &CoreController::didReset, this, &Display::resizeContext);
|
||||
CoreController* controllerP = controller.get();
|
||||
connect(controllerP, &CoreController::stateLoaded, this, &Display::resizeContext);
|
||||
connect(controllerP, &CoreController::stateLoaded, this, &Display::forceDraw);
|
||||
connect(controllerP, &CoreController::rewound, this, &Display::forceDraw);
|
||||
connect(controllerP, &CoreController::paused, this, &Display::pauseDrawing);
|
||||
connect(controllerP, &CoreController::unpaused, this, &Display::unpauseDrawing);
|
||||
connect(controllerP, &CoreController::frameAvailable, this, &Display::framePosted);
|
||||
connect(controllerP, &CoreController::frameAvailable, this, [controllerP, this]() {
|
||||
if (m_showFrameCounter) {
|
||||
m_messagePainter.showFrameCounter(controllerP->frameCounter());
|
||||
}
|
||||
});
|
||||
connect(controllerP, &CoreController::statusPosted, this, &Display::showMessage);
|
||||
connect(controllerP, &CoreController::didReset, this, &Display::resizeContext);
|
||||
}
|
||||
|
||||
void Display::configure(ConfigController* config) {
|
||||
|
@ -102,6 +108,7 @@ void Display::configure(ConfigController* config) {
|
|||
interframeBlending(opts->interframeBlending);
|
||||
filter(opts->resampleVideo);
|
||||
config->updateOption("showOSD");
|
||||
config->updateOption("showFrameCounter");
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (opts->shader) {
|
||||
struct VDir* shader = VDirOpen(opts->shader);
|
||||
|
@ -137,6 +144,13 @@ void Display::showOSDMessages(bool enable) {
|
|||
m_showOSD = enable;
|
||||
}
|
||||
|
||||
void Display::showFrameCounter(bool enable) {
|
||||
m_showFrameCounter = enable;
|
||||
if (!enable) {
|
||||
m_messagePainter.clearFrameCounter();
|
||||
}
|
||||
}
|
||||
|
||||
void Display::filter(bool filter) {
|
||||
m_filter = filter;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
bool hasInterframeBlending() const { return m_interframeBlending; }
|
||||
bool isFiltered() const { return m_filter; }
|
||||
bool isShowOSD() const { return m_showOSD; }
|
||||
bool isShowFrameCounter() const { return m_showFrameCounter; }
|
||||
|
||||
virtual void attach(std::shared_ptr<CoreController>);
|
||||
virtual void configure(ConfigController*);
|
||||
|
@ -69,6 +70,7 @@ public slots:
|
|||
virtual void lockIntegerScaling(bool lock);
|
||||
virtual void interframeBlending(bool enable);
|
||||
virtual void showOSDMessages(bool enable);
|
||||
virtual void showFrameCounter(bool enable);
|
||||
virtual void filter(bool filter);
|
||||
virtual void framePosted() = 0;
|
||||
virtual void setShaders(struct VDir*) = 0;
|
||||
|
@ -89,6 +91,7 @@ private:
|
|||
|
||||
MessagePainter m_messagePainter;
|
||||
bool m_showOSD = true;
|
||||
bool m_showFrameCounter = false;
|
||||
bool m_lockAspectRatio = false;
|
||||
bool m_lockIntegerScaling = false;
|
||||
bool m_interframeBlending = false;
|
||||
|
|
|
@ -95,6 +95,7 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
|
|||
lockIntegerScaling(isIntegerScalingLocked());
|
||||
interframeBlending(hasInterframeBlending());
|
||||
showOSDMessages(isShowOSD());
|
||||
showFrameCounter(isShowFrameCounter());
|
||||
filter(isFiltered());
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
|
@ -218,6 +219,11 @@ void DisplayGL::showOSDMessages(bool enable) {
|
|||
QMetaObject::invokeMethod(m_painter.get(), "showOSD", Q_ARG(bool, enable));
|
||||
}
|
||||
|
||||
void DisplayGL::showFrameCounter(bool enable) {
|
||||
Display::showFrameCounter(enable);
|
||||
QMetaObject::invokeMethod(m_painter.get(), "showFrameCounter", Q_ARG(bool, enable));
|
||||
}
|
||||
|
||||
void DisplayGL::filter(bool filter) {
|
||||
Display::filter(filter);
|
||||
QMetaObject::invokeMethod(m_painter.get(), "filter", Q_ARG(bool, filter));
|
||||
|
@ -429,6 +435,10 @@ void PainterGL::showOSD(bool enable) {
|
|||
m_showOSD = enable;
|
||||
}
|
||||
|
||||
void PainterGL::showFrameCounter(bool enable) {
|
||||
m_showFrameCounter = enable;
|
||||
}
|
||||
|
||||
void PainterGL::filter(bool filter) {
|
||||
m_backend->filter = filter;
|
||||
if (m_started && !m_active) {
|
||||
|
|
|
@ -66,6 +66,7 @@ public slots:
|
|||
void lockIntegerScaling(bool lock) override;
|
||||
void interframeBlending(bool enable) override;
|
||||
void showOSDMessages(bool enable) override;
|
||||
void showFrameCounter(bool enable) override;
|
||||
void filter(bool filter) override;
|
||||
void framePosted() override;
|
||||
void setShaders(struct VDir*) override;
|
||||
|
@ -122,6 +123,7 @@ public slots:
|
|||
void lockIntegerScaling(bool lock);
|
||||
void interframeBlending(bool enable);
|
||||
void showOSD(bool enable);
|
||||
void showFrameCounter(bool enable);
|
||||
void filter(bool filter);
|
||||
void resizeContext();
|
||||
|
||||
|
@ -155,6 +157,7 @@ private:
|
|||
CoreController::Interrupter m_interrupter;
|
||||
bool m_supportsShaders;
|
||||
bool m_showOSD;
|
||||
bool m_showFrameCounter;
|
||||
VideoShader m_shader{};
|
||||
VideoBackend* m_backend = nullptr;
|
||||
QSize m_size;
|
||||
|
|
|
@ -106,7 +106,7 @@ void DisplayQt::paintEvent(QPaintEvent*) {
|
|||
}
|
||||
painter.drawImage(full, m_backing, QRect(0, 0, m_width, m_height));
|
||||
painter.setOpacity(1);
|
||||
if (isShowOSD()) {
|
||||
if (isShowOSD() || isShowFrameCounter()) {
|
||||
messagePainter()->paint(&painter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ MessagePainter::MessagePainter(QObject* parent)
|
|||
{
|
||||
m_messageFont = GBAApp::app()->monospaceFont();
|
||||
m_messageFont.setPixelSize(13);
|
||||
m_frameFont = GBAApp::app()->monospaceFont();
|
||||
m_frameFont.setPixelSize(10);
|
||||
connect(&m_messageTimer, &QTimer::timeout, this, &MessagePainter::clearMessage);
|
||||
m_messageTimer.setSingleShot(true);
|
||||
m_messageTimer.setInterval(5000);
|
||||
|
@ -34,6 +36,9 @@ void MessagePainter::resize(const QSize& size, qreal scaleFactor) {
|
|||
m_world.scale(area / 220., area / 220.);
|
||||
m_local = QPoint(area / 100., drawH - m_messageFont.pixelSize() * m_world.m22() * 1.3);
|
||||
|
||||
QFontMetrics metrics(m_frameFont);
|
||||
m_framePoint = QPoint(drawW / m_world.m11() - metrics.height() * 0.1, metrics.height() * 0.75);
|
||||
|
||||
m_mutex.lock();
|
||||
redraw();
|
||||
m_mutex.unlock();
|
||||
|
@ -72,6 +77,24 @@ void MessagePainter::paint(QPainter* painter) {
|
|||
if (!m_message.text().isEmpty()) {
|
||||
painter->drawPixmap(m_local, m_pixmap);
|
||||
}
|
||||
if (m_drawFrameCounter) {
|
||||
QString frame(tr("Frame %1").arg(m_frameCounter));
|
||||
QFontMetrics metrics(m_frameFont);
|
||||
painter->setWorldTransform(m_world);
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->setFont(m_frameFont);
|
||||
painter->setPen(Qt::black);
|
||||
painter->translate(-metrics.width(frame), 0);
|
||||
const static int ITERATIONS = 11;
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
painter->save();
|
||||
painter->translate(cos(i * 2.0 * M_PI / ITERATIONS) * 0.8, sin(i * 2.0 * M_PI / ITERATIONS) * 0.8);
|
||||
painter->drawText(m_framePoint, frame);
|
||||
painter->restore();
|
||||
}
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(m_framePoint, frame);
|
||||
}
|
||||
}
|
||||
|
||||
void MessagePainter::showMessage(const QString& message) {
|
||||
|
@ -90,3 +113,16 @@ void MessagePainter::clearMessage() {
|
|||
m_mutex.unlock();
|
||||
m_messageTimer.stop();
|
||||
}
|
||||
|
||||
void MessagePainter::showFrameCounter(uint64_t frameCounter) {
|
||||
m_mutex.lock();
|
||||
m_frameCounter = frameCounter;
|
||||
m_drawFrameCounter = true;
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void MessagePainter::clearFrameCounter() {
|
||||
m_mutex.lock();
|
||||
m_drawFrameCounter = false;
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
|
|
@ -27,16 +27,26 @@ public slots:
|
|||
void showMessage(const QString& message);
|
||||
void clearMessage();
|
||||
|
||||
void showFrameCounter(uint64_t);
|
||||
void clearFrameCounter();
|
||||
|
||||
private:
|
||||
void redraw();
|
||||
|
||||
QMutex m_mutex;
|
||||
QStaticText m_message;
|
||||
qreal m_scaleFactor = 1;
|
||||
uint64_t m_frameCounter;
|
||||
bool m_drawFrameCounter = false;
|
||||
|
||||
QPoint m_local;
|
||||
QPixmap m_pixmap;
|
||||
QPixmap m_pixmapBuffer;
|
||||
|
||||
QPointF m_framePoint = QPointF(0, 0);
|
||||
QFont m_frameFont;
|
||||
|
||||
QTimer m_messageTimer{this};
|
||||
QPoint m_local;
|
||||
QTransform m_world;
|
||||
QFont m_messageFont;
|
||||
};
|
||||
|
|
|
@ -450,6 +450,7 @@ void SettingsView::updateConfig() {
|
|||
saveSetting("lockIntegerScaling", m_ui.lockIntegerScaling);
|
||||
saveSetting("interframeBlending", m_ui.interframeBlending);
|
||||
saveSetting("showOSD", m_ui.showOSD);
|
||||
saveSetting("showFrameCounter", m_ui.showFrameCounter);
|
||||
saveSetting("volume", m_ui.volume);
|
||||
saveSetting("mute", m_ui.mute);
|
||||
saveSetting("fastForwardVolume", m_ui.volumeFf);
|
||||
|
@ -668,6 +669,7 @@ void SettingsView::reloadConfig() {
|
|||
loadSetting("lockIntegerScaling", m_ui.lockIntegerScaling);
|
||||
loadSetting("interframeBlending", m_ui.interframeBlending);
|
||||
loadSetting("showOSD", m_ui.showOSD, true);
|
||||
loadSetting("showFrameCounter", m_ui.showFrameCounter);
|
||||
loadSetting("volume", m_ui.volume, 0x100);
|
||||
loadSetting("mute", m_ui.mute, false);
|
||||
loadSetting("fastForwardVolume", m_ui.volumeFf, m_ui.volume->value());
|
||||
|
|
|
@ -667,20 +667,27 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QCheckBox" name="showFrameCounter">
|
||||
<property name="text">
|
||||
<string>Show frame count in OSD</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<widget class="QCheckBox" name="useDiscordPresence">
|
||||
<property name="text">
|
||||
<string>Enable Discord Rich Presence</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0" colspan="2">
|
||||
<item row="18" column="0" colspan="2">
|
||||
<widget class="Line" name="line_13">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<item row="19" column="1">
|
||||
<widget class="QCheckBox" name="autosave">
|
||||
<property name="text">
|
||||
<string>Automatically save state</string>
|
||||
|
@ -690,7 +697,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="1">
|
||||
<item row="20" column="1">
|
||||
<widget class="QCheckBox" name="autoload">
|
||||
<property name="text">
|
||||
<string>Automatically load state</string>
|
||||
|
@ -700,14 +707,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="0" colspan="2">
|
||||
<item row="21" column="0" colspan="2">
|
||||
<widget class="Line" name="line_16">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="1">
|
||||
<item row="22" column="1">
|
||||
<widget class="QCheckBox" name="cheatAutosave">
|
||||
<property name="text">
|
||||
<string>Automatically save cheats</string>
|
||||
|
@ -717,7 +724,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="22" column="1">
|
||||
<item row="23" column="1">
|
||||
<widget class="QCheckBox" name="cheatAutoload">
|
||||
<property name="text">
|
||||
<string>Automatically load cheats</string>
|
||||
|
|
|
@ -835,7 +835,6 @@ void Window::gameStarted() {
|
|||
m_config->updateOption("lockAspectRatio");
|
||||
m_config->updateOption("interframeBlending");
|
||||
m_config->updateOption("resampleVideo");
|
||||
m_config->updateOption("showOSD");
|
||||
if (m_savedScale > 0) {
|
||||
resizeFrame(size * m_savedScale);
|
||||
}
|
||||
|
@ -1706,6 +1705,13 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
}
|
||||
}, this);
|
||||
|
||||
ConfigOption* showFrameCounter = m_config->addOption("showFrameCounter");
|
||||
showFrameCounter->connect([this](const QVariant& value) {
|
||||
if (m_display) {
|
||||
m_display->showFrameCounter(value.toBool());
|
||||
}
|
||||
}, this);
|
||||
|
||||
ConfigOption* videoScale = m_config->addOption("videoScale");
|
||||
videoScale->connect([this](const QVariant& value) {
|
||||
if (m_display) {
|
||||
|
@ -2004,6 +2010,8 @@ void Window::setController(CoreController* controller, const QString& fname) {
|
|||
|
||||
attachDisplay();
|
||||
m_controller->loadConfig(m_config);
|
||||
m_config->updateOption("showOSD");
|
||||
m_config->updateOption("showFrameCounter");
|
||||
m_controller->start();
|
||||
|
||||
if (!m_pendingState.isEmpty()) {
|
||||
|
|
Loading…
Reference in New Issue