aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/wintermute/Base/BRenderSDL.cpp45
-rw-r--r--engines/wintermute/Base/BRenderSDL.h2
-rw-r--r--engines/wintermute/Base/BSurfaceSDL.cpp73
-rw-r--r--engines/wintermute/Base/BSurfaceSDL.h4
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;