mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-25 07:21:14 +01:00
Qt: Implement GBA Interframe Blending
This commit is contained in:
parent
6fc060bdca
commit
cfd0f4661f
@ -12,7 +12,6 @@
|
|||||||
#include <QDropEvent>
|
#include <QDropEvent>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QImage>
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
@ -64,7 +63,8 @@ GBAWidget::GBAWidget(std::weak_ptr<HW::GBA::Core> core, const HW::GBA::CoreInfo&
|
|||||||
const std::optional<NetPlay::PadDetails>& netplay_pad)
|
const std::optional<NetPlay::PadDetails>& netplay_pad)
|
||||||
: QWidget(nullptr, LoadWindowFlags(netplay_pad ? netplay_pad->local_pad : info.device_number)),
|
: QWidget(nullptr, LoadWindowFlags(netplay_pad ? netplay_pad->local_pad : info.device_number)),
|
||||||
m_core(std::move(core)), m_core_info(info), m_local_pad(info.device_number),
|
m_core(std::move(core)), m_core_info(info), m_local_pad(info.device_number),
|
||||||
m_is_local_pad(true), m_volume(0), m_muted(false), m_force_disconnect(false), m_moving(false)
|
m_is_local_pad(true), m_volume(0), m_muted(false), m_force_disconnect(false), m_moving(false),
|
||||||
|
m_interframe_blending(false)
|
||||||
{
|
{
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
if (netplay_pad)
|
if (netplay_pad)
|
||||||
@ -96,13 +96,25 @@ GBAWidget::~GBAWidget()
|
|||||||
void GBAWidget::GameChanged(const HW::GBA::CoreInfo& info)
|
void GBAWidget::GameChanged(const HW::GBA::CoreInfo& info)
|
||||||
{
|
{
|
||||||
m_core_info = info;
|
m_core_info = info;
|
||||||
|
m_previous_frame = QImage();
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAWidget::SetVideoBuffer(std::vector<u32> video_buffer)
|
void GBAWidget::SetVideoBuffer(std::vector<u32> video_buffer)
|
||||||
{
|
{
|
||||||
m_video_buffer = std::move(video_buffer);
|
m_previous_frame = std::move(m_last_frame);
|
||||||
|
if (video_buffer.size() == static_cast<size_t>(m_core_info.width * m_core_info.height))
|
||||||
|
{
|
||||||
|
m_last_frame = QImage(reinterpret_cast<const uchar*>(video_buffer.data()), m_core_info.width,
|
||||||
|
m_core_info.height, QImage::Format_ARGB32)
|
||||||
|
.convertToFormat(QImage::Format_RGB32)
|
||||||
|
.rgbSwapped();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_last_frame = QImage();
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,6 +309,10 @@ void GBAWidget::LoadSettings()
|
|||||||
QString key = QStringLiteral("gbawidget/geometry%1").arg(m_local_pad + 1);
|
QString key = QStringLiteral("gbawidget/geometry%1").arg(m_local_pad + 1);
|
||||||
if (settings.contains(key))
|
if (settings.contains(key))
|
||||||
restoreGeometry(settings.value(key).toByteArray());
|
restoreGeometry(settings.value(key).toByteArray());
|
||||||
|
|
||||||
|
key = QStringLiteral("gbawidget/interframeblending%1").arg(m_local_pad + 1);
|
||||||
|
if (settings.contains(key))
|
||||||
|
m_interframe_blending = settings.value(key).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAWidget::SaveSettings()
|
void GBAWidget::SaveSettings()
|
||||||
@ -305,6 +321,8 @@ void GBAWidget::SaveSettings()
|
|||||||
settings.setValue(QStringLiteral("gbawidget/flags%1").arg(m_local_pad + 1),
|
settings.setValue(QStringLiteral("gbawidget/flags%1").arg(m_local_pad + 1),
|
||||||
static_cast<int>(windowFlags()));
|
static_cast<int>(windowFlags()));
|
||||||
settings.setValue(QStringLiteral("gbawidget/geometry%1").arg(m_local_pad + 1), saveGeometry());
|
settings.setValue(QStringLiteral("gbawidget/geometry%1").arg(m_local_pad + 1), saveGeometry());
|
||||||
|
settings.setValue(QStringLiteral("gbawidget/interframeblending%1").arg(m_local_pad + 1),
|
||||||
|
m_interframe_blending);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GBAWidget::CanControlCore()
|
bool GBAWidget::CanControlCore()
|
||||||
@ -384,6 +402,12 @@ void GBAWidget::contextMenuEvent(QContextMenuEvent* event)
|
|||||||
topmost_action->setChecked(IsAlwaysOnTop());
|
topmost_action->setChecked(IsAlwaysOnTop());
|
||||||
connect(topmost_action, &QAction::triggered, this, [this] { SetAlwaysOnTop(!IsAlwaysOnTop()); });
|
connect(topmost_action, &QAction::triggered, this, [this] { SetAlwaysOnTop(!IsAlwaysOnTop()); });
|
||||||
|
|
||||||
|
auto* blending_action = new QAction(tr("&Interframe Blending"), options_menu);
|
||||||
|
blending_action->setCheckable(true);
|
||||||
|
blending_action->setChecked(m_interframe_blending);
|
||||||
|
connect(blending_action, &QAction::triggered, this,
|
||||||
|
[this] { m_interframe_blending = !m_interframe_blending; });
|
||||||
|
|
||||||
menu->addAction(disconnect_action);
|
menu->addAction(disconnect_action);
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
menu->addAction(load_action);
|
menu->addAction(load_action);
|
||||||
@ -404,6 +428,7 @@ void GBAWidget::contextMenuEvent(QContextMenuEvent* event)
|
|||||||
options_menu->addSeparator();
|
options_menu->addSeparator();
|
||||||
options_menu->addAction(borderless_action);
|
options_menu->addAction(borderless_action);
|
||||||
options_menu->addAction(topmost_action);
|
options_menu->addAction(topmost_action);
|
||||||
|
options_menu->addAction(blending_action);
|
||||||
|
|
||||||
size_menu->addAction(x1_action);
|
size_menu->addAction(x1_action);
|
||||||
size_menu->addAction(x2_action);
|
size_menu->addAction(x2_action);
|
||||||
@ -447,33 +472,32 @@ void GBAWidget::paintEvent(QPaintEvent* event)
|
|||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
painter.fillRect(QRect(QPoint(), size()), Qt::black);
|
painter.fillRect(QRect(QPoint(), size()), Qt::black);
|
||||||
|
|
||||||
if (m_video_buffer.size() == static_cast<size_t>(m_core_info.width * m_core_info.height))
|
const QRect src_rect(0, 0, m_core_info.width, m_core_info.height);
|
||||||
|
QRect target_rect{};
|
||||||
|
if (size() == QSize(m_core_info.width, m_core_info.height))
|
||||||
{
|
{
|
||||||
QImage image(reinterpret_cast<const uchar*>(m_video_buffer.data()), m_core_info.width,
|
target_rect = QRect(0, 0, m_core_info.width, m_core_info.height);
|
||||||
m_core_info.height, QImage::Format_ARGB32);
|
}
|
||||||
image = image.convertToFormat(QImage::Format_RGB32);
|
else if (static_cast<float>(m_core_info.width) / m_core_info.height >
|
||||||
image = image.rgbSwapped();
|
static_cast<float>(width()) / height())
|
||||||
|
{
|
||||||
|
int new_height = width() * m_core_info.height / m_core_info.width;
|
||||||
|
target_rect = QRect(0, (height() - new_height) / 2, width(), new_height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int new_width = height() * m_core_info.width / m_core_info.height;
|
||||||
|
target_rect = QRect((width() - new_width) / 2, 0, new_width, height());
|
||||||
|
}
|
||||||
|
|
||||||
QSize widget_size = size();
|
if (m_interframe_blending && m_previous_frame.size() == src_rect.size())
|
||||||
if (widget_size == QSize(m_core_info.width, m_core_info.height))
|
{
|
||||||
{
|
painter.drawImage(target_rect, m_previous_frame, src_rect);
|
||||||
painter.drawImage(QPoint(), image, QRect(0, 0, m_core_info.width, m_core_info.height));
|
painter.setOpacity(0.5);
|
||||||
}
|
}
|
||||||
else if (static_cast<float>(m_core_info.width) / m_core_info.height >
|
if (m_last_frame.size() == src_rect.size())
|
||||||
static_cast<float>(widget_size.width()) / widget_size.height())
|
{
|
||||||
{
|
painter.drawImage(target_rect, m_last_frame, src_rect);
|
||||||
int new_height = widget_size.width() * m_core_info.height / m_core_info.width;
|
|
||||||
painter.drawImage(
|
|
||||||
QRect(0, (widget_size.height() - new_height) / 2, widget_size.width(), new_height), image,
|
|
||||||
QRect(0, 0, m_core_info.width, m_core_info.height));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int new_width = widget_size.height() * m_core_info.width / m_core_info.height;
|
|
||||||
painter.drawImage(
|
|
||||||
QRect((widget_size.width() - new_width) / 2, 0, new_width, widget_size.height()), image,
|
|
||||||
QRect(0, 0, m_core_info.width, m_core_info.height));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@ -82,7 +83,8 @@ private:
|
|||||||
|
|
||||||
std::weak_ptr<HW::GBA::Core> m_core;
|
std::weak_ptr<HW::GBA::Core> m_core;
|
||||||
HW::GBA::CoreInfo m_core_info;
|
HW::GBA::CoreInfo m_core_info;
|
||||||
std::vector<u32> m_video_buffer;
|
QImage m_last_frame;
|
||||||
|
QImage m_previous_frame;
|
||||||
int m_local_pad;
|
int m_local_pad;
|
||||||
bool m_is_local_pad;
|
bool m_is_local_pad;
|
||||||
std::string m_netplayer_name;
|
std::string m_netplayer_name;
|
||||||
@ -91,6 +93,7 @@ private:
|
|||||||
bool m_force_disconnect;
|
bool m_force_disconnect;
|
||||||
bool m_moving;
|
bool m_moving;
|
||||||
QPoint m_move_pos;
|
QPoint m_move_pos;
|
||||||
|
bool m_interframe_blending;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GBAWidgetController : public QObject
|
class GBAWidgetController : public QObject
|
||||||
|
Loading…
x
Reference in New Issue
Block a user