diff options
19 files changed, 721 insertions, 139 deletions
diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h index 05cb9fc936..d464899b04 100644 --- a/engines/wintermute/base/base_sprite.h +++ b/engines/wintermute/base/base_sprite.h @@ -32,6 +32,7 @@  #include "engines/wintermute/coll_templ.h"  #include "engines/wintermute/base/base_script_holder.h" +#include "engines/wintermute/graphics/transform_tools.h"  namespace Wintermute {  class BaseFrame; @@ -44,17 +45,17 @@ public:  	void setDefaults();  	DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder) -	bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100); +	bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = kDefaultZoomX, float scaleY = kDefaultZoomY);  	int32 _moveY;  	int32 _moveX; -	bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL); -	bool getCurrentFrame(float zoomX = 100, float zoomY = 100); +	bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod, float rotate = kDefaultAngle, TSpriteBlendMode blendMode = BLEND_NORMAL); +	bool getCurrentFrame(float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY);  	void reset();  	bool isChanged();  	bool isFinished();  	bool loadBuffer(byte *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);  	bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); -	bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF); +	bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod);  	bool _looping;  	int32 _currentFrame;  	bool addFrame(const char *filename, uint32 delay = 0, int hotspotX = 0, int hotspotY = 0, Rect32 *rect = nullptr); diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp index d93cf667f1..7012c28feb 100644 --- a/engines/wintermute/base/base_sub_frame.cpp +++ b/engines/wintermute/base/base_sub_frame.cpp @@ -38,6 +38,8 @@  #include "engines/wintermute/base/gfx/base_renderer.h"  #include "engines/wintermute/base/scriptables/script_value.h"  #include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/graphics/transform_tools.h" +#include "engines/wintermute/graphics/transform_struct.h"  namespace Wintermute { @@ -46,8 +48,9 @@ IMPLEMENT_PERSISTENT(BaseSubFrame, false)  //////////////////////////////////////////////////////////////////////////  BaseSubFrame::BaseSubFrame(BaseGame *inGame) : BaseScriptable(inGame, true) {  	_surface = nullptr; -	_hotspotX = _hotspotY = 0; -	_alpha = 0xFFFFFFFF; +	_hotspotX = kDefaultHotspotX; +	_hotspotY = kDefaultHotspotY; +	_alpha = kDefaultRgbaMod;  	_transparent = 0xFFFF00FF;  	_wantsDefaultRect = false; @@ -233,12 +236,18 @@ const char* BaseSubFrame::getSurfaceFilename() {  //////////////////////////////////////////////////////////////////////  bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, TSpriteBlendMode blendMode) { +	 +	rotate = fmod(rotate, 360.0f); +	if (rotate < 0) { +		rotate += 360.0f; +	} +  	if (!_surface) {  		return STATUS_OK;  	}  	if (registerOwner != nullptr && !_decoration) { -		if (zoomX == 100 && zoomY == 100) { +		if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) {  			BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef,  registerOwner, this, x - _hotspotX + getRect().left, y  - _hotspotY + getRect().top, getRect().right - getRect().left, getRect().bottom - getRect().top, zoomX, zoomY, precise));  		} else {  			BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef,  registerOwner, this, (int)(x - (_hotspotX + getRect().left) * (zoomX / 100)), (int)(y - (_hotspotY + getRect().top) * (zoomY / 100)), (int)((getRect().right - getRect().left) * (zoomX / 100)), (int)((getRect().bottom - getRect().top) * (zoomY / 100)), zoomX, zoomY, precise)); @@ -251,17 +260,24 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl  	bool res;  	//if (Alpha==0xFFFFFFFF) Alpha = _alpha; // TODO: better (combine owner's and self alpha) -	if (_alpha != 0xFFFFFFFF) { +	if (_alpha != kDefaultRgbaMod) {  		alpha = _alpha;  	} -	if (rotate != 0.0f) { -		res = _surface->displayTransform((int)(x - _hotspotX * (zoomX / 100)), (int)(y - _hotspotY * (zoomY / 100)), _hotspotX, _hotspotY, getRect(), zoomX, zoomY, alpha, rotate, blendMode, _mirrorX, _mirrorY); +	if (rotate != kDefaultAngle) { +		Point32 boxOffset, rotatedHotspot, hotspotOffset, newOrigin; +		Point32 origin(x, y); +		Rect32 oldRect = getRect(); +		Point32 newHotspot; +		TransformStruct transform = TransformStruct(zoomX, zoomY, rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0); +		Rect32 newRect = TransformTools::newRect (oldRect, transform, &newHotspot); +		newOrigin = origin - newHotspot; +		res = _surface->displayTransform(newOrigin.x, newOrigin.y, oldRect, newRect, transform);   	} else { -		if (zoomX == 100 && zoomY == 100) { +		if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) {  			res = _surface->displayTrans(x - _hotspotX, y - _hotspotY, getRect(), alpha, blendMode, _mirrorX, _mirrorY);  		} else { -			res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / 100)), (int)(y - _hotspotY * (zoomY / 100)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY); +			res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);  		}  	} diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp index 2002463ea4..42ec51f39e 100644 --- a/engines/wintermute/base/gfx/base_surface.cpp +++ b/engines/wintermute/base/gfx/base_surface.cpp @@ -75,8 +75,8 @@ bool BaseSurface::displayHalfTrans(int x, int y, Rect32 rect) {  }  ////////////////////////////////////////////////////////////////////////// -bool BaseSurface::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { -	return displayTransZoom(x, y, rect, zoomX, zoomY, alpha, blendMode, mirrorX, mirrorY); +bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) { +	return displayTransform(x, y, rect, newRect, transform);  }  ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h index b83efa0bb8..e308b29996 100644 --- a/engines/wintermute/base/gfx/base_surface.h +++ b/engines/wintermute/base/gfx/base_surface.h @@ -32,6 +32,7 @@  #include "engines/wintermute/base/base.h"  #include "engines/wintermute/math/rect32.h"  #include "graphics/surface.h" +#include "engines/wintermute/graphics/transform_struct.h"  namespace Wintermute { @@ -49,12 +50,12 @@ public:  	virtual bool displayHalfTrans(int x, int y, Rect32 rect);  	virtual bool isTransparentAt(int x, int y); -	virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; +	virtual bool displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;  	virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;  	virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0;  	virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; -	virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; -	virtual bool displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; +	virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) = 0; +	virtual bool displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;  	virtual bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) = 0;  	virtual bool restore();  	virtual bool create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0; diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index eca2998da5..7905184190 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -60,8 +60,7 @@ BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) {  	_borderLeft = _borderRight = _borderTop = _borderBottom = 0;  	_ratioX = _ratioY = 1.0f; -	setAlphaMod(255); -	setColorMod(255, 255, 255); +	_colorMod = kDefaultRgbaMod;  	_dirtyRect = nullptr;  	_disableDirtyRects = false;  	_tempDisableDirtyRects = 0; @@ -150,18 +149,6 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) {  	return STATUS_OK;  } -void BaseRenderOSystem::setAlphaMod(byte alpha) { -	byte r = RGBCOLGetR(_colorMod); -	byte g = RGBCOLGetB(_colorMod); -	byte b = RGBCOLGetB(_colorMod); -	_colorMod = BS_ARGB(alpha, r, g, b); -} - -void BaseRenderOSystem::setColorMod(byte r, byte g, byte b) { -	byte alpha = RGBCOLGetA(_colorMod); -	_colorMod = BS_ARGB(alpha, r, g, b); -} -  bool BaseRenderOSystem::indicatorFlip() {  	g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_indicatorX, _indicatorY), _renderSurface->pitch, _indicatorX, _indicatorY, _indicatorWidthDrawn, _indicatorHeight);  	g_system->updateScreen(); @@ -256,7 +243,6 @@ void BaseRenderOSystem::fade(uint16 alpha) {  	return fadeToColor(0, 0, 0, dwAlpha);  } -  //////////////////////////////////////////////////////////////////////////  void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect) {  	Common::Rect fillRect; @@ -279,14 +265,14 @@ void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect  	//TODO: This is only here until I'm sure about the final pixelformat  	uint32 col = _renderSurface->format.ARGBToColor(a, r, g, b); -	setAlphaMod(255); -	setColorMod(255, 255, 255);  	Graphics::Surface surf;  	surf.create((uint16)fillRect.width(), (uint16)fillRect.height(), _renderSurface->format);  	Common::Rect sizeRect(fillRect);  	sizeRect.translate(-fillRect.top, -fillRect.left);  	surf.fillRect(fillRect, col); -	drawSurface(nullptr, &surf, &sizeRect, &fillRect, false, false); +	TransformStruct temp = TransformStruct(); +	temp._alphaDisable = false; +	drawSurface(nullptr, &surf, &sizeRect, &fillRect, temp);  	surf.free();  	//SDL_SetRenderDrawColor(_renderer, r, g, b, a); @@ -298,16 +284,18 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const {  	return _renderSurface->format;  } -void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) { +void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) {  +  	if (_tempDisableDirtyRects || _disableDirtyRects) { -		RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha); -		ticket->_colorMod = _colorMod; +		RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); +		ticket->_transform._rgbaMod = _colorMod;  		ticket->_wantsDraw = true;  		_renderQueue.push_back(ticket);  		_previousTicket = ticket;  		drawFromSurface(ticket);  		return;  	} +  	// Start searching from the beginning for the first and second items (since it's empty the first time around  	// then keep incrementing the start-position, to avoid comparing against already used tickets.  	if (_drawNum == 0 || _drawNum == 1) { @@ -320,12 +308,11 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S  	}  	if (owner) { // Fade-tickets are owner-less -		RenderTicket compare(owner, nullptr, srcRect, dstRect, mirrorX, mirrorY, disableAlpha); +		RenderTicket compare(owner, nullptr, srcRect, dstRect, transform);  		compare._batchNum = _batchNum;  		if (_spriteBatch) {  			_batchNum++;  		} -		compare._colorMod = _colorMod;  		RenderQueueIterator it;  		// Avoid calling end() and operator* every time, when potentially going through  		// LOTS of tickets. @@ -334,7 +321,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S  		for (it = _lastAddedTicket; it != endIterator; ++it) {  			compareTicket = *it;  			if (*(compareTicket) == compare && compareTicket->_isValid) { -				compareTicket->_colorMod = _colorMod; +				compareTicket->_transform._rgbaMod = transform._rgbaMod;   				if (_disableDirtyRects) {  					drawFromSurface(compareTicket);  				} else { @@ -349,8 +336,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S  			}  		}  	} -	RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha); -	ticket->_colorMod = _colorMod; +	RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);  	if (!_disableDirtyRects) {  		drawFromTicket(ticket);  		_previousTicket = ticket; @@ -385,12 +371,14 @@ void BaseRenderOSystem::repeatLastDraw(int offsetX, int offsetY, int numTimesX,  		int initLeft = dstRect.left;  		int initRight = dstRect.right; +		TransformStruct temp = TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, BLEND_NORMAL, kDefaultRgbaMod, false, false, kDefaultOffsetX, kDefaultOffsetY); +  		for (int i = 0; i < numTimesY; i++) {  			if (i == 0) {  				dstRect.translate(offsetX, 0);  			}  			for (int j = (i == 0 ? 1 : 0); j < numTimesX; j++) { -				drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, false, false); +				drawSurface(origTicket->_owner, origTicket->getSurface(), &srcRect, &dstRect, temp);   				dstRect.translate(offsetX, 0);  			}  			dstRect.left = initLeft; @@ -535,7 +523,7 @@ void BaseRenderOSystem::drawTickets() {  			// convert from screen-coords to surface-coords.  			dstClip.translate(-offsetX, -offsetY); -			_colorMod = ticket->_colorMod; +			_colorMod = ticket->_transform._rgbaMod;   			drawFromSurface(ticket, &pos, &dstClip);  			_needsFlip = true;  		} diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index 3cb0fa82a3..5531961623 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -33,6 +33,7 @@  #include "common/rect.h"  #include "graphics/surface.h"  #include "common/list.h" +#include "engines/wintermute/graphics/transform_struct.h"  namespace Wintermute {  class BaseSurfaceOSystem; @@ -56,8 +57,6 @@ public:  	BaseImage *takeScreenshot() override; -	void setAlphaMod(byte alpha); -	void setColorMod(byte r, byte g, byte b);  	void invalidateTicket(RenderTicket *renderTicket);  	void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf);  	void drawFromTicket(RenderTicket *renderTicket); @@ -80,7 +79,7 @@ public:  	virtual bool startSpriteBatch() override;  	virtual bool endSpriteBatch() override;  	void endSaveLoad(); -	void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha = false) ; +	void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform);   	void repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY);  	BaseSurface *createSurface() override;  private: diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index 87bb2fdb53..b809318133 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -52,6 +52,7 @@ BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) {  	_lockPixels = nullptr;  	_lockPitch = 0;  	_loaded = false; +	_rotation = 0;  }  ////////////////////////////////////////////////////////////////////////// @@ -319,39 +320,56 @@ bool BaseSurfaceOSystem::endPixelOp() {  //////////////////////////////////////////////////////////////////////////  bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { -	return drawSprite(x, y, &rect, 100, 100, 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY); +	_rotation = 0; +	return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY,  mirrorX, mirrorY));  }  //////////////////////////////////////////////////////////////////////////  bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { -	return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY); +	_rotation = 0; +	return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY));   }  //////////////////////////////////////////////////////////////////////////  bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { -	return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY, offsetX, offsetY); +	_rotation = 0; +	return drawSprite(x, y, &rect, nullptr,  TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY));  }  ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { -	return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY); +bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { +	_rotation = 0; +	return drawSprite(x, y, &rect, nullptr, TransformStruct(zoomX, zoomY, blendMode, alpha, mirrorX, mirrorY));  }  ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { -	return drawSprite(x, y, &rect, zoomX, zoomY, alpha, !transparent, blendMode, mirrorX, mirrorY); +bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { +	_rotation = 0; +	TransformStruct transform; +	if (transparent) { +		transform = TransformStruct(zoomX, zoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha,  mirrorX, mirrorY); +	} else { +		transform = TransformStruct(zoomX, zoomY, mirrorX, mirrorY); +	} +	return drawSprite(x, y, &rect, nullptr, transform);  }  ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { -	return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY); +bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) { +	_rotation = (uint32)transform._angle; +	if (transform._angle < 0.0f) { +		warning("Negative rotation: %d %d", transform._angle, _rotation); +		_rotation = (uint32)(360.0f + transform._angle); +		warning("Negative post rotation: %d %d", transform._angle, _rotation); +	} +	return drawSprite(x, y, &rect, &newRect, transform);  }  ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { +bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) {  	BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);  	if (!_loaded) { @@ -359,17 +377,9 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo  	}  	if (renderer->_forceAlphaColor != 0) { -		alpha = renderer->_forceAlphaColor; +		transform._rgbaMod = renderer->_forceAlphaColor;  	} -	byte r = RGBCOLGetR(alpha); -	byte g = RGBCOLGetG(alpha); -	byte b = RGBCOLGetB(alpha); -	byte a = RGBCOLGetA(alpha); - -	renderer->setAlphaMod(a); -	renderer->setColorMod(r, g, b); -  #if 0 // These are kept for reference if BlendMode is reimplemented at some point.  	if (alphaDisable) {  		SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE); @@ -386,8 +396,8 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo  	srcRect.setHeight(rect->bottom - rect->top);  	Common::Rect position; -	position.left = x + offsetX; -	position.top = y + offsetY; +	position.left = x + transform._offset.x; +	position.top = y + transform._offset.y;  	// Crop off-by-ones:  	if (position.left == -1) { @@ -396,31 +406,34 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo  	if (position.top == -1) {  		position.top = 0; // TODO: Something is wrong  	} - -	position.setWidth((int16)((float)srcRect.width() * zoomX / 100.f)); -	position.setHeight((int16)((float)srcRect.height() * zoomX / 100.f)); - +	if (newRect) { +		position.top = y; +		position.left = x; +		position.right = x + newRect->width(); +		position.bottom = y + newRect->height(); +		position.setWidth(newRect->width()); +		position.setHeight(newRect->height()); +	} else { +		position.setWidth((int16)((float)srcRect.width() * transform._zoom.x / kDefaultZoomX)); +		position.setHeight((int16)((float)srcRect.height() * transform._zoom.y / kDefaultZoomY)); +	}  	renderer->modTargetRect(&position); -	/*  position.left += offsetX; -	    position.top += offsetY;*/ -  	// TODO: This actually requires us to have the SAME source-offsets every time,  	// But no checking is in place for that yet.  	// TODO: Optimize by not doing alpha-blits if we lack or disable alpha -	bool hasAlpha; -	if (_hasAlpha && !alphaDisable) { + +	bool hasAlpha = false; + +	if (_hasAlpha && !transform._alphaDisable) {  		hasAlpha = true; -	} else { -		hasAlpha = false; -	} -	if (alphaDisable) { +	}       +	 +	if (transform._alphaDisable) {  		warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored");  	} - -	renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY, !hasAlpha); - +	renderer->drawSurface(this, _surface, &srcRect, &position, transform);   	return STATUS_OK;  } diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h index 9091ec65b1..5290170db8 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -51,12 +51,12 @@ public:  	bool endPixelOp() override; -	bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; -	bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; -	bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override; +	bool displayTransZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; +	bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; +	bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;  	bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; -	bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; -	bool displayTransform(int x, int y, int hotX, int hotY, Rect32 Rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; +	bool displayZoom(int x, int y, Rect32 rect, int32 zoomX, int32 zoomY, uint32 alpha = kDefaultRgbaMod, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; +	bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) override;  	bool repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) override;  	virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override;  	/*  static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle); @@ -85,10 +85,11 @@ private:  	Graphics::Surface *_surface;  	bool _loaded;  	bool finishLoad(); -	bool drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX = 0, int offsetY = 0); +	bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transformStruct);  	void genAlphaMask(Graphics::Surface *surface);  	uint32 getPixelAt(Graphics::Surface *surface, int x, int y); +	uint32 _rotation;  	bool _hasAlpha;  	void *_lockPixels;  	int _lockPitch; diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index 98c5be62a8..8d9d5325c4 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -26,22 +26,22 @@   * Copyright (c) 2011 Jan Nedoma   */ -#include "engines/wintermute/graphics/transparent_surface.h" +  #include "engines/wintermute/base/gfx/osystem/render_ticket.h" +#include "engines/wintermute/graphics/transform_tools.h" +#include "common/textconsole.h"  namespace Wintermute { -RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) : _owner(owner), -_srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(true), _hasAlpha(!disableAlpha) { -	_colorMod = 0; +RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct transform) : +	_owner(owner), +	_srcRect(*srcRect), +	_dstRect(*dstRect), +	_drawNum(0), +	_isValid(true), +	_wantsDraw(true), +	_transform(transform) {  	_batchNum = 0; -	_mirror = TransparentSurface::FLIP_NONE; -	if (mirrorX) { -		_mirror |= TransparentSurface::FLIP_V; -	} -	if (mirrorY) { -		_mirror |= TransparentSurface::FLIP_H; -	}  	if (surf) {  		_surface = new Graphics::Surface();  		_surface->create((uint16)srcRect->width(), (uint16)srcRect->height(), surf->format); @@ -51,7 +51,13 @@ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(  			memcpy(_surface->getBasePtr(0, i), surf->getBasePtr(srcRect->left, srcRect->top + i), srcRect->width() * _surface->format.bytesPerPixel);  		}  		// Then scale it if necessary -		if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) { +		if (_transform._angle != kDefaultAngle) { +			TransparentSurface src(*_surface, false); +			Graphics::Surface *temp = src.rotoscale(transform); +			_surface->free(); +			delete _surface; +			_surface = temp; +		} else if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) {   			TransparentSurface src(*_surface, false);  			Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height());  			_surface->free(); @@ -60,6 +66,14 @@ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(  		}  	} else {  		_surface = nullptr; +		 +		if (transform._angle != kDefaultAngle) { // Make sure comparison-tickets get the correct width +			Rect32 newDstRect; +			Point32 newHotspot; +			newDstRect = TransformTools::newRect(_srcRect, transform, &newHotspot); +			_dstRect.setWidth(newDstRect.right - newDstRect.left); +			_dstRect.setHeight(newDstRect.bottom - newDstRect.top); +		}  	}  } @@ -70,32 +84,31 @@ RenderTicket::~RenderTicket() {  	}  } -bool RenderTicket::operator==(RenderTicket &t) { +bool RenderTicket::operator==(const RenderTicket &t) const {  	if ((t._owner != _owner) ||  		(t._batchNum != _batchNum) || -		(t._hasAlpha != _hasAlpha) || -		(t._mirror != _mirror) || -		(t._colorMod != _colorMod) || +		(t._transform != _transform)  ||   		(t._dstRect != _dstRect) || -		(t._srcRect != _srcRect)) { +		(t._srcRect != _srcRect)  +	) {  		return false;  	}  	return true;  }  // Replacement for SDL2's SDL_RenderCopy -void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) { +void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {  	TransparentSurface src(*getSurface(), false);  	Common::Rect clipRect;  	clipRect.setWidth(getSurface()->w);  	clipRect.setHeight(getSurface()->h); -	src._enableAlphaBlit = _hasAlpha; -	src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _mirror, &clipRect, _colorMod, clipRect.width(), clipRect.height()); +	src._enableAlphaBlit = !_transform._alphaDisable; +	src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height());  } -void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) { +void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const {  	TransparentSurface src(*getSurface(), false);  	bool doDelete = false;  	if (!clipRect) { @@ -105,8 +118,8 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect  		clipRect->setHeight(getSurface()->h);  	} -	src._enableAlphaBlit = _hasAlpha; -	src.blit(*_targetSurface, dstRect->left, dstRect->top, _mirror, clipRect, _colorMod, clipRect->width(), clipRect->height()); +	src._enableAlphaBlit = !_transform._alphaDisable;  +	src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height());  	if (doDelete) {  		delete clipRect;  	} diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h index 64df3590a1..ec1412b032 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.h +++ b/engines/wintermute/base/gfx/osystem/render_ticket.h @@ -29,6 +29,7 @@  #ifndef WINTERMUTE_RENDER_TICKET_H  #define WINTERMUTE_RENDER_TICKET_H +#include "engines/wintermute/graphics/transparent_surface.h"  #include "graphics/surface.h"  #include "common/rect.h" @@ -37,14 +38,14 @@ namespace Wintermute {  class BaseSurfaceOSystem;  class RenderTicket {  public: -	RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, bool mirrorX = false, bool mirrorY = false, bool disableAlpha = false); -	RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0) {} +	RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform);  +	RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0), _transform(TransformStruct()) {}  	~RenderTicket(); -	const Graphics::Surface *getSurface() { return _surface; } +	const Graphics::Surface *getSurface() const { return _surface; }  	// Non-dirty-rects: -	void drawToSurface(Graphics::Surface *_targetSurface); +	void drawToSurface(Graphics::Surface *_targetSurface) const;  	// Dirty-rects: -	void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect); +	void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const;  	Common::Rect _dstRect;  	uint32 _batchNum; @@ -52,16 +53,15 @@ public:  	bool _isValid;  	bool _wantsDraw;  	uint32 _drawNum; -	uint32 _colorMod; +	TransformStruct _transform;  +	  	BaseSurfaceOSystem *_owner; -	bool operator==(RenderTicket &a); -	const Common::Rect *getSrcRect() { return &_srcRect; } +	bool operator==(const RenderTicket &a) const; +	const Common::Rect *getSrcRect() const { return &_srcRect; }  private:  	Graphics::Surface *_surface;  	Common::Rect _srcRect; -	bool _hasAlpha; -	uint32 _mirror;  };  } // end of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp new file mode 100644 index 0000000000..8edbf765b5 --- /dev/null +++ b/engines/wintermute/graphics/transform_struct.cpp @@ -0,0 +1,93 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * 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. + * + */ + +#include "engines/wintermute/graphics/transform_struct.h" +#include "engines/wintermute/graphics/transparent_surface.h" + +namespace Wintermute { +void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, Point32 offset) { +	_zoom = zoom; +	_angle = angle; +	_hotspot = hotspot; +	_blendMode = blendMode; +	_rgbaMod = rgbaMod; +	_alphaDisable = alphaDisable; +	_flip = 0; +	_flip += TransparentSurface::FLIP_H * mirrorX; +	_flip += TransparentSurface::FLIP_V * mirrorY; +	_offset = offset; +} + + +TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { +	init(Point32(zoomX, zoomY),  +		angle,  +		Point32(hotspotX, hotspotY),  +		false,  +		blendMode,  +		rgbaMod,  +		mirrorX, mirrorY,  +		Point32(offsetX, offsetY)); +} + +TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) { +	init(Point32(zoomX, zoomY),  +		kDefaultAngle,  +		Point32(kDefaultHotspotX, kDefaultHotspotY),  +		false,  +		blendMode,  +		rgbaMod,  +		mirrorX,  +		mirrorY,   +		Point32(kDefaultOffsetX, kDefaultOffsetY)); +} + +TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) { +	init(Point32(zoomX, zoomY),  +		angle,  +		Point32(hotspotX, hotspotY),  +		true,  +		BLEND_NORMAL,  +		kDefaultRgbaMod,  +		false, false, +		Point32(kDefaultOffsetX, kDefaultOffsetY)); +} + +TransformStruct::TransformStruct() { +	init(Point32(kDefaultZoomX, kDefaultZoomY),  +		kDefaultAngle,  +		Point32(kDefaultHotspotX, kDefaultHotspotY),  +		true,  +		BLEND_NORMAL,  +		kDefaultRgbaMod,  +		false, false,   +		Point32(kDefaultOffsetX, kDefaultOffsetY)); +} + +bool TransformStruct::getMirrorX() const { +	return (bool)(_flip & TransparentSurface::FLIP_H); +} + +bool TransformStruct::getMirrorY() const { +	return (bool)(_flip & TransparentSurface::FLIP_V); +} +} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h new file mode 100644 index 0000000000..acde410e89 --- /dev/null +++ b/engines/wintermute/graphics/transform_struct.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * 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. + * + */ + +#ifndef WINTERMUTE_TRANSFORM_STRUCT_H +#define WINTERMUTE_TRANSFORM_STRUCT_H + +#include "engines/wintermute/math/rect32.h" +#include "engines/wintermute/dctypes.h" + +namespace Wintermute { +/**  + * Contains all the required information that define a transform. + * Same source sprite + same TransformStruct = Same resulting sprite. + * Has a number of overloaded constructors to accomodate various argument lists. + */ +	 +const uint32 kDefaultZoomX = 100; +const uint32 kDefaultZoomY = 100; +const uint32 kDefaultRgbaMod = 0xFFFFFFFF; +const int32 kDefaultHotspotX = 0; +const int32 kDefaultHotspotY = 0; +const int32 kDefaultOffsetX = 0; +const int32 kDefaultOffsetY = 0; +const int32 kDefaultAngle = 0; +	 +struct TransformStruct { +private:  +	void init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX, bool mirrorY, Point32 offset); + +public: +	TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0); +	TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false); +	TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0); +	TransformStruct(); +	 +	Point32 _zoom;	 ///< Zoom; 100 = no zoom +	Point32 _hotspot; ///< Position of the hotspot +	uint32 _angle;	 ///< Rotation angle, in degrees +	byte _flip;		 ///< Bitflag: see TransparentSurface::FLIP_XXX +	bool _alphaDisable; +	TSpriteBlendMode _blendMode; +	uint32 _rgbaMod;	  ///< RGBa +	Point32 _offset;   +	 +	bool getMirrorX() const; +	bool getMirrorY() const; + +	bool operator==(const TransformStruct &compare) const { +		return (compare._angle == _angle && +				compare._flip == _flip && +				compare._zoom == _zoom  && +				compare._offset == _offset && +				compare._alphaDisable == _alphaDisable  && +				compare._rgbaMod == _rgbaMod && +				compare._blendMode == _blendMode +				); +	} +  +	bool operator!=(const TransformStruct &compare) const { +		return !(compare == *this); +	} +}; +} // End of namespace Wintermute +#endif diff --git a/engines/wintermute/graphics/transform_tools.cpp b/engines/wintermute/graphics/transform_tools.cpp new file mode 100644 index 0000000000..4f05e19a92 --- /dev/null +++ b/engines/wintermute/graphics/transform_tools.cpp @@ -0,0 +1,74 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * 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. + * + */ + + +#include "engines/wintermute/graphics/transform_tools.h" +#include <math.h> + +namespace Wintermute { +	 +FloatPoint TransformTools::transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) { +	float rotateRad = rotate * M_PI / 180.0f; +	FloatPoint newPoint; +	newPoint.x = (point.x * cos(rotateRad) - point.y * sin(rotateRad)) * zoom.x / kDefaultZoomX; +	newPoint.y = (point.x * sin(rotateRad) + point.y * cos(rotateRad)) * zoom.y / kDefaultZoomY; +	if (mirrorX) { +		newPoint.x *= -1; +	} +	if (mirrorY) { +		newPoint.y *= -1; +	} +	return newPoint; +} + +Rect32 TransformTools::newRect (const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot) { + +	Point32 nw(oldRect.left, oldRect.top); +	Point32 ne(oldRect.right, oldRect.top); +	Point32 sw(oldRect.left, oldRect.bottom); +	Point32 se(oldRect.right, oldRect.bottom); +		 +	FloatPoint nw1, ne1, sw1, se1; + +	nw1 = transformPoint(nw - transform._hotspot, transform._angle, transform._zoom); +	ne1 = transformPoint(ne - transform._hotspot, transform._angle, transform._zoom); +	sw1 = transformPoint(sw - transform._hotspot, transform._angle, transform._zoom); +	se1 = transformPoint(se - transform._hotspot, transform._angle, transform._zoom); +		 +	float top = MIN(nw1.y, MIN(ne1.y, MIN(sw1.y, se1.y))); +	float bottom = MAX(nw1.y, MAX(ne1.y, MAX(sw1.y, se1.y))); +	float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x))); +	float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x))); + +	Rect32 res; +	newHotspot->y = (uint32)(-floor(top)); +	newHotspot->x = (uint32)(-floor(left)); + +	res.top = (int32)(floor(top)) + transform._hotspot.y; +	res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y;  +	res.left = (int32)(floor(left)) + transform._hotspot.x; +	res.right = (int32)(ceil(right)) + transform._hotspot.x; + +	return res; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_tools.h b/engines/wintermute/graphics/transform_tools.h new file mode 100644 index 0000000000..e59c47272a --- /dev/null +++ b/engines/wintermute/graphics/transform_tools.h @@ -0,0 +1,53 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * 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. + * + */ + +#ifndef WINTERMUTE_TRANSFORM_TOOLS_H +#define WINTERMUTE_TRANSFORM_TOOLS_H + +#include "engines/wintermute/math/rect32.h" +#include "engines/wintermute/math/floatpoint.h" +#include "engines/wintermute/graphics/transform_struct.h" + +namespace Wintermute { + +class TransformTools { +public:	 +	/** +	 * Basic transform (scale + rotate) for a single point +	 */	 +	static FloatPoint transformPoint(const FloatPoint &point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false); + +	/** +	 * @param &point the point on which the transform is to be applied +	 * @param rotate the angle in degrees +	 * @param &zoom  zoom x,y in percent +	 * @param mirrorX flip along the vertical axis? +	 * @param mirrorY flip along the horizontal axis? +	 * @return the smallest rect that can contain the transformed sprite +	 * and, as a side-effect, "newHotspot" will tell you where the hotspot will +	 * have ended up in the new rect, for centering. +	 */ +	static Rect32 newRect (const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot);	 +}; + +} // End of namespace Wintermute +#endif diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index dcdcbf247e..5b7c416ee9 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -23,12 +23,124 @@  #include "common/endian.h"  #include "common/util.h"  #include "common/rect.h" +#include "common/math.h"  #include "common/textconsole.h"  #include "graphics/primitives.h"  #include "engines/wintermute/graphics/transparent_surface.h" +#include "engines/wintermute/graphics/transform_tools.h"  namespace Wintermute { + +#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) { + +			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) { +			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  +  byte *TransparentSurface::_lookup = nullptr;  void TransparentSurface::destroyLookup() { @@ -250,12 +362,12 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p  		int inStep = 4;  		int inoStep = img->pitch; -		if (flipping & TransparentSurface::FLIP_V) { +		if (flipping & TransparentSurface::FLIP_H) {  			inStep = -inStep;  			xp = img->w - 1;  		} -		if (flipping & TransparentSurface::FLIP_H) { +		if (flipping & TransparentSurface::FLIP_V) {  			inoStep = -inoStep;  			yp = img->h - 1;  		} @@ -383,16 +495,54 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p  	return retSize;  } -TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const { +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. + +	Point32 newHotspot;  	Common::Rect srcRect(0, 0, (int16)w, (int16)h); -	Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight); -	return scale(srcRect, dstRect); +	Rect32 rect = TransformTools::newRect(Rect32 (srcRect), transform, &newHotspot); +	Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top)); + +	TransparentSurface *target = new TransparentSurface(); +	assert(format.bytesPerPixel == 4); + +	int dstW = dstRect.width(); +	int dstH = dstRect.height(); + +	target->create((uint16)dstW, (uint16)dstH, this->format); + +	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; + +			targX = ((x1 * invCos - y1 * invSin)) * kDefaultZoomX / transform._zoom.x + srcRect.left;  +			targY = ((x1 * invSin + y1 * invCos)) * kDefaultZoomY / transform._zoom.y + srcRect.top;  +				 +			targX += transform._hotspot.x; +			targY += transform._hotspot.y; +			 +#if ENABLE_BILINEAR +			copyPixelBilinear(targX, targY, x, y, srcRect, dstRect, this, target);  +#else +			copyPixelNearestNeighbor(targX, targY, x, y, srcRect, dstRect, this, target);  +#endif +		} +	} +	return target;  } -// Copied from clone2727's https://github.com/clone2727/scummvm/blob/pegasus/engines/pegasus/surface.cpp#L247 -TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const { -	// I'm doing simple linear scaling here -	// dstRect(x, y) = srcRect(x * srcW / dstW, y * srcH / dstH); +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); +		  	TransparentSurface *target = new TransparentSurface();  	assert(format.bytesPerPixel == 4); @@ -404,11 +554,18 @@ TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const  	target->create((uint16)dstW, (uint16)dstH, this->format); + +	float projX; +	float projY;  	for (int y = 0; y < dstH; y++) {  		for (int x = 0; x < dstW; x++) { -			uint32 color = READ_UINT32((const byte *)getBasePtr(x * srcW / dstW + srcRect.left, -														  y * srcH / dstH + srcRect.top)); -			WRITE_UINT32((byte *)target->getBasePtr(x + dstRect.left, y + dstRect.top), color); +			projX = x / (float)dstW * srcW; +			projY = y / (float)dstH * srcH; +#if ENABLE_BILINEAR +			copyPixelBilinear(projX, projY, x, y, srcRect, dstRect, this, target);  +#else +			copyPixelNearestNeighbor(projX, projY, x, y, srcRect, dstRect, this, target);  +#endif  		}  	}  	return target; diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index dc079a1fbc..7b5579f389 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -23,6 +23,10 @@  #define GRAPHICS_TRANSPARENTSURFACE_H  #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 @@ -49,6 +53,11 @@ struct TransparentSurface : public Graphics::Surface {  	void setColorKey(char r, char g, char b);  	void disableColorKey(); +#if ENABLE_BILINEAR +	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 +	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. @@ -102,9 +111,9 @@ struct TransparentSurface : public Graphics::Surface {  	                  uint color = BS_ARGB(255, 255, 255, 255),  	                  int width = -1, int height = -1);  	void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false); -	// The following scale-code supports arbitrary scaling (i.e. no repeats of column 0 at the end of lines) -	TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const; -	TransparentSurface *scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const; + +	TransparentSurface *scale (uint16 newWidth, uint16 newHeight) const; +	TransparentSurface *rotoscale (const TransformStruct &transform) const;    	static byte *_lookup;  	static void destroyLookup();  private: diff --git a/engines/wintermute/math/floatpoint.h b/engines/wintermute/math/floatpoint.h new file mode 100644 index 0000000000..0c47ef09d7 --- /dev/null +++ b/engines/wintermute/math/floatpoint.h @@ -0,0 +1,52 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * 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. + * + */ + +#ifndef WINTERMUTE_FLOATPOINT_H +#define WINTERMUTE_FLOATPOINT_H + +namespace Wintermute { + +struct FloatPoint { +	float x; +	float y; +	FloatPoint() : x(0), y(0) {} +	FloatPoint(float x1, float y1) : x(x1), y(y1) {} +	bool operator==(const FloatPoint &p) const { return x == p.x && y == p.y; } +	bool operator!=(const FloatPoint  &p) const { return x != p.x || y != p.y; } +	FloatPoint operator+(const FloatPoint &delta) const { return FloatPoint (x + delta.x, y + delta.y);	} +	FloatPoint operator-(const FloatPoint &delta) const { return FloatPoint (x - delta.x, y - delta.y);	} + +	FloatPoint& operator+=(const FloatPoint &delta) { +		x += delta.x; +		y += delta.y; +		return *this; +	} +	FloatPoint& operator-=(const FloatPoint &delta) { +		x -= delta.x; +		y -= delta.y; +		return *this; +	} +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/math/rect32.h b/engines/wintermute/math/rect32.h index 190c1135cf..79d6e80017 100644 --- a/engines/wintermute/math/rect32.h +++ b/engines/wintermute/math/rect32.h @@ -24,12 +24,38 @@  #define WINTERMUTE_RECT32_H  #include "common/system.h" +#include "engines/wintermute/math/floatpoint.h" +#include "common/rect.h"  namespace Wintermute {  struct Point32 {  	int32 x;  	int32 y; +	Point32() : x(0), y(0) {} +	Point32(int32 x1, int32 y1) : x(x1), y(y1) {} +	bool operator==(const Point32 &p) const { return x == p.x && y == p.y; } +	bool operator!=(const Point32 &p) const { return x != p.x || y != p.y; } +	Point32 operator+(const Point32 &delta) const {	return Point32(x + delta.x, y + delta.y);	} +	Point32 operator-(const Point32 &delta) const {	return Point32(x - delta.x, y - delta.y);	} + +	Point32 &operator+=(const Point32 &delta) { +		x += delta.x; +		y += delta.y; +		return *this; +	} + +	Point32 &operator-=(const Point32 &delta) { +		x -= delta.x; +		y -= delta.y; +		return *this; +	} +	 +	operator FloatPoint() { +		return FloatPoint(x,y); +	} + +  };  struct Rect32 { @@ -38,6 +64,7 @@ struct Rect32 {  	Rect32() : top(0), left(0), bottom(0), right(0) {}  	Rect32(int32 w, int32 h) : top(0), left(0), bottom(h), right(w) {} +	Rect32(const Common::Rect &rect) : top(rect.top), left(rect.left), bottom(rect.bottom), right(rect.right) {}  	Rect32(int32 x1, int32 y1, int32 x2, int32 y2) : top(y1), left(x1), bottom(y2), right(x2) {  		assert(isValidRect());  	} diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index 32931bf05f..95f9ba2ffb 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -89,6 +89,8 @@ MODULE_OBJS := \  	base/save_thumb_helper.o \  	base/timer.o \  	detection.o \ +	graphics/transform_struct.o \ +	graphics/transform_tools.o \  	graphics/transparent_surface.o \  	math/math_util.o \  	math/matrix4.o \  | 
