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

Quick fix for xbrz scaling artifacts on window borders

Ivan Savenko 10 сар өмнө
parent
commit
0842ada1c7

+ 1 - 1
client/render/IImage.h

@@ -115,7 +115,7 @@ public:
 
 	virtual std::shared_ptr<const ISharedImage> horizontalFlip() const = 0;
 	virtual std::shared_ptr<const ISharedImage> verticalFlip() const = 0;
-	virtual std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette) const = 0;
+	virtual std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const = 0;
 	virtual std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const = 0;
 
 

+ 1 - 1
client/renderSDL/CBitmapFont.cpp

@@ -201,7 +201,7 @@ CBitmapFont::CBitmapFont(const std::string & filename):
 		static const std::map<std::string, EScalingAlgorithm> filterNameToEnum = {
 			{ "nearest", EScalingAlgorithm::NEAREST},
 			{ "bilinear", EScalingAlgorithm::BILINEAR},
-			{ "xbrz", EScalingAlgorithm::XBRZ}
+			{ "xbrz", EScalingAlgorithm::XBRZ_ALPHA}
 		};
 
 		auto filterName = settings["video"]["fontUpscalingFilter"].String();

+ 10 - 4
client/renderSDL/SDLImage.cpp

@@ -278,7 +278,7 @@ void SDLImageShared::optimizeSurface()
 	}
 }
 
-std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palette * palette) const
+std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode mode) const
 {
 	if (factor <= 0)
 		throw std::runtime_error("Unable to scale by integer value of " + std::to_string(factor));
@@ -293,7 +293,13 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL
 	if(preScaleFactor == factor)
 		return shared_from_this();
 	else if(preScaleFactor == 1)
-		scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ);
+	{
+		// dump heuristics to differentiate tileable UI elements from map object / combat assets
+		if (mode == EImageBlitMode::OPAQUE || mode == EImageBlitMode::COLORKEY || mode == EImageBlitMode::SIMPLE)
+			scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_OPAQUE);
+		else
+			scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_ALPHA);
+	}
 	else
 		scaled = CSDL_Ext::scaleSurface(surf, (surf->w / preScaleFactor) * factor, (surf->h / preScaleFactor) * factor);
 
@@ -589,12 +595,12 @@ void SDLImageRGB::scaleTo(const Point & size)
 
 void SDLImageIndexed::scaleInteger(int factor)
 {
-	image = image->scaleInteger(factor, currentPalette);
+	image = image->scaleInteger(factor, currentPalette, blitMode);
 }
 
 void SDLImageRGB::scaleInteger(int factor)
 {
-	image = image->scaleInteger(factor, nullptr);
+	image = image->scaleInteger(factor, nullptr, blitMode);
 }
 
 void SDLImageRGB::exportBitmap(const boost::filesystem::path & path) const

+ 1 - 1
client/renderSDL/SDLImage.h

@@ -60,7 +60,7 @@ public:
 	std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const override;
 	std::shared_ptr<const ISharedImage> horizontalFlip() const override;
 	std::shared_ptr<const ISharedImage> verticalFlip() const override;
-	std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette) const override;
+	std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const override;
 	std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const override;
 
 	friend class SDLImageLoader;

+ 8 - 3
client/renderSDL/SDL_Extensions.cpp

@@ -683,12 +683,17 @@ SDL_Surface * CSDL_Ext::scaleSurfaceIntegerFactor(SDL_Surface * surf, int factor
 		case EScalingAlgorithm::BILINEAR:
 			xbrz::bilinearScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
 			break;
-		case EScalingAlgorithm::XBRZ:
-			tbb::parallel_for(tbb::blocked_range<size_t>(0, intermediate->h, granulation), [factor, srcPixels, dstPixels, intermediate](const tbb::blocked_range<size_t> & r)
+		case EScalingAlgorithm::XBRZ_ALPHA:
+		case EScalingAlgorithm::XBRZ_OPAQUE:
+		{
+			auto format = algorithm == EScalingAlgorithm::XBRZ_OPAQUE ? xbrz::ColorFormat::ARGB_CLAMPED : xbrz::ColorFormat::ARGB;
+			tbb::parallel_for(tbb::blocked_range<size_t>(0, intermediate->h, granulation), [factor, srcPixels, dstPixels, intermediate, format](const tbb::blocked_range<size_t> & r)
 			{
-				xbrz::scale(factor, srcPixels, dstPixels, intermediate->w, intermediate->h, xbrz::ColorFormat::ARGB, {}, r.begin(), r.end());
+
+				xbrz::scale(factor, srcPixels, dstPixels, intermediate->w, intermediate->h, format, {}, r.begin(), r.end());
 			});
 			break;
+		}
 		default:
 			throw std::runtime_error("invalid scaling algorithm!");
 	}

+ 2 - 1
client/renderSDL/SDL_Extensions.h

@@ -31,7 +31,8 @@ enum class EScalingAlgorithm : int8_t
 {
 	NEAREST,
 	BILINEAR,
-	XBRZ
+	XBRZ_OPAQUE, // xbrz, image edges are considered to have same color as pixel inside image
+	XBRZ_ALPHA // xbrz, image edges are considered to be transparent
 };
 
 namespace CSDL_Ext

+ 17 - 0
client/xBRZ/xbrz.cpp

@@ -1195,6 +1195,22 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth
             }
             break;
 
+        case ColorFormat::ARGB_CLAMPED:
+            switch (factor)
+            {
+                case 2:
+                    return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
+                case 3:
+                    return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
+                case 4:
+                    return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
+                case 5:
+                    return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
+                case 6:
+                    return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
+            }
+            break;
+
         case ColorFormat::ARGB:
             switch (factor)
             {
@@ -1238,6 +1254,7 @@ bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, doub
         case ColorFormat::RGB:
             return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
         case ColorFormat::ARGB:
+        case ColorFormat::ARGB_CLAMPED:
             return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
         case ColorFormat::ARGB_UNBUFFERED:
             return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;

+ 1 - 0
client/xBRZ/xbrz.h

@@ -44,6 +44,7 @@ enum class ColorFormat //from high bits -> low bits, 8 bit per channel
 {
     RGB,  //8 bit for each red, green, blue, upper 8 bits unused
     ARGB, //including alpha channel, BGRA byte order on little-endian machines
+    ARGB_CLAMPED, // like ARGB, but edges are treated as opaque, with same color as edge
     ARGB_UNBUFFERED, //like ARGB, but without the one-time buffer creation overhead (ca. 100 - 300 ms) at the expense of a slightly slower scaling time
 };