implemented fullscreen stretch modes

This commit is contained in:
Joakim L. Gilje
2021-12-07 13:47:42 +01:00
parent 2d9020070f
commit 61a2cf986b
10 changed files with 201 additions and 43 deletions

View File

@@ -21,6 +21,8 @@ add_library(ui STATIC
qt_rendererstack.cpp qt_rendererstack.cpp
qt_rendererstack.hpp qt_rendererstack.hpp
qt_rendererstack.ui qt_rendererstack.ui
qt_renderercomon.cpp
qt_renderercomon.hpp
qt_softwarerenderer.cpp qt_softwarerenderer.cpp
qt_softwarerenderer.hpp qt_softwarerenderer.hpp
qt_hardwarerenderer.cpp qt_hardwarerenderer.cpp

View File

@@ -14,14 +14,8 @@ void HardwareRenderer::initializeGL()
initializeOpenGLFunctions(); initializeOpenGLFunctions();
} }
void HardwareRenderer::paintGL() void HardwareRenderer::paintGL() {
{ onPaint(this);
QPainter painter(this);
painter.setRenderHint(QPainter::SmoothPixmapTransform, video_filter_method > 0 ? true : false);
painter.drawImage(QRect(0, 0, width(), height()), image, QRect(sx, sy, sw, sh));
// "release" image, reducing it's refcount, so renderstack::blit()
// won't have to reallocate
image = QImage();
} }
void HardwareRenderer::setRenderType(RenderType type) { void HardwareRenderer::setRenderType(RenderType type) {
@@ -41,9 +35,11 @@ void HardwareRenderer::setRenderType(RenderType type) {
void HardwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) { void HardwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) {
image = img; image = img;
sx = x; source.setRect(x, y, w, h);
sy = y;
sw = w;
sh = h;
update(); update();
} }
void HardwareRenderer::resizeEvent(QResizeEvent *event) {
onResize(width(), height());
QOpenGLWidget::resizeEvent(event);
}

View File

@@ -10,11 +10,13 @@
#include <mutex> #include <mutex>
#include <QApplication> #include <QApplication>
#include "qt_renderercomon.hpp"
#ifdef WAYLAND #ifdef WAYLAND
#include "wl_mouse.hpp" #include "wl_mouse.hpp"
#endif #endif
class HardwareRenderer : public QOpenGLWidget, protected QOpenGLFunctions class HardwareRenderer : public QOpenGLWidget, protected QOpenGLFunctions, public RendererCommon
{ {
Q_OBJECT Q_OBJECT
@@ -49,7 +51,6 @@ public:
public slots: public slots:
void onBlit(const QImage& img, int, int, int, int); void onBlit(const QImage& img, int, int, int, int);
private: protected:
QImage image; void resizeEvent(QResizeEvent *event) override;
int sx, sy, sw, sh;
}; };

View File

@@ -139,6 +139,20 @@ MainWindow::MainWindow(QWidget *parent) :
ui->actionLinear->setChecked(true); ui->actionLinear->setChecked(true);
break; break;
} }
switch (video_fullscreen_scale) {
case FULLSCR_SCALE_FULL:
ui->actionFullScreen_stretch->setChecked(true);
break;
case FULLSCR_SCALE_43:
ui->actionFullScreen_43->setChecked(true);
break;
case FULLSCR_SCALE_KEEPRATIO:
ui->actionFullScreen_keepRatio->setChecked(true);
break;
case FULLSCR_SCALE_INT:
ui->actionFullScreen_int->setChecked(true);
break;
}
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
ui->gles->setFocusPolicy(Qt::NoFocus); ui->gles->setFocusPolicy(Qt::NoFocus);
@@ -735,6 +749,10 @@ void MainWindow::on_actionFullscreen_triggered() {
showFullScreen(); showFullScreen();
video_fullscreen = 1; video_fullscreen = 1;
} }
auto widget = ui->stackedWidget->currentWidget();
auto rc = dynamic_cast<RendererCommon*>(widget);
rc->onResize(widget->width(), widget->height());
} }
void MainWindow::setTitle_(const wchar_t *title) void MainWindow::setTitle_(const wchar_t *title)
@@ -932,3 +950,40 @@ void MainWindow::on_actionLinear_triggered() {
video_filter_method = 1; video_filter_method = 1;
ui->actionNearest->setChecked(false); ui->actionNearest->setChecked(false);
} }
static void update_fullscreen_scale_checkboxes(Ui::MainWindow* ui, QAction* selected) {
ui->actionFullScreen_stretch->setChecked(ui->actionFullScreen_stretch == selected);
ui->actionFullScreen_43->setChecked(ui->actionFullScreen_43 == selected);
ui->actionFullScreen_keepRatio->setChecked(ui->actionFullScreen_keepRatio == selected);
ui->actionFullScreen_int->setChecked(ui->actionFullScreen_int == selected);
if (video_fullscreen > 0) {
auto widget = ui->stackedWidget->currentWidget();
auto rc = dynamic_cast<RendererCommon*>(widget);
rc->onResize(widget->width(), widget->height());
}
device_force_redraw();
config_save();
}
void MainWindow::on_actionFullScreen_stretch_triggered() {
video_fullscreen_scale = FULLSCR_SCALE_FULL;
update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_stretch);
}
void MainWindow::on_actionFullScreen_43_triggered() {
video_fullscreen_scale = FULLSCR_SCALE_43;
update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_43);
}
void MainWindow::on_actionFullScreen_keepRatio_triggered() {
video_fullscreen_scale = FULLSCR_SCALE_KEEPRATIO;
update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_keepRatio);
}
void MainWindow::on_actionFullScreen_int_triggered() {
video_fullscreen_scale = FULLSCR_SCALE_INT;
update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_int);
}

View File

@@ -64,6 +64,10 @@ private slots:
void on_action2x_triggered(); void on_action2x_triggered();
void on_actionLinear_triggered(); void on_actionLinear_triggered();
void on_actionNearest_triggered(); void on_actionNearest_triggered();
void on_actionFullScreen_int_triggered();
void on_actionFullScreen_keepRatio_triggered();
void on_actionFullScreen_43_triggered();
void on_actionFullScreen_stretch_triggered();
void refreshMediaMenu(); void refreshMediaMenu();
void showMessage_(const QString& header, const QString& message); void showMessage_(const QString& header, const QString& message);

View File

@@ -111,10 +111,10 @@
<property name="title"> <property name="title">
<string>Fullscreen stretch mode</string> <string>Fullscreen stretch mode</string>
</property> </property>
<addaction name="actionFull_screen_stretch"/> <addaction name="actionFullScreen_stretch"/>
<addaction name="action4_3"/> <addaction name="actionFullScreen_43"/>
<addaction name="actionSquare_pixels_Keep_ratio"/> <addaction name="actionFullScreen_keepRatio"/>
<addaction name="actionInteger_scale"/> <addaction name="actionFullScreen_int"/>
</widget> </widget>
<widget class="QMenu" name="menuEGA_S_VGA_settings"> <widget class="QMenu" name="menuEGA_S_VGA_settings">
<property name="title"> <property name="title">
@@ -362,7 +362,7 @@
<string>Linear</string> <string>Linear</string>
</property> </property>
</action> </action>
<action name="actionFull_screen_stretch"> <action name="actionFullScreen_stretch">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -370,7 +370,7 @@
<string>Full screen stretch</string> <string>Full screen stretch</string>
</property> </property>
</action> </action>
<action name="action4_3"> <action name="actionFullScreen_43">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -378,7 +378,7 @@
<string>4:3</string> <string>4:3</string>
</property> </property>
</action> </action>
<action name="actionSquare_pixels_Keep_ratio"> <action name="actionFullScreen_keepRatio">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -386,7 +386,7 @@
<string>Square pixels (Keep ratio)</string> <string>Square pixels (Keep ratio)</string>
</property> </property>
</action> </action>
<action name="actionInteger_scale"> <action name="actionFullScreen_int">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>

View File

@@ -0,0 +1,89 @@
#include "qt_renderercomon.hpp"
#include <QPainter>
#include <QWidget>
#include <cmath>
extern "C" {
#include <86box/86box.h>
#include <86box/video.h>
}
RendererCommon::RendererCommon() = default;
void RendererCommon::onPaint(QPaintDevice* device) {
QPainter painter(device);
painter.setRenderHint(QPainter::SmoothPixmapTransform, video_filter_method > 0 ? true : false);
painter.drawImage(destination, image, source);
// "release" image, reducing it's refcount, so renderstack::blit()
// won't have to reallocate
image = QImage();
}
static void integer_scale(double *d, double *g) {
double ratio;
if (*d > *g) {
ratio = std::floor(*d / *g);
*d = *g * ratio;
} else {
ratio = std::ceil(*d / *g);
*d = *g / ratio;
}
}
void RendererCommon::onResize(int width, int height) {
if (video_fullscreen == 0) {
destination.setRect(0, 0, width, height);
return;
}
double dx, dy, dw, dh, gsr;
double hw = width;
double hh = height;
double gw = source.width();
double gh = source.height();
double hsr = hw / hh;
switch (video_fullscreen_scale) {
case FULLSCR_SCALE_INT:
gsr = gw / gh;
if (gsr <= hsr) {
dw = hh * gsr;
dh = hh;
} else {
dw = hw;
dh = hw / gsr;
}
integer_scale(&dw, &gw);
integer_scale(&dh, &gh);
dx = (hw - dw) / 2.0;
dy = (hh - dh) / 2.0;
destination.setRect(dx, dy, dw, dh);
break;
case FULLSCR_SCALE_43:
case FULLSCR_SCALE_KEEPRATIO:
if (video_fullscreen_scale == FULLSCR_SCALE_43) {
gsr = 4.0 / 3.0;
} else {
gsr = gw / gh;
}
if (gsr <= hsr) {
dw = hh * gsr;
dh = hh;
} else {
dw = hw;
dh = hw / gsr;
}
dx = (hw - dw) / 2.0;
dy = (hh - dh) / 2.0;
destination.setRect(dx, dy, dw, dh);
break;
case FULLSCR_SCALE_FULL:
default:
destination.setRect(0, 0, hw, hh);
break;
}
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <QRect>
#include <QImage>
class QWidget;
class RendererCommon
{
public:
RendererCommon();
void onResize(int width, int height);
protected:
void onPaint(QPaintDevice* device);
QImage image;
QRect source, destination;
};

View File

@@ -1,26 +1,19 @@
#include "qt_softwarerenderer.hpp" #include "qt_softwarerenderer.hpp"
extern "C" {
#include <86box/86box.h>
}
#include <QPainter>
SoftwareRenderer::SoftwareRenderer(QWidget *parent) : QWidget(parent) {} SoftwareRenderer::SoftwareRenderer(QWidget *parent) : QWidget(parent) {}
void SoftwareRenderer::paintEvent(QPaintEvent *event) { void SoftwareRenderer::paintEvent(QPaintEvent *event) {
(void) event; (void) event;
onPaint(this);
QPainter painter(this);
painter.setRenderHint(QPainter::SmoothPixmapTransform, video_filter_method > 0 ? true : false);
painter.drawImage(QRect(0, 0, width(), height()), image, QRect(sx, sy, sw, sh));
image = QImage();
} }
void SoftwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) { void SoftwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) {
image = img; image = img;
sx = x; source.setRect(x, y, w, h);
sy = y;
sw = w;
sh = h;
update(); update();
} }
void SoftwareRenderer::resizeEvent(QResizeEvent *event) {
onResize(width(), height());
QWidget::resizeEvent(event);
}

View File

@@ -2,21 +2,20 @@
#define SOFTWARERENDERER_HPP #define SOFTWARERENDERER_HPP
#include <QWidget> #include <QWidget>
#include "qt_renderercomon.hpp"
class SoftwareRenderer : public QWidget class SoftwareRenderer : public QWidget, public RendererCommon
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit SoftwareRenderer(QWidget *parent = nullptr); explicit SoftwareRenderer(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
public slots: public slots:
void onBlit(const QImage& img, int, int, int, int); void onBlit(const QImage& img, int, int, int, int);
private: protected:
QImage image; void resizeEvent(QResizeEvent *event) override;
int sx, sy, sw, sh;
}; };
#endif // SOFTWARERENDERER_HPP #endif // SOFTWARERENDERER_HPP