WINTERMUTE: Add displayTiled function to replace repeatLastDraw

This avoids queueing many tickets for a UITiledImage, replacing
them by a single tiled ticket.
This commit is contained in:
Willem Jan Palenstijn 2013-09-25 19:47:39 +02:00
parent 4e12600d70
commit 057b01951a
9 changed files with 107 additions and 82 deletions

View File

@ -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);

View File

@ -55,7 +55,6 @@ BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) {
_lastFrameIter = _renderQueue.end();
_needsFlip = true;
_skipThisFrame = false;
_previousTicket = nullptr;
_borderLeft = _borderRight = _borderTop = _borderBottom = 0;
_ratioX = _ratioY = 1.0f;
@ -265,7 +264,6 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
ticket->_transform._rgbaMod = _colorMod;
ticket->_wantsDraw = true;
_renderQueue.push_back(ticket);
_previousTicket = ticket;
drawFromSurface(ticket);
return;
}
@ -296,7 +294,6 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S
drawFromSurface(compareTicket);
} else {
drawFromQueuedTicket(it);
_previousTicket = compareTicket;
}
return;
}
@ -305,57 +302,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 (!_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;
@ -614,7 +567,6 @@ 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;

View File

@ -111,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:
/**
@ -130,7 +129,6 @@ private:
Common::Rect *_dirtyRect;
Common::List<RenderTicket *> _renderQueue;
RenderQueueIterator _lastAddedTicket;
RenderTicket *_previousTicket;
bool _needsFlip;
uint32 _drawNum; ///< The global number of the current draw-operation.

View File

@ -380,6 +380,14 @@ bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newR
return drawSprite(x, y, &rect, &newRect, transform);
}
//////////////////////////////////////////////////////////////////////////
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();

View File

@ -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);

View File

@ -50,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();
@ -109,7 +115,19 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {
src._alphaMode = _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 {
@ -118,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) {
@ -129,7 +147,47 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect
src._alphaMode = _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;
}

View File

@ -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,

View File

@ -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
);
}

View File

@ -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();