[Scummvm-git-logs] scummvm master -> ad722f31cc0e6cd73e4333d6b29ac4896e62dcb2

sev- sev at scummvm.org
Sat Jul 18 10:17:00 UTC 2020


This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
42019d4252 GRAPHICS: Move code for nearest neighbour scaling out of TransparentSurface
b2f2069fb0 GRAPHICS: Move code for bilinear scaling out of TransparentSurface
ff1474591f GRAPHICS: Allow using scaleBlitBilinear using different pixel formats and pitches
352653b8a2 GRAPHICS: Add a function for scaling a standard Graphics::Surface
ad722f31cc SCI32: Allow using HQ video with pixel formats other than RGBA8888


Commit: 42019d42527097a929ace8af1986b4b4124bad25
    https://github.com/scummvm/scummvm/commit/42019d42527097a929ace8af1986b4b4124bad25
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2020-07-18T12:16:52+02:00

Commit Message:
GRAPHICS: Move code for nearest neighbour scaling out of TransparentSurface

Changed paths:
    graphics/conversion.cpp
    graphics/conversion.h
    graphics/transparent_surface.cpp
    graphics/transparent_surface.h


diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp
index 27180b80ad..a9eaa7d80a 100644
--- a/graphics/conversion.cpp
+++ b/graphics/conversion.cpp
@@ -167,4 +167,59 @@ bool crossBlit(byte *dst, const byte *src,
 	return true;
 }
 
+namespace {
+
+template <typename Size>
+void scaleNN(byte *dst, const byte *src,
+               const uint dstPitch, const uint srcPitch,
+               const uint dstW, const uint dstH,
+               const uint srcW, const uint srcH,
+               int *scaleCacheX) {
+
+	const uint dstDelta = (dstPitch - dstW * sizeof(Size));
+
+	for (uint y = 0; y < dstH; y++) {
+		const Size *srcP = (const Size *)(src + ((y * srcH) / dstH) * srcPitch);
+		for (uint x = 0; x < dstW; x++) {
+			int val = srcP[scaleCacheX[x]];
+			*(Size *)dst = val;
+			dst += sizeof(Size);
+		}
+		dst += dstDelta;
+	}
+}
+
+} // End of anonymous namespace
+
+bool scaleBlit(byte *dst, const byte *src,
+               const uint dstPitch, const uint srcPitch,
+               const uint dstW, const uint dstH,
+               const uint srcW, const uint srcH,
+               const Graphics::PixelFormat &fmt) {
+
+	int *scaleCacheX = new int[dstW];
+	for (uint x = 0; x < dstW; x++) {
+		scaleCacheX[x] = (x * srcW) / dstW;
+	}
+
+	switch (fmt.bytesPerPixel) {
+	case 1:
+		scaleNN<uint8>(dst, src, dstPitch, srcPitch, dstW,  dstH, srcW, srcH, scaleCacheX);
+		break;
+	case 2:
+		scaleNN<uint16>(dst, src, dstPitch, srcPitch, dstW,  dstH, srcW, srcH, scaleCacheX);
+		break;
+	case 4:
+		scaleNN<uint32>(dst, src, dstPitch, srcPitch, dstW,  dstH, srcW, srcH, scaleCacheX);
+		break;
+	default:
+		delete[] scaleCacheX;
+		return false;
+	}
+
+	delete[] scaleCacheX;
+
+	return true;
+}
+			
 } // End of namespace Graphics
diff --git a/graphics/conversion.h b/graphics/conversion.h
index 8ca529acc0..04240c576d 100644
--- a/graphics/conversion.h
+++ b/graphics/conversion.h
@@ -72,6 +72,12 @@ bool crossBlit(byte *dst, const byte *src,
                const uint w, const uint h,
                const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt);
 
+bool scaleBlit(byte *dst, const byte *src,
+               const uint dstPitch, const uint srcPitch,
+               const uint dstW, const uint dstH,
+               const uint srcW, const uint srcH,
+               const Graphics::PixelFormat &fmt);
+
 } // End of namespace Graphics
 
 #endif // GRAPHICS_CONVERSION_H
diff --git a/graphics/transparent_surface.cpp b/graphics/transparent_surface.cpp
index eb8d3fe5ce..94d206ebb1 100644
--- a/graphics/transparent_surface.cpp
+++ b/graphics/transparent_surface.cpp
@@ -33,6 +33,7 @@
 #include "common/rect.h"
 #include "common/math.h"
 #include "common/textconsole.h"
+#include "graphics/conversion.h"
 #include "graphics/primitives.h"
 #include "graphics/transparent_surface.h"
 #include "graphics/transform_tools.h"
@@ -1068,26 +1069,7 @@ TransparentSurface *TransparentSurface::scaleT(uint16 newWidth, uint16 newHeight
 		delete[] say;
 
 	} else {
-		int *scaleCacheX = new int[dstW];
-		for (int x = 0; x < dstW; x++) {
-			scaleCacheX[x] = (x * srcW) / dstW;
-		}
-
-		switch (format.bytesPerPixel) {
-		case 1:
-			scaleNN<uint8>(scaleCacheX, target);
-			break;
-		case 2:
-			scaleNN<uint16>(scaleCacheX, target);
-			break;
-		case 4:
-			scaleNN<uint32>(scaleCacheX, target);
-			break;
-		default:
-			error("Can only scale 8bpp, 16bpp, and 32bpp");
-		}
-
-		delete[] scaleCacheX;
+		scaleBlit((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, dstW, dstH, srcW, srcH, format);
 	}
 
 	return target;
@@ -1171,26 +1153,11 @@ TransparentSurface *TransparentSurface::convertTo(const PixelFormat &dstFormat,
 	return surface;
 }
 
-template <typename Size>
-void TransparentSurface::scaleNN(int *scaleCacheX, TransparentSurface *target) const {
-	for (int y = 0; y < target->h; y++) {
-		Size *destP = (Size *)target->getBasePtr(0, y);
-		const Size *srcP = (const Size *)getBasePtr(0, (y * h) / target->h);
-		for (int x = 0; x < target->w; x++) {
-			*destP++ = srcP[scaleCacheX[x]];
-		}
-	}
-}
-
 template TransparentSurface *TransparentSurface::rotoscaleT<FILTER_NEAREST>(const TransformStruct &transform) const;
 template TransparentSurface *TransparentSurface::rotoscaleT<FILTER_BILINEAR>(const TransformStruct &transform) const;
 template TransparentSurface *TransparentSurface::scaleT<FILTER_NEAREST>(uint16 newWidth, uint16 newHeight) const;
 template TransparentSurface *TransparentSurface::scaleT<FILTER_BILINEAR>(uint16 newWidth, uint16 newHeight) const;
 
-template void TransparentSurface::scaleNN<uint8>(int *scaleCacheX, TransparentSurface *target) const;
-template void TransparentSurface::scaleNN<uint16>(int *scaleCacheX, TransparentSurface *target) const;
-template void TransparentSurface::scaleNN<uint32>(int *scaleCacheX, TransparentSurface *target) const;
-
 TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
 	return rotoscaleT<FILTER_BILINEAR>(transform);
 }
diff --git a/graphics/transparent_surface.h b/graphics/transparent_surface.h
index 8bfddef8c1..3c2b29b7b3 100644
--- a/graphics/transparent_surface.h
+++ b/graphics/transparent_surface.h
@@ -177,9 +177,6 @@ struct TransparentSurface : public Graphics::Surface {
 	void setAlphaMode(AlphaType);
 private:
 	AlphaType _alphaMode;
-
-	template <typename Size>
-	void scaleNN(int *scaleCacheX, TransparentSurface *target) const;
 };
 
 /**


Commit: b2f2069fb0472717ecfae33dbd1e4ac3e667f535
    https://github.com/scummvm/scummvm/commit/b2f2069fb0472717ecfae33dbd1e4ac3e667f535
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2020-07-18T12:16:52+02:00

Commit Message:
GRAPHICS: Move code for bilinear scaling out of TransparentSurface

Changed paths:
    graphics/conversion.cpp
    graphics/conversion.h
    graphics/transparent_surface.cpp


diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp
index a9eaa7d80a..e86c8217b9 100644
--- a/graphics/conversion.cpp
+++ b/graphics/conversion.cpp
@@ -221,5 +221,201 @@ bool scaleBlit(byte *dst, const byte *src,
 
 	return true;
 }
-			
+
+/*
+
+The function below is adapted from SDL_rotozoom.c,
+taken from SDL_gfx-2.0.18.
+
+Its copyright notice:
+
+=============================================================================
+SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
+
+Copyright (C) 2001-2012  Andreas Schiffler
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+
+Andreas Schiffler -- aschiffler at ferzkopp dot net
+=============================================================================
+
+
+The functions have been adapted for different structures and coordinate
+systems.
+
+*/
+
+struct tColorRGBA { byte r; byte g; byte b; byte a; };
+
+bool scaleBlitBilinear(byte *dst, const byte *src,
+                       const uint dstPitch, const uint srcPitch,
+                       const uint dstW, const uint dstH,
+                       const uint srcW, const uint srcH,
+                       const Graphics::PixelFormat &fmt) {
+	assert(fmt.bytesPerPixel == 4);
+
+	bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
+
+
+	int *sax = new int[dstW + 1];
+	int *say = new int[dstH + 1];
+	assert(sax && say);
+
+	/*
+	* Precalculate row increments
+	*/
+	int spixelw = (srcW - 1);
+	int spixelh = (srcH - 1);
+	int sx = (int)(65536.0f * (float) spixelw / (float) (dstW - 1));
+	int sy = (int)(65536.0f * (float) spixelh / (float) (dstH - 1));
+
+	/* Maximum scaled source size */
+	int ssx = (srcW << 16) - 1;
+	int ssy = (srcH << 16) - 1;
+
+	/* Precalculate horizontal row increments */
+	int csx = 0;
+	int *csax = sax;
+	for (uint x = 0; x <= dstW; x++) {
+		*csax = csx;
+		csax++;
+		csx += sx;
+
+		/* Guard from overflows */
+		if (csx > ssx) {
+			csx = ssx;
+		}
+	}
+
+	/* Precalculate vertical row increments */
+	int csy = 0;
+	int *csay = say;
+	for (uint y = 0; y <= dstH; y++) {
+		*csay = csy;
+		csay++;
+		csy += sy;
+
+		/* Guard from overflows */
+		if (csy > ssy) {
+			csy = ssy;
+		}
+	}
+
+	const tColorRGBA *sp = (const tColorRGBA *) src;
+	tColorRGBA *dp = (tColorRGBA *) dst;
+	int spixelgap = srcW;
+
+	if (flipx) {
+		sp += spixelw;
+	}
+	if (flipy) {
+		sp += spixelgap * spixelh;
+	}
+
+	csay = say;
+	for (uint y = 0; y < dstH; y++) {
+		const tColorRGBA *csp = sp;
+		csax = sax;
+		for (uint x = 0; x < dstW; x++) {
+			/*
+			* Setup color source pointers
+			*/
+			int ex = (*csax & 0xffff);
+			int ey = (*csay & 0xffff);
+			int cx = (*csax >> 16);
+			int cy = (*csay >> 16);
+
+			const tColorRGBA *c00, *c01, *c10, *c11;
+			c00 = sp;
+			c01 = sp;
+			c10 = sp;
+			if (cy < spixelh) {
+				if (flipy) {
+					c10 -= spixelgap;
+				} else {
+					c10 += spixelgap;
+				}
+			}
+			c11 = c10;
+			if (cx < spixelw) {
+				if (flipx) {
+					c01--;
+					c11--;
+				} else {
+					c01++;
+					c11++;
+				}
+			}
+
+			/*
+			* Draw and interpolate colors
+			*/
+			int t1, t2;
+			t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
+			t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
+			dp->r = (((t2 - t1) * ey) >> 16) + t1;
+			t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
+			t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
+			dp->g = (((t2 - t1) * ey) >> 16) + t1;
+			t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
+			t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
+			dp->b = (((t2 - t1) * ey) >> 16) + t1;
+			t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
+			t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
+			dp->a = (((t2 - t1) * ey) >> 16) + t1;
+
+			/*
+			* Advance source pointer x
+			*/
+			int *salastx = csax;
+			csax++;
+			int sstepx = (*csax >> 16) - (*salastx >> 16);
+			if (flipx) {
+				sp -= sstepx;
+			} else {
+				sp += sstepx;
+			}
+
+			/*
+			* Advance destination pointer x
+			*/
+			dp++;
+		}
+		/*
+		* Advance source pointer y
+		*/
+		int *salasty = csay;
+		csay++;
+		int sstepy = (*csay >> 16) - (*salasty >> 16);
+		sstepy *= spixelgap;
+		if (flipy) {
+			sp = csp - sstepy;
+		} else {
+			sp = csp + sstepy;
+		}
+	}
+
+	delete[] sax;
+	delete[] say;
+
+	return true;
+}
+
 } // End of namespace Graphics
diff --git a/graphics/conversion.h b/graphics/conversion.h
index 04240c576d..1e5486864a 100644
--- a/graphics/conversion.h
+++ b/graphics/conversion.h
@@ -78,6 +78,12 @@ bool scaleBlit(byte *dst, const byte *src,
                const uint srcW, const uint srcH,
                const Graphics::PixelFormat &fmt);
 
+bool scaleBlitBilinear(byte *dst, const byte *src,
+                       const uint dstPitch, const uint srcPitch,
+                       const uint dstW, const uint dstH,
+                       const uint srcW, const uint srcH,
+                       const Graphics::PixelFormat &fmt);
+
 } // End of namespace Graphics
 
 #endif // GRAPHICS_CONVERSION_H
diff --git a/graphics/transparent_surface.cpp b/graphics/transparent_surface.cpp
index 94d206ebb1..4d9000914f 100644
--- a/graphics/transparent_surface.cpp
+++ b/graphics/transparent_surface.cpp
@@ -751,7 +751,7 @@ void TransparentSurface::setAlphaMode(AlphaType mode) {
 
 /*
 
-The below two functions are adapted from SDL_rotozoom.c,
+The function below is adapted from SDL_rotozoom.c,
 taken from SDL_gfx-2.0.18.
 
 Its copyright notice:
@@ -914,162 +914,12 @@ TransparentSurface *TransparentSurface::scaleT(uint16 newWidth, uint16 newHeight
 
 	TransparentSurface *target = new TransparentSurface();
 
-	int srcW = w;
-	int srcH = h;
-	int dstW = newWidth;
-	int dstH = newHeight;
-
-	target->create((uint16)dstW, (uint16)dstH, format);
+	target->create(newWidth, newHeight, format);
 
 	if (filteringMode == FILTER_BILINEAR) {
-		assert(format.bytesPerPixel == 4);
-
-		bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
-
-
-		int *sax = new int[dstW + 1];
-		int *say = new int[dstH + 1];
-		assert(sax && say);
-
-		/*
-		* Precalculate row increments
-		*/
-		int spixelw = (srcW - 1);
-		int spixelh = (srcH - 1);
-		int sx = (int)(65536.0f * (float) spixelw / (float) (dstW - 1));
-		int sy = (int)(65536.0f * (float) spixelh / (float) (dstH - 1));
-
-		/* Maximum scaled source size */
-		int ssx = (srcW << 16) - 1;
-		int ssy = (srcH << 16) - 1;
-
-		/* Precalculate horizontal row increments */
-		int csx = 0;
-		int *csax = sax;
-		for (int x = 0; x <= dstW; x++) {
-			*csax = csx;
-			csax++;
-			csx += sx;
-
-			/* Guard from overflows */
-			if (csx > ssx) {
-				csx = ssx;
-			}
-		}
-
-		/* Precalculate vertical row increments */
-		int csy = 0;
-		int *csay = say;
-		for (int y = 0; y <= dstH; y++) {
-			*csay = csy;
-			csay++;
-			csy += sy;
-
-			/* Guard from overflows */
-			if (csy > ssy) {
-				csy = ssy;
-			}
-		}
-
-		const tColorRGBA *sp = (const tColorRGBA *) getBasePtr(0, 0);
-		tColorRGBA *dp = (tColorRGBA *) target->getBasePtr(0, 0);
-		int spixelgap = srcW;
-
-		if (flipx) {
-			sp += spixelw;
-		}
-		if (flipy) {
-			sp += spixelgap * spixelh;
-		}
-
-		csay = say;
-		for (int y = 0; y < dstH; y++) {
-			const tColorRGBA *csp = sp;
-			csax = sax;
-			for (int x = 0; x < dstW; x++) {
-				/*
-				* Setup color source pointers
-				*/
-				int ex = (*csax & 0xffff);
-				int ey = (*csay & 0xffff);
-				int cx = (*csax >> 16);
-				int cy = (*csay >> 16);
-
-				const tColorRGBA *c00, *c01, *c10, *c11;
-				c00 = sp;
-				c01 = sp;
-				c10 = sp;
-				if (cy < spixelh) {
-					if (flipy) {
-						c10 -= spixelgap;
-					} else {
-						c10 += spixelgap;
-					}
-				}
-				c11 = c10;
-				if (cx < spixelw) {
-					if (flipx) {
-						c01--;
-						c11--;
-					} else {
-						c01++;
-						c11++;
-					}
-				}
-
-				/*
-				* Draw and interpolate colors
-				*/
-				int t1, t2;
-				t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
-				t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
-				dp->r = (((t2 - t1) * ey) >> 16) + t1;
-				t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
-				t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
-				dp->g = (((t2 - t1) * ey) >> 16) + t1;
-				t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
-				t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
-				dp->b = (((t2 - t1) * ey) >> 16) + t1;
-				t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
-				t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
-				dp->a = (((t2 - t1) * ey) >> 16) + t1;
-
-				/*
-				* Advance source pointer x
-				*/
-				int *salastx = csax;
-				csax++;
-				int sstepx = (*csax >> 16) - (*salastx >> 16);
-				if (flipx) {
-					sp -= sstepx;
-				} else {
-					sp += sstepx;
-				}
-
-				/*
-				* Advance destination pointer x
-				*/
-				dp++;
-			}
-			/*
-			* Advance source pointer y
-			*/
-			int *salasty = csay;
-			csay++;
-			int sstepy = (*csay >> 16) - (*salasty >> 16);
-			sstepy *= spixelgap;
-			if (flipy) {
-				sp = csp - sstepy;
-			} else {
-				sp = csp + sstepy;
-			}
-		}
-
-		delete[] sax;
-		delete[] say;
-
+		scaleBlitBilinear((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, target->w, target->h, w, h, format);
 	} else {
-		scaleBlit((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, dstW, dstH, srcW, srcH, format);
+		scaleBlit((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, target->w, target->h, w, h, format);
 	}
 
 	return target;


Commit: ff1474591ffe5d7155e8b3e2f987ef3511c0bb04
    https://github.com/scummvm/scummvm/commit/ff1474591ffe5d7155e8b3e2f987ef3511c0bb04
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2020-07-18T12:16:52+02:00

Commit Message:
GRAPHICS: Allow using scaleBlitBilinear using different pixel formats and pitches

Changed paths:
    graphics/conversion.cpp


diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp
index e86c8217b9..8df8a53b9f 100644
--- a/graphics/conversion.cpp
+++ b/graphics/conversion.cpp
@@ -224,7 +224,7 @@ bool scaleBlit(byte *dst, const byte *src,
 
 /*
 
-The function below is adapted from SDL_rotozoom.c,
+The functions below are adapted from SDL_rotozoom.c,
 taken from SDL_gfx-2.0.18.
 
 Its copyright notice:
@@ -257,82 +257,66 @@ Andreas Schiffler -- aschiffler at ferzkopp dot net
 =============================================================================
 
 
-The functions have been adapted for different structures and coordinate
-systems.
+The functions have been adapted for different structures, coordinate
+systems and pixel formats.
 
 */
 
-struct tColorRGBA { byte r; byte g; byte b; byte a; };
-
-bool scaleBlitBilinear(byte *dst, const byte *src,
-                       const uint dstPitch, const uint srcPitch,
-                       const uint dstW, const uint dstH,
-                       const uint srcW, const uint srcH,
-                       const Graphics::PixelFormat &fmt) {
-	assert(fmt.bytesPerPixel == 4);
-
-	bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
+namespace {
 
+inline byte scaleBlitBilinearInterpolate(byte c01, byte c00, byte c11, byte c10, int ex, int ey) {
+	int t1 = ((((c01 - c00) * ex) >> 16) + c00) & 0xff;
+	int t2 = ((((c11 - c10) * ex) >> 16) + c10) & 0xff;
+	return (((t2 - t1) * ey) >> 16) + t1;
+}
 
-	int *sax = new int[dstW + 1];
-	int *say = new int[dstH + 1];
-	assert(sax && say);
+template <typename Size>
+Size scaleBlitBilinearInterpolate(Size c01, Size c00, Size c11, Size c10, int ex, int ey,
+                                  const Graphics::PixelFormat &fmt) {
+	byte c01_a, c01_r, c01_g, c01_b;
+	fmt.colorToARGB(c01, c01_a, c01_r, c01_g, c01_b);
 
-	/*
-	* Precalculate row increments
-	*/
-	int spixelw = (srcW - 1);
-	int spixelh = (srcH - 1);
-	int sx = (int)(65536.0f * (float) spixelw / (float) (dstW - 1));
-	int sy = (int)(65536.0f * (float) spixelh / (float) (dstH - 1));
+	byte c00_a, c00_r, c00_g, c00_b;
+	fmt.colorToARGB(c00, c00_a, c00_r, c00_g, c00_b);
 
-	/* Maximum scaled source size */
-	int ssx = (srcW << 16) - 1;
-	int ssy = (srcH << 16) - 1;
+	byte c11_a, c11_r, c11_g, c11_b;
+	fmt.colorToARGB(c11, c11_a, c11_r, c11_g, c11_b);
 
-	/* Precalculate horizontal row increments */
-	int csx = 0;
-	int *csax = sax;
-	for (uint x = 0; x <= dstW; x++) {
-		*csax = csx;
-		csax++;
-		csx += sx;
+	byte c10_a, c10_r, c10_g, c10_b;
+	fmt.colorToARGB(c10, c10_a, c10_r, c10_g, c10_b);
 
-		/* Guard from overflows */
-		if (csx > ssx) {
-			csx = ssx;
-		}
-	}
+	byte dp_a = scaleBlitBilinearInterpolate(c01_a, c00_a, c11_a, c10_a, ex, ey);
+	byte dp_r = scaleBlitBilinearInterpolate(c01_r, c00_r, c11_r, c10_r, ex, ey);
+	byte dp_g = scaleBlitBilinearInterpolate(c01_g, c00_g, c11_g, c10_g, ex, ey);
+	byte dp_b = scaleBlitBilinearInterpolate(c01_b, c00_b, c11_b, c10_b, ex, ey);
+	return fmt.ARGBToColor(dp_a, dp_r, dp_g, dp_b);
+}
 
-	/* Precalculate vertical row increments */
-	int csy = 0;
-	int *csay = say;
-	for (uint y = 0; y <= dstH; y++) {
-		*csay = csy;
-		csay++;
-		csy += sy;
+template <typename Size, bool flipx, bool flipy> // TODO: See mirroring comment in RenderTicket ctor
+void scaleBlitBilinearLogic(byte *dst, const byte *src,
+                            const uint dstPitch, const uint srcPitch,
+                            const uint dstW, const uint dstH,
+							const uint srcW, const uint srcH,
+                            const Graphics::PixelFormat &fmt,
+                            int *sax, int *say) {
 
-		/* Guard from overflows */
-		if (csy > ssy) {
-			csy = ssy;
-		}
-	}
+	int spixelw = (srcW - 1);
+	int spixelh = (srcH - 1);
 
-	const tColorRGBA *sp = (const tColorRGBA *) src;
-	tColorRGBA *dp = (tColorRGBA *) dst;
-	int spixelgap = srcW;
+	const byte *sp = src;
 
 	if (flipx) {
 		sp += spixelw;
 	}
 	if (flipy) {
-		sp += spixelgap * spixelh;
+		sp += srcPitch * spixelh;
 	}
 
-	csay = say;
+	int *csay = say;
 	for (uint y = 0; y < dstH; y++) {
-		const tColorRGBA *csp = sp;
-		csax = sax;
+		Size *dp = (Size *)(dst + (dstPitch * y));
+		const byte *csp = sp;
+		int *csax = sax;
 		for (uint x = 0; x < dstW; x++) {
 			/*
 			* Setup color source pointers
@@ -342,45 +326,30 @@ bool scaleBlitBilinear(byte *dst, const byte *src,
 			int cx = (*csax >> 16);
 			int cy = (*csay >> 16);
 
-			const tColorRGBA *c00, *c01, *c10, *c11;
-			c00 = sp;
-			c01 = sp;
-			c10 = sp;
+			const byte *c00, *c01, *c10, *c11;
+			c00 = c01 = c10 = sp;
 			if (cy < spixelh) {
 				if (flipy) {
-					c10 -= spixelgap;
+					c10 -= srcPitch;
 				} else {
-					c10 += spixelgap;
+					c10 += srcPitch;
 				}
 			}
 			c11 = c10;
 			if (cx < spixelw) {
 				if (flipx) {
-					c01--;
-					c11--;
+					c01 -= sizeof(Size);
+					c11 -= sizeof(Size);
 				} else {
-					c01++;
-					c11++;
+					c01 += sizeof(Size);
+					c11 += sizeof(Size);
 				}
 			}
 
 			/*
 			* Draw and interpolate colors
 			*/
-			int t1, t2;
-			t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
-			t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
-			dp->r = (((t2 - t1) * ey) >> 16) + t1;
-			t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
-			t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
-			dp->g = (((t2 - t1) * ey) >> 16) + t1;
-			t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
-			t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
-			dp->b = (((t2 - t1) * ey) >> 16) + t1;
-			t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
-			t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
-			dp->a = (((t2 - t1) * ey) >> 16) + t1;
-
+			*dp = scaleBlitBilinearInterpolate(*(const Size *)c01, *(const Size *)c00, *(const Size *)c11, *(const Size *)c10, ex, ey, fmt);
 			/*
 			* Advance source pointer x
 			*/
@@ -388,9 +357,9 @@ bool scaleBlitBilinear(byte *dst, const byte *src,
 			csax++;
 			int sstepx = (*csax >> 16) - (*salastx >> 16);
 			if (flipx) {
-				sp -= sstepx;
+				sp -= sstepx * sizeof(Size);
 			} else {
-				sp += sstepx;
+				sp += sstepx * sizeof(Size);
 			}
 
 			/*
@@ -404,13 +373,79 @@ bool scaleBlitBilinear(byte *dst, const byte *src,
 		int *salasty = csay;
 		csay++;
 		int sstepy = (*csay >> 16) - (*salasty >> 16);
-		sstepy *= spixelgap;
+		sstepy *= srcPitch;
 		if (flipy) {
 			sp = csp - sstepy;
 		} else {
 			sp = csp + sstepy;
 		}
 	}
+}
+
+} // End of anonymous namespace
+
+bool scaleBlitBilinear(byte *dst, const byte *src,
+                       const uint dstPitch, const uint srcPitch,
+                       const uint dstW, const uint dstH,
+                       const uint srcW, const uint srcH,
+                       const Graphics::PixelFormat &fmt) {
+	if (fmt.bytesPerPixel != 2 && fmt.bytesPerPixel != 4)
+		return false;
+
+	int *sax = new int[dstW + 1];
+	int *say = new int[dstH + 1];
+	assert(sax && say);
+
+	/*
+	* Precalculate row increments
+	*/
+	int spixelw = (srcW - 1);
+	int spixelh = (srcH - 1);
+	int sx = (int)(65536.0f * (float) spixelw / (float) (dstW - 1));
+	int sy = (int)(65536.0f * (float) spixelh / (float) (dstH - 1));
+
+	/* Maximum scaled source size */
+	int ssx = (srcW << 16) - 1;
+	int ssy = (srcH << 16) - 1;
+
+	/* Precalculate horizontal row increments */
+	int csx = 0;
+	int *csax = sax;
+	for (uint x = 0; x <= dstW; x++) {
+		*csax = csx;
+		csax++;
+		csx += sx;
+
+		/* Guard from overflows */
+		if (csx > ssx) {
+			csx = ssx;
+		}
+	}
+
+	/* Precalculate vertical row increments */
+	int csy = 0;
+	int *csay = say;
+	for (uint y = 0; y <= dstH; y++) {
+		*csay = csy;
+		csay++;
+		csy += sy;
+
+		/* Guard from overflows */
+		if (csy > ssy) {
+			csy = ssy;
+		}
+	}
+
+	if (fmt.bytesPerPixel == 4) {
+		scaleBlitBilinearLogic<uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
+	} else if (fmt.bytesPerPixel == 2) {
+		scaleBlitBilinearLogic<uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
+	} else {
+		delete[] sax;
+		delete[] say;
+
+		return false;
+	}
 
 	delete[] sax;
 	delete[] say;


Commit: 352653b8a2d491f9c1bc514a17ec720a31f71e3d
    https://github.com/scummvm/scummvm/commit/352653b8a2d491f9c1bc514a17ec720a31f71e3d
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2020-07-18T12:16:52+02:00

Commit Message:
GRAPHICS: Add a function for scaling a standard Graphics::Surface

This also makes use of it in the SCI and Wintermute engines

Changed paths:
    engines/sci/graphics/video32.cpp
    engines/wintermute/base/base_persistence_manager.cpp
    engines/wintermute/base/gfx/base_image.cpp
    engines/wintermute/base/gfx/osystem/render_ticket.cpp
    graphics/surface.cpp
    graphics/surface.h
    graphics/transparent_surface.cpp
    graphics/transparent_surface.h


diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 6b8f9e54b5..5b164bc9a0 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -30,7 +30,6 @@
 #include "common/system.h"               // for g_system
 #include "engines/engine.h"              // for Engine, g_engine
 #include "graphics/palette.h"            // for PaletteManager
-#include "graphics/transparent_surface.h" // for TransparentSurface
 #include "sci/console.h"                 // for Console
 #include "sci/engine/features.h"         // for GameFeatures
 #include "sci/engine/state.h"            // for EngineState
@@ -242,20 +241,16 @@ void VideoPlayer::renderFrame(const Graphics::Surface &nextFrame) const {
 
 	if (_decoder->getWidth() != _drawRect.width() || _decoder->getHeight() != _drawRect.height()) {
 		Graphics::Surface *const unscaledFrame(convertedFrame);
-		// TODO: The only reason TransparentSurface is used here because it is
-		// where common scaler code is right now, which should just be part of
-		// Graphics::Surface (or some free functions).
-		const Graphics::TransparentSurface tsUnscaledFrame(*unscaledFrame);
 #ifdef USE_RGB_COLOR
 		if (_hqVideoMode) {
-			convertedFrame = tsUnscaledFrame.scaleT<Graphics::FILTER_BILINEAR>(_drawRect.width(), _drawRect.height());
+			convertedFrame = unscaledFrame->scale(_drawRect.width(), _drawRect.height(), true);
 		} else {
 #elif 1
 		{
 #else
 		}
 #endif
-			convertedFrame = tsUnscaledFrame.scaleT<Graphics::FILTER_NEAREST>(_drawRect.width(), _drawRect.height());
+			convertedFrame = unscaledFrame->scale(_drawRect.width(), _drawRect.height(), false);
 		}
 		assert(convertedFrame);
 		if (freeConvertedFrame) {
diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp
index 5a694e7ce2..ad38f5d529 100644
--- a/engines/wintermute/base/base_persistence_manager.cpp
+++ b/engines/wintermute/base/base_persistence_manager.cpp
@@ -36,7 +36,6 @@
 #include "engines/wintermute/base/gfx/base_image.h"
 #include "engines/wintermute/base/save_thumb_helper.h"
 #include "engines/wintermute/base/sound/base_sound.h"
-#include "graphics/transparent_surface.h"
 #include "engines/wintermute/wintermute.h"
 #include "graphics/scaler.h"
 #include "image/bmp.h"
@@ -173,11 +172,9 @@ void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &des
 		Image::BitmapDecoder bmpDecoder;
 		if (bmpDecoder.loadStream(thumbStream)) {
 			const Graphics::Surface *bmpSurface = bmpDecoder.getSurface();
-			Graphics::TransparentSurface *scaleableSurface = new Graphics::TransparentSurface(*bmpSurface, false);
-			Graphics::Surface *scaled = scaleableSurface->scale(kThumbnailWidth, kThumbnailHeight2);
+			Graphics::Surface *scaled = bmpSurface->scale(kThumbnailWidth, kThumbnailHeight2);
 			Graphics::Surface *thumb = scaled->convertTo(g_system->getOverlayFormat());
 			desc.setThumbnail(thumb);
-			delete scaleableSurface;
 			scaled->free();
 			delete scaled;
 		}
diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp
index a1548b83ea..963de43fc8 100644
--- a/engines/wintermute/base/gfx/base_image.cpp
+++ b/engines/wintermute/base/gfx/base_image.cpp
@@ -28,7 +28,6 @@
 
 #include "engines/wintermute/base/gfx/base_image.h"
 #include "engines/wintermute/base/base_file_manager.h"
-#include "graphics/transparent_surface.h"
 #include "graphics/surface.h"
 #include "image/png.h"
 #include "image/jpeg.h"
@@ -112,14 +111,13 @@ bool BaseImage::saveBMPFile(const Common::String &filename) const {
 //////////////////////////////////////////////////////////////////////////
 bool BaseImage::resize(int newWidth, int newHeight) {
 	// WME Lite used FILTER_BILINEAR with FreeImage_Rescale here.
-	Graphics::TransparentSurface temp(*_surface, true);
+	Graphics::Surface *temp = _surface->scale((uint16)newWidth, (uint16)newHeight);
 	if (_deletableSurface) {
 		_deletableSurface->free();
 		delete _deletableSurface;
 		_deletableSurface = nullptr;
 	}
-	_surface = _deletableSurface = temp.scale((uint16)newWidth, (uint16)newHeight);
-	temp.free();
+	_surface = _deletableSurface = temp;
 	return true;
 }
 
@@ -216,13 +214,13 @@ bool BaseImage::writeBMPToStream(Common::WriteStream *stream) const {
 bool BaseImage::copyFrom(BaseImage *origImage, int newWidth, int newHeight) {
 	// WME Lite used FILTER_BILINEAR with FreeImage_Rescale here.
 
-	Graphics::TransparentSurface temp(*origImage->_surface, false);
+	Graphics::Surface *temp = origImage->_surface->scale((uint16)newWidth, (uint16)newHeight);
 	if (_deletableSurface) {
 		_deletableSurface->free();
 		delete _deletableSurface;
 		_deletableSurface = nullptr;
 	}
-	_surface = _deletableSurface = temp.scale((uint16)newWidth, (uint16)newHeight);
+	_surface = _deletableSurface = temp;
 	return true;
 }
 
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
index e092e3cf17..d5297d6529 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
@@ -72,13 +72,7 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s
 		} else if ((dstRect->width() != srcRect->width() ||
 					dstRect->height() != srcRect->height()) &&
 					_transform._numTimesX * _transform._numTimesY == 1) {
-			Graphics::TransparentSurface src(*_surface, false);
-			Graphics::Surface *temp;
-			if (owner->_gameRef->getBilinearFiltering()) {
-				temp = src.scaleT<Graphics::FILTER_BILINEAR>(dstRect->width(), dstRect->height());
-			} else {
-				temp = src.scaleT<Graphics::FILTER_NEAREST>(dstRect->width(), dstRect->height());
-			}
+			Graphics::Surface *temp = _surface->scale(dstRect->width(), dstRect->height(), owner->_gameRef->getBilinearFiltering());
 			_surface->free();
 			delete _surface;
 			_surface = temp;
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index e2e3401cc2..d389f139ef 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -368,6 +368,21 @@ void Surface::flipVertical(const Common::Rect &r) {
 	delete[] temp;
 }
 
+Graphics::Surface *Surface::scale(uint16 newWidth, uint16 newHeight, bool filtering) const {
+
+	Graphics::Surface *target = new Graphics::Surface();
+
+	target->create(newWidth, newHeight, format);
+
+	if (filtering) {
+		scaleBlitBilinear((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, target->w, target->h, w, h, format);
+	} else {
+		scaleBlit((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, target->w, target->h, w, h, format);
+	}
+
+	return target;
+}
+
 void Surface::convertToInPlace(const PixelFormat &dstFormat, const byte *palette) {
 	// Do not convert to the same format and ignore empty surfaces.
 	if (format == dstFormat || pixels == 0) {
diff --git a/graphics/surface.h b/graphics/surface.h
index 8728106273..b7ada5ec28 100644
--- a/graphics/surface.h
+++ b/graphics/surface.h
@@ -334,6 +334,19 @@ public:
 	 * @param r Rect to flip
 	 */
 	void flipVertical(const Common::Rect &r);
+
+	/**
+	 * Scale the data to the given size.
+	 *
+	 * The calling code must call free on the returned surface and then delete
+	 * it.
+	 *
+	 * @param newWidth the resulting width.
+	 * @param newHeight the resulting height.
+	 * @param filtering Whether or not to use bilinear filtering.
+	 */
+	Graphics::Surface *scale(uint16 newWidth, uint16 newHeight, bool filtering = false) const;
+
 };
 
 /**
diff --git a/graphics/transparent_surface.cpp b/graphics/transparent_surface.cpp
index 4d9000914f..21dd893b47 100644
--- a/graphics/transparent_surface.cpp
+++ b/graphics/transparent_surface.cpp
@@ -909,14 +909,13 @@ TransparentSurface *TransparentSurface::rotoscaleT(const TransformStruct &transf
 	return target;
 }
 
-template <TFilteringMode filteringMode>
-TransparentSurface *TransparentSurface::scaleT(uint16 newWidth, uint16 newHeight) const {
+TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight, bool filtering) const {
 
 	TransparentSurface *target = new TransparentSurface();
 
 	target->create(newWidth, newHeight, format);
 
-	if (filteringMode == FILTER_BILINEAR) {
+	if (filtering) {
 		scaleBlitBilinear((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, target->w, target->h, w, h, format);
 	} else {
 		scaleBlit((byte *)target->getPixels(), (const byte *)getPixels(), target->pitch, pitch, target->w, target->h, w, h, format);
@@ -1005,15 +1004,9 @@ TransparentSurface *TransparentSurface::convertTo(const PixelFormat &dstFormat,
 
 template TransparentSurface *TransparentSurface::rotoscaleT<FILTER_NEAREST>(const TransformStruct &transform) const;
 template TransparentSurface *TransparentSurface::rotoscaleT<FILTER_BILINEAR>(const TransformStruct &transform) const;
-template TransparentSurface *TransparentSurface::scaleT<FILTER_NEAREST>(uint16 newWidth, uint16 newHeight) const;
-template TransparentSurface *TransparentSurface::scaleT<FILTER_BILINEAR>(uint16 newWidth, uint16 newHeight) const;
 
 TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
 	return rotoscaleT<FILTER_BILINEAR>(transform);
 }
 
-TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const {
-	return scaleT<FILTER_NEAREST>(newWidth, newHeight);
-}
-
 } // End of namespace Graphics
diff --git a/graphics/transparent_surface.h b/graphics/transparent_surface.h
index 3c2b29b7b3..ae0de7d2e2 100644
--- a/graphics/transparent_surface.h
+++ b/graphics/transparent_surface.h
@@ -145,12 +145,10 @@ struct TransparentSurface : public Graphics::Surface {
 	 *
 	 * @param newWidth the resulting width.
 	 * @param newHeight the resulting height.
+	 * @param filtering Whether or not to use bilinear filtering.
 	 * @see TransformStruct
 	 */
-	template <TFilteringMode filteringMode>
-	TransparentSurface *scaleT(uint16 newWidth, uint16 newHeight) const;
-
-	TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const;
+	TransparentSurface *scale(uint16 newWidth, uint16 newHeight, bool filtering = false) const;
 
 	/**
 	 * @brief Rotoscale function; this returns a transformed version of this surface after rotation and


Commit: ad722f31cc0e6cd73e4333d6b29ac4896e62dcb2
    https://github.com/scummvm/scummvm/commit/ad722f31cc0e6cd73e4333d6b29ac4896e62dcb2
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2020-07-18T12:16:52+02:00

Commit Message:
SCI32: Allow using HQ video with pixel formats other than RGBA8888

This should fix Trac #11332.

Changed paths:
    engines/sci/graphics/video32.cpp


diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 5b164bc9a0..8c1741686e 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -80,19 +80,26 @@ bool VideoPlayer::startHQVideo() {
 	// Optimize rendering performance for unscaled videos, and allow
 	// better-than-NN interpolation for videos that are scaled
 	if (shouldStartHQVideo()) {
-		// TODO: Search for and use the best supported format (which may be
-		// lower than 32bpp) once the scaling code in Graphics supports
-		// 16bpp/24bpp, and once the SDL backend can correctly communicate
-		// supported pixel formats above whatever format is currently used by
-		// _hwsurface. Right now, this will either show an error dialog (OpenGL)
-		// or just crash entirely (SDL) if the backend does not support this
-		// 32bpp pixel format, which sucks since this code really ought to be
-		// able to fall back to NN scaling for games with 256-color videos
-		// without any error.
-		const Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
-		g_sci->_gfxFrameout->setPixelFormat(format);
-		_hqVideoMode = (g_system->getScreenFormat() == format);
-		return _hqVideoMode;
+		const Common::List<Graphics::PixelFormat> outFormats = g_system->getSupportedFormats();
+		Graphics::PixelFormat bestFormat = outFormats.front();
+		if (bestFormat.bytesPerPixel != 2 && bestFormat.bytesPerPixel != 4) {
+			Common::List<Graphics::PixelFormat>::const_iterator it;
+			for (it = outFormats.begin(); it != outFormats.end(); ++it) {
+				if (it->bytesPerPixel == 2 || it->bytesPerPixel == 4) {
+					bestFormat = *it;
+					break;
+				}
+			}
+		}
+
+		if (bestFormat.bytesPerPixel != 2 && bestFormat.bytesPerPixel != 4) {
+			warning("Failed to find any valid output pixel format");
+			_hqVideoMode = false;
+		} else {
+			g_sci->_gfxFrameout->setPixelFormat(bestFormat);
+			_hqVideoMode = (g_system->getScreenFormat() != Graphics::PixelFormat::createFormatCLUT8());
+			return _hqVideoMode;
+		}
 	} else {
 		_hqVideoMode = false;
 	}




More information about the Scummvm-git-logs mailing list