[Scummvm-cvs-logs] scummvm master -> 8c8b1b7da749d69078b1be88a00d5ba29e64413a

wjp wjp at usecode.org
Sun Oct 6 17:37:37 CEST 2013


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

Summary:
8c8b1b7da7 WINTERMUTE: Integrate SDL_rotozoom code for scale/rotoscale


Commit: 8c8b1b7da749d69078b1be88a00d5ba29e64413a
    https://github.com/scummvm/scummvm/commit/8c8b1b7da749d69078b1be88a00d5ba29e64413a
Author: Willem Jan Palenstijn (wjp at usecode.org)
Date: 2013-10-06T08:36:32-07:00

Commit Message:
WINTERMUTE: Integrate SDL_rotozoom code for scale/rotoscale

Changed paths:
    engines/wintermute/graphics/transparent_surface.cpp
    engines/wintermute/graphics/transparent_surface.h



diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp
index f5528b1..43deb62 100644
--- a/engines/wintermute/graphics/transparent_surface.cpp
+++ b/engines/wintermute/graphics/transparent_surface.cpp
@@ -17,8 +17,16 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * The bottom part of this is file is adapted from SDL_rotozoom.c. The
+ * relevant copyright notice for those specific functions can be found at the
+ * top of that section.
+ *
  */
 
+
+
 #include "common/algorithm.h"
 #include "common/endian.h"
 #include "common/util.h"
@@ -29,6 +37,8 @@
 #include "engines/wintermute/graphics/transparent_surface.h"
 #include "engines/wintermute/graphics/transform_tools.h"
 
+//#define ENABLE_BILINEAR
+
 namespace Wintermute {
 
 void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
@@ -269,119 +279,6 @@ void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *o
 	}
 }
 
-#if ENABLE_BILINEAR
-void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) {
-
-	// TODO: Do some optimization on this. This is completely naive.
-	
-	int srcW = srcRect.width();
-	int srcH = srcRect.height();
-	int dstW = dstRect.width();
-	int dstH = dstRect.height();
-
-	assert(dstX >= 0 && dstX < dstW);
-	assert(dstY >= 0 && dstY < dstH);
-
-	float x1 = floor(projX);
-	float x2 = ceil(projX);
-	float y1 = floor(projY);
-	float y2 = ceil(projY);
-
-	uint32 Q11, Q12, Q21, Q22;
-
-	if (x1 >= srcW || x1 < 0 || y1 >= srcH || y1 < 0) {
-		Q11 = 0;
-	} else {
-		Q11 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y1 + srcRect.top)));
-	}
-
-	if (x1 >= srcW || x1 < 0 || y2 >= srcH || y2 < 0) {
-		Q12 = 0;
-	} else {
-		Q12 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y2 + srcRect.top)));
-	}
-
-	if (x2 >= srcW || x2 < 0 || y1 >= srcH || y1 < 0) {
-		Q21 = 0;
-	} else {
-		Q21 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y1 + srcRect.top)));
-	}
-
-	if (x2 >= srcW || x2 < 0 || y2 >= srcH || y2 < 0) {
-		Q22 = 0;
-	} else {
-		Q22 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y2 + srcRect.top)));
-	}
-
-	byte *Q11s = (byte *)&Q11;
-	byte *Q12s = (byte *)&Q12;
-	byte *Q21s = (byte *)&Q21;
-	byte *Q22s = (byte *)&Q22;
-
-	uint32 color;
-	byte *dest = (byte *)&color;
-
-	float q11x = (x2 - projX);
-	float q11y = (y2 - projY);
-	float q21x = (projX - x1);
-	float q21y = (y2 - projY);
-	float q12x = (x2 - projX);
-	float q12y = (projY - y1);
-
-	if (x1 == x2 && y1 == y2) {
-		for (int c = 0; c < 4; c++) {
-			dest[c] = ((float)Q11s[c]);
-		}
-	} else {
-
-		if (x1 == x2) {
-			q11x = 0.5;
-			q12x = 0.5;
-			q21x = 0.5;
-		} else if (y1 == y2) {
-			q11y = 0.5;
-			q12y = 0.5;
-			q21y = 0.5;
-		}
-
-		for (int c = 0; c < 4; c++) {
-			dest[c] = (byte)(
-			              ((float)Q11s[c]) * q11x * q11y +
-			              ((float)Q21s[c]) * q21x * q21y +
-			              ((float)Q12s[c]) * q12x * q12y +
-			              ((float)Q22s[c]) * (1.0 -
-			                                  q11x * q11y -
-			                                  q21x * q21y -
-			                                  q12x * q12y)
-			          );
-		}
-	}
-	WRITE_UINT32((byte *)dst->getBasePtr(dstX + dstRect.left, dstY + dstRect.top), color);
-}
-#else
-void TransparentSurface::copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) {
-
-	// TODO: Have the Rect arguments become completely useless at this point?
-
-	int srcW = srcRect.width();
-	int srcH = srcRect.height();
-	int dstW = dstRect.width();
-	int dstH = dstRect.height();
-
-	assert(dstX >= 0 && dstX < dstW);
-	assert(dstY >= 0 && dstY < dstH);
-
-	uint32 color;
-
-	if (projX >= srcW || projX < 0 || projY >= srcH || projY < 0) {
-		color = 0;
-	} else {
-		color = READ_UINT32((const byte *)src->getBasePtr((int)projX, (int)projY));
-	}
-
-	WRITE_UINT32((byte *)dst->getBasePtr(dstX, dstY), color);
-}
-#endif
 
 TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {}
 
@@ -655,6 +552,88 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p
 	return retSize;
 }
 
+/**
+ * Writes a color key to the alpha channel of the surface
+ * @param rKey  the red component of the color key
+ * @param gKey  the green component of the color key
+ * @param bKey  the blue component of the color key
+ * @param overwriteAlpha if true, all other alpha will be set fully opaque
+ */
+void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) {
+	assert(format.bytesPerPixel == 4);
+	for (int i = 0; i < h; i++) {
+		for (int j = 0; j < w; j++) {
+			uint32 pix = ((uint32 *)pixels)[i * w + j];
+			uint8 r, g, b, a;
+			format.colorToARGB(pix, a, r, g, b);
+			if (r == rKey && g == gKey && b == bKey) {
+				a = 0;
+				((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
+			} else if (overwriteAlpha) {
+				a = 255;
+				((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
+			}
+		}
+	}
+}
+
+TransparentSurface::AlphaType TransparentSurface::getAlphaMode() const {
+	return _alphaMode;
+}
+
+void TransparentSurface::setAlphaMode(TransparentSurface::AlphaType mode) {
+	_alphaMode = mode;
+}
+
+
+
+
+
+
+/*
+
+The below two functions are 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.
+
+*/
+
+
+
+
+
 TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
 
 	assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway.
@@ -667,33 +646,98 @@ TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transfo
 	TransparentSurface *target = new TransparentSurface();
 	assert(format.bytesPerPixel == 4);
 
+	int srcW = w;
+	int srcH = h;
 	int dstW = dstRect.width();
 	int dstH = dstRect.height();
 
 	target->create((uint16)dstW, (uint16)dstH, this->format);
 
+	if (transform._zoom.x == 0 || transform._zoom.y == 0)
+		return target;
+
 	uint32 invAngle = 360 - (transform._angle % 360);
 	float invCos = cos(invAngle * M_PI / 180.0);
 	float invSin = sin(invAngle * M_PI / 180.0);
-	float targX;
-	float targY;
 
-	for (int y = 0; y < dstH; y++) {
-		for (int x = 0; x < dstW; x++) {
-			int x1 = x - newHotspot.x;
-			int y1 = y - newHotspot.y;
+	struct tColorRGBA { byte r; byte g; byte b; byte a; };
+	int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x));
+	int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x));
+	int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y));
+	int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y));
+
 
-			targX = ((x1 * invCos - y1 * invSin)) * kDefaultZoomX / transform._zoom.x + srcRect.left;
-			targY = ((x1 * invSin + y1 * invCos)) * kDefaultZoomY / transform._zoom.y + srcRect.top;
+	bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
 
-			targX += transform._hotspot.x;
-			targY += transform._hotspot.y;
+	int xd = (srcRect.left + transform._hotspot.x) << 16;
+	int yd = (srcRect.top + transform._hotspot.y) << 16;
+	int cx = newHotspot.x;
+	int cy = newHotspot.y;
 
-#if ENABLE_BILINEAR
-			copyPixelBilinear(targX, targY, x, y, srcRect, dstRect, this, target);
+	int ax = -icosx * cx;
+	int ay = -isiny * cx;
+	int sw = srcW - 1;
+	int sh = srcH - 1;
+
+	tColorRGBA *pc = (tColorRGBA*)target->getBasePtr(0, 0);
+
+	for (int y = 0; y < dstH; y++) {
+		int t = cy - y;
+		int sdx = ax + (isinx * t) + xd;
+		int sdy = ay - (icosy * t) + yd;
+		for (int x = 0; x < dstW; x++) {
+			int dx = (sdx >> 16);
+			int dy = (sdy >> 16);
+			if (flipx) dx = sw - dx;
+			if (flipy) dy = sh - dy;
+
+#ifdef ENABLE_BILINEAR
+			if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) {
+				const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
+				tColorRGBA c00, c01, c10, c11, cswap;
+				c00 = *sp;
+				sp += 1;
+				c01 = *sp;
+				sp += (this->pitch/4);
+				c11 = *sp;
+				sp -= 1;
+				c10 = *sp;
+				if (flipx) {
+					cswap = c00; c00=c01; c01=cswap;
+					cswap = c10; c10=c11; c11=cswap;
+				}
+				if (flipy) {
+					cswap = c00; c00=c10; c10=cswap;
+					cswap = c01; c01=c11; c11=cswap;
+				}
+				/*
+				* Interpolate colors
+				*/
+				int ex = (sdx & 0xffff);
+				int ey = (sdy & 0xffff);
+				int t1, t2;
+				t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
+				t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
+				pc->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;
+				pc->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;
+				pc->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;
+				pc->a = (((t2 - t1) * ey) >> 16) + t1;
+			}
 #else
-			copyPixelNearestNeighbor(targX, targY, x, y, srcRect, dstRect, this, target);
+			if ((dx >= 0) && (dy >= 0) && (dx < srcW) && (dy < srcH)) {
+				const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
+				*pc = *sp;
+			}
 #endif
+			sdx += icosx;
+			sdy += isiny;
+			pc++;
 		}
 	}
 	return target;
@@ -715,15 +759,153 @@ TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight)
 
 	target->create((uint16)dstW, (uint16)dstH, this->format);
 
-#if ENABLE_BILINEAR
+#ifdef ENABLE_BILINEAR
+
+	// NB: The actual order of these bytes may not be correct, but
+	// since all values are treated equal, that does not matter.
+	struct tColorRGBA { byte r; byte g; byte b; byte a; };
+
+	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++) {
-		float projY = y / (float)dstH * srcH;
+		const tColorRGBA *csp = sp;
+		csax = sax;
 		for (int x = 0; x < dstW; x++) {
-			float projX = x / (float)dstW * srcW;
-			copyPixelBilinear(projX, projY, x, y, srcRect, dstRect, this, target);
+			/*
+			* 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;
+
 #else
+
 	int *scaleCacheX = new int[dstW];
 	for (int x = 0; x < dstW; x++)
 		scaleCacheX[x] = (x * srcW) / dstW;
@@ -735,42 +917,15 @@ TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight)
 			*destP++ = srcP[scaleCacheX[x]];
 	}
 	delete[] scaleCacheX;
+
 #endif
 
 	return target;
 
 }
 
-/**
- * Writes a color key to the alpha channel of the surface
- * @param rKey  the red component of the color key
- * @param gKey  the green component of the color key
- * @param bKey  the blue component of the color key
- * @param overwriteAlpha if true, all other alpha will be set fully opaque
- */
-void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) {
-	assert(format.bytesPerPixel == 4);
-	for (int i = 0; i < h; i++) {
-		for (int j = 0; j < w; j++) {
-			uint32 pix = ((uint32 *)pixels)[i * w + j];
-			uint8 r, g, b, a;
-			format.colorToARGB(pix, a, r, g, b);
-			if (r == rKey && g == gKey && b == bKey) {
-				a = 0;
-				((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
-			} else if (overwriteAlpha) {
-				a = 255;
-				((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
-			}
-		}
-	}
-}
 
-TransparentSurface::AlphaType TransparentSurface::getAlphaMode() const {
-	return _alphaMode;
-}
 
-void TransparentSurface::setAlphaMode(TransparentSurface::AlphaType mode) {
-	_alphaMode = mode;
-}
+
+
 } // End of namespace Wintermute
diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h
index 5f44cf0..b887c05 100644
--- a/engines/wintermute/graphics/transparent_surface.h
+++ b/engines/wintermute/graphics/transparent_surface.h
@@ -25,9 +25,6 @@
 #include "graphics/surface.h"
 #include "engines/wintermute/graphics/transform_struct.h"
 
-#define ENABLE_BILINEAR 0
-
-
 /*
  * This code is based on Broken Sword 2.5 engine
  *
@@ -53,31 +50,6 @@ struct TransparentSurface : public Graphics::Surface {
 	void setColorKey(char r, char g, char b);
 	void disableColorKey();
 
-#if ENABLE_BILINEAR
-	/*
-	 * Pick color from a point in source and copy it to a pixel in target.
-	 * The point in the source can be a float - we have subpixel accuracy in the arguments.
-	 * We do bilinear interpolation to estimate the color of the point even if the 
-	 * point is specuified w/subpixel accuracy.
-	 *
-	 * @param projX, projY, point in the source to pick color from.
-	 * @param dstX, dstY destionation pixel
-	 * @param *src, *dst pointer to the source and dest surfaces
-	 */
-	static void copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst);
-#else
-	/*
-	 * Pick color from a point in source and copy it to a pixel in target.
-	 * The point in the source can be a float - we have subpixel accuracy in the arguments.
-	 * HOWEVER, this particular function just does nearest neighbor.
-	 * Use copyPixelBilinear if you interpolation.
-	 *
-	 * @param projX, projY, point in the source to pick color from.
-	 * @param dstX, dstY destionation pixel
-	 * @param *src, *dst pointer to the source and dest surfaces
-	 */
-	static void copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst);
-#endif
 	// Enums
 	/**
 	 @brief The possible flipping parameters for the blit methode.






More information about the Scummvm-git-logs mailing list