Skip to content

Commit

Permalink
Merge pull request #1040 from zigmar/mouse-events-scaling
Browse files Browse the repository at this point in the history
Implements mouse input scaling and an auto screen scaling option for both windowed and fullscreen modes
  • Loading branch information
FilmBoy84 committed Jun 1, 2021
2 parents 568c597 + d35b88d commit f3e590e
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 21 deletions.
43 changes: 33 additions & 10 deletions framework/framework.cpp
Expand Up @@ -557,8 +557,8 @@ void Framework::translateSdlEvents()
break;
case SDL_MOUSEMOTION:
fwE = new MouseEvent(EVENT_MOUSE_MOVE);
fwE->mouse().X = e.motion.x;
fwE->mouse().Y = e.motion.y;
fwE->mouse().X = coordWindowToDisplayX(e.motion.x);
fwE->mouse().Y = coordWindowToDisplayY(e.motion.y);
fwE->mouse().DeltaX = e.motion.xrel;
fwE->mouse().DeltaY = e.motion.yrel;
fwE->mouse().WheelVertical = 0; // These should be handled
Expand All @@ -574,8 +574,8 @@ void Framework::translateSdlEvents()
{
int mx, my;
fwE->mouse().Button = SDL_GetMouseState(&mx, &my);
fwE->mouse().X = mx;
fwE->mouse().Y = my;
fwE->mouse().X = coordWindowToDisplayX(mx);
fwE->mouse().Y = coordWindowToDisplayY(my);
fwE->mouse().DeltaX = 0; // FIXME: This might cause problems?
fwE->mouse().DeltaY = 0;
fwE->mouse().WheelVertical = e.wheel.y;
Expand All @@ -585,8 +585,8 @@ void Framework::translateSdlEvents()
break;
case SDL_MOUSEBUTTONDOWN:
fwE = new MouseEvent(EVENT_MOUSE_DOWN);
fwE->mouse().X = e.button.x;
fwE->mouse().Y = e.button.y;
fwE->mouse().X = coordWindowToDisplayX(e.button.x);
fwE->mouse().Y = coordWindowToDisplayY(e.button.y);
fwE->mouse().DeltaX = 0; // FIXME: This might cause problems?
fwE->mouse().DeltaY = 0;
fwE->mouse().WheelVertical = 0;
Expand All @@ -596,8 +596,8 @@ void Framework::translateSdlEvents()
break;
case SDL_MOUSEBUTTONUP:
fwE = new MouseEvent(EVENT_MOUSE_UP);
fwE->mouse().X = e.button.x;
fwE->mouse().Y = e.button.y;
fwE->mouse().X = coordWindowToDisplayX(e.button.x);
fwE->mouse().Y = coordWindowToDisplayY(e.button.y);
fwE->mouse().DeltaX = 0; // FIXME: This might cause problems?
fwE->mouse().DeltaY = 0;
fwE->mouse().WheelVertical = 0;
Expand Down Expand Up @@ -852,16 +852,24 @@ void Framework::displayInitialise()
// size)
int scaleX = Options::screenScaleXOption.get();
int scaleY = Options::screenScaleYOption.get();
const bool autoScale = Options::screenAutoScale.get();

if (scaleX != 100 || scaleY != 100)
if (scaleX != 100 || scaleY != 100 || autoScale)
{
float scaleXFloat = (float)scaleX / 100.0f;
float scaleYFloat = (float)scaleY / 100.0f;
if (autoScale)
{
constexpr int referenceWidth = 1280;
scaleYFloat = scaleXFloat = (float)referenceWidth / p->windowSize.x;
LogInfo("Autoscaling enabled, scaling by (%f,%f)", scaleXFloat, scaleYFloat);
}

p->displaySize.x = (int)((float)p->windowSize.x * scaleXFloat);
p->displaySize.y = (int)((float)p->windowSize.y * scaleYFloat);
if (p->displaySize.x < 640 || p->displaySize.y < 480)
{
LogWarning("Requested scaled size of %s is lower than {640,480} and probably "
LogWarning("Requested scaled size of %d is lower than {640,480} and probably "
"won't work, so forcing 640x480",
p->displaySize.x);
p->displaySize.x = std::max(640, p->displaySize.x);
Expand Down Expand Up @@ -898,6 +906,21 @@ int Framework::displayGetHeight() { return p->displaySize.y; }

Vec2<int> Framework::displayGetSize() { return p->displaySize; }

int Framework::coordWindowToDisplayX(int x) const
{
return (float)x / p->windowSize.x * p->displaySize.x;
}

int Framework::coordWindowToDisplayY(int y) const
{
return (float)y / p->windowSize.y * p->displaySize.y;
}

Vec2<int> Framework::coordWindowsToDisplay(const Vec2<int> &coord) const
{
return Vec2<int>(coordWindowToDisplayX(coord.x), coordWindowToDisplayY(coord.y));
}

bool Framework::displayHasWindow() const
{
if (createWindow == false)
Expand Down
7 changes: 6 additions & 1 deletion framework/framework.h
Expand Up @@ -73,6 +73,11 @@ class Framework
bool displayHasWindow() const;
void *getWindowHandle() const;

// Map coordinates from window to display, for scaled displays
int coordWindowToDisplayX(int x) const;
int coordWindowToDisplayY(int y) const;
Vec2<int> coordWindowsToDisplay(const Vec2<int> &coord) const;

bool isSlowMode();
void setSlowMode(bool SlowEnabled);

Expand All @@ -97,7 +102,7 @@ class Framework
void threadPoolTaskEnqueue(std::function<void()> task);
// add new work item to the pool
template <class F, class... Args>
auto threadPoolEnqueue(F &&f, Args &&... args)
auto threadPoolEnqueue(F &&f, Args &&...args)
-> std::shared_future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
Expand Down
4 changes: 2 additions & 2 deletions framework/logger.cpp
Expand Up @@ -15,8 +15,8 @@ void defaultLogFunction(LogLevel level, UString prefix, const UString &text)
{
UString levelPrefix;
// Only print Warning/Errors by default
if (level >= LogLevel::Info)
return;
// if (level >= LogLevel::Info)
// return;
switch (level)
{
case LogLevel::Error:
Expand Down
4 changes: 4 additions & 0 deletions framework/options.cpp
Expand Up @@ -40,6 +40,7 @@ void dumpOptionsToLog()
dumpOption(screenFullscreenOption);
dumpOption(screenScaleXOption);
dumpOption(screenScaleYOption);
dumpOption(screenAutoScale);
dumpOption(languageOption);

dumpOption(targetFPS);
Expand Down Expand Up @@ -217,6 +218,9 @@ ConfigOptionInt screenScaleXOption("Framework.Screen", "ScaleX",
"Scale screen in X direction by (percent)", 100);
ConfigOptionInt screenScaleYOption("Framework.Screen", "ScaleY",
"Scale screen in Y direction by (percent)", 100);
ConfigOptionBool screenAutoScale(
"Framework.Screen", "AutoScale",
"Automatically scale up game viewport for modern screens (overrides ScaleX and ScaleY)", true);
ConfigOptionString languageOption("Framework", "Language",
"The language used ingame (empty for system default)", "");

Expand Down
1 change: 1 addition & 0 deletions framework/options.h
Expand Up @@ -18,6 +18,7 @@ extern ConfigOptionInt screenHeightOption;
extern ConfigOptionBool screenFullscreenOption;
extern ConfigOptionInt screenScaleXOption;
extern ConfigOptionInt screenScaleYOption;
extern ConfigOptionBool screenAutoScale;
extern ConfigOptionString languageOption;

extern ConfigOptionInt frameLimit;
Expand Down
98 changes: 96 additions & 2 deletions tools/launcher/launcherwindow.cpp
Expand Up @@ -3,6 +3,7 @@
#include <QProcess>
#include <QSize>
#include <array>
#include <string_view>
#include <utility>

#include "launcherwindow.h"
Expand Down Expand Up @@ -45,10 +46,11 @@ static std::list<std::pair<UString, ModInfo>> enumerateMods()
return foundMods;
}

constexpr std::array<QSize, 4> default_resolutions = {
constexpr std::array<QSize, 6> default_resolutions = {

// Use {0,0} as a placeholder for 'custom', expected to be the first index
QSize{0, 0}, QSize{640, 480}, QSize{1280, 720}, QSize{1920, 1080}};
QSize{0, 0}, QSize{640, 480}, QSize{1280, 720},
QSize{1920, 1080}, QSize{2560, 1440}, QSize{3200, 1800}};

constexpr QSize MINIMUM_RESOLUTION = {640, 480};
constexpr QSize MAXIMUM_RESOLUTION = {100000, 100000};
Expand Down Expand Up @@ -89,6 +91,7 @@ LauncherWindow::LauncherWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui
? Qt::CheckState::Checked
: Qt::CheckState::Unchecked);
setupResolutionDisplay();
setupScaling();

ui->cdPath->setText(QString::fromStdString(OpenApoc::Options::cdPathOption.get()));
ui->dataPath->setText(QString::fromStdString(OpenApoc::Options::dataPathOption.get()));
Expand Down Expand Up @@ -182,13 +185,104 @@ void LauncherWindow::setResolutionSelection(int index)
}
}

enum class ScalingType
{
Auto = 0,
None,
Scale_150,
Scale_200,
Scale_300,
Scale_400,
Custom, // Fallback value: if combination of options does not match any predefined option, just
// show 'custom' which, until changed to something else, won't modify stored options.
_count
};

struct ScalingOption
{
const ScalingType type;
const std::string_view label;
const int scale_value; // Corresponding screen scale values from options

constexpr ScalingOption(ScalingType type, std::string_view label, int scale_value)
: type(type), label(label), scale_value(scale_value)
{
}
};

constexpr std::array<ScalingOption, static_cast<int>(ScalingType::_count)> scaling_options = {
ScalingOption{ScalingType::Auto, "Auto", -1},
ScalingOption{ScalingType::None, "None", 100},
ScalingOption{ScalingType::Scale_150, "150%", 66},
ScalingOption{ScalingType::Scale_200, "200%", 50},
ScalingOption{ScalingType::Scale_300, "300%", 33},
ScalingOption{ScalingType::Scale_400, "400%", 25},
ScalingOption{ScalingType::Custom, "Custom", -1}};

void LauncherWindow::setupScaling()
{
auto &comboBox = *ui->scaleBox;
comboBox.clear();
for (const auto &option : scaling_options)
{
comboBox.addItem(option.label.data());
}

const bool autoScale = OpenApoc::Options::screenAutoScale.get();
ScalingType currentType = ScalingType::Custom;
if (autoScale)
{
currentType = ScalingType::Auto;
}
else
{
const QSize screenScale = {OpenApoc::Options::screenScaleXOption.get(),
OpenApoc::Options::screenScaleYOption.get()};

for (const auto &option : scaling_options)
{
if (option.scale_value == screenScale.width() &&
option.scale_value == screenScale.height())
{
currentType = option.type;
break;
}
}
}

comboBox.setCurrentIndex(static_cast<int>(currentType));
}

void LauncherWindow::saveScalingOptions()
{
int index = ui->scaleBox->currentIndex();
LogAssert(index >= 0 && index < scaling_options.size());

if (scaling_options[index].type == ScalingType::Auto)
{
OpenApoc::Options::screenAutoScale.set(true);
}
else if (scaling_options[index].type == ScalingType::Custom)
{
// Do nothing - keep previous settings
}
else
{
OpenApoc::Options::screenAutoScale.set(false);
OpenApoc::Options::screenScaleXOption.set(scaling_options[index].scale_value);
OpenApoc::Options::screenScaleYOption.set(scaling_options[index].scale_value);
}
}

void LauncherWindow::setLanguageSelection(int index)
{
selectedLanguageID = ui->languageBox->itemData(index).toString().toStdString();
}

void LauncherWindow::saveConfig()
{
saveScalingOptions();

const auto &comboBox = *ui->resolutionBox;
// Index 0 is always custom resolution
if (comboBox.currentIndex() == 0)
Expand Down
2 changes: 2 additions & 0 deletions tools/launcher/launcherwindow.h
Expand Up @@ -40,6 +40,8 @@ class LauncherWindow : public QMainWindow

private:
void setupResolutionDisplay();
void setupScaling();
void saveScalingOptions();
void saveConfig();
void setupModList();
void showModInfo(const OpenApoc::ModInfo &info);
Expand Down
26 changes: 20 additions & 6 deletions tools/launcher/launcherwindow.ui
Expand Up @@ -40,6 +40,9 @@
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QComboBox" name="resolutionBox"/>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="fullscreenCheckBox">
<property name="text">
Expand Down Expand Up @@ -86,7 +89,7 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
Expand All @@ -99,10 +102,7 @@
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="resolutionBox"/>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="languageLabel">
<property name="text">
<string>Language</string>
Expand All @@ -116,9 +116,23 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QComboBox" name="languageBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="scaleLabel">
<property name="text">
<string>Screen scale</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="scaleBox">
<property name="toolTip">
<string>Scale up game viewport to accomidate modern screen resolution.</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
Expand Down

0 comments on commit f3e590e

Please sign in to comment.