Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for viewport scaling #129

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions d2dx-defaults.cfg
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
#
# This is an example config file for D2DX.
#
# If you don't like the default settings, you can edit this file, rename it to "d2dx.cfg"
# and place it in the game folder.
# If you don't like the default settings, you can edit this file, rename it to "d2dx.cfg", and place it in the game folder.
#

[window]
scale=1 # range 1-3, an integer scale factor for the window
position=[-1,-1] # if [-1,-1] the window will be centered, otherwise placed at the explicit position given here
frameless=false # if true, the window frame (caption bar etc) will be removed
scale=1 # range 1-3, an integer scale factor for the window
position=[-1,-1] # if [-1,-1] the window will be centered, otherwise placed at the explicit position given here
frameless=false # if true, the window frame (caption bar etc) will be removed

[game]
size=[-1,-1] # if [-1,-1] d2dx will decide a suitable game size, otherwise will use the size given here
filtering=0 # if 0, will use high quality filtering (sharp, more pixelated)
# 1, will use bilinear filtering (blurry)
# 2, will use catmull-rom filtering (higher quality than bilinear)
scale=3.0 # scale the size of the viewport (capped to screen size, maintains aspect ratio)
size=[-1,-1] # if [-1,-1] d2dx will decide a suitable game size, otherwise will use the size given here
filtering=0 # if 0, will use high quality filtering (sharp, more pixelated)
# 1, will use bilinear filtering (blurry)
# 2, will use catmull-rom filtering (higher quality than bilinear)

#
# Opt-outs from default D2DX behavior
#
[optouts]
noclipcursor=false # if true, will not lock the mouse cursor to the game window
nofpsfix=false # if true, will not apply the basic fps fix (precludes high fps support)
noresmod=false # if true, will not apply the built-in D2HD resolution mod (precludes widescreen support)
nowide=false # if true, will not choose a widescreen resolution (if noresmod is true, this does nothing)
nologo=false # if true, will not display the D2DX logo on the title screen
novsync=false # if true, will not use vertical sync
noaa=false # if true, will not apply anti-aliasing to jagged edges
nocompatmodefix=false # if true, will not block the use of "Windows XP compatibility mode"
notitlechange=false # if true, will not change the window title text
nomotionprediction=false # if true, will not run the game graphics at high fps
noclipcursor=false # if true, will not lock the mouse cursor to the game window
nofpsfix=false # if true, will not apply the basic fps fix (precludes high fps support)
noresmod=false # if true, will not apply the built-in D2HD resolution mod (precludes widescreen support)
nowide=false # if true, will not choose a widescreen resolution (if noresmod is true, this does nothing)
nologo=false # if true, will not display the D2DX logo on the title screen
novsync=false # if true, will not use vertical sync
noaa=false # if true, will not apply anti-aliasing to jagged edges
nocompatmodefix=false # if true, will not block the use of "Windows XP compatibility mode"
notitlechange=false # if true, will not change the window title text
nomotionprediction=false # if true, will not run the game graphics at high fps
25 changes: 12 additions & 13 deletions src/d2dx/Metrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,28 +184,27 @@ _Use_decl_annotations_
Rect d2dx::Metrics::GetRenderRect(
Size gameSize,
Size desktopSize,
bool wide) noexcept
bool wide,
double gameScale) noexcept
{
int32_t scaleFactor = 1;

while (
gameSize.width * (scaleFactor + 1) <= desktopSize.width &&
gameSize.height * (scaleFactor + 1) <= desktopSize.height)
bool fitToScreen = false;

if (gameScale * gameSize.width > desktopSize.width || gameScale * gameSize.height > desktopSize.height)
{
++scaleFactor;
gameScale = 1.0;
fitToScreen = true;
}

Rect rect
{
(desktopSize.width - gameSize.width * scaleFactor) / 2,
(desktopSize.height - gameSize.height * scaleFactor) / 2,
gameSize.width * scaleFactor,
gameSize.height * scaleFactor
(int32_t)((desktopSize.width - gameSize.width * gameScale) / 2),
(int32_t)((desktopSize.height - gameSize.height * gameScale) / 2),
(int32_t)(gameSize.width * gameScale),
(int32_t)(gameSize.height * gameScale)
};

/* Allow for a small amount of black margin on all sides. When more than that,
rescale the image with a non-integer factor. */
if (rect.offset.x < 0 || rect.offset.y < 0 || (rect.offset.x >= 16 && rect.offset.y >= 16))
if (fitToScreen || rect.offset.x < 0 || rect.offset.y < 0)
{
float scaleFactorF = (float)desktopSize.width / rect.size.width;
int32_t scaledHeight = (int32_t)(rect.size.height * scaleFactorF);
Expand Down
3 changes: 2 additions & 1 deletion src/d2dx/Metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ namespace d2dx
Rect GetRenderRect(
_In_ Size gameSize,
_In_ Size desktopSize,
_In_ bool wide) noexcept;
_In_ bool wide,
_In_ double gameScale) noexcept;

Buffer<Size> GetStandardDesktopSizes() noexcept;
}
Expand Down
24 changes: 24 additions & 0 deletions src/d2dx/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ void Options::ApplyCfg(
{
_filtering = (FilteringOption)filtering.u.i;
}

auto gameScale = toml_double_in(game, "scale");
if (gameScale.ok)
{
SetGameScale(gameScale.u.d);
}
}

auto window = toml_table_in(root, "window");
Expand Down Expand Up @@ -227,3 +233,21 @@ FilteringOption Options::GetFiltering() const
{
return _filtering;
}

double Options::GetGameScale() const
{
return _gameScale;
}

void Options::SetGameScale(
_In_ double gameScale)
{
if (gameScale < 1.0)
{
_gameScale = 1.0;
}
else
{
_gameScale = gameScale;
}
}
6 changes: 6 additions & 0 deletions src/d2dx/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,17 @@ namespace d2dx

FilteringOption GetFiltering() const;

double GetGameScale() const;

void SetGameScale(
_In_ double gameScale);

private:
uint32_t _flags = 0;
int32_t _windowScale = 1;
Offset _windowPosition{ -1, -1 };
Size _userSpecifiedGameSize{ -1, -1 };
FilteringOption _filtering{ FilteringOption::HighQuality };
double _gameScale = 3.0;
};
}
20 changes: 16 additions & 4 deletions src/d2dx/RenderContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ RenderContext::RenderContext(
_renderRect = Metrics::GetRenderRect(
gameSize,
_screenMode == ScreenMode::FullscreenDefault ? _desktopSize : _windowSize,
!_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoWide));
!_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoWide),
_d2dxContext->GetOptions().GetGameScale());

#ifndef NDEBUG
ShowCursor_Real(TRUE);
Expand Down Expand Up @@ -849,7 +850,8 @@ void RenderContext::SetSizes(
_renderRect = Metrics::GetRenderRect(
_gameSize,
displaySize,
!_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoWide));
!_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoWide),
_d2dxContext->GetOptions().GetGameScale());

bool centerOnCurrentPosition = _hasAdjustedWindowPlacement;
_hasAdjustedWindowPlacement = true;
Expand Down Expand Up @@ -892,7 +894,8 @@ void RenderContext::SetSizes(
_renderRect = Metrics::GetRenderRect(
_gameSize,
_windowSize,
!_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoWide));
!_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoWide),
_d2dxContext->GetOptions().GetGameScale());

windowRect = { 0, 0, _windowSize.width, _windowSize.height };
AdjustWindowRect(&windowRect, windowStyle, FALSE);
Expand Down Expand Up @@ -1021,13 +1024,22 @@ void RenderContext::GetCurrentMetrics(

void RenderContext::ClipCursor()
{
if (_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoClipCursor))
if (_d2dxContext->GetOptions().GetFlag(OptionsFlag::NoClipCursor) && _screenMode == ScreenMode::Windowed)
{
UnclipCursor();
return;
}

RECT clipRect;
::GetClientRect(_hWnd, &clipRect);

clipRect.left += _renderRect.offset.x;
clipRect.right -= _renderRect.offset.x;

// Not 100% sure why this works.
clipRect.bottom -= _renderRect.offset.y * 2;

// Casting a scalar to a point is confusing.
::ClientToScreen(_hWnd, (LPPOINT)&clipRect.left);
::ClientToScreen(_hWnd, (LPPOINT)&clipRect.right);
::ClipCursor(&clipRect);
Expand Down
9 changes: 3 additions & 6 deletions src/d2dxtests/TestMetrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,16 @@ namespace d2dxtests
void AssertThatGameSizeIsIntegerScale(Size desktopSize, bool wide, bool lenient)
{
auto suggestedGameSize = d2dx::Metrics::GetSuggestedGameSize(desktopSize, wide);
auto renderRect = d2dx::Metrics::GetRenderRect(suggestedGameSize, desktopSize, wide);

// The gameScale parameter is not fully covered by tests. This should be fixed.
auto renderRect = d2dx::Metrics::GetRenderRect(suggestedGameSize, desktopSize, wide, 999999999.0);
Assert::IsTrue(renderRect.offset.x >= 0);
Assert::IsTrue(renderRect.offset.y >= 0);
Assert::IsTrue(renderRect.size.width > 0);
Assert::IsTrue(renderRect.size.height > 0);
Assert::IsTrue((renderRect.offset.x + renderRect.size.width) <= desktopSize.width);
Assert::IsTrue((renderRect.offset.y + renderRect.size.height) <= desktopSize.height);

if (renderRect.offset.x > 0 && renderRect.offset.y > 0)
{
Assert::IsTrue(renderRect.offset.x < 16 || renderRect.offset.y < 16);
}

int32_t reconstructedDesktopWidth = renderRect.size.width + renderRect.offset.x * 2;
int32_t reconstructedDesktopHeight = renderRect.size.height + renderRect.offset.y * 2;

Expand Down