2
0
Эх сурвалжийг харах

Implement selection of upscaling filter in launcher

Ivan Savenko 1 жил өмнө
parent
commit
d6059b044d

+ 3 - 1
client/render/Canvas.cpp

@@ -10,6 +10,8 @@
 #include "StdInc.h"
 #include "Canvas.h"
 
+#include "../gui/CGuiHandler.h"
+#include "../render/IScreenHandler.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "Colors.h"
 #include "IImage.h"
@@ -63,7 +65,7 @@ int Canvas::getScalingFactor() const
 {
 	if (scalingPolicy == CanvasScalingPolicy::IGNORE)
 		return 1;
-	return 2; // TODO: get from screen handler
+	return GH.screenHandler().getScalingFactor();
 }
 
 Point Canvas::transformPos(const Point & input)

+ 4 - 1
client/renderSDL/CBitmapFont.cpp

@@ -252,8 +252,11 @@ void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & char
 
 	posX += character.leftOffset * scalingFactor;
 
+	auto sdlColor = CSDL_Ext::toSDL(color);
+
 	if (atlasImage->format->palette)
-		atlasImage->format->palette->colors[255] = CSDL_Ext::toSDL(color);
+		SDL_SetPaletteColors(atlasImage->format->palette, &sdlColor, 255, 1);
+//		atlasImage->format->palette->colors[255] = CSDL_Ext::toSDL(color);
 	else
 		SDL_SetSurfaceColorMod(atlasImage, color.r, color.g, color.b);
 

+ 4 - 1
client/renderSDL/RenderHandler.cpp

@@ -13,10 +13,13 @@
 #include "SDLImage.h"
 #include "ImageScaled.h"
 
+#include "../gui/CGuiHandler.h"
+
 #include "../render/CAnimation.h"
 #include "../render/CDefFile.h"
 #include "../render/Colors.h"
 #include "../render/ColorFilter.h"
+#include "../render/IScreenHandler.h"
 
 #include "../../lib/json/JsonUtils.h"
 #include "../../lib/filesystem/Filesystem.h"
@@ -130,7 +133,7 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
 
 int RenderHandler::getScalingFactor() const
 {
-	return 2;
+	return GH.screenHandler().getScalingFactor();
 }
 
 std::shared_ptr<IImage> RenderHandler::createImageReference(const ImageLocator & locator, std::shared_ptr<ISharedImage> input, EImageBlitMode mode)

+ 7 - 0
client/renderSDL/SDL_Extensions.cpp

@@ -12,7 +12,9 @@
 
 #include "SDL_PixelAccess.h"
 
+#include "../gui/CGuiHandler.h"
 #include "../render/Graphics.h"
+#include "../render/IScreenHandler.h"
 #include "../render/Colors.h"
 #include "../CMT.h"
 #include "../xBRZ/xbrz.h"
@@ -772,5 +774,10 @@ void CSDL_Ext::getClipRect(SDL_Surface * src, Rect & other)
 	other = CSDL_Ext::fromSDL(rect);
 }
 
+int CSDL_Ext::CClipRectGuard::getScalingFactor() const
+{
+	return GH.screenHandler().getScalingFactor();
+}
+
 template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<3>(int, int);
 template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<4>(int, int);

+ 1 - 4
client/renderSDL/SDL_Extensions.h

@@ -111,10 +111,7 @@ using TColorPutterAlpha = void (*)(uint8_t *&, const uint8_t &, const uint8_t &,
 		SDL_Surface * surf;
 		Rect oldRect;
 
-		int getScalingFactor() const
-		{
-			return 2;
-		}
+		int getScalingFactor() const;
 
 	public:
 		CClipRectGuard(SDL_Surface * surface, const Rect & rect): surf(surface)

+ 63 - 7
client/renderSDL/ScreenHandler.cpp

@@ -38,15 +38,14 @@ SDL_Surface * screen2 = nullptr; //and hlp surface (used to store not-active int
 SDL_Surface * screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
 
 static const std::string NAME = GameConstants::VCMI_VERSION; //application name
+static constexpr Point heroes3Resolution = Point(800, 600);
 
 std::tuple<int, int> ScreenHandler::getSupportedScalingRange() const
 {
-	// Renderer upscaling factor. TODO: make configurable
-	static const int scalingFactor = 2;
 	// H3 resolution, any resolution smaller than that is not correctly supported
-	static const Point minResolution = Point(800, 600) * scalingFactor;
+	static constexpr Point minResolution = heroes3Resolution;
 	// arbitrary limit on *downscaling*. Allow some downscaling, if requested by user. Should be generally limited to 100+ for all but few devices
-	static const double minimalScaling = 50;
+	static constexpr double minimalScaling = 50;
 
 	Point renderResolution = getRenderResolution();
 	double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
@@ -103,7 +102,15 @@ Point ScreenHandler::getPreferredLogicalResolution() const
 
 int ScreenHandler::getScalingFactor() const
 {
-	return 2;
+	switch (upscalingFilter)
+	{
+		case EUpscalingFilter::NONE: return 1;
+		case EUpscalingFilter::XBRZ_2: return 2;
+		case EUpscalingFilter::XBRZ_3: return 3;
+		case EUpscalingFilter::XBRZ_4: return 4;
+	}
+
+	throw std::runtime_error("invalid upscaling filter");
 }
 
 Point ScreenHandler::getLogicalResolution() const
@@ -303,12 +310,61 @@ void ScreenHandler::initializeWindow()
 		handleFatalError(message, true);
 	}
 
+	selectUpscalingFilter();
+	selectDownscalingFilter();
+
 	SDL_RendererInfo info;
 	SDL_GetRendererInfo(mainRenderer, &info);
-	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, settings["video"]["scalingMode"].String().c_str());
 	logGlobal->info("Created renderer %s", info.name);
 }
 
+EUpscalingFilter ScreenHandler::loadUpscalingFilter() const
+{
+	static const std::map<std::string, EUpscalingFilter> upscalingFilterTypes =
+	{
+		{"auto", EUpscalingFilter::AUTO },
+		{"none", EUpscalingFilter::NONE },
+		{"xbrz2", EUpscalingFilter::XBRZ_2 },
+		{"xbrz3", EUpscalingFilter::XBRZ_3 },
+		{"xbrz4", EUpscalingFilter::XBRZ_4 }
+	};
+
+	auto filterName = settings["video"]["upscalingFilter"].String();
+	auto filter = upscalingFilterTypes.at(filterName);
+
+	if (filter != EUpscalingFilter::AUTO)
+		return filter;
+
+	// else - autoselect
+	Point outputResolution = getRenderResolution();
+	Point logicalResolution = getPreferredLogicalResolution();
+
+	float scaleX = static_cast<float>(outputResolution.x) / logicalResolution.x;
+	float scaleY = static_cast<float>(outputResolution.x) / logicalResolution.x;
+	float scaling = std::min(scaleX, scaleY);
+
+	if (scaling <= 1.0f)
+		return EUpscalingFilter::NONE;
+	if (scaling <= 2.0f)
+		return EUpscalingFilter::XBRZ_2;
+	if (scaling <= 3.0f)
+		return EUpscalingFilter::XBRZ_3;
+
+	return EUpscalingFilter::XBRZ_4;
+}
+
+void ScreenHandler::selectUpscalingFilter()
+{
+	upscalingFilter	= loadUpscalingFilter();
+	logGlobal->debug("Selected upscaling filter %d", static_cast<int>(upscalingFilter));
+}
+
+void ScreenHandler::selectDownscalingFilter()
+{
+	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, settings["video"]["downscalingFilter"].String().c_str());
+	logGlobal->debug("Selected downscaling filter %s", settings["video"]["downscalingFilter"].String());
+}
+
 void ScreenHandler::initializeScreenBuffers()
 {
 #ifdef VCMI_ENDIAN_BIG
@@ -323,7 +379,7 @@ void ScreenHandler::initializeScreenBuffers()
 	int amask = 0xFF000000;
 #endif
 
-	auto logicalSize = getPreferredLogicalResolution();
+	auto logicalSize = getPreferredLogicalResolution() * getScalingFactor();
 	SDL_RenderSetLogicalSize(mainRenderer, logicalSize.x, logicalSize.y);
 
 	screen = SDL_CreateRGBSurface(0, logicalSize.x, logicalSize.y, 32, rmask, gmask, bmask, amask);

+ 19 - 0
client/renderSDL/ScreenHandler.h

@@ -29,9 +29,23 @@ enum class EWindowMode
 	FULLSCREEN_EXCLUSIVE
 };
 
+enum class EUpscalingFilter
+{
+	AUTO, // used only for loading from config, replaced with autoselected value on init
+	NONE,
+	//BILINEAR, // TODO?
+	//BICUBIC, // TODO?
+	XBRZ_2,
+	XBRZ_3,
+	XBRZ_4,
+	// NOTE: xbrz also provides x5 and x6 filters, but those would require high-end gaming PC's due to huge memory usage with no visible gain
+};
+
 /// This class is responsible for management of game window and its main rendering surface
 class ScreenHandler final : public IScreenHandler
 {
+	EUpscalingFilter upscalingFilter = EUpscalingFilter::AUTO;
+
 	/// Dimensions of target surfaces/textures, this value is what game logic views as screen size
 	Point getPreferredLogicalResolution() const;
 
@@ -69,6 +83,11 @@ class ScreenHandler final : public IScreenHandler
 
 	/// Performs validation of settings and updates them to valid values if necessary
 	void validateSettings();
+
+	EUpscalingFilter loadUpscalingFilter() const;
+
+	void selectDownscalingFilter();
+	void selectUpscalingFilter();
 public:
 
 	/// Creates and initializes screen, window and SDL state

+ 8 - 2
config/schemas/settings.json

@@ -166,7 +166,8 @@
 				"showfps",
 				"targetfps",
 				"vsync",
-				"scalingMode"
+				"upscalingFilter",
+				"downscalingFilter"
 			],
 			"properties" : {
 				"resolution" : {
@@ -230,7 +231,12 @@
 					"type" : "boolean",
 					"default" : true
 				},
-				"scalingMode" : {
+				"upscalingFilter" : {
+					"type" : "string",
+					"enum" : [ "auto", "none", "xbrz2", "xbrz3", "xbrz4" ],
+					"default" : "auto"
+				},
+				"downscalingFilter" : {
 					"type" : "string",
 					"enum" : [ "nearest", "linear", "best" ],
 					"default" : "best"

+ 21 - 2
launcher/settingsView/csettingsview_moc.cpp

@@ -39,6 +39,15 @@ static constexpr std::array cursorTypesList =
 };
 
 static constexpr std::array upscalingFilterTypes =
+{
+	"auto",
+	"none",
+	"xbrz2",
+	"xbrz3",
+	"xbrz4"
+};
+
+static constexpr std::array downscalingFilterTypes =
 {
 	"nearest",
 	"linear",
@@ -138,10 +147,14 @@ void CSettingsView::loadSettings()
 	Languages::fillLanguages(ui->comboBoxLanguage, false);
 	fillValidRenderers();
 
-	std::string upscalingFilter = settings["video"]["scalingMode"].String();
+	std::string upscalingFilter = settings["video"]["upscalingFilter"].String();
 	int upscalingFilterIndex = vstd::find_pos(upscalingFilterTypes, upscalingFilter);
 	ui->comboBoxUpscalingFilter->setCurrentIndex(upscalingFilterIndex);
 
+	std::string downscalingFilter = settings["video"]["downscalingFilter"].String();
+	int downscalingFilterIndex = vstd::find_pos(downscalingFilterTypes, upscalingFilter);
+	ui->comboBoxDownscalingFilter->setCurrentIndex(downscalingFilterIndex);
+
 	ui->sliderMusicVolume->setValue(settings["general"]["music"].Integer());
 	ui->sliderSoundVolume->setValue(settings["general"]["sound"].Integer());
 	ui->sliderRelativeCursorSpeed->setValue(settings["general"]["relativePointerSpeedMultiplier"].Integer());
@@ -645,10 +658,16 @@ void CSettingsView::on_buttonIgnoreSslErrors_clicked(bool checked)
 
 void CSettingsView::on_comboBoxUpscalingFilter_currentIndexChanged(int index)
 {
-	Settings node = settings.write["video"]["scalingMode"];
+	Settings node = settings.write["video"]["upscalingFilter"];
 	node->String() = upscalingFilterTypes[index];
 }
 
+void CSettingsView::on_comboBoxDownscalingFilter_currentIndexChanged(int index)
+{
+	Settings node = settings.write["video"]["downscalingFilter"];
+	node->String() = downscalingFilterTypes[index];
+}
+
 void CSettingsView::on_sliderMusicVolume_valueChanged(int value)
 {
 	Settings node = settings.write["general"]["music"];

+ 1 - 0
launcher/settingsView/csettingsview_moc.h

@@ -67,6 +67,7 @@ private slots:
 
 	void on_buttonIgnoreSslErrors_clicked(bool checked);
 	void on_comboBoxUpscalingFilter_currentIndexChanged(int index);
+	void on_comboBoxDownscalingFilter_currentIndexChanged(int index);
 	void on_sliderMusicVolume_valueChanged(int value);
 	void on_sliderSoundVolume_valueChanged(int value);
 	void on_buttonRelativeCursorMode_toggled(bool value);

+ 42 - 14
launcher/settingsView/csettingsview_moc.ui

@@ -48,8 +48,8 @@
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>730</width>
-        <height>1691</height>
+        <width>729</width>
+        <height>1396</height>
        </rect>
       </property>
       <layout class="QGridLayout" name="gridLayout" columnstretch="2,0,1,1,1">
@@ -57,7 +57,6 @@
         <widget class="QLabel" name="labelGeneral">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -301,7 +300,6 @@
         <widget class="QLabel" name="labelArtificialIntelligence">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -516,7 +514,6 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         <widget class="QLabel" name="labelVideo">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -532,7 +529,6 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         <widget class="QLabel" name="labelAudio">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -606,7 +602,7 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         </widget>
        </item>
        <item row="23" column="1" colspan="4">
-        <widget class="QComboBox" name="comboBoxUpscalingFilter">
+        <widget class="QComboBox" name="comboBoxDownscalingFilter">
          <item>
           <property name="text">
            <string>Nearest</string>
@@ -619,7 +615,7 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
          </item>
          <item>
           <property name="text">
-           <string>Best (Linear)</string>
+           <string>Automatic (Linear)</string>
           </property>
          </item>
         </widget>
@@ -747,7 +743,6 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         <widget class="QLabel" name="labelInputMouse_2">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -852,7 +847,6 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         <widget class="QLabel" name="labelNetwork">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -894,9 +888,9 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         </widget>
        </item>
        <item row="23" column="0">
-        <widget class="QLabel" name="labelUpscalingFilter">
+        <widget class="QLabel" name="labelDownscalingFilter">
          <property name="text">
-          <string>Upscaling Filter</string>
+          <string>Downscaling Filter</string>
          </property>
         </widget>
        </item>
@@ -942,7 +936,6 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         <widget class="QLabel" name="labelInputMouse">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -1020,7 +1013,6 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
         <widget class="QLabel" name="labelInputMouse_3">
          <property name="font">
           <font>
-           <weight>75</weight>
            <bold>true</bold>
           </font>
          </property>
@@ -1160,6 +1152,42 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
          </property>
         </widget>
        </item>
+       <item row="22" column="0">
+        <widget class="QLabel" name="labelUpscalingFilter">
+         <property name="text">
+          <string>Upscaling Filter</string>
+         </property>
+        </widget>
+       </item>
+       <item row="22" column="1" colspan="4">
+        <widget class="QComboBox" name="comboBoxUpscalingFilter">
+         <item>
+          <property name="text">
+           <string>Automatic</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>None</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>xBRZ x2</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>xBRZ x3</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>xBRZ x4</string>
+          </property>
+         </item>
+        </widget>
+       </item>
       </layout>
      </widget>
     </widget>