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.hpp
qt_rendererstack.ui
qt_renderercomon.cpp
qt_renderercomon.hpp
qt_softwarerenderer.cpp
qt_softwarerenderer.hpp
qt_hardwarerenderer.cpp

View File

@@ -14,14 +14,8 @@ void HardwareRenderer::initializeGL()
initializeOpenGLFunctions();
}
void HardwareRenderer::paintGL()
{
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::paintGL() {
onPaint(this);
}
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) {
image = img;
sx = x;
sy = y;
sw = w;
sh = h;
source.setRect(x, y, w, h);
update();
}
void HardwareRenderer::resizeEvent(QResizeEvent *event) {
onResize(width(), height());
QOpenGLWidget::resizeEvent(event);
}

View File

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

View File

@@ -139,6 +139,20 @@ MainWindow::MainWindow(QWidget *parent) :
ui->actionLinear->setChecked(true);
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);
ui->gles->setFocusPolicy(Qt::NoFocus);
@@ -735,6 +749,10 @@ void MainWindow::on_actionFullscreen_triggered() {
showFullScreen();
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)
@@ -932,3 +950,40 @@ void MainWindow::on_actionLinear_triggered() {
video_filter_method = 1;
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_actionLinear_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 showMessage_(const QString& header, const QString& message);

View File

@@ -111,10 +111,10 @@
<property name="title">
<string>Fullscreen stretch mode</string>
</property>
<addaction name="actionFull_screen_stretch"/>
<addaction name="action4_3"/>
<addaction name="actionSquare_pixels_Keep_ratio"/>
<addaction name="actionInteger_scale"/>
<addaction name="actionFullScreen_stretch"/>
<addaction name="actionFullScreen_43"/>
<addaction name="actionFullScreen_keepRatio"/>
<addaction name="actionFullScreen_int"/>
</widget>
<widget class="QMenu" name="menuEGA_S_VGA_settings">
<property name="title">
@@ -362,7 +362,7 @@
<string>Linear</string>
</property>
</action>
<action name="actionFull_screen_stretch">
<action name="actionFullScreen_stretch">
<property name="checkable">
<bool>true</bool>
</property>
@@ -370,7 +370,7 @@
<string>Full screen stretch</string>
</property>
</action>
<action name="action4_3">
<action name="actionFullScreen_43">
<property name="checkable">
<bool>true</bool>
</property>
@@ -378,7 +378,7 @@
<string>4:3</string>
</property>
</action>
<action name="actionSquare_pixels_Keep_ratio">
<action name="actionFullScreen_keepRatio">
<property name="checkable">
<bool>true</bool>
</property>
@@ -386,7 +386,7 @@
<string>Square pixels (Keep ratio)</string>
</property>
</action>
<action name="actionInteger_scale">
<action name="actionFullScreen_int">
<property name="checkable">
<bool>true</bool>
</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"
extern "C" {
#include <86box/86box.h>
}
#include <QPainter>
SoftwareRenderer::SoftwareRenderer(QWidget *parent) : QWidget(parent) {}
void SoftwareRenderer::paintEvent(QPaintEvent *event) {
(void) event;
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();
onPaint(this);
}
void SoftwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) {
image = img;
sx = x;
sy = y;
sw = w;
sh = h;
source.setRect(x, y, w, h);
update();
}
void SoftwareRenderer::resizeEvent(QResizeEvent *event) {
onResize(width(), height());
QWidget::resizeEvent(event);
}

View File

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