mirror of https://github.com/mgba-emu/mgba.git
Qt: Expose DisplayQt as a VideoBackend
This commit is contained in:
parent
dda5634189
commit
428a29dae3
|
@ -10,6 +10,7 @@
|
|||
#include "DisplayGL.h"
|
||||
#include "DisplayQt.h"
|
||||
#include "LogController.h"
|
||||
#include "VideoProxy.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <mgba-util/vfs.h>
|
||||
|
@ -124,6 +125,13 @@ void QGBA::Display::configure(ConfigController* config) {
|
|||
#endif
|
||||
}
|
||||
|
||||
VideoBackend* QGBA::Display::videoBackend() {
|
||||
if (m_videoProxy) {
|
||||
return m_videoProxy->backend();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void QGBA::Display::resizeEvent(QResizeEvent*) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
m_messagePainter.resize(size(), devicePixelRatioF());
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
|
||||
virtual void setVideoProxy(std::shared_ptr<VideoProxy> proxy) { m_videoProxy = proxy; }
|
||||
std::shared_ptr<VideoProxy> videoProxy() { return m_videoProxy; }
|
||||
virtual VideoBackend* videoBackend();
|
||||
|
||||
signals:
|
||||
void drawingStarted();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -19,13 +19,28 @@ using namespace QGBA;
|
|||
DisplayQt::DisplayQt(QWidget* parent)
|
||||
: Display(parent)
|
||||
{
|
||||
m_backend.init = &DisplayQt::init;
|
||||
m_backend.deinit = &DisplayQt::deinit;
|
||||
m_backend.setLayerDimensions = &DisplayQt::setLayerDimensions;
|
||||
m_backend.layerDimensions = &DisplayQt::layerDimensions;
|
||||
m_backend.swap = &DisplayQt::swap;
|
||||
m_backend.clear = &DisplayQt::clear;
|
||||
m_backend.contextResized = &DisplayQt::contextResized;
|
||||
m_backend.setImageSize = &DisplayQt::setImageSize;
|
||||
m_backend.imageSize = &DisplayQt::imageSize;
|
||||
m_backend.setImage = &DisplayQt::setImage;
|
||||
m_backend.drawFrame = &DisplayQt::drawFrame;
|
||||
m_backend.filter = isFiltered();
|
||||
m_backend.lockAspectRatio = isAspectRatioLocked();
|
||||
m_backend.lockIntegerScaling = isIntegerScalingLocked();
|
||||
m_backend.interframeBlending = hasInterframeBlending();
|
||||
m_backend.user = this;
|
||||
}
|
||||
|
||||
void DisplayQt::startDrawing(std::shared_ptr<CoreController> controller) {
|
||||
QSize size = controller->screenDimensions();
|
||||
m_width = size.width();
|
||||
m_height = size.height();
|
||||
m_backing = QImage();
|
||||
m_oldBacking = QImage();
|
||||
m_isDrawing = true;
|
||||
m_context = controller;
|
||||
|
@ -39,44 +54,51 @@ void DisplayQt::stopDrawing() {
|
|||
|
||||
void DisplayQt::lockAspectRatio(bool lock) {
|
||||
Display::lockAspectRatio(lock);
|
||||
m_backend.lockAspectRatio = lock;
|
||||
update();
|
||||
}
|
||||
|
||||
void DisplayQt::lockIntegerScaling(bool lock) {
|
||||
Display::lockIntegerScaling(lock);
|
||||
m_backend.lockIntegerScaling = lock;
|
||||
update();
|
||||
}
|
||||
|
||||
void DisplayQt::interframeBlending(bool lock) {
|
||||
Display::interframeBlending(lock);
|
||||
m_backend.interframeBlending = lock;
|
||||
update();
|
||||
}
|
||||
|
||||
void DisplayQt::filter(bool filter) {
|
||||
Display::filter(filter);
|
||||
m_backend.filter = filter;
|
||||
update();
|
||||
}
|
||||
|
||||
void DisplayQt::framePosted() {
|
||||
update();
|
||||
const color_t* buffer = m_context->drawContext();
|
||||
if (const_cast<const QImage&>(m_backing).bits() == reinterpret_cast<const uchar*>(buffer)) {
|
||||
if (const_cast<const QImage&>(m_layers[VIDEO_LAYER_IMAGE]).bits() == reinterpret_cast<const uchar*>(buffer)) {
|
||||
return;
|
||||
}
|
||||
m_oldBacking = m_backing;
|
||||
m_oldBacking = m_layers[VIDEO_LAYER_IMAGE];
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB16);
|
||||
m_layers[VIDEO_LAYER_IMAGE] = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB16);
|
||||
#else
|
||||
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB555);
|
||||
m_layers[VIDEO_LAYER_IMAGE] = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB555);
|
||||
#endif
|
||||
#else
|
||||
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_ARGB32);
|
||||
m_backing = m_backing.convertToFormat(QImage::Format_RGB32);
|
||||
m_layers[VIDEO_LAYER_IMAGE] = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_ARGB32);
|
||||
m_layers[VIDEO_LAYER_IMAGE] = m_layers[VIDEO_LAYER_IMAGE].convertToFormat(QImage::Format_RGB32);
|
||||
#endif
|
||||
#ifndef COLOR_5_6_5
|
||||
m_backing = m_backing.rgbSwapped();
|
||||
m_layers[VIDEO_LAYER_IMAGE] = m_layers[VIDEO_LAYER_IMAGE].rgbSwapped();
|
||||
#endif
|
||||
m_layerDims[VIDEO_LAYER_IMAGE].setWidth(m_width);
|
||||
m_layerDims[VIDEO_LAYER_IMAGE].setHeight(m_height);
|
||||
redoBounds();
|
||||
}
|
||||
|
||||
void DisplayQt::resizeContext() {
|
||||
|
@ -88,12 +110,13 @@ void DisplayQt::resizeContext() {
|
|||
m_width = size.width();
|
||||
m_height = size.height();
|
||||
m_oldBacking = QImage();
|
||||
m_backing = QImage();
|
||||
m_layers[VIDEO_LAYER_IMAGE] = QImage();
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayQt::setBackgroundImage(const QImage& image) {
|
||||
m_background = image;
|
||||
m_layers[VIDEO_LAYER_BACKGROUND] = image;
|
||||
redoBounds();
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -104,91 +127,125 @@ void DisplayQt::paintEvent(QPaintEvent*) {
|
|||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
}
|
||||
|
||||
QRect bgRect(0, 0, m_background.width(), m_background.height());
|
||||
QRect imRect(0, 0, m_width, m_height);
|
||||
QSize outerFrame = contentSize();
|
||||
struct mRectangle frame;
|
||||
VideoBackendGetFrame(&m_backend, &frame);
|
||||
QPoint origin(-frame.x, -frame.y);
|
||||
QRect full(clampSize(contentSize(), size(), isAspectRatioLocked(), isIntegerScalingLocked()));
|
||||
painter.save();
|
||||
painter.translate(full.topLeft());
|
||||
painter.scale(full.width() / static_cast<qreal>(frame.width), full.height() / static_cast<qreal>(frame.height));
|
||||
|
||||
if (bgRect.width() > imRect.width()) {
|
||||
imRect.moveLeft(bgRect.width() - imRect.width());
|
||||
} else {
|
||||
bgRect.moveLeft(imRect.width() - bgRect.width());
|
||||
}
|
||||
|
||||
if (bgRect.height() > imRect.height()) {
|
||||
imRect.moveTop(bgRect.height() - imRect.height());
|
||||
} else {
|
||||
bgRect.moveTop(imRect.height() - bgRect.height());
|
||||
}
|
||||
|
||||
QRect full(clampSize(outerFrame, size(), isAspectRatioLocked(), isIntegerScalingLocked()));
|
||||
|
||||
if (m_background.isNull()) {
|
||||
imRect = full;
|
||||
} else {
|
||||
if (imRect.x()) {
|
||||
imRect.moveLeft(imRect.x() * full.width() / bgRect.width() / 2);
|
||||
imRect.setWidth(imRect.width() * full.width() / bgRect.width());
|
||||
bgRect.setWidth(full.width());
|
||||
} else {
|
||||
bgRect.moveLeft(bgRect.x() * full.width() / imRect.width() / 2);
|
||||
bgRect.setWidth(bgRect.width() * full.width() / imRect.width());
|
||||
imRect.setWidth(full.width());
|
||||
}
|
||||
if (imRect.y()) {
|
||||
imRect.moveTop(imRect.y() * full.height() / bgRect.height() / 2);
|
||||
imRect.setHeight(imRect.height() * full.height() / bgRect.height());
|
||||
bgRect.setHeight(full.height());
|
||||
} else {
|
||||
bgRect.moveTop(bgRect.y() * full.height() / imRect.height() / 2);
|
||||
bgRect.setHeight(bgRect.height() * full.height() / imRect.height());
|
||||
imRect.setHeight(full.height());
|
||||
}
|
||||
|
||||
if (bgRect.right() > imRect.right()) {
|
||||
if (bgRect.right() < full.right()) {
|
||||
imRect.translate((full.right() - bgRect.right()), 0);
|
||||
bgRect.translate((full.right() - bgRect.right()), 0);
|
||||
}
|
||||
} else {
|
||||
if (imRect.right() < full.right()) {
|
||||
bgRect.translate((full.right() - imRect.right()), 0);
|
||||
imRect.translate((full.right() - imRect.right()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (bgRect.bottom() > imRect.bottom()) {
|
||||
if (bgRect.bottom() < full.bottom()) {
|
||||
imRect.translate(0, (full.bottom() - bgRect.bottom()));
|
||||
bgRect.translate(0, (full.bottom() - bgRect.bottom()));
|
||||
}
|
||||
} else {
|
||||
if (imRect.bottom() < full.bottom()) {
|
||||
bgRect.translate(0, (full.bottom() - imRect.bottom()));
|
||||
imRect.translate(0, (full.bottom() - imRect.bottom()));
|
||||
}
|
||||
}
|
||||
painter.drawImage(bgRect, m_background);
|
||||
if (!m_layers[VIDEO_LAYER_BACKGROUND].isNull()) {
|
||||
painter.drawImage(m_layerDims[VIDEO_LAYER_BACKGROUND].translated(origin), m_layers[VIDEO_LAYER_BACKGROUND]);
|
||||
}
|
||||
|
||||
if (hasInterframeBlending()) {
|
||||
painter.drawImage(imRect, m_oldBacking, QRect(0, 0, m_width, m_height));
|
||||
painter.drawImage(m_layerDims[VIDEO_LAYER_IMAGE].translated(origin), m_oldBacking, QRect(0, 0, m_width, m_height));
|
||||
painter.setOpacity(0.5);
|
||||
}
|
||||
painter.drawImage(imRect, m_backing, QRect(0, 0, m_width, m_height));
|
||||
painter.drawImage(m_layerDims[VIDEO_LAYER_IMAGE].translated(origin), m_layers[VIDEO_LAYER_IMAGE], QRect(0, 0, m_width, m_height));
|
||||
|
||||
for (int i = VIDEO_LAYER_IMAGE + 1; i < VIDEO_LAYER_MAX; ++i) {
|
||||
if (m_layers[i].isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
painter.drawImage(m_layerDims[i].translated(origin), m_layers[i]);
|
||||
}
|
||||
|
||||
painter.restore();
|
||||
painter.setOpacity(1);
|
||||
if (isShowOSD() || isShowFrameCounter()) {
|
||||
messagePainter()->paint(&painter);
|
||||
}
|
||||
}
|
||||
|
||||
QSize DisplayQt::contentSize() const {
|
||||
QSize outerFrame(m_width, m_height);
|
||||
void DisplayQt::redoBounds() {
|
||||
const static std::initializer_list<VideoLayer> centeredLayers{VIDEO_LAYER_BACKGROUND};
|
||||
mRectangle frame = {0};
|
||||
frame.width = m_width;
|
||||
frame.height = m_height;
|
||||
|
||||
if (m_background.width() > outerFrame.width()) {
|
||||
outerFrame.setWidth(m_background.width());
|
||||
for (VideoLayer l : centeredLayers) {
|
||||
mRectangle dims{};
|
||||
dims.width = m_layers[l].width();
|
||||
dims.height = m_layers[l].height();
|
||||
mRectangleCenter(&frame, &dims);
|
||||
m_layerDims[l].setX(dims.x);
|
||||
m_layerDims[l].setY(dims.y);
|
||||
m_layerDims[l].setWidth(dims.width);
|
||||
m_layerDims[l].setHeight(dims.height);
|
||||
}
|
||||
if (m_background.height() > outerFrame.height()) {
|
||||
outerFrame.setHeight(m_background.height());
|
||||
}
|
||||
return outerFrame;
|
||||
}
|
||||
|
||||
QSize DisplayQt::contentSize() const {
|
||||
unsigned w, h;
|
||||
VideoBackendGetFrameSize(&m_backend, &w, &h);
|
||||
return {w, h};
|
||||
}
|
||||
|
||||
void DisplayQt::init(struct VideoBackend*, WHandle) {
|
||||
}
|
||||
|
||||
void DisplayQt::deinit(struct VideoBackend*) {
|
||||
}
|
||||
|
||||
void DisplayQt::setLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct mRectangle* dims) {
|
||||
DisplayQt* self = static_cast<DisplayQt*>(v->user);
|
||||
if (layer > self->m_layerDims.size()) {
|
||||
return;
|
||||
}
|
||||
self->m_layerDims[layer] = QRect(dims->x, dims->y, dims->width, dims->height);
|
||||
}
|
||||
|
||||
void DisplayQt::layerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct mRectangle* dims) {
|
||||
DisplayQt* self = static_cast<DisplayQt*>(v->user);
|
||||
if (layer > self->m_layerDims.size()) {
|
||||
return;
|
||||
}
|
||||
QRect rect = self->m_layerDims[layer];
|
||||
dims->x = rect.x();
|
||||
dims->y = rect.y();
|
||||
dims->width = rect.width();
|
||||
dims->height = rect.height();
|
||||
}
|
||||
|
||||
void DisplayQt::swap(struct VideoBackend*) {
|
||||
}
|
||||
|
||||
void DisplayQt::clear(struct VideoBackend*) {
|
||||
}
|
||||
|
||||
void DisplayQt::contextResized(struct VideoBackend*, unsigned, unsigned) {
|
||||
}
|
||||
|
||||
void DisplayQt::setImageSize(struct VideoBackend* v, enum VideoLayer layer, int w, int h) {
|
||||
DisplayQt* self = static_cast<DisplayQt*>(v->user);
|
||||
if (layer > self->m_layers.size()) {
|
||||
return;
|
||||
}
|
||||
self->m_layers[layer] = QImage(w, h, QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
void DisplayQt::imageSize(struct VideoBackend* v, enum VideoLayer layer, int* w, int* h) {
|
||||
DisplayQt* self = static_cast<DisplayQt*>(v->user);
|
||||
if (layer > self->m_layers.size()) {
|
||||
return;
|
||||
}
|
||||
*w = self->m_layers[layer].width();
|
||||
*h = self->m_layers[layer].height();
|
||||
}
|
||||
|
||||
void DisplayQt::setImage(struct VideoBackend* v, enum VideoLayer layer, const void* frame) {
|
||||
DisplayQt* self = static_cast<DisplayQt*>(v->user);
|
||||
if (layer > self->m_layers.size()) {
|
||||
return;
|
||||
}
|
||||
QImage image = self->m_layers[layer];
|
||||
image = QImage(static_cast<const uchar*>(frame), image.width(), image.height(), QImage::Format_ARGB32).rgbSwapped();
|
||||
self->m_layers[layer] = image;
|
||||
}
|
||||
|
||||
void DisplayQt::drawFrame(struct VideoBackend* v) {
|
||||
QMetaObject::invokeMethod(static_cast<DisplayQt*>(v->user), "update");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -10,6 +10,9 @@
|
|||
#include <QImage>
|
||||
#include <QTimer>
|
||||
|
||||
#include <mgba/feature/video-backend.h>
|
||||
#include <array>
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class DisplayQt : public Display {
|
||||
|
@ -23,6 +26,7 @@ public:
|
|||
bool supportsShaders() const override { return false; }
|
||||
VideoShader* shaders() override { return nullptr; }
|
||||
QSize contentSize() const override;
|
||||
VideoBackend* videoBackend() override { return &m_backend; }
|
||||
|
||||
public slots:
|
||||
void stopDrawing() override;
|
||||
|
@ -44,12 +48,27 @@ protected:
|
|||
virtual void paintEvent(QPaintEvent*) override;
|
||||
|
||||
private:
|
||||
void redoBounds();
|
||||
|
||||
static void init(struct VideoBackend*, WHandle);
|
||||
static void deinit(struct VideoBackend*);
|
||||
static void setLayerDimensions(struct VideoBackend*, enum VideoLayer, const struct mRectangle*);
|
||||
static void layerDimensions(const struct VideoBackend*, enum VideoLayer, struct mRectangle*);
|
||||
static void swap(struct VideoBackend*);
|
||||
static void clear(struct VideoBackend*);
|
||||
static void contextResized(struct VideoBackend*, unsigned w, unsigned h);
|
||||
static void setImageSize(struct VideoBackend*, enum VideoLayer, int w, int h);
|
||||
static void imageSize(struct VideoBackend*, enum VideoLayer, int* w, int* h);
|
||||
static void setImage(struct VideoBackend*, enum VideoLayer, const void* frame);
|
||||
static void drawFrame(struct VideoBackend*);
|
||||
|
||||
VideoBackend m_backend{};
|
||||
std::array<QRect, VIDEO_LAYER_MAX> m_layerDims;
|
||||
std::array<QImage, VIDEO_LAYER_MAX> m_layers;
|
||||
bool m_isDrawing = false;
|
||||
int m_width = -1;
|
||||
int m_height = -1;
|
||||
QImage m_backing{nullptr};
|
||||
QImage m_oldBacking{nullptr};
|
||||
QImage m_background;
|
||||
std::shared_ptr<CoreController> m_context = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -634,10 +634,7 @@ void Window::scriptingOpen() {
|
|||
m_display->installEventFilter(m_scripting.get());
|
||||
}
|
||||
|
||||
std::shared_ptr<VideoProxy> proxy = m_display->videoProxy();
|
||||
if (proxy) {
|
||||
m_scripting->setVideoBackend(proxy->backend());
|
||||
}
|
||||
m_scripting->setVideoBackend(m_display->videoBackend());
|
||||
}
|
||||
ScriptingView* view = new ScriptingView(m_scripting.get(), m_config);
|
||||
openView(view);
|
||||
|
@ -1082,7 +1079,7 @@ void Window::reloadDisplayDriver() {
|
|||
m_display->setVideoProxy(proxy);
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
if (m_scripting) {
|
||||
m_scripting->setVideoBackend(proxy->backend());
|
||||
m_scripting->setVideoBackend(m_display->videoBackend());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -2135,10 +2132,7 @@ void Window::setController(CoreController* controller, const QString& fname) {
|
|||
if (m_scripting) {
|
||||
m_scripting->setController(m_controller);
|
||||
|
||||
std::shared_ptr<VideoProxy> proxy = m_display->videoProxy();
|
||||
if (proxy) {
|
||||
m_scripting->setVideoBackend(proxy->backend());
|
||||
}
|
||||
m_scripting->setVideoBackend(m_display->videoBackend());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue