diff options
| -rw-r--r-- | engines/wintermute/graphics/transparent_surface.cpp | 575 | ||||
| -rw-r--r-- | engines/wintermute/graphics/transparent_surface.h | 91 | 
2 files changed, 442 insertions, 224 deletions
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index cd200354f7..4ba74b01de 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -31,9 +31,262 @@  namespace Wintermute { +void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); +void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); + +// These gather together various blendPixel functions for use with templates. + +class BlenderAdditive { +public: +	static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); +	static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); +	static void blendPixel(byte *in, byte *out); +	static void blendPixel(byte *in, byte *out, int colorMod); +}; + +class BlenderSubtractive { +public: +	static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); +	static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); +	static void blendPixel(byte *in, byte *out); +	static void blendPixel(byte *in, byte *out, int colorMod); +}; + +class BlenderNormal { +public: +	static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); +	static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); +	static void blendPixel(byte *in, byte *out); +	static void blendPixel(byte *in, byte *out, int colorMod); +}; + +/** + * Perform additive blending of a pixel, applying beforehand a given colormod. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + * @param *outa, *outr, *outg, *outb pointer to the colormod components. + */ + +void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { + + +	assert(!(*cr == 255 && *ca == 255 && *cb == 255 && *cg == 255)); +	// Just use the faster, sans-colormod version + +	if (*ca != 255) { +		ina = (ina) * (*ca) >> 8; +	} + +	if (ina == 0) { +		return; +	} else { +		if (*cb != 255) +			*outb = MIN(*outb + ((inb * (*cb) * ina) >> 16), 255); +		else +			*outb = MIN(*outb + (inb * ina >> 8), 255); + +		if (*cg != 255) +			*outg = MIN(*outg + ((ing * (*cg) * ina) >> 16), 255); +		else +			*outg = MIN(*outg + (ing * ina >> 8), 255); + +		if (*cr != 255) +			*outr = MIN(*outr + ((inr * (*cr) * ina) >> 16), 255); +		else +			*outr = MIN(*outr + (inr * ina >> 8), 255); +	} +} + +/** + * Perform subtractive blending of a pixel, applying beforehand a given colormod. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + * @param *outa, *outr, *outg, *outb pointer to the colormod components. + */ + +void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { + +	assert(!(*cr == 255 && *ca == 255 && *cb == 255 && *cg == 255)); +	// Just use the faster, sans-colormod version + +	//if (*ca != 255) { +	//	ina = ina * (*ca) >> 8; +	// } + +	// As weird as it is, evidence suggests that alphamod is ignored when doing +	// subtractive... + +	// TODO if ina == 255 fast version + +	if (ina == 0) { +		return; +	} else { +		if (*cb != 255) +			*outb = MAX(*outb - ((inb * (*cb)  * (*outb) * ina) >> 24), 0); +		else +			*outb = MAX(*outb - (inb * (*outb) * ina >> 16), 0); + +		if (*cg != 255) +			*outg = MAX(*outg - ((ing * (*cg)  * (*outg) * ina) >> 24), 0); +		else +			*outg = MAX(*outg - (ing * (*outg) * ina >> 16), 0); + +		if (*cr != 255) +			*outr = MAX(*outr - ((inr * (*cr) *  (*outr) * ina) >> 24), 0); +		else +			*outr = MAX(*outr - (inr * (*outr) * ina >> 16), 0); +	} +} + +/** + * Perform "regular" alphablending of a pixel, applying beforehand a given colormod. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + * @param *outa, *outr, *outg, *outb pointer to the colormod components. + */ + +void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { + +	assert(!(*cr == 255 && *ca == 255 && *cb == 255 && *cg == 255)); +	// Just use the faster, sans-colormod version + +	if (*ca != 255) { +		ina = ina * (*ca) >> 8; +	} + +	if (ina == 0) { +		return; +	} else if (ina == 255) { +		if (*cb != 255) +			*outb = (inb * (*cb)) >> 8; +		else +			*outb = inb; + +		if (*cr != 255) +			*outr = (inr * (*cr)) >> 8; +		else +			*outr = inr; + +		if (*cg != 255) +			*outg = (ing * (*cg)) >> 8; +		else +			*outg = ing; + +		*outa = ina; + +		return; + +	} else { + +		*outa = 255; +		*outb = (*outb * (255 - ina) >> 8); +		*outr = (*outr * (255 - ina) >> 8); +		*outg = (*outg * (255 - ina) >> 8); + +		if (*cb == 0) +			*outb = *outb; +		else if (*cb != 255) +			*outb = *outb + (inb * ina * (*cb) >> 16); +		else +			*outb = *outb + (inb * ina >> 8); + +		if (*cr == 0) +			*outr = *outr; +		else if (*cr != 255) +			*outr = *outr + (inr * ina * (*cr) >> 16); +		else +			*outr = *outr + (inr * ina >> 8); + +		if (*cg == 0) +			*outg = *outg; +		else if (*cg != 255) +			*outg = *outg + (ing * ina * (*cg) >> 16); +		else +			*outg = *outg + (ing * ina >> 8); + +		return; +	} +} + +/** + * Perform "regular" alphablending of a pixel. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + */ + +void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { + +	if (ina == 0) { +		return; +	} else if (ina == 255) { +		*outb = inb; +		*outg = ing; +		*outr = inr; +		*outa = ina; +		return; +	} else { +		*outa = 255; +		*outb = ((inb * ina) + *outb * (255 - ina)) >> 8; +		*outg = ((ing * ina) + *outg * (255 - ina)) >> 8; +		*outr = ((inr * ina) + *outr * (255 - ina)) >> 8; +	} +} + +/** + * Perform subtractive blending of a pixel. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + */ + +void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { + +	if (ina == 0) { +		return; +	} else if (ina == 255) { +		*outa = *outa; +		*outr = *outr - (inr * (*outr) >> 8); +		*outg = *outg - (ing * (*outg) >> 8); +		*outb = *outb - (inb * (*outb) >> 8); +		return; +	} else { +		*outa = *outa; +		*outb = MAX(*outb - ((inb * (*outb)) * ina >> 16), 0); +		*outg = MAX(*outg - ((ing * (*outg)) * ina >> 16), 0); +		*outr = MAX(*outr - ((inr * (*outr)) * ina >> 16), 0); +		return; +	} +} + +/** + * Perform additive blending of a pixel. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + */ + +void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { + +	if (ina == 0) { +		return; +	} else if (ina == 255) { +		*outa = *outa; +		*outr = MIN(*outr + inr, 255); +		*outg = MIN(*outg + ing, 255); +		*outb = MIN(*outb + inb, 255); +		return; +	} else { +		*outa = *outa; +		*outb = MIN((inb * ina >> 8) + *outb, 255); +		*outg = MIN((ing * ina >> 8) + *outg, 255); +		*outr = MIN((inr * ina >> 8) + *outr, 255); +		return; +	} +}  #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(); @@ -106,20 +359,23 @@ void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, i  		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) -					  ); +			              ((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(); @@ -157,21 +413,19 @@ TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Sur  	}  } -void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { -	byte *in, *out; - -#ifdef SCUMM_LITTLE_ENDIAN -	const int aIndex = 0; -#else -	const int aIndex = 3; -#endif +void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +/** + * Optimized version of doBlit to be used w/opaque blitting (no alpha). + */ +	byte *in; +	byte *out;  	for (uint32 i = 0; i < height; i++) {  		out = outo;  		in = ino;  		memcpy(out, in, width * 4);  		for (uint32 j = 0; j < width; j++) { -			out[aIndex] = 0xFF; +			out[TransparentSurface::kAIndex] = 0xFF;  			out += 4;  		}  		outo += pitch; @@ -179,112 +433,111 @@ void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pit  	}  } -void doBlitBinary(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { -	byte *in, *out; -	 -#ifdef SCUMM_LITTLE_ENDIAN -	const int aIndex = 0; -#else -	const int aIndex = 3; -#endif -	const int aShift = 0;//img->format.aShift; +/** + * Optimized version of doBlit to be used w/binary blitting (blit or no-blit, no blending). + */ + +void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { + +	byte *in; +	byte *out;  	for (uint32 i = 0; i < height; i++) {  		out = outo;  		in = ino;  		for (uint32 j = 0; j < width; j++) {  			uint32 pix = *(uint32 *)in; -			int a = (pix >> aShift) & 0xff; -			in += inStep; +			int a = (pix >> TransparentSurface::kAShift) & 0xff;  			if (a == 0) { // Full transparency -				out += 4;  			} else { // Full opacity (Any value not exactly 0 is Opaque here)  				*(uint32 *)out = pix; -				out[aIndex] = 0xFF; -				out += 4; +				out[TransparentSurface::kAIndex] = 0xFF;  			} +			out += 4; +			in += inStep;  		}  		outo += pitch;  		ino += inoStep;  	}  } -void doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { -	byte *in, *out; +/** + * What we have here is a template method that calls blendPixel() from a different + * class - the one we call it with - thus performing a different type of blending. + * + * @param *ino a pointer to the input surface + * @param *outo a pointer to the output surface + * @param width width of the input surface + * @param height height of the input surface + * @param pitch pitch of the output surface - that is, width in bytes of every row, usually bpp * width of the TARGET surface (the area we are blitting to might be smaller, do the math) + * @inStep size in bytes to skip to address each pixel, usually bpp of the source surface + * @inoStep width in bytes of every row on the *input* surface / kind of like pitch + * @color colormod in 0xAARRGGBB format - 0xFFFFFFFF for no colormod + */ -#ifdef SCUMM_LITTLE_ENDIAN -	const int aIndex = 0; -	const int bIndex = 1; -	const int gIndex = 2; -	const int rIndex = 3; -#else -	const int aIndex = 3; -	const int bIndex = 2; -	const int gIndex = 1; -	const int rIndex = 0; -#endif +template<class Blender>  +void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) { -	const int bShift = 8;//img->format.bShift; -	const int gShift = 16;//img->format.gShift; -	const int rShift = 24;//img->format.rShift; -	const int aShift = 0;//img->format.aShift; +	byte *in; +	byte *out; -	const int bShiftTarget = 8;//target.format.bShift; -	const int gShiftTarget = 16;//target.format.gShift; -	const int rShiftTarget = 24;//target.format.rShift; +	if (color == 0xffffffff) { -	for (uint32 i = 0; i < height; i++) { -		out = outo; -		in = ino; -		for (uint32 j = 0; j < width; j++) { -			uint32 pix = *(uint32 *)in; -			uint32 oPix = *(uint32 *) out; -			int b = (pix >> bShift) & 0xff; -			int g = (pix >> gShift) & 0xff; -			int r = (pix >> rShift) & 0xff; -			int a = (pix >> aShift) & 0xff; -			int outb, outg, outr, outa; -			in += inStep; +		for (uint32 i = 0; i < height; i++) { +			out = outo; +			in = ino; +			for (uint32 j = 0; j < width; j++) { -			switch (a) { -				case 0: // Full transparency -					out += 4; -					break; -				case 255: // Full opacity -					outb = b; -					outg = g; -					outr = r; -					outa = a; - -					out[aIndex] = outa; -					out[bIndex] = outb; -					out[gIndex] = outg; -					out[rIndex] = outr; -					out += 4; -					break; - -				default: // alpha blending -					outa = 255; -					outb = ((b * a) + ((oPix >> bShiftTarget) & 0xff) * (255-a)) >> 8; -					outg = ((g * a) + ((oPix >> gShiftTarget) & 0xff) * (255-a)) >> 8; -					outr = ((r * a) + ((oPix >> rShiftTarget) & 0xff) * (255-a)) >> 8; - -					out[aIndex] = outa; -					out[bIndex] = outb; -					out[gIndex] = outg; -					out[rIndex] = outr; -					out += 4; +				byte *outa = &out[TransparentSurface::kAIndex]; +				byte *outr = &out[TransparentSurface::kRIndex]; +				byte *outg = &out[TransparentSurface::kGIndex]; +				byte *outb = &out[TransparentSurface::kBIndex]; + +				Blender::blendPixel(in[TransparentSurface::kAIndex], +					in[TransparentSurface::kRIndex], +					in[TransparentSurface::kGIndex], +					in[TransparentSurface::kBIndex], +					outa, outr, outg, outb); + +				in += inStep; +				out += 4;  			} +			outo += pitch; +			ino += inoStep; +		} +	} else { + +		byte ca = (color >> TransparentSurface::kAModShift) & 0xFF; +		byte cr = (color >> TransparentSurface::kRModShift) & 0xFF; +		byte cg = (color >> TransparentSurface::kGModShift) & 0xFF; +		byte cb = (color >> TransparentSurface::kBModShift) & 0xFF; + +		for (uint32 i = 0; i < height; i++) { +			out = outo; +			in = ino; +			for (uint32 j = 0; j < width; j++) { + +				byte *outa = &out[TransparentSurface::kAIndex]; +				byte *outr = &out[TransparentSurface::kRIndex]; +				byte *outg = &out[TransparentSurface::kGIndex]; +				byte *outb = &out[TransparentSurface::kBIndex]; + +				Blender::blendPixel(in[TransparentSurface::kAIndex], +					in[TransparentSurface::kRIndex], +					in[TransparentSurface::kGIndex], +					in[TransparentSurface::kBIndex], +					outa, outr, outg, outb, &ca, &cr, &cg, &cb); +				in += inStep; +				out += 4; +			} +			outo += pitch; +			ino += inoStep;  		} -		outo += pitch; -		ino += inoStep;  	}  } - -Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height) { -	int ca = (color >> 24) & 0xff; +Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {  	Common::Rect retSize;  	retSize.top = 0; @@ -292,13 +545,11 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p  	retSize.setWidth(0);  	retSize.setHeight(0);  	// Check if we need to draw anything at all +	int ca = (color >> 24) & 0xff; +  	if (ca == 0)  		return retSize; -	int cr = (color >> 16) & 0xff; -	int cg = (color >> 8) & 0xff; -	int cb = (color >> 0) & 0xff; -  	// Create an encapsulating surface for the data  	TransparentSurface srcImage(*this, false);  	// TODO: Is the data really in the screen format? @@ -325,11 +576,11 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p  		srcImage.h = pPartRect->height();  		debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, -			  pPartRect->left,  pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); +		      pPartRect->left,  pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);  	} else {  		debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0, -			  srcImage.w, srcImage.h, color, width, height); +		      srcImage.w, srcImage.h, color, width, height);  	}  	if (width == -1) @@ -385,117 +636,24 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p  			yp = img->h - 1;  		} -		byte *ino = (byte *)img->getBasePtr(xp, yp); +		byte *ino= (byte *)img->getBasePtr(xp, yp);  		byte *outo = (byte *)target.getBasePtr(posX, posY); -		byte *in, *out; - -#ifdef SCUMM_LITTLE_ENDIAN -		const int aIndex = 0; -		const int bIndex = 1; -		const int gIndex = 2; -		const int rIndex = 3; -#else -		const int aIndex = 3; -		const int bIndex = 2; -		const int gIndex = 1; -		const int rIndex = 0; -#endif -		const int bShift = 8;//img->format.bShift; -		const int gShift = 16;//img->format.gShift; -		const int rShift = 24;//img->format.rShift; -		const int aShift = 0;//img->format.aShift; - -		const int bShiftTarget = 8;//target.format.bShift; -		const int gShiftTarget = 16;//target.format.gShift; -		const int rShiftTarget = 24;//target.format.rShift; - -		if (ca == 255 && cb == 255 && cg == 255 && cr == 255) { -			if (_alphaMode == ALPHA_FULL) { -				doBlitAlpha(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); -			} else if (_alphaMode == ALPHA_BINARY) { -				doBlitBinary(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); -			} else if (_alphaMode == ALPHA_OPAQUE) { -				doBlitOpaque(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); -			} +		if (color == 0xFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) { +			doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); +		} else if (color == 0xFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) { +			doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);  		} else { -			for (int i = 0; i < img->h; i++) { -				out = outo; -				in = ino; -				for (int j = 0; j < img->w; j++) { -					uint32 pix = *(uint32 *)in; -					uint32 o_pix = *(uint32 *) out; -					int b = (pix >> bShift) & 0xff; -					int g = (pix >> gShift) & 0xff; -					int r = (pix >> rShift) & 0xff; -					int a = (pix >> aShift) & 0xff; -					int outb, outg, outr, outa; -					in += inStep; - -					if (ca != 255) { -						a = a * ca >> 8; -					} -					switch (a) { -					case 0: // Full transparency -						out += 4; -						break; -					case 255: // Full opacity -						if (cb != 255) -							outb = (b * cb) >> 8; -						else -							outb = b; - -						if (cg != 255) -							outg = (g * cg) >> 8; -						else -							outg = g; - -						if (cr != 255) -							outr = (r * cr) >> 8; -						else -							outr = r; -						outa = a; -						out[aIndex] = outa; -						out[bIndex] = outb; -						out[gIndex] = outg; -						out[rIndex] = outr; -						out += 4; -						break; - -					default: // alpha blending -						outa = 255; -						outb = ((o_pix >> bShiftTarget) & 0xff) * (255 - a); -						outg = ((o_pix >> gShiftTarget) & 0xff) * (255 - a); -						outr = ((o_pix >> rShiftTarget) & 0xff) * (255 - a); -						if (cb == 0) -							outb = outb >> 8; -						else if (cb != 255) -							outb = ((outb<<8) + b * a * cb) >> 16; -						else -							outb = (outb + b * a) >> 8; -						if (cg == 0) -							outg = outg >> 8; -						else if (cg != 255) -							outg = ((outg<<8) + g * a * cg) >> 16; -						else -							outg = (outg + g * a) >> 8; -						if (cr == 0) -							outr = outr >> 8; -						else if (cr != 255) -							outr = ((outr<<8) + r * a * cr) >> 16; -						else -							outr = (outr + r * a) >> 8; -						out[aIndex] = outa; -						out[bIndex] = outb; -						out[gIndex] = outg; -						out[rIndex] = outr; -						out += 4; -					} -				} -				outo += target.pitch; -				ino += inoStep; +			if (blendMode == BLEND_ADDITIVE) { +				doBlit<BlenderAdditive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); +			} else if (blendMode == BLEND_SUBTRACTIVE) { +				doBlit<BlenderSubtractive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); +			} else { +				assert(blendMode == BLEND_NORMAL); +				doBlit<BlenderNormal>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);  			}  		} +  	}  	retSize.setWidth(img->w); @@ -555,6 +713,7 @@ TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transfo  }  TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const { +  	Common::Rect srcRect(0, 0, (int16)w, (int16)h);  	Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight); diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index 598aaa55d7..821b5c5943 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -54,8 +54,28 @@ struct TransparentSurface : public Graphics::Surface {  	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 @@ -63,26 +83,50 @@ struct TransparentSurface : public Graphics::Surface {  	 @brief The possible flipping parameters for the blit methode.  	 */  	enum FLIP_FLAGS { -		/// The image will not be flipped. -		FLIP_NONE = 0, -		/// The image will be flipped at the horizontal axis. -		FLIP_H = 1, -		/// The image will be flipped at the vertical axis. -		FLIP_V = 2, -		/// The image will be flipped at the horizontal and vertical axis. -		FLIP_HV = FLIP_H | FLIP_V, -		/// The image will be flipped at the horizontal and vertical axis. -		FLIP_VH = FLIP_H | FLIP_V +	    /// The image will not be flipped. +	    FLIP_NONE = 0, +	    /// The image will be flipped at the horizontal axis. +	    FLIP_H = 1, +	    /// The image will be flipped at the vertical axis. +	    FLIP_V = 2, +	    /// The image will be flipped at the horizontal and vertical axis. +	    FLIP_HV = FLIP_H | FLIP_V, +	    /// The image will be flipped at the horizontal and vertical axis. +	    FLIP_VH = FLIP_H | FLIP_V  	};  	enum AlphaType { -		ALPHA_OPAQUE = 0, -		ALPHA_BINARY = 1, -		ALPHA_FULL = 2 +	    ALPHA_OPAQUE = 0, +	    ALPHA_BINARY = 1, +	    ALPHA_FULL = 2  	};  	AlphaType _alphaMode; +	#ifdef SCUMM_LITTLE_ENDIAN +	static const int kAIndex = 0; +	static const int kBIndex = 1; +	static const int kGIndex = 2; +	static const int kRIndex = 3; +	#else +	static const int kAIndex = 3; +	static const int kBIndex = 2; +	static const int kGIndex = 1; +	static const int kRIndex = 0; +	#endif + +	static const int kBShift = 8;//img->format.bShift; +	static const int kGShift = 16;//img->format.gShift; +	static const int kRShift = 24;//img->format.rShift; +	static const int kAShift = 0;//img->format.aShift; + + +	static const int kBModShift = 0;//img->format.bShift; +	static const int kGModShift = 8;//img->format.gShift; +	static const int kRModShift = 16;//img->format.rShift; +	static const int kAModShift = 24;//img->format.aShift; + +  	/**  	 @brief renders the surface to another surface  	 @param pDest a pointer to the target image. In most cases this is the framebuffer. @@ -115,10 +159,26 @@ struct TransparentSurface : public Graphics::Surface {  	                  int flipping = FLIP_NONE,  	                  Common::Rect *pPartRect = nullptr,  	                  uint color = BS_ARGB(255, 255, 255, 255), -	                  int width = -1, int height = -1); +	                  int width = -1, int height = -1, +	                  TSpriteBlendMode blend = BLEND_NORMAL);  	void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false); - +	 +	/** +	 * @brief Scale function; this returns a transformed version of this surface after rotation and +	 * scaling. Please do not use this if angle != 0, use rotoscale. +	 * +	 * @param transform a TransformStruct wrapping the required info. @see TransformStruct +	 *  +	 */  	TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const; + +	/** +	 * @brief Rotoscale function; this returns a transformed version of this surface after rotation and +	 * scaling. Please do not use this if angle == 0, use plain old scaling function. +	 * +	 * @param transform a TransformStruct wrapping the required info. @see TransformStruct +	 *  +	 */  	TransparentSurface *rotoscale(const TransformStruct &transform) const;  }; @@ -134,7 +194,6 @@ struct TransparentSurface : public Graphics::Surface {      }  };*/ -  } // End of namespace Wintermute  | 
