Skip to content

Commit

Permalink
Add support for scaled resolutions (#6516)
Browse files Browse the repository at this point in the history
  • Loading branch information
ihhub committed Feb 5, 2023
1 parent 26d546d commit 0c94c69
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 150 deletions.
207 changes: 120 additions & 87 deletions src/engine/screen.cpp

Large diffs are not rendered by default.

59 changes: 52 additions & 7 deletions src/engine/screen.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2020 - 2022 *
* Copyright (C) 2020 - 2023 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
Expand All @@ -23,6 +23,7 @@
#include <cstdint>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "image.h"
Expand All @@ -33,6 +34,40 @@ namespace fheroes2
class Cursor;
class Display;

struct ResolutionInfo
{
ResolutionInfo() = default;

ResolutionInfo( const int32_t width_, const int32_t height_, const int32_t scale_ )
: width( width_ )
, height( height_ )
, scale( scale_ )
{
// Do nothing.
}

bool operator==( const ResolutionInfo & info ) const
{
return width == info.width && height == info.height && scale == info.scale;
}

bool operator!=( const ResolutionInfo & info ) const
{
return !operator==( info );
}

bool operator<( const ResolutionInfo & info ) const
{
return std::tie( width, height, scale ) < std::tie( info.width, info.height, info.scale );
}

int32_t width{ 0 };

int32_t height{ 0 };

int32_t scale{ 1 };
};

class BaseRenderEngine
{
public:
Expand All @@ -51,7 +86,7 @@ namespace fheroes2
return _isFullScreen;
}

virtual std::vector<Size> getAvailableResolutions() const
virtual std::vector<ResolutionInfo> getAvailableResolutions() const
{
return {};
}
Expand All @@ -66,12 +101,12 @@ namespace fheroes2
// Do nothing.
}

virtual fheroes2::Rect getActiveWindowROI() const
virtual Rect getActiveWindowROI() const
{
return {};
}

virtual fheroes2::Size getCurrentScreenResolution() const
virtual Size getCurrentScreenResolution() const
{
return {};
}
Expand Down Expand Up @@ -109,7 +144,7 @@ namespace fheroes2
// Do nothing.
}

virtual bool allocate( int32_t &, int32_t &, bool )
virtual bool allocate( ResolutionInfo & /*unused*/, bool /*unused*/ )
{
return false;
}
Expand Down Expand Up @@ -159,8 +194,11 @@ namespace fheroes2
// Update the area which will be rendered on the next render() call.
void updateNextRenderRoi( const Rect & roi );

// Do not call this method. It serves as a patch over the basic class.
void resize( int32_t width_, int32_t height_ ) override;

void setResolution( ResolutionInfo info );

bool isDefaultSize() const
{
return width() == DEFAULT_WIDTH && height() == DEFAULT_HEIGHT;
Expand All @@ -186,6 +224,11 @@ namespace fheroes2
// nullptr input parameter is used to reset pallette to default one.
void changePalette( const uint8_t * palette = nullptr, const bool forceDefaultPaletteUpdate = false ) const;

int32_t scale() const
{
return _scale;
}

friend BaseRenderEngine & engine();
friend Cursor & cursor();

Expand All @@ -200,6 +243,8 @@ namespace fheroes2
// Previous area drawn on the screen.
Rect _prevRoi;

int32_t _scale;

// Only for cases of direct drawing on rendered 8-bit image.
void linkRenderSurface( uint8_t * surface )
{
Expand Down Expand Up @@ -229,9 +274,9 @@ namespace fheroes2

bool isFocusActive() const;

virtual void update( const fheroes2::Image & image, int32_t offsetX, int32_t offsetY )
virtual void update( const Image & image, int32_t offsetX, int32_t offsetY )
{
_image = fheroes2::Sprite( image, offsetX, offsetY );
_image = Sprite( image, offsetX, offsetY );
}

void setPosition( int32_t x, int32_t y )
Expand Down
10 changes: 8 additions & 2 deletions src/fheroes2/dialog/dialog_graphics_settings.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2022 *
* Copyright (C) 2022 - 2023 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
Expand Down Expand Up @@ -64,7 +64,13 @@ namespace
void drawResolution( const fheroes2::Rect & optionRoi )
{
const fheroes2::Display & display = fheroes2::Display::instance();
std::string resolutionName = std::to_string( display.width() ) + 'x' + std::to_string( display.height() );
std::string resolutionName;
if ( display.scale() > 1 ) {
resolutionName = std::to_string( display.width() ) + 'x' + std::to_string( display.height() ) + " (x" + std::to_string( display.scale() ) + ')';
}
else {
resolutionName = std::to_string( display.width() ) + 'x' + std::to_string( display.height() );
}

fheroes2::drawOption( optionRoi, fheroes2::AGG::GetICN( ICN::SPANEL, Settings::Get().isEvilInterfaceEnabled() ? 17 : 16 ), _( "Resolution" ),
std::move( resolutionName ), fheroes2::UiOptionTextWidth::TWO_ELEMENTS_ROW );
Expand Down
97 changes: 62 additions & 35 deletions src/fheroes2/dialog/dialog_resolution.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2020 - 2022 *
* Copyright (C) 2020 - 2023 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
Expand All @@ -20,8 +20,8 @@

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "agg_image.h"
Expand All @@ -36,7 +36,6 @@
#include "localevent.h"
#include "math_base.h"
#include "screen.h"
#include "text.h"
#include "translations.h"
#include "ui_button.h"
#include "ui_dialog.h"
Expand All @@ -46,29 +45,49 @@

namespace
{
const int editBoxLength = 266;
const int32_t editBoxLength = 266;
const int32_t resolutionItemHeight = 19;
// TODO: this is a hack over partially incorrect text height calculation. Fix it later together with the Text classes.
const int32_t textOffsetYCorrection = 6;
const std::string middleText = " x ";

std::string GetResolutionString( const fheroes2::Size & resolution )
std::pair<std::string, std::string> getResolutionStrings( const fheroes2::ResolutionInfo & resolution )
{
return std::to_string( resolution.width ) + " x " + std::to_string( resolution.height );
if ( resolution.scale > 1 ) {
return std::make_pair( std::to_string( resolution.width ), std::to_string( resolution.height ) + " (x" + std::to_string( resolution.scale ) + ")" );
}

return std::make_pair( std::to_string( resolution.width ), std::to_string( resolution.height ) );
}

class ResolutionList : public Interface::ListBox<fheroes2::Size>
class ResolutionList : public Interface::ListBox<fheroes2::ResolutionInfo>
{
public:
using Interface::ListBox<fheroes2::Size>::ActionListSingleClick;
using Interface::ListBox<fheroes2::Size>::ActionListPressRight;
using Interface::ListBox<fheroes2::Size>::ActionListDoubleClick;
using Interface::ListBox<fheroes2::ResolutionInfo>::ActionListSingleClick;
using Interface::ListBox<fheroes2::ResolutionInfo>::ActionListPressRight;
using Interface::ListBox<fheroes2::ResolutionInfo>::ActionListDoubleClick;

explicit ResolutionList( const fheroes2::Point & offset )
: Interface::ListBox<fheroes2::Size>( offset )
: Interface::ListBox<fheroes2::ResolutionInfo>( offset )
, _isDoubleClicked( false )
{}
{
// Do nothing.
}

void RedrawItem( const fheroes2::Size & resolution, int32_t offsetX, int32_t offsetY, bool current ) override
void RedrawItem( const fheroes2::ResolutionInfo & resolution, int32_t offsetX, int32_t offsetY, bool current ) override
{
const Text text( GetResolutionString( resolution ), ( current ? Font::YELLOW_BIG : Font::BIG ) );
text.Blit( ( editBoxLength - text.w() ) / 2 + offsetX, offsetY, editBoxLength );
const fheroes2::FontType fontType = current ? fheroes2::FontType::normalYellow() : fheroes2::FontType::normalWhite();

const auto [leftText, rightText] = getResolutionStrings( resolution );
const int32_t middleTextSize = fheroes2::Text( middleText, fontType ).width();
const int32_t leftTextSize = fheroes2::Text( leftText, fontType ).width();

const fheroes2::Text resolutionText( leftText + middleText + rightText, fontType );

const int32_t textOffsetX = offsetX + editBoxLength / 2 - leftTextSize - middleTextSize / 2;
const int32_t textOffsetY = offsetY + ( resolutionItemHeight - resolutionText.height() + textOffsetYCorrection ) / 2;

resolutionText.draw( textOffsetX, textOffsetY, fheroes2::Display::instance() );
}

void RedrawBackground( const fheroes2::Point & dst ) override
Expand All @@ -87,17 +106,17 @@ namespace
// Do nothing.
}

void ActionListSingleClick( fheroes2::Size & ) override
void ActionListSingleClick( fheroes2::ResolutionInfo & /*unused*/ ) override
{
// Do nothing.
}

void ActionListPressRight( fheroes2::Size & ) override
void ActionListPressRight( fheroes2::ResolutionInfo & /*unused*/ ) override
{
// Do nothing.
}

void ActionListDoubleClick( fheroes2::Size & ) override
void ActionListDoubleClick( fheroes2::ResolutionInfo & /*unused*/ ) override
{
_isDoubleClicked = true;
}
Expand All @@ -111,14 +130,22 @@ namespace
bool _isDoubleClicked;
};

void RedrawInfo( const fheroes2::Point & dst, const fheroes2::Size & resolution )
void RedrawInfo( const fheroes2::Point & dst, const fheroes2::ResolutionInfo & resolution, fheroes2::Image & output )
{
Text text( _( "Select Game Resolution:" ), Font::YELLOW_BIG );
text.Blit( dst.x + ( 377 - text.w() ) / 2, dst.y + 30 );
fheroes2::Text text( _( "Select Game Resolution:" ), fheroes2::FontType::normalYellow() );
text.draw( dst.x + ( 377 - text.width() ) / 2, dst.y + 32, output );

if ( resolution.width > 0 && resolution.height > 0 ) {
text.Set( GetResolutionString( resolution ), Font::YELLOW_BIG );
text.Blit( dst.x + ( editBoxLength - text.w() ) / 2 + 41, dst.y + 287 + ( 19 - text.h() + 2 ) / 2, editBoxLength );
const fheroes2::FontType fontType = fheroes2::FontType::normalYellow();

const auto [leftText, rightText] = getResolutionStrings( resolution );
const int32_t middleTextSize = fheroes2::Text( middleText, fontType ).width();
const int32_t leftTextSize = fheroes2::Text( leftText, fontType ).width();

const int32_t textOffsetX = dst.x + 41 + editBoxLength / 2 - leftTextSize - middleTextSize / 2;

const fheroes2::Text resolutionText( leftText + middleText + rightText, fontType );
resolutionText.draw( textOffsetX, dst.y + 287 + ( resolutionItemHeight - text.height() + textOffsetYCorrection ) / 2, output );
}
}
}
Expand All @@ -127,7 +154,7 @@ namespace Dialog
{
bool SelectResolution()
{
std::vector<fheroes2::Size> resolutions = fheroes2::engine().getAvailableResolutions();
std::vector<fheroes2::ResolutionInfo> resolutions = fheroes2::engine().getAvailableResolutions();
if ( resolutions.empty() )
return false;

Expand Down Expand Up @@ -161,16 +188,17 @@ namespace Dialog
{ 0, 0, originalSlider.width(), 8 }, { 0, 7, originalSlider.width(), 8 } );
resList.setScrollBarArea( { roi.x + 328, roi.y + 73, 12, 180 } );
resList.setScrollBarImage( scrollbarSlider );
resList.SetAreaMaxItems( 11 );
resList.SetAreaItems( { roi.x + 41, roi.y + 55 + 3, editBoxLength, 215 } );
const int32_t maximumItems = 11;
resList.SetAreaMaxItems( maximumItems );
resList.SetAreaItems( { roi.x + 41, roi.y + 55 + 4, editBoxLength, resolutionItemHeight * maximumItems } );

resList.SetListContent( resolutions );

const fheroes2::Size currentResolution( display.width(), display.height() );
const fheroes2::ResolutionInfo currentResolution{ display.width(), display.height(), display.scale() };

fheroes2::Size selectedResolution;
fheroes2::ResolutionInfo selectedResolution;
for ( size_t i = 0; i < resolutions.size(); ++i ) {
if ( resolutions[i].width == currentResolution.width && resolutions[i].height == currentResolution.height ) {
if ( resolutions[i] == currentResolution ) {
resList.SetCurrent( i );
selectedResolution = resList.GetCurrent();
break;
Expand All @@ -182,7 +210,7 @@ namespace Dialog
buttonOk.draw();
buttonCancel.draw();

RedrawInfo( roi.getPosition(), selectedResolution );
RedrawInfo( roi.getPosition(), selectedResolution, display );

display.render();

Expand All @@ -200,7 +228,7 @@ namespace Dialog
}
}
else if ( le.MouseClickLeft( buttonCancel.area() ) || Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_CANCEL ) ) {
selectedResolution = { 0, 0 };
selectedResolution = {};
break;
}
else if ( le.MousePressRight( buttonCancel.area() ) ) {
Expand All @@ -225,13 +253,12 @@ namespace Dialog
resList.Redraw();
buttonOk.draw();
buttonCancel.draw();
RedrawInfo( roi.getPosition(), selectedResolution );
RedrawInfo( roi.getPosition(), selectedResolution, display );
display.render();
}

if ( selectedResolution.width > 0 && selectedResolution.height > 0
&& ( selectedResolution.width != currentResolution.width || selectedResolution.height != currentResolution.height ) ) {
display.resize( selectedResolution.width, selectedResolution.height );
if ( selectedResolution.width > 0 && selectedResolution.height > 0 && selectedResolution.scale > 0 && selectedResolution != currentResolution ) {
display.setResolution( selectedResolution );

#if !defined( MACOS_APP_BUNDLE )
const fheroes2::Image & appIcon = CreateImageFromZlib( 32, 32, iconImage, sizeof( iconImage ), true );
Expand Down
3 changes: 1 addition & 2 deletions src/fheroes2/game/fheroes2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
#include "image_palette.h"
#include "localevent.h"
#include "logging.h"
#include "math_base.h"
#include "screen.h"
#include "settings.h"
#include "system.h"
Expand Down Expand Up @@ -131,7 +130,7 @@ namespace

fheroes2::Display & display = fheroes2::Display::instance();

display.resize( conf.VideoMode().width, conf.VideoMode().height );
display.setResolution( conf.currentResolutionInfo() );
display.fill( 0 ); // start from a black screen

fheroes2::engine().setTitle( GetCaption() );
Expand Down

0 comments on commit 0c94c69

Please sign in to comment.