diff options
| author | Einar Johan Trøan Sømåen | 2012-06-12 19:49:58 +0200 | 
|---|---|---|
| committer | Einar Johan Trøan Sømåen | 2012-06-12 19:49:58 +0200 | 
| commit | 2e3aec48adc591d6496823f234631332e2f4af59 (patch) | |
| tree | 6ae9e7a057d61e70dc6728a0a95e28f7fc803368 | |
| parent | 92b7703265c83b9dfec702ada156d78fe4eb93ea (diff) | |
| download | scummvm-rg350-2e3aec48adc591d6496823f234631332e2f4af59.tar.gz scummvm-rg350-2e3aec48adc591d6496823f234631332e2f4af59.tar.bz2 scummvm-rg350-2e3aec48adc591d6496823f234631332e2f4af59.zip | |
WINTERMUTE: Optimize the blitting in BSurfaceSDL by adding scale-caching, and alpha-less blits for completely opaque surfaces.
| -rw-r--r-- | engines/wintermute/Base/BRenderSDL.cpp | 45 | ||||
| -rw-r--r-- | engines/wintermute/Base/BRenderSDL.h | 2 | ||||
| -rw-r--r-- | engines/wintermute/Base/BSurfaceSDL.cpp | 73 | ||||
| -rw-r--r-- | engines/wintermute/Base/BSurfaceSDL.h | 4 | 
4 files changed, 116 insertions, 8 deletions
| diff --git a/engines/wintermute/Base/BRenderSDL.cpp b/engines/wintermute/Base/BRenderSDL.cpp index 2457de8f51..14c2d2a6e4 100644 --- a/engines/wintermute/Base/BRenderSDL.cpp +++ b/engines/wintermute/Base/BRenderSDL.cpp @@ -301,6 +301,51 @@ void CBRenderSDL::drawFromSurface(Graphics::Surface *surf, Common::Rect *srcRect  		mirror |= TransparentSurface::FLIP_H;
  	src.blit(*_renderSurface, dstRect->left, dstRect->top, mirror, srcRect,BS_ARGB(a, r, g, b), dstRect->width(), dstRect->height() );
  }
 +
 +void CBRenderSDL::drawOpaqueFromSurface(Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, byte r, byte g, byte b, byte a, bool mirrorX, bool mirrorY) {
 +	TransparentSurface src(*surf, false);
 +	TransparentSurface *img = NULL;
 +	TransparentSurface *imgScaled = NULL;
 +	byte *savedPixels = NULL;
 +	if ((dstRect->width() != surf->w) || (dstRect->height() != surf->h)) {
 +		img = imgScaled = src.scale(dstRect->width(), dstRect->height());
 +		savedPixels = (byte *)img->pixels;
 +	} else {
 +		img = &src;
 +	}
 +
 +	int posX = dstRect->left;	
 +	int posY = dstRect->top;
 +	
 +	// Handle off-screen clipping
 +	if (posY < 0) {
 +		img->h = MAX(0, (int)img->h - -posY);
 +		img->pixels = (byte *)img->pixels + img->pitch * -posY;
 +		posY = 0;
 +	}
 +	
 +	if (posX < 0) {
 +		img->w = MAX(0, (int)img->w - -posX);
 +		img->pixels = (byte *)img->pixels + (-posX * 4);
 +		posX = 0;
 +	}
 +	
 +	img->w = CLIP((int)img->w, 0, (int)MAX((int)_renderSurface->w - posX, 0));
 +	img->h = CLIP((int)img->h, 0, (int)MAX((int)_renderSurface->h - posY, 0));
 +	
 +	for (int i = 0; i < img->h; i++) {
 +		void *destPtr = _renderSurface->getBasePtr(posX, posY + i);
 +		void *srcPtr = img->getBasePtr(0, i);
 +		memcpy(destPtr, srcPtr, _renderSurface->format.bytesPerPixel * img->w);
 +	}
 +	
 +	if (imgScaled) {
 +		imgScaled->pixels = savedPixels;
 +		imgScaled->free();
 +		delete imgScaled;
 +		imgScaled = NULL;
 +	}
 +}
  //////////////////////////////////////////////////////////////////////////
  HRESULT CBRenderSDL::DrawLine(int X1, int Y1, int X2, int Y2, uint32 Color) {
  	static bool hasWarned = false;
 diff --git a/engines/wintermute/Base/BRenderSDL.h b/engines/wintermute/Base/BRenderSDL.h index ccdca89be5..efcdc5cc4a 100644 --- a/engines/wintermute/Base/BRenderSDL.h +++ b/engines/wintermute/Base/BRenderSDL.h @@ -59,7 +59,7 @@ public:  	CBImage *TakeScreenshot();
  	void drawFromSurface(Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, byte r = 255, byte g = 255, byte b = 255, byte a = 255, bool mirrorX = false, bool mirrorY = false);
 -
 +	void drawOpaqueFromSurface(Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, byte r = 255, byte g = 255, byte b = 255, byte a = 255, bool mirrorX = false, bool mirrorY = false);
  	HRESULT SetViewport(int left, int top, int right, int bottom);
 diff --git a/engines/wintermute/Base/BSurfaceSDL.cpp b/engines/wintermute/Base/BSurfaceSDL.cpp index 200a34166a..025019ae8c 100644 --- a/engines/wintermute/Base/BSurfaceSDL.cpp +++ b/engines/wintermute/Base/BSurfaceSDL.cpp @@ -47,6 +47,7 @@ namespace WinterMute {  //////////////////////////////////////////////////////////////////////////
  CBSurfaceSDL::CBSurfaceSDL(CBGame *inGame) : CBSurface(inGame) {
  	_surface = new Graphics::Surface();
 +	_scaledSurface = NULL;
  	_alphaMask = NULL;
  	_lockPixels = NULL;
 @@ -56,14 +57,41 @@ CBSurfaceSDL::CBSurfaceSDL(CBGame *inGame) : CBSurface(inGame) {  //////////////////////////////////////////////////////////////////////////
  CBSurfaceSDL::~CBSurfaceSDL() {
  	//TODO
 -	delete _surface;
 +	if (_surface) {
 +		_surface->free();
 +		delete _surface;
 +		_surface = NULL;
 +	}
 +
 +	if (_scaledSurface) {
 +		_scaledSurface->free();
 +		delete _scaledSurface;
 +		_scaledSurface = NULL;
 +	}
  #if 0
  	if (_texture) SDL_DestroyTexture(_texture);
  	delete[] _alphaMask;
  	_alphaMask = NULL;
 -
 -	Game->AddMem(-_width * _height * 4);
  #endif
 +	Game->AddMem(-_width * _height * 4);
 +}
 +
 +bool hasTransparency(Graphics::Surface *surf) {
 +	if (surf->format.bytesPerPixel != 4) {
 +		warning("hasTransparency:: non 32 bpp surface passed as argument");
 +		return false;
 +	}
 +	uint8 r,g,b,a;
 +	for (int i = 0; i < surf->h; i++) {
 +		for (int j = 0; j < surf->w; j++) {
 +			uint32 pix = *(uint32*)surf->getBasePtr(j, i);
 +			surf->format.colorToARGB(pix, a, r, g, b);
 +			if (a != 255) {
 +				return true;
 +			}	
 +		}
 +	}
 +	return false;
  }
  //////////////////////////////////////////////////////////////////////////
 @@ -154,6 +182,8 @@ HRESULT CBSurfaceSDL::create(const char *filename, bool default_ck, byte ck_red,  		_surface = new Graphics::Surface();
  		_surface->copyFrom(*surface);
  	}
 +	
 +	_hasAlpha = hasTransparency(_surface);
  	//SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); //TODO
  	//_texture = SdlUtil::CreateTextureFromSurface(renderer->GetSdlRenderer(), surf);
 @@ -293,9 +323,9 @@ HRESULT CBSurfaceSDL::create(int width, int height) {  #endif
  	_width = width;
  	_height = height;
 -#if 0
 +
  	Game->AddMem(_width * _height * 4);
 -#endif
 +
  	_valid = true;
  	return S_OK;
 @@ -492,7 +522,38 @@ HRESULT CBSurfaceSDL::drawSprite(int x, int y, RECT *Rect, float ZoomX, float Zo  	position.left += offsetX;
  	position.top += offsetY;
 -	renderer->drawFromSurface(_surface, &srcRect, &position, r, g, b, a, mirrorX, mirrorY);
 +	// TODO: This actually requires us to have the SAME source-offsets every time,
 +	// But no checking is in place for that yet.
 +	Graphics::Surface drawSrc;
 +	drawSrc.w = position.width();
 +	drawSrc.h = position.height();
 +	drawSrc.format = _surface->format;
 +
 +	if (position.width() != srcRect.width() || position.height() != srcRect.height()) {
 +		if (_scaledSurface && position.width() == _scaledSurface->w && position.height() == _scaledSurface->h) {
 +			drawSrc.pixels = _scaledSurface->pixels;
 +			drawSrc.pitch = _scaledSurface->pitch;
 +		} else {
 +			delete _scaledSurface;
 +			TransparentSurface src(*_surface, false);
 +			_scaledSurface = src.scale(position.width(), position.height());
 +			drawSrc.pixels = _scaledSurface->pixels;
 +			drawSrc.pitch = _scaledSurface->pitch;
 +		}
 +	} else { // No scaling
 +		drawSrc.pitch = _surface->pitch;
 +		drawSrc.pixels = &((char *)_surface->pixels)[srcRect.top * _surface->pitch + srcRect.left * 4];
 +	}
 +	srcRect.left = 0;
 +	srcRect.top = 0;
 +	srcRect.setWidth(drawSrc.w);
 +	srcRect.setHeight(drawSrc.h);
 +
 +	if (_hasAlpha && !AlphaDisable) {
 +		renderer->drawFromSurface(&drawSrc, &srcRect, &position, r, g, b, a, mirrorX, mirrorY);
 +	} else {
 +		renderer->drawOpaqueFromSurface(&drawSrc, &srcRect, &position, r, g, b, a, mirrorX, mirrorY);
 +	}
  #if 0
  	SDL_RenderCopy(renderer->GetSdlRenderer(), _texture, &srcRect, &position);
  #endif
 diff --git a/engines/wintermute/Base/BSurfaceSDL.h b/engines/wintermute/Base/BSurfaceSDL.h index 961d7e0cdd..34d25b43b5 100644 --- a/engines/wintermute/Base/BSurfaceSDL.h +++ b/engines/wintermute/Base/BSurfaceSDL.h @@ -34,7 +34,7 @@  #include "graphics/surface.h"
  namespace WinterMute {
 -
 +class TransparentSurface;
  class CBSurfaceSDL : public CBSurface {
  public:
  	CBSurfaceSDL(CBGame *inGame);
 @@ -78,11 +78,13 @@ public:  private:
  //	SDL_Texture *_texture;
  	Graphics::Surface *_surface;
 +	TransparentSurface *_scaledSurface;
  	HRESULT drawSprite(int x, int y, RECT *Rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX = 0, int offsetY = 0);
  	void genAlphaMask(Graphics::Surface *surface);
  	uint32 getPixel(Graphics::Surface *surface, int x, int y);
 +	bool _hasAlpha;
  	void *_lockPixels;
  	int _lockPitch;
  	byte *_alphaMask;
 | 
