aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2013-05-06 03:49:21 -0700
committerEugene Sandulenko2013-05-06 03:49:21 -0700
commit4a62d6c25a4994a72c59ca3b8f2913ead565a173 (patch)
tree63b8027b1f8d68eb66f9822f1a786c955ec14adf
parentcc3f4a36b22ad894e30eaa3e840b9388d8bd104b (diff)
parent4fc57dac8fd6865494d21acfddeb69ab7fb1ad5c (diff)
downloadscummvm-rg350-4a62d6c25a4994a72c59ca3b8f2913ead565a173.tar.gz
scummvm-rg350-4a62d6c25a4994a72c59ca3b8f2913ead565a173.tar.bz2
scummvm-rg350-4a62d6c25a4994a72c59ca3b8f2913ead565a173.zip
Merge pull request #320 from johndoe123/sword25-gfx
SWORD25: Optimized graphics drawing
-rw-r--r--engines/sword25/gfx/animation.cpp8
-rw-r--r--engines/sword25/gfx/animation.h2
-rw-r--r--engines/sword25/gfx/bitmapresource.h10
-rw-r--r--engines/sword25/gfx/dynamicbitmap.cpp16
-rw-r--r--engines/sword25/gfx/dynamicbitmap.h2
-rw-r--r--engines/sword25/gfx/graphicengine.cpp1
-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.cpp5
-rw-r--r--engines/sword25/gfx/image/vectorimage.h3
-rw-r--r--engines/sword25/gfx/microtiles.cpp164
-rw-r--r--engines/sword25/gfx/microtiles.h65
-rw-r--r--engines/sword25/gfx/panel.cpp14
-rw-r--r--engines/sword25/gfx/panel.h8
-rw-r--r--engines/sword25/gfx/renderobject.cpp56
-rw-r--r--engines/sword25/gfx/renderobject.h41
-rw-r--r--engines/sword25/gfx/renderobjectmanager.cpp73
-rw-r--r--engines/sword25/gfx/renderobjectmanager.h20
-rw-r--r--engines/sword25/gfx/rootrenderobject.h2
-rw-r--r--engines/sword25/gfx/staticbitmap.cpp10
-rw-r--r--engines/sword25/gfx/staticbitmap.h2
-rw-r--r--engines/sword25/gfx/text.cpp12
-rw-r--r--engines/sword25/gfx/text.h2
-rw-r--r--engines/sword25/module.mk1
27 files changed, 670 insertions, 192 deletions
diff --git a/engines/sword25/gfx/animation.cpp b/engines/sword25/gfx/animation.cpp
index 22a4dfb71b..1660c393c0 100644
--- a/engines/sword25/gfx/animation.cpp
+++ b/engines/sword25/gfx/animation.cpp
@@ -170,7 +170,7 @@ void Animation::setFrame(uint nr) {
forceRefresh();
}
-bool Animation::doRender() {
+bool Animation::doRender(RectangleList *updateRects) {
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
assert(animationDescriptionPtr);
assert(_currentFrame < animationDescriptionPtr->getFrameCount());
@@ -191,12 +191,14 @@ bool Animation::doRender() {
result = pBitmapResource->blit(_absoluteX, _absoluteY,
(animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) |
(animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0),
- 0, _modulationColor, _width, _height);
+ 0, _modulationColor, _width, _height,
+ updateRects);
} else {
result = pBitmapResource->blit(_absoluteX, _absoluteY,
(animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) |
(animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0),
- 0, _modulationColor, -1, -1);
+ 0, _modulationColor, -1, -1,
+ updateRects);
}
// Resource freigeben
diff --git a/engines/sword25/gfx/animation.h b/engines/sword25/gfx/animation.h
index 60070be214..44255e3b64 100644
--- a/engines/sword25/gfx/animation.h
+++ b/engines/sword25/gfx/animation.h
@@ -151,7 +151,7 @@ public:
void setCallbacks();
protected:
- virtual bool doRender();
+ virtual bool doRender(RectangleList *updateRects);
private:
enum Direction {
diff --git a/engines/sword25/gfx/bitmapresource.h b/engines/sword25/gfx/bitmapresource.h
index f1278f3885..72b8a3ea1f 100644
--- a/engines/sword25/gfx/bitmapresource.h
+++ b/engines/sword25/gfx/bitmapresource.h
@@ -123,9 +123,10 @@ public:
int flipping = FLIP_NONE,
Common::Rect *pSrcPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
- int width = -1, int height = -1) {
+ int width = -1, int height = -1,
+ RectangleList *updateRects = 0) {
assert(_pImage);
- return _pImage->blit(posX, posY, flipping, pSrcPartRect, color, width, height);
+ return _pImage->blit(posX, posY, flipping, pSrcPartRect, color, width, height, updateRects);
}
/**
@@ -202,6 +203,11 @@ public:
return _pImage->isColorModulationAllowed();
}
+ bool isSolid() {
+ assert(_pImage);
+ return _pImage->isSolid();
+ }
+
private:
Image *_pImage;
};
diff --git a/engines/sword25/gfx/dynamicbitmap.cpp b/engines/sword25/gfx/dynamicbitmap.cpp
index 137d943575..242508bf85 100644
--- a/engines/sword25/gfx/dynamicbitmap.cpp
+++ b/engines/sword25/gfx/dynamicbitmap.cpp
@@ -53,10 +53,13 @@ DynamicBitmap::DynamicBitmap(InputPersistenceBlock &reader, RenderObjectPtr<Rend
bool DynamicBitmap::createRenderedImage(uint width, uint height) {
bool result = false;
_image.reset(new RenderedImage(width, height, result));
-
+
_originalWidth = _width = width;
_originalHeight = _height = height;
+ _image->setIsTransparent(false);
+ _isSolid = true;
+
return result;
}
@@ -70,11 +73,11 @@ uint DynamicBitmap::getPixel(int x, int y) const {
return _image->getPixel(x, y);
}
-bool DynamicBitmap::doRender() {
+bool DynamicBitmap::doRender(RectangleList *updateRects) {
// Get the frame buffer object
GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
assert(pGfx);
-
+
// Draw the bitmap
bool result;
if (_scaleFactorX == 1.0f && _scaleFactorY == 1.0f) {
@@ -85,7 +88,8 @@ bool DynamicBitmap::doRender() {
result = _image->blit(_absoluteX, _absoluteY,
(_flipV ? BitmapResource::FLIP_V : 0) |
(_flipH ? BitmapResource::FLIP_H : 0),
- 0, _modulationColor, -1, -1);
+ 0, _modulationColor, -1, -1,
+ updateRects);
#else
// WIP: A bit faster code
@@ -103,13 +107,15 @@ bool DynamicBitmap::doRender() {
result = _image->blit(_absoluteX, _absoluteY,
(_flipV ? BitmapResource::FLIP_V : 0) |
(_flipH ? BitmapResource::FLIP_H : 0),
- 0, _modulationColor, _width, _height);
+ 0, _modulationColor, _width, _height,
+ updateRects);
}
return result;
}
bool DynamicBitmap::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
+ ++_version; // Update version to display the new video image
return _image->setContent(pixeldata, size, offset, stride);
}
diff --git a/engines/sword25/gfx/dynamicbitmap.h b/engines/sword25/gfx/dynamicbitmap.h
index 35ed9a9341..ed53776577 100644
--- a/engines/sword25/gfx/dynamicbitmap.h
+++ b/engines/sword25/gfx/dynamicbitmap.h
@@ -59,7 +59,7 @@ public:
virtual bool unpersist(InputPersistenceBlock &reader);
protected:
- virtual bool doRender();
+ virtual bool doRender(RectangleList *updateRects);
private:
DynamicBitmap(RenderObjectPtr<RenderObject> parentPtr, uint width, uint height);
diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
index 216d801f3e..bfdb51481b 100644
--- a/engines/sword25/gfx/graphicengine.cpp
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -216,7 +216,6 @@ bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) {
}
}
- g_system->copyRectToScreen(_backSurface.getBasePtr(rect.left, rect.top), _backSurface.pitch, rect.left, rect.top, rect.width(), rect.height());
}
return true;
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 84c674f276..ab895b5cef 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -603,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;
@@ -624,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;
diff --git a/engines/sword25/gfx/microtiles.cpp b/engines/sword25/gfx/microtiles.cpp
new file mode 100644
index 0000000000..8dceed5348
--- /dev/null
+++ b/engines/sword25/gfx/microtiles.cpp
@@ -0,0 +1,164 @@
+/* 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 "sword25/gfx/microtiles.h"
+
+namespace Sword25 {
+
+MicroTileArray::MicroTileArray(int16 width, int16 height) {
+ _tilesW = (width / TileSize) + ((width % TileSize) > 0 ? 1 : 0);
+ _tilesH = (height / TileSize) + ((height % TileSize) > 0 ? 1 : 0);
+ _tiles = new BoundingBox[_tilesW * _tilesH];
+ clear();
+}
+
+MicroTileArray::~MicroTileArray() {
+ delete[] _tiles;
+}
+
+void MicroTileArray::addRect(Common::Rect r) {
+
+ int ux0, uy0, ux1, uy1;
+ int tx0, ty0, tx1, ty1;
+ int ix0, iy0, ix1, iy1;
+
+ r.clip(Common::Rect(0, 0, 799, 599));
+
+ ux0 = r.left / TileSize;
+ uy0 = r.top / TileSize;
+ ux1 = r.right / TileSize;
+ uy1 = r.bottom / TileSize;
+
+ tx0 = r.left % TileSize;
+ ty0 = r.top % TileSize;
+ tx1 = r.right % TileSize;
+ ty1 = r.bottom % TileSize;
+
+ for (int yc = uy0; yc <= uy1; yc++) {
+ for (int xc = ux0; xc <= ux1; xc++) {
+ ix0 = (xc == ux0) ? tx0 : 0;
+ ix1 = (xc == ux1) ? tx1 : TileSize - 1;
+ iy0 = (yc == uy0) ? ty0 : 0;
+ iy1 = (yc == uy1) ? ty1 : TileSize - 1;
+ updateBoundingBox(_tiles[xc + yc * _tilesW], ix0, iy0, ix1, iy1);
+ }
+ }
+
+}
+
+void MicroTileArray::clear() {
+ memset(_tiles, 0, _tilesW * _tilesH * sizeof(BoundingBox));
+}
+
+byte MicroTileArray::TileX0(const BoundingBox &boundingBox) {
+ return (boundingBox >> 24) & 0xFF;
+}
+
+byte MicroTileArray::TileY0(const BoundingBox &boundingBox) {
+ return (boundingBox >> 16) & 0xFF;
+}
+
+byte MicroTileArray::TileX1(const BoundingBox &boundingBox) {
+ return (boundingBox >> 8) & 0xFF;
+}
+
+byte MicroTileArray::TileY1(const BoundingBox &boundingBox) {
+ return boundingBox & 0xFF;
+}
+
+bool MicroTileArray::isBoundingBoxEmpty(const BoundingBox &boundingBox) {
+ return boundingBox == EmptyBoundingBox;
+}
+
+bool MicroTileArray::isBoundingBoxFull(const BoundingBox &boundingBox) {
+ return boundingBox == FullBoundingBox;
+}
+
+void MicroTileArray::setBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1) {
+ boundingBox = (x0 << 24) | (y0 << 16) | (x1 << 8) | y1;
+}
+
+void MicroTileArray::updateBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1) {
+ if (!isBoundingBoxEmpty(boundingBox)) {
+ x0 = MIN(TileX0(boundingBox), x0);
+ y0 = MIN(TileY0(boundingBox), y0);
+ x1 = MAX(TileX1(boundingBox), x1);
+ y1 = MAX(TileY1(boundingBox), y1);
+ }
+ setBoundingBox(boundingBox, x0, y0, x1, y1);
+}
+
+RectangleList *MicroTileArray::getRectangles() {
+
+ RectangleList *rects = new RectangleList();
+
+ int x, y;
+ int x0, y0, x1, y1;
+ int i = 0;
+
+ for (y = 0; y < _tilesH; ++y) {
+ for (x = 0; x < _tilesW; ++x) {
+
+ int start;
+ int finish = 0;
+ BoundingBox boundingBox = _tiles[i];
+
+ if (isBoundingBoxEmpty(boundingBox)) {
+ ++i;
+ continue;
+ }
+
+ x0 = (x * TileSize) + TileX0(boundingBox);
+ y0 = (y * TileSize) + TileY0(boundingBox);
+ y1 = (y * TileSize) + TileY1(boundingBox);
+
+ start = i;
+
+ if (TileX1(boundingBox) == TileSize - 1 && x != _tilesW - 1) { // check if the tile continues
+ while (!finish) {
+ ++x;
+ ++i;
+ if (x == _tilesW || i >= _tilesW * _tilesH ||
+ TileY0(_tiles[i]) != TileY0(boundingBox) ||
+ TileY1(_tiles[i]) != TileY1(boundingBox) ||
+ TileX0(_tiles[i]) != 0)
+ {
+ --x;
+ --i;
+ finish = 1;
+ }
+ }
+ }
+
+ x1 = (x * TileSize) + TileX1(_tiles[i]);
+
+ rects->push_back(Common::Rect(x0, y0, x1 + 1, y1 + 1));
+
+ ++i;
+ }
+ }
+
+ return rects;
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/gfx/microtiles.h b/engines/sword25/gfx/microtiles.h
new file mode 100644
index 0000000000..454fc39f37
--- /dev/null
+++ b/engines/sword25/gfx/microtiles.h
@@ -0,0 +1,65 @@
+/* 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 SWORD25_MICROTILES_H
+#define SWORD25_MICROTILES_H
+
+#include "common/scummsys.h"
+#include "common/list.h"
+#include "common/util.h"
+#include "common/rect.h"
+
+namespace Sword25 {
+
+typedef uint32 BoundingBox;
+
+const BoundingBox FullBoundingBox = 0x00001F1F;
+const BoundingBox EmptyBoundingBox = 0x00000000;
+const int TileSize = 32;
+
+class RectangleList : public Common::List<Common::Rect> {
+};
+
+class MicroTileArray {
+public:
+ MicroTileArray(int16 width, int16 height);
+ ~MicroTileArray();
+ void addRect(Common::Rect r);
+ void clear();
+ RectangleList *getRectangles();
+protected:
+ BoundingBox *_tiles;
+ int16 _tilesW, _tilesH;
+ byte TileX0(const BoundingBox &boundingBox);
+ byte TileY0(const BoundingBox &boundingBox);
+ byte TileX1(const BoundingBox &boundingBox);
+ byte TileY1(const BoundingBox &boundingBox);
+ bool isBoundingBoxEmpty(const BoundingBox &boundingBox);
+ bool isBoundingBoxFull(const BoundingBox &boundingBox);
+ void setBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1);
+ void updateBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1);
+};
+
+} // namespace Sword25
+
+#endif // SWORD25_MICROTILES_H
diff --git a/engines/sword25/gfx/panel.cpp b/engines/sword25/gfx/panel.cpp
index 6d5b2a623d..931b9cdbe7 100644
--- a/engines/sword25/gfx/panel.cpp
+++ b/engines/sword25/gfx/panel.cpp
@@ -36,6 +36,8 @@
#include "sword25/gfx/graphicengine.h"
#include "sword25/gfx/image/image.h"
+#include "sword25/gfx/renderobjectmanager.h"
+
namespace Sword25 {
Panel::Panel(RenderObjectPtr<RenderObject> parentPtr, int width, int height, uint color) :
@@ -67,7 +69,7 @@ Panel::Panel(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parent
Panel::~Panel() {
}
-bool Panel::doRender() {
+bool Panel::doRender(RectangleList *updateRects) {
// Falls der Alphawert 0 ist, ist das Panel komplett durchsichtig und es muss nichts gezeichnet werden.
if (_color >> 24 == 0)
return true;
@@ -75,7 +77,15 @@ bool Panel::doRender() {
GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
assert(gfxPtr);
- return gfxPtr->fill(&_bbox, _color);
+ for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) {
+ const Common::Rect &clipRect = *it;
+ if (_bbox.intersects(clipRect)) {
+ Common::Rect intersectionRect = _bbox.findIntersectingRect(clipRect);
+ gfxPtr->fill(&intersectionRect, _color);
+ }
+ }
+
+ return true;
}
bool Panel::persist(OutputPersistenceBlock &writer) {
diff --git a/engines/sword25/gfx/panel.h b/engines/sword25/gfx/panel.h
index cbf04ce40f..74a93247b6 100644
--- a/engines/sword25/gfx/panel.h
+++ b/engines/sword25/gfx/panel.h
@@ -51,15 +51,17 @@ public:
return _color;
}
void setColor(uint color) {
- _color = color;
- forceRefresh();
+ if (_color != color) {
+ _color = color;
+ forceRefresh();
+ }
}
virtual bool persist(OutputPersistenceBlock &writer);
virtual bool unpersist(InputPersistenceBlock &reader);
protected:
- virtual bool doRender();
+ virtual bool doRender(RectangleList *updateRects);
private:
uint _color;
diff --git a/engines/sword25/gfx/renderobject.cpp b/engines/sword25/gfx/renderobject.cpp
index a977eb80ba..807c1eb64b 100644
--- a/engines/sword25/gfx/renderobject.cpp
+++ b/engines/sword25/gfx/renderobject.cpp
@@ -48,6 +48,8 @@
namespace Sword25 {
+int RenderObject::_nextGlobalVersion = 0;
+
RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle) :
_managerPtr(0),
_parentPtr(parentPtr),
@@ -65,7 +67,9 @@ RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type,
_type(type),
_initSuccess(false),
_refreshForced(true),
- _handle(0) {
+ _handle(0),
+ _version(++_nextGlobalVersion),
+ _isSolid(false) {
// Renderobject registrieren, abhängig vom Handle-Parameter entweder mit beliebigem oder vorgegebenen Handle.
if (handle == 0)
@@ -106,13 +110,12 @@ RenderObject::~RenderObject() {
RenderObjectRegistry::instance().deregisterObject(this);
}
-bool RenderObject::render() {
+void RenderObject::preRender(RenderObjectQueue *renderQueue) {
// Objektänderungen validieren
validateObject();
- // Falls das Objekt nicht sichtbar ist, muss gar nichts gezeichnet werden
if (!_visible)
- return true;
+ return;
// Falls notwendig, wird die Renderreihenfolge der Kinderobjekte aktualisiert.
if (_childChanged) {
@@ -120,13 +123,36 @@ bool RenderObject::render() {
_childChanged = false;
}
+ renderQueue->add(this);
+
+ RENDEROBJECT_ITER it = _children.begin();
+ for (; it != _children.end(); ++it)
+ (*it)->preRender(renderQueue);
+
+}
+
+bool RenderObject::render(RectangleList *updateRects, const Common::Array<int> &updateRectsMinZ) {
+
+ // Falls das Objekt nicht sichtbar ist, muss gar nichts gezeichnet werden
+ if (!_visible)
+ return true;
+
// Objekt zeichnen.
- doRender();
+ bool needRender = false;
+ int index = 0;
+
+ // Only draw if the bounding box intersects any update rectangle and
+ // the object is in front of the minimum Z value.
+ for (RectangleList::iterator rectIt = updateRects->begin(); !needRender && rectIt != updateRects->end(); ++rectIt, ++index)
+ needRender = (_bbox.contains(*rectIt) || _bbox.intersects(*rectIt)) && getAbsoluteZ() >= updateRectsMinZ[index];
+
+ if (needRender)
+ doRender(updateRects);
// Dann müssen die Kinder gezeichnet werden
RENDEROBJECT_ITER it = _children.begin();
for (; it != _children.end(); ++it)
- if (!(*it)->render())
+ if (!(*it)->render(updateRects, updateRectsMinZ))
return false;
return true;
@@ -157,6 +183,8 @@ bool RenderObject::updateObjectState() {
// Die Bounding-Box neu berechnen und Update-Regions registrieren.
updateBoxes();
+
+ ++_version;
// Änderungen Validieren
validateObject();
@@ -191,9 +219,10 @@ Common::Rect RenderObject::calcBoundingBox() const {
return bbox;
}
-void RenderObject::calcAbsolutePos(int &x, int &y) const {
+void RenderObject::calcAbsolutePos(int &x, int &y, int &z) const {
x = calcAbsoluteX();
y = calcAbsoluteY();
+ z = calcAbsoluteZ();
}
int RenderObject::calcAbsoluteX() const {
@@ -210,6 +239,13 @@ int RenderObject::calcAbsoluteY() const {
return _y;
}
+int RenderObject::calcAbsoluteZ() const {
+ if (_parentPtr.isValid())
+ return _parentPtr->getAbsoluteZ() + _z;
+ else
+ return _z;
+}
+
void RenderObject::deleteAllChildren() {
// Es ist nicht notwendig die Liste zu iterieren, da jedes Kind für sich DetatchChildren an diesem Objekt aufruft und sich somit
// selber entfernt. Daher muss immer nur ein beliebiges Element (hier das letzte) gelöscht werden, bis die Liste leer ist.
@@ -253,7 +289,7 @@ void RenderObject::sortRenderObjects() {
}
void RenderObject::updateAbsolutePos() {
- calcAbsolutePos(_absoluteX, _absoluteY);
+ calcAbsolutePos(_absoluteX, _absoluteY, _absoluteZ);
RENDEROBJECT_ITER it = _children.begin();
for (; it != _children.end(); ++it)
@@ -285,8 +321,10 @@ void RenderObject::setY(int y) {
void RenderObject::setZ(int z) {
if (z < 0)
error("Tried to set a negative Z value (%d).", z);
- else
+ else {
_z = z;
+ updateAbsolutePos();
+ }
}
void RenderObject::setVisible(bool visible) {
diff --git a/engines/sword25/gfx/renderobject.h b/engines/sword25/gfx/renderobject.h
index f963ccaeb3..7e0334ee88 100644
--- a/engines/sword25/gfx/renderobject.h
+++ b/engines/sword25/gfx/renderobject.h
@@ -53,6 +53,8 @@ namespace Sword25 {
class Kernel;
class RenderObjectManager;
+class RenderObjectQueue;
+class RectangleList;
class Bitmap;
class Animation;
class AnimationTemplate;
@@ -211,6 +213,9 @@ public:
// Interface
// ---------
+
+ void preRender(RenderObjectQueue *renderQueue);
+
/**
@brief Rendert des Objekt und alle seine Unterobjekte.
@return Gibt false zurück, falls beim Rendern ein Fehler aufgetreten ist.
@@ -218,7 +223,8 @@ public:
Dieses kann entweder direkt geschehen oder durch den Aufruf von UpdateObjectState() an einem Vorfahren-Objekt.<br>
Diese Methode darf nur von BS_RenderObjectManager aufgerufen werden.
*/
- bool render();
+ bool render(RectangleList *updateRects, const Common::Array<int> &updateRectsMinZ);
+
/**
@brief Bereitet das Objekt und alle seine Unterobjekte auf einen Rendervorgang vor.
Hierbei werden alle Dirty-Rectangles berechnet und die Renderreihenfolge aktualisiert.
@@ -230,7 +236,7 @@ public:
@brief Löscht alle Kinderobjekte.
*/
void deleteAllChildren();
-
+
// Accessor-Methoden
// -----------------
/**
@@ -299,6 +305,11 @@ public:
int getZ() const {
return _z;
}
+
+ int getAbsoluteZ() const {
+ return _absoluteZ;
+ }
+
/**
@brief Gibt die Breite des Objektes zurück.
*/
@@ -352,6 +363,15 @@ public:
return _handle;
}
+ // Get the RenderObjects current version
+ int getVersion() const {
+ return _version;
+ }
+
+ bool isSolid() const {
+ return _isSolid;
+ }
+
// Persistenz-Methoden
// -------------------
virtual bool persist(OutputPersistenceBlock &writer);
@@ -370,9 +390,10 @@ protected:
int _x; ///< Die X-Position des Objektes relativ zum Eltern-Objekt
int _y; ///< Die Y-Position des Objektes relativ zum Eltern-Objekt
+ int _z; ///< Der Z-Wert des Objektes relativ zum Eltern-Objekt
int _absoluteX; ///< Die absolute X-Position des Objektes
int _absoluteY; ///< Die absolute Y-Position des Objektes
- int _z; ///< Der Z-Wert des Objektes relativ zum Eltern-Objekt
+ int _absoluteZ;
int _width; ///< Die Breite des Objektes
int _height; ///< Die Höhe des Objektes
bool _visible; ///< Ist true, wenn das Objekt sichtbar ist
@@ -388,6 +409,13 @@ protected:
int _oldZ;
bool _oldVisible;
+ static int _nextGlobalVersion;
+
+ int _version;
+
+ // This should be set to true if the RenderObject is NOT alpha-blended to optimize drawing
+ bool _isSolid;
+
/// Ein Pointer auf den BS_RenderObjektManager, der das Objekt verwaltet.
RenderObjectManager *_managerPtr;
@@ -402,7 +430,7 @@ protected:
@return Gibt false zurück, falls das Rendern fehlgeschlagen ist.
@remark
*/
- virtual bool doRender() = 0; // { return true; }
+ virtual bool doRender(RectangleList *updateRects) = 0; // { return true; }
// RenderObject-Baum Variablen
// ---------------------------
@@ -472,7 +500,7 @@ private:
/**
@brief Berechnet die absolute Position des Objektes.
*/
- void calcAbsolutePos(int &x, int &y) const;
+ void calcAbsolutePos(int &x, int &y, int &z) const;
/**
@brief Berechnet die absolute Position des Objektes auf der X-Achse.
*/
@@ -481,6 +509,9 @@ private:
@brief Berechnet die absolute Position des Objektes.
*/
int calcAbsoluteY() const;
+
+ int calcAbsoluteZ() const;
+
/**
@brief Sortiert alle Kinderobjekte nach ihrem Renderang.
*/
diff --git a/engines/sword25/gfx/renderobjectmanager.cpp b/engines/sword25/gfx/renderobjectmanager.cpp
index 38289991eb..994d9367ab 100644
--- a/engines/sword25/gfx/renderobjectmanager.cpp
+++ b/engines/sword25/gfx/renderobjectmanager.cpp
@@ -41,17 +41,37 @@
#include "sword25/gfx/timedrenderobject.h"
#include "sword25/gfx/rootrenderobject.h"
+#include "common/system.h"
+
namespace Sword25 {
+void RenderObjectQueue::add(RenderObject *renderObject) {
+ push_back(RenderObjectQueueItem(renderObject, renderObject->getBbox(), renderObject->getVersion()));
+}
+
+bool RenderObjectQueue::exists(const RenderObjectQueueItem &renderObjectQueueItem) {
+ for (RenderObjectQueue::iterator it = begin(); it != end(); ++it)
+ if ((*it)._renderObject == renderObjectQueueItem._renderObject &&
+ (*it)._version == renderObjectQueueItem._version)
+ return true;
+ return false;
+}
+
RenderObjectManager::RenderObjectManager(int width, int height, int framebufferCount) :
_frameStarted(false) {
// Wurzel des BS_RenderObject-Baumes erzeugen.
_rootPtr = (new RootRenderObject(this, width, height))->getHandle();
+ _uta = new MicroTileArray(width, height);
+ _currQueue = new RenderObjectQueue();
+ _prevQueue = new RenderObjectQueue();
}
RenderObjectManager::~RenderObjectManager() {
// Die Wurzel des Baumes löschen, damit werden alle BS_RenderObjects mitgelöscht.
_rootPtr.erase();
+ delete _uta;
+ delete _currQueue;
+ delete _prevQueue;
}
void RenderObjectManager::startFrame() {
@@ -76,7 +96,58 @@ bool RenderObjectManager::render() {
_frameStarted = false;
// Die Render-Methode der Wurzel aufrufen. Dadurch wird das rekursive Rendern der Baumelemente angestoßen.
- return _rootPtr->render();
+
+ _currQueue->clear();
+ _rootPtr->preRender(_currQueue);
+
+ _uta->clear();
+
+ // Add rectangles of objects which don't exist in this frame any more
+ for (RenderObjectQueue::iterator it = _prevQueue->begin(); it != _prevQueue->end(); ++it)
+ if (!_currQueue->exists(*it))
+ _uta->addRect((*it)._bbox);
+ // Add rectangles of objects which are different from the previous frame
+ for (RenderObjectQueue::iterator it = _currQueue->begin(); it != _currQueue->end(); ++it)
+ if (!_prevQueue->exists(*it))
+ _uta->addRect((*it)._bbox);
+
+ RectangleList *updateRects = _uta->getRectangles();
+ Common::Array<int> updateRectsMinZ;
+
+ updateRectsMinZ.reserve(updateRects->size());
+
+ // Calculate the minimum drawing Z value of each update rectangle
+ // Solid bitmaps with a Z order less than the value calculated here would be overdrawn again and
+ // so don't need to be drawn in the first place which speeds things up a bit.
+ for (RectangleList::iterator rectIt = updateRects->begin(); rectIt != updateRects->end(); ++rectIt) {
+ int minZ = 0;
+ for (RenderObjectQueue::iterator it = _currQueue->reverse_begin(); it != _currQueue->end(); --it) {
+ if ((*it)._renderObject->isVisible() && (*it)._renderObject->isSolid() &&
+ (*it)._renderObject->getBbox().contains(*rectIt)) {
+ minZ = (*it)._renderObject->getAbsoluteZ();
+ break;
+ }
+ }
+ updateRectsMinZ.push_back(minZ);
+ }
+
+ if (_rootPtr->render(updateRects, updateRectsMinZ)) {
+ // Copy updated rectangles to the video screen
+ Graphics::Surface *backSurface = Kernel::getInstance()->getGfx()->getSurface();
+ for (RectangleList::iterator rectIt = updateRects->begin(); rectIt != updateRects->end(); ++rectIt) {
+ const int x = (*rectIt).left;
+ const int y = (*rectIt).top;
+ const int width = (*rectIt).width();
+ const int height = (*rectIt).height();
+ g_system->copyRectToScreen(backSurface->getBasePtr(x, y), backSurface->pitch, x, y, width, height);
+ }
+ }
+
+ delete updateRects;
+
+ SWAP(_currQueue, _prevQueue);
+
+ return true;
}
void RenderObjectManager::attatchTimedRenderObject(RenderObjectPtr<TimedRenderObject> renderObjectPtr) {
diff --git a/engines/sword25/gfx/renderobjectmanager.h b/engines/sword25/gfx/renderobjectmanager.h
index 9e7efd8e60..1db91dfbe6 100644
--- a/engines/sword25/gfx/renderobjectmanager.h
+++ b/engines/sword25/gfx/renderobjectmanager.h
@@ -47,11 +47,28 @@
#include "sword25/gfx/renderobjectptr.h"
#include "sword25/kernel/persistable.h"
+#include "sword25/gfx/microtiles.h"
+
namespace Sword25 {
class Kernel;
class RenderObject;
class TimedRenderObject;
+class RenderObjectManager;
+
+struct RenderObjectQueueItem {
+ RenderObject *_renderObject;
+ Common::Rect _bbox;
+ int _version;
+ RenderObjectQueueItem(RenderObject *renderObject, const Common::Rect &bbox, int version)
+ : _renderObject(renderObject), _bbox(bbox), _version(version) {}
+};
+
+class RenderObjectQueue : public Common::List<RenderObjectQueueItem> {
+public:
+ void add(RenderObject *renderObject);
+ bool exists(const RenderObjectQueueItem &renderObjectQueueItem);
+};
/**
@brief Diese Klasse ist für die Verwaltung von BS_RenderObjects zuständig.
@@ -114,6 +131,9 @@ private:
typedef Common::Array<RenderObjectPtr<TimedRenderObject> > RenderObjectList;
RenderObjectList _timedRenderObjects;
+ MicroTileArray *_uta;
+ RenderObjectQueue *_currQueue, *_prevQueue;
+
// RenderObject-Tree Variablen
// ---------------------------
// Der Baum legt die hierachische Ordnung der BS_RenderObjects fest.
diff --git a/engines/sword25/gfx/rootrenderobject.h b/engines/sword25/gfx/rootrenderobject.h
index 4782fad175..f1b19d6bae 100644
--- a/engines/sword25/gfx/rootrenderobject.h
+++ b/engines/sword25/gfx/rootrenderobject.h
@@ -59,7 +59,7 @@ private:
}
protected:
- virtual bool doRender() {
+ virtual bool doRender(RectangleList *updateRects) {
return true;
}
};
diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp
index 0ae07b36b5..91b93e8910 100644
--- a/engines/sword25/gfx/staticbitmap.cpp
+++ b/engines/sword25/gfx/staticbitmap.cpp
@@ -71,6 +71,8 @@ bool StaticBitmap::initBitmapResource(const Common::String &filename) {
// RenderObject Eigenschaften aktualisieren
_originalWidth = _width = bitmapPtr->getWidth();
_originalHeight = _height = bitmapPtr->getHeight();
+
+ _isSolid = bitmapPtr->isSolid();
// Bild-Resource freigeben
bitmapPtr->release();
@@ -81,7 +83,7 @@ bool StaticBitmap::initBitmapResource(const Common::String &filename) {
StaticBitmap::~StaticBitmap() {
}
-bool StaticBitmap::doRender() {
+bool StaticBitmap::doRender(RectangleList *updateRects) {
// Bitmap holen
Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
assert(resourcePtr);
@@ -98,12 +100,14 @@ bool StaticBitmap::doRender() {
result = bitmapResourcePtr->blit(_absoluteX, _absoluteY,
(_flipV ? BitmapResource::FLIP_V : 0) |
(_flipH ? BitmapResource::FLIP_H : 0),
- 0, _modulationColor, -1, -1);
+ 0, _modulationColor, -1, -1,
+ updateRects);
} else {
result = bitmapResourcePtr->blit(_absoluteX, _absoluteY,
(_flipV ? BitmapResource::FLIP_V : 0) |
(_flipH ? BitmapResource::FLIP_H : 0),
- 0, _modulationColor, _width, _height);
+ 0, _modulationColor, _width, _height,
+ updateRects);
}
// Resource freigeben
diff --git a/engines/sword25/gfx/staticbitmap.h b/engines/sword25/gfx/staticbitmap.h
index e66ede02b4..90b92b4331 100644
--- a/engines/sword25/gfx/staticbitmap.h
+++ b/engines/sword25/gfx/staticbitmap.h
@@ -65,7 +65,7 @@ public:
virtual bool unpersist(InputPersistenceBlock &reader);
protected:
- virtual bool doRender();
+ virtual bool doRender(RectangleList *updateRects);
private:
Common::String _resourceFilename;
diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp
index 82bb7cdff7..d4aaa90682 100644
--- a/engines/sword25/gfx/text.cpp
+++ b/engines/sword25/gfx/text.cpp
@@ -91,9 +91,11 @@ bool Text::setFont(const Common::String &font) {
}
void Text::setText(const Common::String &text) {
- _text = text;
- updateFormat();
- forceRefresh();
+ if (_text != text) {
+ _text = text;
+ updateFormat();
+ forceRefresh();
+ }
}
void Text::setColor(uint modulationColor) {
@@ -129,7 +131,7 @@ void Text::setAutoWrapThreshold(uint autoWrapThreshold) {
}
}
-bool Text::doRender() {
+bool Text::doRender(RectangleList *updateRects) {
// Font-Resource locken.
FontResource *fontPtr = lockFontResource();
if (!fontPtr)
@@ -171,7 +173,7 @@ bool Text::doRender() {
Common::Rect renderRect(curX, curY, curX + curRect.width(), curY + curRect.height());
renderRect.translate(curRect.left - curX, curRect.top - curY);
- result = charMapPtr->blit(curX, curY, Image::FLIP_NONE, &renderRect, _modulationColor);
+ result = charMapPtr->blit(curX, curY, Image::FLIP_NONE, &renderRect, _modulationColor, -1, -1, updateRects);
if (!result)
break;
diff --git a/engines/sword25/gfx/text.h b/engines/sword25/gfx/text.h
index a0d668014f..94e7a30865 100644
--- a/engines/sword25/gfx/text.h
+++ b/engines/sword25/gfx/text.h
@@ -136,7 +136,7 @@ public:
virtual bool unpersist(InputPersistenceBlock &reader);
protected:
- virtual bool doRender();
+ virtual bool doRender(RectangleList *updateRects);
private:
Text(RenderObjectPtr<RenderObject> parentPtr);
diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk
index e24a221244..234baec165 100644
--- a/engines/sword25/module.mk
+++ b/engines/sword25/module.mk
@@ -16,6 +16,7 @@ MODULE_OBJS := \
gfx/fontresource.o \
gfx/graphicengine.o \
gfx/graphicengine_script.o \
+ gfx/microtiles.o \
gfx/panel.o \
gfx/renderobject.o \
gfx/renderobjectmanager.o \