aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillem Jan Palenstijn2013-10-01 06:06:51 -0700
committerWillem Jan Palenstijn2013-10-01 06:06:51 -0700
commit574a2a64fe23f050032e12d3d85213a656a836be (patch)
treeca8387e85e2d8075d33be0cdebdfb9342bcf7a5b
parentd2f05efd04a57d4ce5e946e872f153eb2eaf9eb8 (diff)
parent2ec84600a9bcfd68366816d9e1f951d500a21637 (diff)
downloadscummvm-rg350-574a2a64fe23f050032e12d3d85213a656a836be.tar.gz
scummvm-rg350-574a2a64fe23f050032e12d3d85213a656a836be.tar.bz2
scummvm-rg350-574a2a64fe23f050032e12d3d85213a656a836be.zip
Merge pull request #402 from wjp/wme_rendering
WINTERMUTE: Speed up rendering
-rw-r--r--engines/wintermute/base/gfx/base_surface.h2
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.cpp193
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.h20
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp18
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.h2
-rw-r--r--engines/wintermute/base/gfx/osystem/render_ticket.cpp71
-rw-r--r--engines/wintermute/base/gfx/osystem/render_ticket.h4
-rw-r--r--engines/wintermute/graphics/transform_struct.cpp15
-rw-r--r--engines/wintermute/graphics/transform_struct.h7
-rw-r--r--engines/wintermute/ui/ui_tiled_image.cpp27
10 files changed, 164 insertions, 195 deletions
diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h
index 42fd593f61..a53748e9aa 100644
--- a/engines/wintermute/base/gfx/base_surface.h
+++ b/engines/wintermute/base/gfx/base_surface.h
@@ -56,7 +56,7 @@ public:
virtual bool display(int x, int y, Rect32 rect, 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, float zoomX, float 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 displayTiled(int x, int y, Rect32 rect, 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;
virtual bool create(int width, int height);
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index 4a1bfb867d..39691628ab 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -52,17 +52,14 @@ BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) {
_renderSurface = new Graphics::Surface();
_blankSurface = new Graphics::Surface();
_drawNum = 1;
+ _lastFrameIter = _renderQueue.end();
_needsFlip = true;
- _spriteBatch = false;
- _batchNum = 0;
_skipThisFrame = false;
- _previousTicket = nullptr;
_borderLeft = _borderRight = _borderTop = _borderBottom = 0;
_ratioX = _ratioY = 1.0f;
_dirtyRect = nullptr;
_disableDirtyRects = false;
- _tempDisableDirtyRects = 0;
if (ConfMan.hasKey("dirty_rects")) {
_disableDirtyRects = !ConfMan.getBool("dirty_rects");
}
@@ -154,9 +151,6 @@ bool BaseRenderOSystem::indicatorFlip() {
}
bool BaseRenderOSystem::flip() {
- if (_renderQueue.size() > DIRTY_RECT_LIMIT) {
- _tempDisableDirtyRects++;
- }
if (_skipThisFrame) {
_skipThisFrame = false;
delete _dirtyRect;
@@ -164,10 +158,11 @@ bool BaseRenderOSystem::flip() {
g_system->updateScreen();
_needsFlip = false;
_drawNum = 1;
+ _lastFrameIter = _renderQueue.end();
addDirtyRect(_renderRect);
return true;
}
- if (!_tempDisableDirtyRects && !_disableDirtyRects) {
+ if (!_disableDirtyRects) {
drawTickets();
} else {
// Clear the scale-buffered tickets that wasn't reused.
@@ -183,8 +178,8 @@ bool BaseRenderOSystem::flip() {
}
}
}
- if (_needsFlip || _disableDirtyRects || _tempDisableDirtyRects) {
- if (_disableDirtyRects || _tempDisableDirtyRects) {
+ if (_needsFlip || _disableDirtyRects) {
+ if (_disableDirtyRects) {
g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h);
}
// g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height());
@@ -194,22 +189,7 @@ bool BaseRenderOSystem::flip() {
_needsFlip = false;
}
_drawNum = 1;
-
- if (_tempDisableDirtyRects && !_disableDirtyRects) {
- _tempDisableDirtyRects--;
- if (!_tempDisableDirtyRects) {
- Common::Rect screen(_screenRect.top, _screenRect.left, _screenRect.bottom, _screenRect.right);
- addDirtyRect(screen);
-
- // The queue has been ignored but updated, and is guaranteed to be in draw-order when run without dirty-rects.
- RenderQueueIterator it = _renderQueue.begin();
- int drawNum = 1;
- while (it != _renderQueue.end()) {
- (*it)->_drawNum = drawNum++;
- ++it;
- }
- }
- }
+ _lastFrameIter = _renderQueue.end();
return STATUS_OK;
}
@@ -217,7 +197,7 @@ bool BaseRenderOSystem::flip() {
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::fill(byte r, byte g, byte b, Common::Rect *rect) {
_clearColor = _renderSurface->format.ARGBToColor(0xFF, r, g, b);
- if (!_disableDirtyRects && !_tempDisableDirtyRects) {
+ if (!_disableDirtyRects) {
return STATUS_OK;
}
if (!rect) {
@@ -278,11 +258,10 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const {
void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) {
- if (_tempDisableDirtyRects || _disableDirtyRects) {
+ if (_disableDirtyRects) {
RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
ticket->_wantsDraw = true;
_renderQueue.push_back(ticket);
- _previousTicket = ticket;
drawFromSurface(ticket);
return;
}
@@ -300,10 +279,6 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
if (owner) { // Fade-tickets are owner-less
RenderTicket compare(owner, nullptr, srcRect, dstRect, transform);
- compare._batchNum = _batchNum;
- if (_spriteBatch) {
- _batchNum++;
- }
RenderQueueIterator it;
// Avoid calling end() and operator* every time, when potentially going through
// LOTS of tickets.
@@ -315,12 +290,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
if (_disableDirtyRects) {
drawFromSurface(compareTicket);
} else {
- drawFromTicket(compareTicket);
- _previousTicket = compareTicket;
- }
- if (_renderQueue.size() > DIRTY_RECT_LIMIT) {
- drawTickets();
- _tempDisableDirtyRects = 3;
+ drawFromQueuedTicket(it);
}
return;
}
@@ -329,57 +299,13 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
if (!_disableDirtyRects) {
drawFromTicket(ticket);
- _previousTicket = ticket;
} else {
ticket->_wantsDraw = true;
_renderQueue.push_back(ticket);
- _previousTicket = ticket;
drawFromSurface(ticket);
}
}
-void BaseRenderOSystem::repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY) {
- if (_previousTicket && _lastAddedTicket != _renderQueue.end()) {
- RenderTicket *origTicket = _previousTicket;
-
- // Make sure drawSurface WILL start from the correct _lastAddedTicket
- if (!_tempDisableDirtyRects && !_disableDirtyRects && *_lastAddedTicket != origTicket) {
- RenderQueueIterator it;
- RenderQueueIterator endIterator = _renderQueue.end();
- for (it = _renderQueue.begin(); it != endIterator; ++it) {
- if ((*it) == _previousTicket) {
- _lastAddedTicket = it;
- break;
- }
- }
- }
- Common::Rect srcRect(0, 0, 0, 0);
- srcRect.setWidth(origTicket->getSrcRect()->width());
- srcRect.setHeight(origTicket->getSrcRect()->height());
-
- Common::Rect dstRect = origTicket->_dstRect;
- 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, temp);
- dstRect.translate(offsetX, 0);
- }
- dstRect.left = initLeft;
- dstRect.right = initRight;
- dstRect.translate(0, offsetY);
- }
- } else {
- error("Repeat-draw failed (did you forget to draw something before this?)");
- }
-}
-
void BaseRenderOSystem::invalidateTicket(RenderTicket *renderTicket) {
addDirtyRect(renderTicket->_dstRect);
renderTicket->_isValid = false;
@@ -397,59 +323,40 @@ void BaseRenderOSystem::invalidateTicketsFromSurface(BaseSurfaceOSystem *surf) {
void BaseRenderOSystem::drawFromTicket(RenderTicket *renderTicket) {
renderTicket->_wantsDraw = true;
- // A new item always has _drawNum == 0
- if (renderTicket->_drawNum == 0) {
- // In-order
- if (_renderQueue.empty() || _drawNum > (_renderQueue.back())->_drawNum) {
- renderTicket->_drawNum = _drawNum++;
- _renderQueue.push_back(renderTicket);
- addDirtyRect(renderTicket->_dstRect);
- ++_lastAddedTicket;
- } else {
- // Before something
- RenderQueueIterator pos;
- for (pos = _renderQueue.begin(); pos != _renderQueue.end(); pos++) {
- if ((*pos)->_drawNum >= _drawNum) {
- break;
- }
- }
- _renderQueue.insert(pos, renderTicket);
- renderTicket->_drawNum = _drawNum++;
- // Increment the following tickets, so they still are in line
- RenderQueueIterator it;
- for (it = pos; it != _renderQueue.end(); ++it) {
- (*it)->_drawNum++;
- (*it)->_wantsDraw = false;
- }
- addDirtyRect(renderTicket->_dstRect);
- _lastAddedTicket = pos;
- }
+
+ ++_lastFrameIter;
+ // In-order
+ if (_renderQueue.empty() || _lastFrameIter == _renderQueue.end()) {
+ _lastFrameIter--;
+ _renderQueue.push_back(renderTicket);
+ ++_lastFrameIter;
+ addDirtyRect(renderTicket->_dstRect);
+ ++_lastAddedTicket;
} else {
- // Was drawn last round, still in the same order
- if (_drawNum == renderTicket->_drawNum) {
- _drawNum++;
- ++_lastAddedTicket;
- } else {
- // Remove the ticket from the list
- RenderQueueIterator it = _renderQueue.begin();
- while (it != _renderQueue.end()) {
- if ((*it) == renderTicket) {
- it = _renderQueue.erase(it);
- break;
- } else {
- ++it;
- }
- }
- if (it != _renderQueue.end()) {
- // Decreement the following tickets.
- for (; it != _renderQueue.end(); ++it) {
- (*it)->_drawNum--;
- }
- }
- // Is not in order, so readd it as if it was a new ticket
- renderTicket->_drawNum = 0;
- drawFromTicket(renderTicket);
- }
+ // Before something
+ RenderQueueIterator pos = _lastFrameIter;
+ _renderQueue.insert(pos, renderTicket);
+ --_lastFrameIter;
+ addDirtyRect(renderTicket->_dstRect);
+ _lastAddedTicket = pos;
+ }
+}
+
+void BaseRenderOSystem::drawFromQueuedTicket(const RenderQueueIterator &ticket) {
+ RenderTicket *renderTicket = *ticket;
+ renderTicket->_wantsDraw = true;
+
+ ++_lastFrameIter;
+ // Was drawn last round, still in the same order
+ if (*_lastFrameIter == renderTicket) {
+ _drawNum++;
+ ++_lastAddedTicket;
+ } else {
+ --_lastFrameIter;
+ // Remove the ticket from the list
+ _renderQueue.erase(ticket);
+ // Is not in order, so readd it as if it was a new ticket
+ drawFromTicket(renderTicket);
}
}
@@ -468,16 +375,13 @@ void BaseRenderOSystem::drawTickets() {
// Note: We draw invalid tickets too, otherwise we wouldn't be honouring
// the draw request they obviously made BEFORE becoming invalid, either way
// we have a copy of their data, so their invalidness won't affect us.
- uint32 decrement = 0;
while (it != _renderQueue.end()) {
if ((*it)->_wantsDraw == false) {
RenderTicket *ticket = *it;
addDirtyRect((*it)->_dstRect);
it = _renderQueue.erase(it);
delete ticket;
- decrement++;
} else {
- (*it)->_drawNum -= decrement;
++it;
}
}
@@ -494,9 +398,9 @@ void BaseRenderOSystem::drawTickets() {
// Apply the clear-color to the dirty rect.
_renderSurface->fillRect(*_dirtyRect, _clearColor);
_drawNum = 1;
+ _lastFrameIter = _renderQueue.end();
for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) {
RenderTicket *ticket = *it;
- assert(ticket->_drawNum == _drawNum);
++_drawNum;
if (ticket->_dstRect.intersects(*_dirtyRect)) {
// dstClip is the area we want redrawn.
@@ -520,16 +424,13 @@ void BaseRenderOSystem::drawTickets() {
it = _renderQueue.begin();
// Clean out the old tickets
- decrement = 0;
while (it != _renderQueue.end()) {
if ((*it)->_isValid == false) {
RenderTicket *ticket = *it;
addDirtyRect((*it)->_dstRect);
it = _renderQueue.erase(it);
delete ticket;
- decrement++;
} else {
- (*it)->_drawNum -= decrement;
++it;
}
}
@@ -549,7 +450,7 @@ void BaseRenderOSystem::drawFromSurface(RenderTicket *ticket, Common::Rect *dstR
bool BaseRenderOSystem::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
// This function isn't used outside of indicator-displaying, and thus quite unused in
// BaseRenderOSystem when dirty-rects are enabled.
- if (!_tempDisableDirtyRects && !_disableDirtyRects && !_indicatorDisplay) {
+ if (!_disableDirtyRects && !_indicatorDisplay) {
error("BaseRenderOSystem::DrawLine - doesn't work for dirty rects yet");
}
@@ -656,11 +557,11 @@ void BaseRenderOSystem::endSaveLoad() {
delete ticket;
}
_lastAddedTicket = _renderQueue.begin();
- _previousTicket = nullptr;
// HACK: After a save the buffer will be drawn before the scripts get to update it,
// so just skip this single frame.
_skipThisFrame = true;
_drawNum = 1;
+ _lastFrameIter = _renderQueue.end();
_renderSurface->fillRect(Common::Rect(0, 0, _renderSurface->h, _renderSurface->w), _renderSurface->format.ARGBToColor(255, 0, 0, 0));
g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h);
@@ -668,14 +569,10 @@ void BaseRenderOSystem::endSaveLoad() {
}
bool BaseRenderOSystem::startSpriteBatch() {
- _spriteBatch = true;
- _batchNum = 1;
return STATUS_OK;
}
bool BaseRenderOSystem::endSpriteBatch() {
- _spriteBatch = false;
- _batchNum = 0;
return STATUS_OK;
}
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
index 2ae3b6cfeb..ab62d242c0 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
@@ -62,6 +62,8 @@ public:
BaseRenderOSystem(BaseGame *inGame);
~BaseRenderOSystem();
+ typedef Common::List<RenderTicket *>::iterator RenderQueueIterator;
+
Common::String getName() const;
bool initRenderer(int width, int height, bool windowed) override;
@@ -79,11 +81,16 @@ public:
void invalidateTicket(RenderTicket *renderTicket);
void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf);
/**
- * Insert a ticket into the queue, adding a dirty rect if it's
- * new, or out-of-order from last draw from the ticket.
- * param renderTicket the ticket to be added.
+ * Insert a new ticket into the queue, adding a dirty rect
+ * @param renderTicket the ticket to be added.
*/
void drawFromTicket(RenderTicket *renderTicket);
+ /**
+ * Re-insert an existing ticket into the queue, adding a dirty rect
+ * out-of-order from last draw from the ticket.
+ * @param ticket iterator pointing to the ticket to be added.
+ */
+ void drawFromQueuedTicket(const RenderQueueIterator &ticket);
bool setViewport(int left, int top, int right, int bottom) override;
bool setViewport(Rect32 *rect) override { return BaseRenderer::setViewport(rect); }
@@ -104,7 +111,6 @@ public:
virtual bool endSpriteBatch() override;
void endSaveLoad();
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:
/**
@@ -120,14 +126,13 @@ private:
void drawFromSurface(RenderTicket *ticket);
// Dirty-rects:
void drawFromSurface(RenderTicket *ticket, Common::Rect *dstRect, Common::Rect *clipRect);
- typedef Common::List<RenderTicket *>::iterator RenderQueueIterator;
Common::Rect *_dirtyRect;
Common::List<RenderTicket *> _renderQueue;
RenderQueueIterator _lastAddedTicket;
- RenderTicket *_previousTicket;
bool _needsFlip;
uint32 _drawNum; ///< The global number of the current draw-operation.
+ RenderQueueIterator _lastFrameIter;
Common::Rect _renderRect;
Graphics::Surface *_renderSurface;
Graphics::Surface *_blankSurface;
@@ -138,9 +143,6 @@ private:
int _borderBottom;
bool _disableDirtyRects;
- uint32 _tempDisableDirtyRects;
- bool _spriteBatch;
- uint32 _batchNum;
float _ratioX;
float _ratioY;
uint32 _clearColor;
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
index e04af45dd9..67d8f3f425 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
@@ -381,6 +381,14 @@ bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newR
}
//////////////////////////////////////////////////////////////////////////
+bool BaseSurfaceOSystem::displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) {
+ assert(numTimesX > 0 && numTimesY > 0);
+ TransformStruct transform(numTimesX, numTimesY);
+ return drawSprite(x, y, &rect, nullptr, transform);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) {
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);
@@ -424,8 +432,8 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect,
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));
+ position.setWidth((int16)((float)srcRect.width() * transform._zoom.x / kDefaultZoomX) * transform._numTimesX);
+ position.setHeight((int16)((float)srcRect.height() * transform._zoom.y / kDefaultZoomY) * transform._numTimesY);
}
renderer->modTargetRect(&position);
@@ -441,12 +449,6 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect,
return STATUS_OK;
}
-bool BaseSurfaceOSystem::repeatLastDisplayOp(int offsetX, int offsetY, int numTimesX, int numTimesY) {
- BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);
- renderer->repeatLastDraw(offsetX, offsetY, numTimesX, numTimesY);
- return STATUS_OK;
-}
-
bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAlpha) {
_loaded = true;
_surface->free();
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
index 340a5a5ffc..67f45f66db 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
@@ -58,7 +58,7 @@ public:
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 = 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 displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY);
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);
static int DLL_CALLCONV SeekProc(fi_handle handle, long offset, int origin);
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
index 94512eb583..7a926c3e36 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
@@ -38,11 +38,9 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s
_owner(owner),
_srcRect(*srcRect),
_dstRect(*dstRect),
- _drawNum(0),
_isValid(true),
_wantsDraw(true),
_transform(transform) {
- _batchNum = 0;
if (surf) {
_surface = new Graphics::Surface();
_surface->create((uint16)srcRect->width(), (uint16)srcRect->height(), surf->format);
@@ -52,13 +50,19 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s
memcpy(_surface->getBasePtr(0, i), surf->getBasePtr(srcRect->left, srcRect->top + i), srcRect->width() * _surface->format.bytesPerPixel);
}
// Then scale it if necessary
+ //
+ // NB: The numTimesX/numTimesY properties don't yet mix well with
+ // scaling and rotation, but there is no need for that functionality at
+ // the moment.
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()) {
+ } else if ((dstRect->width() != srcRect->width() ||
+ dstRect->height() != srcRect->height()) &&
+ _transform._numTimesX * _transform._numTimesY == 1) {
TransparentSurface src(*_surface, false);
Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height());
_surface->free();
@@ -87,7 +91,6 @@ RenderTicket::~RenderTicket() {
bool RenderTicket::operator==(const RenderTicket &t) const {
if ((t._owner != _owner) ||
- (t._batchNum != _batchNum) ||
(t._transform != _transform) ||
(t._dstRect != _dstRect) ||
(t._srcRect != _srcRect)
@@ -112,7 +115,19 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {
src.setAlphaMode(_owner->getAlphaType());
}
}
- src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height());
+
+ int y = _dstRect.top;
+ int w = _dstRect.width() / _transform._numTimesX;
+ int h = _dstRect.height() / _transform._numTimesY;
+
+ for (int ry = 0; ry < _transform._numTimesY; ++ry) {
+ int x = _dstRect.left;
+ for (int rx = 0; rx < _transform._numTimesX; ++rx) {
+ src.blit(*_targetSurface, x, y, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height());
+ x += w;
+ }
+ y += h;
+ }
}
void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const {
@@ -121,8 +136,8 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect
if (!clipRect) {
doDelete = true;
clipRect = new Common::Rect();
- clipRect->setWidth(getSurface()->w);
- clipRect->setHeight(getSurface()->h);
+ clipRect->setWidth(getSurface()->w * _transform._numTimesX);
+ clipRect->setHeight(getSurface()->h * _transform._numTimesY);
}
if (_owner) {
@@ -132,7 +147,47 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect
src.setAlphaMode(_owner->getAlphaType());
}
}
- src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height(), _transform._blendMode);
+
+ if (_transform._numTimesX * _transform._numTimesY == 1) {
+
+ src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height(), _transform._blendMode);
+
+ } else {
+
+ // clipRect is a subrect of the full numTimesX*numTimesY rect
+ Common::Rect subRect;
+
+ int y = 0;
+ int w = getSurface()->w;
+ int h = getSurface()->h;
+ assert(w == _dstRect.width() / _transform._numTimesX);
+ assert(h == _dstRect.height() / _transform._numTimesY);
+
+ int basex = dstRect->left - clipRect->left;
+ int basey = dstRect->top - clipRect->top;
+
+ for (int ry = 0; ry < _transform._numTimesY; ++ry) {
+ int x = 0;
+ for (int rx = 0; rx < _transform._numTimesX; ++rx) {
+
+ subRect.left = x;
+ subRect.top = y;
+ subRect.setWidth(w);
+ subRect.setHeight(w);
+
+ if (subRect.intersects(*clipRect)) {
+ subRect.clip(*clipRect);
+ subRect.translate(-x, -y);
+ src.blit(*_targetSurface, basex + x + subRect.left, basey + y + subRect.top, _transform._flip, &subRect, _transform._rgbaMod, subRect.width(), subRect.height(), _transform._blendMode);
+
+ }
+
+ x += w;
+ }
+ y += h;
+ }
+ }
+
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 875102d01c..e824c09fe7 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.h
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.h
@@ -52,7 +52,7 @@ class BaseSurfaceOSystem;
class RenderTicket {
public:
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() : _isValid(true), _wantsDraw(false), _transform(TransformStruct()) {}
~RenderTicket();
const Graphics::Surface *getSurface() const { return _surface; }
// Non-dirty-rects:
@@ -61,11 +61,9 @@ public:
void drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const;
Common::Rect _dstRect;
- uint32 _batchNum;
bool _isValid;
bool _wantsDraw;
- uint32 _drawNum;
TransformStruct _transform;
diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp
index 643c6b413f..822c06f42f 100644
--- a/engines/wintermute/graphics/transform_struct.cpp
+++ b/engines/wintermute/graphics/transform_struct.cpp
@@ -35,6 +35,8 @@ void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alp
_flip += TransparentSurface::FLIP_H * mirrorX;
_flip += TransparentSurface::FLIP_V * mirrorY;
_offset = offset;
+ _numTimesX = 1;
+ _numTimesY = 1;
}
TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) {
@@ -83,6 +85,19 @@ TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 h
Point32(kDefaultOffsetX, kDefaultOffsetY));
}
+TransformStruct::TransformStruct(int32 numTimesX, int32 numTimesY) {
+ init(Point32(kDefaultZoomX, kDefaultZoomY),
+ kDefaultAngle,
+ Point32(kDefaultHotspotX, kDefaultHotspotY),
+ false,
+ BLEND_NORMAL,
+ kDefaultRgbaMod,
+ false, false,
+ Point32(kDefaultOffsetX, kDefaultOffsetY));
+ _numTimesX = numTimesX;
+ _numTimesY = numTimesY;
+}
+
TransformStruct::TransformStruct() {
init(Point32(kDefaultZoomX, kDefaultZoomY),
kDefaultAngle,
diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h
index 90a4c1f846..d5a03ea331 100644
--- a/engines/wintermute/graphics/transform_struct.h
+++ b/engines/wintermute/graphics/transform_struct.h
@@ -51,6 +51,7 @@ public:
TransformStruct(float zoomX, float 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(int32 numTimesX, int32 numTimesY);
TransformStruct();
Point32 _zoom; ///< Zoom; 100 = no zoom
@@ -61,6 +62,8 @@ public:
TSpriteBlendMode _blendMode;
uint32 _rgbaMod; ///< RGBa
Point32 _offset;
+ int32 _numTimesX;
+ int32 _numTimesY;
bool getMirrorX() const;
bool getMirrorY() const;
@@ -72,7 +75,9 @@ public:
compare._offset == _offset &&
compare._alphaDisable == _alphaDisable &&
compare._rgbaMod == _rgbaMod &&
- compare._blendMode == _blendMode
+ compare._blendMode == _blendMode &&
+ compare._numTimesX == _numTimesX &&
+ compare._numTimesY == _numTimesY
);
}
diff --git a/engines/wintermute/ui/ui_tiled_image.cpp b/engines/wintermute/ui/ui_tiled_image.cpp
index de4b86a6dd..7c28c139f4 100644
--- a/engines/wintermute/ui/ui_tiled_image.cpp
+++ b/engines/wintermute/ui/ui_tiled_image.cpp
@@ -75,8 +75,6 @@ bool UITiledImage::display(int x, int y, int width, int height) {
int nuColumns = (width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) / tileWidth;
int nuRows = (height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) / tileHeight;
- int col, row;
-
_gameRef->_renderer->startSpriteBatch();
// top left/right
@@ -88,27 +86,24 @@ bool UITiledImage::display(int x, int y, int width, int height) {
_image->_surface->displayTrans(x + (_upLeft.right - _upLeft.left) + nuColumns * tileWidth, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downRight);
// left/right
- int yyy = y + (_upMiddle.bottom - _upMiddle.top);
- for (row = 0; row < nuRows; row++) {
- _image->_surface->displayTrans(x, yyy, _middleLeft);
- _image->_surface->displayTrans(x + (_middleLeft.right - _middleLeft.left) + nuColumns * tileWidth, yyy, _middleRight);
- yyy += tileWidth;
+ if (nuRows > 0) {
+ int yyy = y + (_upMiddle.bottom - _upMiddle.top);
+ _image->_surface->displayTiled(x, yyy, _middleLeft, 1, nuRows);
+ _image->_surface->displayTiled(x + (_middleLeft.right - _middleLeft.left) + nuColumns * tileWidth, yyy, _middleRight, 1, nuRows);
}
// top/bottom
- int xxx = x + (_upLeft.right - _upLeft.left);
- for (col = 0; col < nuColumns; col++) {
- _image->_surface->displayTrans(xxx, y, _upMiddle);
- _image->_surface->displayTrans(xxx, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downMiddle);
- xxx += tileWidth;
+ if (nuColumns > 0) {
+ int xxx = x + (_upLeft.right - _upLeft.left);
+ _image->_surface->displayTiled(xxx, y, _upMiddle, nuColumns, 1);
+ _image->_surface->displayTiled(xxx, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downMiddle, nuColumns, 1);
}
// tiles
if (nuRows > 0 && nuColumns > 0) {
- yyy = y + (_upMiddle.bottom - _upMiddle.top);
- xxx = x + (_upLeft.right - _upLeft.left);
- _image->_surface->displayTrans(xxx, yyy, _middleMiddle);
- _image->_surface->repeatLastDisplayOp(tileWidth, tileWidth, nuColumns, nuRows);
+ int yyy = y + (_upMiddle.bottom - _upMiddle.top);
+ int xxx = x + (_upLeft.right - _upLeft.left);
+ _image->_surface->displayTiled(xxx, yyy, _middleMiddle, nuColumns, nuRows);
}
_gameRef->_renderer->endSpriteBatch();