aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/gfx/image
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/gfx/image')
-rw-r--r--engines/sword25/gfx/image/image.h7
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp324
-rw-r--r--engines/sword25/gfx/image/renderedimage.h8
-rw-r--r--engines/sword25/gfx/image/swimage.cpp3
-rw-r--r--engines/sword25/gfx/image/swimage.h3
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp6
-rw-r--r--engines/sword25/gfx/image/vectorimage.h3
7 files changed, 206 insertions, 148 deletions
diff --git a/engines/sword25/gfx/image/image.h b/engines/sword25/gfx/image/image.h
index f1934656da..9d7fc43251 100644
--- a/engines/sword25/gfx/image/image.h
+++ b/engines/sword25/gfx/image/image.h
@@ -46,6 +46,8 @@
namespace Sword25 {
+class RectangleList;
+
class Image {
public:
virtual ~Image() {}
@@ -129,7 +131,8 @@ public:
int flipping = FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
- int width = -1, int height = -1) = 0;
+ int width = -1, int height = -1,
+ RectangleList *updateRects = 0) = 0;
/**
@brief fills a rectangular section of the image with a color.
@@ -202,6 +205,8 @@ public:
@brief Returns true, if the content of the BS_Image is allowed to be replaced by call of SetContent().
*/
virtual bool isSetContentAllowed() const = 0;
+
+ virtual bool isSolid() const { return false; }
//@}
};
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index 27ee4ef182..c8a6666046 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -38,6 +38,8 @@
#include "sword25/gfx/image/imgloader.h"
#include "sword25/gfx/image/renderedimage.h"
+#include "sword25/gfx/renderobjectmanager.h"
+
#include "common/system.h"
namespace Sword25 {
@@ -99,7 +101,8 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz
RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
_data(0),
_width(0),
- _height(0) {
+ _height(0),
+ _isTransparent(true) {
result = false;
PackageManager *pPackage = Kernel::getInstance()->getPackage();
@@ -142,6 +145,11 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
_doCleanup = true;
+#if defined(SCUMM_LITTLE_ENDIAN)
+ // Makes sense for LE only at the moment
+ checkForTransparency();
+#endif
+
return;
}
@@ -149,7 +157,8 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
RenderedImage::RenderedImage(uint width, uint height, bool &result) :
_width(width),
- _height(height) {
+ _height(height),
+ _isTransparent(true) {
_data = new byte[width * height * 4];
Common::fill(_data, &_data[width * height * 4], 0);
@@ -162,7 +171,7 @@ RenderedImage::RenderedImage(uint width, uint height, bool &result) :
return;
}
-RenderedImage::RenderedImage() : _width(0), _height(0), _data(0) {
+RenderedImage::RenderedImage() : _width(0), _height(0), _data(0), _isTransparent(true) {
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
_doCleanup = false;
@@ -219,7 +228,7 @@ uint RenderedImage::getPixel(int x, int y) {
// -----------------------------------------------------------------------------
-bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height) {
+bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, RectangleList *updateRects) {
int ca = (color >> 24) & 0xff;
// Check if we need to draw anything at all
@@ -282,156 +291,175 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe
img = &srcImage;
}
- // 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)_backSurface->w - posX, 0));
- img->h = CLIP((int)img->h, 0, (int)MAX((int)_backSurface->h - posY, 0));
-
- if ((img->w > 0) && (img->h > 0)) {
- int xp = 0, yp = 0;
-
- int inStep = 4;
- int inoStep = img->pitch;
- if (flipping & Image::FLIP_V) {
- inStep = -inStep;
- xp = img->w - 1;
+ for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) {
+ const Common::Rect &clipRect = *it;
+
+ int skipLeft = 0, skipTop = 0;
+ int drawX = posX, drawY = posY;
+ int drawWidth = img->w;
+ int drawHeight = img->h;
+
+ // Handle clipping
+ if (drawX < clipRect.left) {
+ skipLeft = clipRect.left - drawX;
+ drawWidth -= skipLeft;
+ drawX = clipRect.left;
}
-
- if (flipping & Image::FLIP_H) {
- inoStep = -inoStep;
- yp = img->h - 1;
+
+ if (drawY < clipRect.top) {
+ skipTop = clipRect.top - drawY;
+ drawHeight -= skipTop;
+ drawY = clipRect.top;
}
- byte *ino = (byte *)img->getBasePtr(xp, yp);
- byte *outo = (byte *)_backSurface->getBasePtr(posX, posY);
- byte *in, *out;
-
- for (int i = 0; i < img->h; i++) {
- out = outo;
- in = ino;
- for (int j = 0; j < img->w; j++) {
- uint32 pix = *(uint32 *)in;
- int b = (pix >> 0) & 0xff;
- int g = (pix >> 8) & 0xff;
- int r = (pix >> 16) & 0xff;
- int a = (pix >> 24) & 0xff;
- in += inStep;
-
- if (ca != 255) {
- a = a * ca >> 8;
- }
+ if (drawX + drawWidth >= clipRect.right)
+ drawWidth = clipRect.right - drawX;
+
+ if (drawY + drawHeight >= clipRect.bottom)
+ drawHeight = clipRect.bottom - drawY;
+
+ if ((drawWidth > 0) && (drawHeight > 0)) {
+ int xp = 0, yp = 0;
+
+ int inStep = 4;
+ int inoStep = img->pitch;
+ if (flipping & Image::FLIP_V) {
+ inStep = -inStep;
+ xp = img->w - 1 - skipLeft;
+ } else {
+ xp = skipLeft;
+ }
+
+ if (flipping & Image::FLIP_H) {
+ inoStep = -inoStep;
+ yp = img->h - 1 - skipTop;
+ } else {
+ yp = skipTop;
+ }
+
+ byte *ino = (byte *)img->getBasePtr(xp, yp);
+ byte *outo = (byte *)_backSurface->getBasePtr(drawX, drawY);
- switch (a) {
- case 0: // Full transparency
- out += 4;
- break;
- case 255: // Full opacity
#if defined(SCUMM_LITTLE_ENDIAN)
- if (cb != 255)
- *out++ = (b * cb) >> 8;
- else
- *out++ = b;
-
- if (cg != 255)
- *out++ = (g * cg) >> 8;
- else
- *out++ = g;
-
- if (cr != 255)
- *out++ = (r * cr) >> 8;
- else
- *out++ = r;
-
- *out++ = a;
+ // Simple memcpy if the source bitmap doesn't have transparent pixels and the drawing transparency is 255
+ // NOTE Only possible with LE-machines at the moment, maybe it would be feasible to convert the bitmap pixels at loading time?
+ if (!_isTransparent && ca == 255) {
+ for (int i = 0; i < drawHeight; i++) {
+ memcpy(outo, ino, drawWidth * 4);
+ outo += _backSurface->pitch;
+ ino += inoStep;
+ }
+ } else
+#endif
+ {
+ byte *in, *out;
+ for (int i = 0; i < drawHeight; i++) {
+ out = outo;
+ in = ino;
+ for (int j = 0; j < drawWidth; j++) {
+ uint32 pix = *(uint32 *)in;
+ int a = (pix >> 24) & 0xff;
+ in += inStep;
+
+ if (ca != 255) {
+ a = a * ca >> 8;
+ }
+
+ if (a == 0) {
+ // Full transparency
+ out += 4;
+ continue;
+ }
+
+ int b = (pix >> 0) & 0xff;
+ int g = (pix >> 8) & 0xff;
+ int r = (pix >> 16) & 0xff;
+
+ if (a == 255) {
+#if defined(SCUMM_LITTLE_ENDIAN)
+ if (cb != 255)
+ b = (b * cb) >> 8;
+ if (cg != 255)
+ g = (g * cg) >> 8;
+ if (cr != 255)
+ r = (r * cr) >> 8;
+ *(uint32 *)out = (255 << 24) | (r << 16) | (g << 8) | b;
+ out += 4;
#else
- *out++ = a;
-
- if (cr != 255)
- *out++ = (r * cr) >> 8;
- else
- *out++ = r;
-
- if (cg != 255)
- *out++ = (g * cg) >> 8;
- else
- *out++ = g;
-
- if (cb != 255)
- *out++ = (b * cb) >> 8;
- else
- *out++ = b;
+ *out++ = a;
+ if (cr != 255)
+ *out++ = (r * cr) >> 8;
+ else
+ *out++ = r;
+ if (cg != 255)
+ *out++ = (g * cg) >> 8;
+ else
+ *out++ = g;
+ if (cb != 255)
+ *out++ = (b * cb) >> 8;
+ else
+ *out++ = b;
#endif
- break;
-
- default: // alpha blending
+ } else {
#if defined(SCUMM_LITTLE_ENDIAN)
- if (cb == 0)
- *out = 0;
- else if (cb != 255)
- *out += ((b - *out) * a * cb) >> 16;
- else
- *out += ((b - *out) * a) >> 8;
- out++;
- if (cg == 0)
- *out = 0;
- else if (cg != 255)
- *out += ((g - *out) * a * cg) >> 16;
- else
- *out += ((g - *out) * a) >> 8;
- out++;
- if (cr == 0)
- *out = 0;
- else if (cr != 255)
- *out += ((r - *out) * a * cr) >> 16;
- else
- *out += ((r - *out) * a) >> 8;
- out++;
- *out = 255;
- out++;
+ pix = *(uint32 *)out;
+ int outb = (pix >> 0) & 0xff;
+ int outg = (pix >> 8) & 0xff;
+ int outr = (pix >> 16) & 0xff;
+ if (cb == 0)
+ outb = 0;
+ else if (cb != 255)
+ outb += ((b - outb) * a * cb) >> 16;
+ else
+ outb += ((b - outb) * a) >> 8;
+ if (cg == 0)
+ outg = 0;
+ else if (cg != 255)
+ outg += ((g - outg) * a * cg) >> 16;
+ else
+ outg += ((g - outg) * a) >> 8;
+ if (cr == 0)
+ outr = 0;
+ else if (cr != 255)
+ outr += ((r - outr) * a * cr) >> 16;
+ else
+ outr += ((r - outr) * a) >> 8;
+ *(uint32 *)out = (255 << 24) | (outr << 16) | (outg << 8) | outb;
+ out += 4;
#else
- *out = 255;
- out++;
- if (cr == 0)
- *out = 0;
- else if (cr != 255)
- *out += ((r - *out) * a * cr) >> 16;
- else
- *out += ((r - *out) * a) >> 8;
- out++;
- if (cg == 0)
- *out = 0;
- else if (cg != 255)
- *out += ((g - *out) * a * cg) >> 16;
- else
- *out += ((g - *out) * a) >> 8;
- out++;
- if (cb == 0)
- *out = 0;
- else if (cb != 255)
- *out += ((b - *out) * a * cb) >> 16;
- else
- *out += ((b - *out) * a) >> 8;
- out++;
+ *out = 255;
+ out++;
+ if (cr == 0)
+ *out = 0;
+ else if (cr != 255)
+ *out += ((r - *out) * a * cr) >> 16;
+ else
+ *out += ((r - *out) * a) >> 8;
+ out++;
+ if (cg == 0)
+ *out = 0;
+ else if (cg != 255)
+ *out += ((g - *out) * a * cg) >> 16;
+ else
+ *out += ((g - *out) * a) >> 8;
+ out++;
+ if (cb == 0)
+ *out = 0;
+ else if (cb != 255)
+ *out += ((b - *out) * a * cb) >> 16;
+ else
+ *out += ((b - *out) * a) >> 8;
+ out++;
#endif
+ }
+ }
+ outo += _backSurface->pitch;
+ ino += inoStep;
}
}
- outo += _backSurface->pitch;
- ino += inoStep;
- }
- g_system->copyRectToScreen(_backSurface->getBasePtr(posX, posY), _backSurface->pitch, posX, posY,
- img->w, img->h);
+ }
+
}
if (imgScaled) {
@@ -467,6 +495,20 @@ void RenderedImage::copyDirectly(int posX, int posY) {
g_system->copyRectToScreen(data, _backSurface->pitch, posX, posY, w, h);
}
+void RenderedImage::checkForTransparency() {
+ // Check if the source bitmap has any transparent pixels at all
+ _isTransparent = false;
+ byte *data = _data;
+ for (int i = 0; i < _height; i++) {
+ for (int j = 0; j < _width; j++) {
+ _isTransparent = data[3] != 0xff;
+ if (_isTransparent)
+ return;
+ data += 4;
+ }
+ }
+}
+
/**
* Scales a passed surface, creating a new surface with the result
* @param srcImage Source image to scale
diff --git a/engines/sword25/gfx/image/renderedimage.h b/engines/sword25/gfx/image/renderedimage.h
index f92a5b39b4..a25b258592 100644
--- a/engines/sword25/gfx/image/renderedimage.h
+++ b/engines/sword25/gfx/image/renderedimage.h
@@ -75,7 +75,8 @@ public:
int flipping = Image::FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
- int width = -1, int height = -1);
+ int width = -1, int height = -1,
+ RectangleList *updateRects = 0);
virtual bool fill(const Common::Rect *pFillRect, uint color);
virtual bool setContent(const byte *pixeldata, uint size, uint offset = 0, uint stride = 0);
void replaceContent(byte *pixeldata, int width, int height);
@@ -105,14 +106,19 @@ public:
static Graphics::Surface *scale(const Graphics::Surface &srcImage, int xSize, int ySize);
+ void setIsTransparent(bool isTransparent) { _isTransparent = isTransparent; }
+ virtual bool isSolid() const { return !_isTransparent; }
+
private:
byte *_data;
int _width;
int _height;
bool _doCleanup;
+ bool _isTransparent;
Graphics::Surface *_backSurface;
+ void checkForTransparency();
static int *scaleLine(int size, int srcSize);
};
diff --git a/engines/sword25/gfx/image/swimage.cpp b/engines/sword25/gfx/image/swimage.cpp
index 0b9cc11df2..7e4c3143f5 100644
--- a/engines/sword25/gfx/image/swimage.cpp
+++ b/engines/sword25/gfx/image/swimage.cpp
@@ -79,7 +79,8 @@ bool SWImage::blit(int posX, int posY,
int flipping,
Common::Rect *pPartRect,
uint color,
- int width, int height) {
+ int width, int height,
+ RectangleList *updateRects) {
error("Blit() is not supported.");
return false;
}
diff --git a/engines/sword25/gfx/image/swimage.h b/engines/sword25/gfx/image/swimage.h
index 5f348958b2..a35127a41d 100644
--- a/engines/sword25/gfx/image/swimage.h
+++ b/engines/sword25/gfx/image/swimage.h
@@ -58,7 +58,8 @@ public:
int flipping = Image::FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
- int width = -1, int height = -1);
+ int width = -1, int height = -1,
+ RectangleList *updateRects = 0);
virtual bool fill(const Common::Rect *fillRectPtr, uint color);
virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride);
virtual uint getPixel(int x, int y);
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index 81f4fc2ad5..ab895b5cef 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -190,6 +190,7 @@ Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement)
ArtVpath *vec = art_bez_path_to_vec(bez, 0.5);
if (vec[0].code == ART_END) {
+ free(vec);
continue;
} else {
x0 = x1 = vec[0].x;
@@ -602,7 +603,8 @@ bool VectorImage::blit(int posX, int posY,
int flipping,
Common::Rect *pPartRect,
uint color,
- int width, int height) {
+ int width, int height,
+ RectangleList *updateRects) {
static VectorImage *oldThis = 0;
static int oldWidth = -2;
static int oldHeight = -2;
@@ -623,7 +625,7 @@ bool VectorImage::blit(int posX, int posY,
RenderedImage *rend = new RenderedImage();
rend->replaceContent(_pixelData, width, height);
- rend->blit(posX, posY, flipping, pPartRect, color, width, height);
+ rend->blit(posX, posY, flipping, pPartRect, color, width, height, updateRects);
delete rend;
diff --git a/engines/sword25/gfx/image/vectorimage.h b/engines/sword25/gfx/image/vectorimage.h
index 959f251c14..d1760a433e 100644
--- a/engines/sword25/gfx/image/vectorimage.h
+++ b/engines/sword25/gfx/image/vectorimage.h
@@ -212,7 +212,8 @@ public:
int flipping = FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
- int width = -1, int height = -1);
+ int width = -1, int height = -1,
+ RectangleList *updateRects = 0);
class SWFBitStream;