diff --git a/src/86box.c b/src/86box.c
index 7b67e3ba9..ceb492b7d 100644
--- a/src/86box.c
+++ b/src/86box.c
@@ -234,6 +234,9 @@ int portable_mode = 0; /* We are runn
int monitor_edid = 0; /* (C) Which EDID to use. 0=default, 1=custom. */
char monitor_edid_path[1024] = { 0 }; /* (C) Path to custom EDID */
+double video_gl_input_scale = 1.0; /* (C) OpenGL 3.x input scale */
+int video_gl_input_scale_mode = FULLSCR_SCALE_FULL; /* (C) OpenGL 3.x input stretch mode */
+
// Accelerator key array
struct accelKey acc_keys[NUM_ACCELS];
diff --git a/src/config.c b/src/config.c
index a4c3be03a..a3c2dc0ec 100644
--- a/src/config.c
+++ b/src/config.c
@@ -227,6 +227,9 @@ load_general(void)
video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1);
video_vsync = ini_section_get_int(cat, "video_gl_vsync", 0);
+ video_gl_input_scale = ini_section_get_double(cat, "video_gl_input_scale", 1.0);
+ video_gl_input_scale_mode = ini_section_get_int(cat, "video_gl_input_scale_mode", FULLSCR_SCALE_FULL);
+
window_remember = ini_section_get_int(cat, "window_remember", 0);
if (window_remember) {
p = ini_section_get_string(cat, "window_coordinates", NULL);
@@ -2398,6 +2401,18 @@ save_general(void)
else
ini_section_delete_var(cat, "do_auto_pause");
+ if (video_gl_input_scale != 1.0) {
+ ini_section_set_double(cat, "video_gl_input_scale", video_gl_input_scale);
+ } else {
+ ini_section_delete_var(cat, "video_gl_input_scale");
+ }
+
+ if (video_gl_input_scale_mode != FULLSCR_SCALE_FULL) {
+ ini_section_set_int(cat, "video_gl_input_scale_mode", video_gl_input_scale_mode);
+ } else {
+ ini_section_delete_var(cat, "video_gl_input_scale_mode");
+ }
+
if (force_constant_mouse)
ini_section_set_int(cat, "force_constant_mouse", force_constant_mouse);
else
diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h
index 8696cbabd..08def802b 100644
--- a/src/include/86box/86box.h
+++ b/src/include/86box/86box.h
@@ -140,6 +140,8 @@ extern int force_43; /* (C) video */
extern int video_filter_method; /* (C) video */
extern int video_vsync; /* (C) video */
extern int video_framerate; /* (C) video */
+extern double video_gl_input_scale; /* (C) OpenGL 3.x input scale */
+extern int video_gl_input_scale_mode; /* (C) OpenGL 3.x input stretch mode */
extern int gfxcard[GFXCARD_MAX]; /* (C) graphics/video card */
extern int bugger_enabled; /* (C) enable ISAbugger */
extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */
diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp
index f345a15c4..2f644a8ce 100644
--- a/src/qt/qt_mainwindow.cpp
+++ b/src/qt/qt_mainwindow.cpp
@@ -530,6 +530,8 @@ MainWindow::MainWindow(QWidget *parent)
#endif
}
ui->stackedWidget->switchRenderer(newVidApi);
+ ui->menuOpenGL_input_scale->setEnabled(newVidApi == RendererStack::Renderer::OpenGL3);
+ ui->menuOpenGL_input_stretch_mode->setEnabled(newVidApi == RendererStack::Renderer::OpenGL3);
if (!show_second_monitors)
return;
for (int i = 1; i < MONITORS_NUM; i++) {
@@ -550,6 +552,41 @@ MainWindow::MainWindow(QWidget *parent)
break;
}
+ ui->action_0_5x_2->setChecked(video_gl_input_scale < 1.0);
+ ui->action_1x_2->setChecked(video_gl_input_scale >= 1.0 && video_gl_input_scale < 1.5);
+ ui->action1_5x_2->setChecked(video_gl_input_scale >= 1.5 && video_gl_input_scale < 2.0);
+ ui->action_2x_2->setChecked(video_gl_input_scale >= 2.0 && video_gl_input_scale < 3.0);
+ ui->action_3x_2->setChecked(video_gl_input_scale >= 3.0 && video_gl_input_scale < 4.0);
+ ui->action_4x_2->setChecked(video_gl_input_scale >= 4.0 && video_gl_input_scale < 5.0);
+ ui->action_5x_2->setChecked(video_gl_input_scale >= 5.0 && video_gl_input_scale < 6.0);
+ ui->action_6x_2->setChecked(video_gl_input_scale >= 6.0 && video_gl_input_scale < 7.0);
+ ui->action_7x_2->setChecked(video_gl_input_scale >= 7.0 && video_gl_input_scale < 8.0);
+ ui->action_8x_2->setChecked(video_gl_input_scale >= 8.0);
+
+ actGroup = new QActionGroup(this);
+ actGroup->addAction(ui->action_0_5x_2);
+ actGroup->addAction(ui->action_1x_2);
+ actGroup->addAction(ui->action1_5x_2);
+ actGroup->addAction(ui->action_2x_2);
+ actGroup->addAction(ui->action_3x_2);
+ actGroup->addAction(ui->action_4x_2);
+ actGroup->addAction(ui->action_5x_2);
+ actGroup->addAction(ui->action_6x_2);
+ actGroup->addAction(ui->action_7x_2);
+ actGroup->addAction(ui->action_8x_2);
+ connect(actGroup, &QActionGroup::triggered, this, [this](QAction* action) {
+ if (action == ui->action_0_5x_2) video_gl_input_scale = 0.5;
+ if (action == ui->action_1x_2) video_gl_input_scale = 1;
+ if (action == ui->action1_5x_2) video_gl_input_scale = 1.5;
+ if (action == ui->action_2x_2) video_gl_input_scale = 2;
+ if (action == ui->action_3x_2) video_gl_input_scale = 3;
+ if (action == ui->action_4x_2) video_gl_input_scale = 4;
+ if (action == ui->action_5x_2) video_gl_input_scale = 5;
+ if (action == ui->action_6x_2) video_gl_input_scale = 6;
+ if (action == ui->action_7x_2) video_gl_input_scale = 7;
+ if (action == ui->action_8x_2) video_gl_input_scale = 8;
+ });
+
switch (scale) {
default:
break;
@@ -633,6 +670,38 @@ MainWindow::MainWindow(QWidget *parent)
actGroup->addAction(ui->actionFullScreen_keepRatio);
actGroup->addAction(ui->actionFullScreen_int);
actGroup->addAction(ui->actionFullScreen_int43);
+ switch (video_gl_input_scale_mode) {
+ default:
+ break;
+ case FULLSCR_SCALE_FULL:
+ ui->action_Full_screen_stretch_gl->setChecked(true);
+ break;
+ case FULLSCR_SCALE_43:
+ ui->action_4_3_gl->setChecked(true);
+ break;
+ case FULLSCR_SCALE_KEEPRATIO:
+ ui->action_Square_pixels_keep_ratio_gl->setChecked(true);
+ break;
+ case FULLSCR_SCALE_INT:
+ ui->action_Integer_scale_gl->setChecked(true);
+ break;
+ case FULLSCR_SCALE_INT43:
+ ui->action4_3_Integer_scale_gl->setChecked(true);
+ break;
+ }
+ actGroup = new QActionGroup(this);
+ actGroup->addAction(ui->action_Full_screen_stretch_gl);
+ actGroup->addAction(ui->action_4_3_gl);
+ actGroup->addAction(ui->action_Square_pixels_keep_ratio_gl);
+ actGroup->addAction(ui->action_Integer_scale_gl);
+ actGroup->addAction(ui->action4_3_Integer_scale_gl);
+ connect(actGroup, &QActionGroup::triggered, this, [this](QAction* action) {
+ if (action == ui->action_Full_screen_stretch_gl) video_gl_input_scale_mode = FULLSCR_SCALE_FULL;
+ if (action == ui->action_4_3_gl) video_gl_input_scale_mode = FULLSCR_SCALE_43;
+ if (action == ui->action_Square_pixels_keep_ratio_gl) video_gl_input_scale_mode = FULLSCR_SCALE_KEEPRATIO;
+ if (action == ui->action_Integer_scale_gl) video_gl_input_scale_mode = FULLSCR_SCALE_INT;
+ if (action == ui->action4_3_Integer_scale_gl) video_gl_input_scale_mode = FULLSCR_SCALE_INT43;
+ });
switch (video_grayscale) {
default:
break;
@@ -1714,6 +1783,21 @@ MainWindow::on_actionInverted_VGA_monitor_triggered()
video_toggle_option(ui->actionInverted_VGA_monitor, &invert_display);
}
+static void
+update_scaled_checkboxes_gl(Ui::MainWindow *ui, QAction *selected)
+{
+ ui->action_0_5x_2->setChecked(ui->action_0_5x_2 == selected);
+ ui->action_1x_2->setChecked(ui->action_1x_2 == selected);
+ ui->action1_5x_2->setChecked(ui->action1_5x_2 == selected);
+ ui->action_2x_2->setChecked(ui->action_2x_2 == selected);
+ ui->action_3x_2->setChecked(ui->action_3x_2 == selected);
+ ui->action_4x_2->setChecked(ui->action_4x_2 == selected);
+ ui->action_5x_2->setChecked(ui->action_5x_2 == selected);
+ ui->action_6x_2->setChecked(ui->action_6x_2 == selected);
+ ui->action_7x_2->setChecked(ui->action_7x_2 == selected);
+ ui->action_8x_2->setChecked(ui->action_8x_2 == selected);
+}
+
static void
update_scaled_checkboxes(Ui::MainWindow *ui, QAction *selected)
{
diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui
index 5ad597459..9c719cba6 100644
--- a/src/qt/qt_mainwindow.ui
+++ b/src/qt/qt_mainwindow.ui
@@ -186,6 +186,31 @@
+
+
@@ -195,6 +220,8 @@
+
+
@@ -894,6 +921,134 @@
&CGA composite settings...
+
+
+ true
+
+
+ &Full screen stretch
+
+
+
+
+ true
+
+
+ &4:3
+
+
+
+
+ true
+
+
+ &Square pixels (keep ratio)
+
+
+
+
+ true
+
+
+ &Integer scale
+
+
+
+
+ true
+
+
+ 4:&3 Integer scale
+
+
+
+
+ true
+
+
+ &1x
+
+
+
+
+ true
+
+
+ &0.5x
+
+
+
+
+ true
+
+
+ &1x
+
+
+
+
+ true
+
+
+ 1.&5x
+
+
+
+
+ true
+
+
+ &2x
+
+
+
+
+ true
+
+
+ &3x
+
+
+
+
+ true
+
+
+ &4x
+
+
+
+
+ true
+
+
+ &5x
+
+
+
+
+ true
+
+
+ &6x
+
+
+
+
+ true
+
+
+ &7x
+
+
+
+
+ true
+
+
+ &8x
+
+
diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp
index 4ec091eb2..cecc8ea9c 100644
--- a/src/qt/qt_openglrenderer.cpp
+++ b/src/qt/qt_openglrenderer.cpp
@@ -1386,6 +1386,8 @@ OpenGLRenderer::getOptions(QWidget *parent)
return new OpenGLShaderManagerDialog(parent);
}
+extern void standalone_scale(QRect &destination, int width, int height, QRect source, int scalemode);
+
void
OpenGLRenderer::render()
{
@@ -1428,19 +1430,16 @@ OpenGLRenderer::render()
{
struct shader_pass *pass = &active_shader->scene;
- struct {
- uint32_t x;
- uint32_t y;
- uint32_t w;
- uint32_t h;
- } rect;
- rect.x = 0;
- rect.y = 0;
- rect.w = source.width();
- rect.h = source.height();
+ QRect rect;
+ rect.setX(0);
+ rect.setY(0);
+ rect.setWidth(source.width() * video_gl_input_scale);
+ rect.setHeight(source.height() * video_gl_input_scale);
- pass->state.input_size[0] = pass->state.output_size[0] = rect.w;
- pass->state.input_size[1] = pass->state.output_size[1] = rect.h;
+ standalone_scale(rect, source.width(), source.height(), rect, video_gl_input_scale_mode);
+
+ pass->state.input_size[0] = pass->state.output_size[0] = rect.width();
+ pass->state.input_size[1] = pass->state.output_size[1] = rect.height();
pass->state.input_texture_size[0] = pass->state.output_texture_size[0] = next_pow2(pass->state.output_size[0]);
pass->state.input_texture_size[1] = pass->state.output_texture_size[1] = next_pow2(pass->state.output_size[1]);
diff --git a/src/qt/qt_renderercommon.cpp b/src/qt/qt_renderercommon.cpp
index 56217b611..b71e19e75 100644
--- a/src/qt/qt_renderercommon.cpp
+++ b/src/qt/qt_renderercommon.cpp
@@ -49,6 +49,73 @@ integer_scale(double *d, double *g)
}
}
+void
+standalone_scale(QRect &destination, int width, int height, QRect source, int scalemode)
+{
+ double dx;
+ double dy;
+ double dw;
+ double dh;
+ double gsr;
+
+ double hw = width;
+ double hh = height;
+ double gw = source.width();
+ double gh = source.height();
+ double hsr = hw / hh;
+ double r43 = 4.0 / 3.0;
+
+ switch (scalemode) {
+ case FULLSCR_SCALE_INT:
+ case FULLSCR_SCALE_INT43:
+ gsr = gw / gh;
+
+ if (scalemode == FULLSCR_SCALE_INT43) {
+ gh = gw / r43;
+
+ gsr = r43;
+ }
+
+ 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((int) dx, (int) dy, (int) dw, (int) dh);
+ break;
+ case FULLSCR_SCALE_43:
+ case FULLSCR_SCALE_KEEPRATIO:
+ if (scalemode == FULLSCR_SCALE_43)
+ gsr = r43;
+ 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((int) dx, (int) dy, (int) dw, (int) dh);
+ break;
+ case FULLSCR_SCALE_FULL:
+ default:
+ destination.setRect(0, 0, (int) hw, (int) hh);
+ break;
+ }
+}
+
void
RendererCommon::onResize(int width, int height)
{