diff options
author | richiesams | 2013-08-17 09:46:18 -0500 |
---|---|---|
committer | richiesams | 2013-08-18 19:52:53 -0500 |
commit | e769164f791d19b69cbe7cb0be99fc474c562ed4 (patch) | |
tree | b1e8f97c97fa531ee4bf99b3f3df46b373f14772 /engines/zvision | |
parent | 7d24f46e7e2c7d6322b2842d349986dc484eb063 (diff) | |
download | scummvm-rg350-e769164f791d19b69cbe7cb0be99fc474c562ed4.tar.gz scummvm-rg350-e769164f791d19b69cbe7cb0be99fc474c562ed4.tar.bz2 scummvm-rg350-e769164f791d19b69cbe7cb0be99fc474c562ed4.zip |
ZVISION: Render images by specifying a destination and then clipping
Instead of specifying a subRect. This also reverts the code that rendered to a
backbuffer and then did a full backbuffer warp. Wrapping is done in the RenderTable
Diffstat (limited to 'engines/zvision')
-rw-r--r-- | engines/zvision/render_manager.cpp | 200 | ||||
-rw-r--r-- | engines/zvision/render_manager.h | 18 | ||||
-rw-r--r-- | engines/zvision/render_table.cpp | 50 | ||||
-rw-r--r-- | engines/zvision/render_table.h | 2 |
4 files changed, 134 insertions, 136 deletions
diff --git a/engines/zvision/render_manager.cpp b/engines/zvision/render_manager.cpp index 1f2c3a20c7..e4106109ba 100644 --- a/engines/zvision/render_manager.cpp +++ b/engines/zvision/render_manager.cpp @@ -38,16 +38,19 @@ RenderManager::RenderManager(OSystem *system, const Common::Rect workingWindow, : _system(system), _workingWidth(workingWindow.width()), _workingHeight(workingWindow.height()), + _screenCenterX((workingWindow.left + workingWindow.right) /2), + _screenCenterY((workingWindow.top + workingWindow.bottom) /2), _workingWindow(workingWindow), _pixelFormat(pixelFormat), _currentBackground(0), _backgroundWidth(0), _backgroundHeight(0), _backgroundInverseVelocity(0), + _backgroundOffset(0, 0), _accumulatedVelocityMilliseconds(0), - _renderTable(workingWindow.width(), workingWindow.height()) { - _backbuffer.create(_workingWidth, _workingHeight, pixelFormat); - _warpedBackbuffer = new uint16[_workingWidth *_workingHeight]; + _renderTable(_workingWidth, _workingHeight) { + + _warpedBuffer = new uint16[_workingWidth *_workingHeight]; } RenderManager::~RenderManager() { @@ -55,8 +58,7 @@ RenderManager::~RenderManager() { delete _currentBackground; } - _backbuffer.free(); - delete[] _warpedBackbuffer; + delete[] _warpedBuffer; } void RenderManager::update(uint deltaTimeInMillis) { @@ -73,111 +75,83 @@ void RenderManager::update(uint deltaTimeInMillis) { } // Choose the direction of movement using the sign of the velocity - moveBackground(_backgroundInverseVelocity < 0 ? -numberOfSteps : numberOfSteps); + moveBackground(_backgroundInverseVelocity < 0 ? numberOfSteps : -numberOfSteps); } +} - // Warp the entire backbuffer - RenderTable::RenderState state = _renderTable.getRenderState(); - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - _renderTable.mutateImage((uint16 *)_backbuffer.getBasePtr(0, 0), _warpedBackbuffer, _workingWidth, _workingHeight); - _system->copyRectToScreen(_warpedBackbuffer, _backbuffer.pitch, _workingWindow.left, _workingWindow.top, _backbuffer.w, _backbuffer.h); - } else { - _system->copyRectToScreen(_backbuffer.getBasePtr(0, 0), _backbuffer.pitch, _workingWindow.left, _workingWindow.top, _backbuffer.w, _backbuffer.h); +void RenderManager::renderSubRectToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap, bool isTransposed) { + int16 subRectX = 0; + int16 subRectY = 0; + + // Take care of negative destinations + if (destinationX < 0) { + subRectX = destinationX + surface.w; + destinationX = 0; + if (wrap) { + _backgroundOffset.x += surface.w; + } + } else if (destinationX >= surface.w) { + // Take care of extreme positive destinations + destinationX -= surface.w; + if (wrap) { + _backgroundOffset.x -= surface.w; + } } - // Blit the backbuffer to the screen - -} + // Take care of negative destinations + if (destinationY < 0) { + subRectY = destinationY + surface.h; + destinationY = 0; + if (wrap) { + _backgroundOffset.y += surface.h; + } + } else if (destinationY >= surface.h) { + // Take care of extreme positive destinations + destinationY -= surface.h; + if (wrap) { + _backgroundOffset.y -= surface.h; + } + } -void RenderManager::renderSubRectToBackbuffer(Graphics::Surface &surface, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle, bool wrap, bool isTransposed) { if (wrap) { _backgroundWidth = surface.w; _backgroundHeight = surface.h; - } - // If subRect is empty, use the entire image - if (subRectangle.isEmpty()) - subRectangle = Common::Rect(subRectangle.left, subRectangle.top, subRectangle.left + surface.w, subRectangle.top + surface.h); - - // Clip destRect to working window bounds - Common::Rect destRect(destinationX, destinationY, destinationX + subRectangle.width(), destinationY + subRectangle.height()); - destRect.clip(_workingWidth, _workingHeight); - // Clip subRect to working window bounds - subRectangle.translate(destRect.left - destinationX, destRect.top - destinationY); - subRectangle.setWidth(destRect.width()); - subRectangle.setHeight(destRect.height()); - // Clip to image bounds - Common::Point subRectOrigOrigin(subRectangle.left, subRectangle.top); - subRectangle.clip(surface.w, surface.h); - - // If the image is to be wrapped, check if it's smaller than destRect - // If it is, then call renderSubRectToScreen with a subRect representing wrapping - if (wrap && subRectangle.width() < destRect.width()) { - uint32 wrapDestX; - uint32 wrapDestY; - Common::Rect wrapSubRect; - - if (_backgroundWidth - subRectangle.left < destRect.width()) { - wrapDestX = destRect.left + subRectangle.width(); - wrapDestY = destRect.top; - wrapSubRect = Common::Rect(0, 0, destRect.width() - subRectangle.width(), subRectangle.bottom); - } else { - wrapDestX = destRect.left; - wrapDestY = destRect.top; - wrapSubRect = Common::Rect(_backgroundWidth - subRectangle.width(), 0, _backgroundWidth - 1, subRectangle.bottom); + if (destinationX > 0) { + // Move destinationX to 0 + subRectX = surface.w - destinationX; + destinationX = 0; } - renderSubRectToBackbuffer(surface, wrapDestX, wrapDestY, wrapSubRect, false, isTransposed); - } else if (wrap && subRectangle.height() < destRect.height()) { - uint32 wrapDestX; - uint32 wrapDestY; - Common::Rect wrapSubRect; - - if (_backgroundHeight - subRectangle.top < destRect.height()) { - wrapDestX = destRect.left; - wrapDestY = destRect.height() - subRectangle.height(); - wrapSubRect = Common::Rect(0, 0, subRectangle.right, destRect.height() - subRectangle.height()); - } else { - wrapDestX = destRect.left; - wrapDestY = destRect.top; - wrapSubRect = Common::Rect(0, _backgroundHeight - subRectangle.height(), subRectangle.right, _backgroundHeight - 1); + if (destinationY > 0) { + // Move destinationY to 0 + subRectX = surface.w - destinationX; + destinationY = 0; } - - renderSubRectToBackbuffer(surface, wrapDestX, wrapDestY, wrapSubRect, false, isTransposed); - } else { - // Clip destRect to image bounds - destRect.translate(subRectangle.left - subRectOrigOrigin.x, subRectangle.top - subRectOrigOrigin.y); - destRect.setWidth(subRectangle.width()); - destRect.setHeight(subRectangle.height()); } - // Check all Rects for validity - if (!subRectangle.isValidRect() || subRectangle.isEmpty() || !destRect.isValidRect() || destRect.isEmpty()) - return; + // Clip subRect to working window bounds + Common::Rect subRect(subRectX, subRectY, subRectX + _workingWidth, subRectY + _workingHeight); - if (isTransposed) { - copyTransposedRectToBackbuffer((uint16 *)surface.getBasePtr(0, 0), surface.h, destRect.left, destRect.top, destRect.width(), destRect.height(), subRectangle); - } else { - _backbuffer.copyRectToSurface(surface.getBasePtr(subRectangle.left, subRectangle.top), surface.pitch, destRect.left, destRect.top, destRect.width(), destRect.height()); + if (!wrap) { + // Clip to image bounds + subRect.clip(surface.w, surface.h); } -} -void RenderManager::copyTransposedRectToBackbuffer(const uint16 *buffer, int imageWidth, int destinationX, int destinationY, int width, int height, const Common::Rect &subRect) { - uint16 *dest = (uint16 *)_backbuffer.getBasePtr(0, 0); - - for (int16 x = subRect.left; x < subRect.right; x++) { - int16 normalizedX = x - subRect.left + destinationX; - int columnOffset = x * imageWidth; + // Check destRect for validity + if (!subRect.isValidRect() || subRect.isEmpty()) + return; - for (int16 y = subRect.top; y < subRect.bottom; y++) { - int16 normalizeY = y - subRect.top + destinationY; + if (_renderTable.getRenderState() == RenderTable::FLAT) { + _system->copyRectToScreen(surface.getBasePtr(subRect.left, subRect.top), surface.pitch, destinationX + _workingWindow.left, destinationY + _workingWindow.top, subRect.width(), subRect.height()); + } else { + _renderTable.mutateImage((uint16 *)surface.getBasePtr(0, 0), _warpedBuffer, surface.w, surface.h, destinationX, destinationY, subRect, wrap, isTransposed); - dest[normalizeY * _backbuffer.w + normalizedX] = buffer[columnOffset + y]; - } + _system->copyRectToScreen(_warpedBuffer, _workingWidth * sizeof(uint16), destinationX + _workingWindow.left, destinationY + _workingWindow.top, subRect.width(), subRect.height()); } } -void RenderManager::renderImageToBackbuffer(const Common::String &fileName, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle, bool wrap) { +void RenderManager::renderImageToScreen(const Common::String &fileName, uint32 destinationX, uint32 destinationY, bool wrap) { Common::File file; if (!file.open(fileName)) { @@ -185,10 +159,10 @@ void RenderManager::renderImageToBackbuffer(const Common::String &fileName, uint return; } - renderImageToBackbuffer(file, destinationX, destinationY, subRectangle); + renderImageToScreen(file, destinationX, destinationY); } -void RenderManager::renderImageToBackbuffer(Common::SeekableReadStream &stream, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle, bool wrap) { +void RenderManager::renderImageToScreen(Common::SeekableReadStream &stream, uint32 destinationX, uint32 destinationY, bool wrap) { // Read the magic number // Some files are true TGA, while others are TGZ uint32 fileType; @@ -217,7 +191,7 @@ void RenderManager::renderImageToBackbuffer(Common::SeekableReadStream &stream, Graphics::Surface surface; surface.init(imageWidth, imageHeight, pitch, buffer, _pixelFormat); - renderSubRectToBackbuffer(surface, destinationX, destinationY, subRectangle, wrap, isTransposed); + renderSubRectToScreen(surface, destinationX, destinationY, wrap, isTransposed); // We have to use delete[] instead of calling surface.free() because we created the memory with new[] delete[] buffer; @@ -241,7 +215,7 @@ void RenderManager::renderImageToBackbuffer(Common::SeekableReadStream &stream, tgaSurface.w = temp; } - renderSubRectToBackbuffer(tgaSurface, destinationX, destinationY, subRectangle, wrap, isTransposed); + renderSubRectToScreen(tgaSurface, destinationX, destinationY, wrap, isTransposed); tga.destroy(); } } @@ -280,15 +254,20 @@ void RenderManager::setBackgroundImage(const Common::String &fileName) { } _currentBackground = file; - // Purposely make the subRectangle empty. renderImageToScreen will then set the width and height automatically. - renderImageToBackbuffer(*_currentBackground, 0, 0, Common::Rect(_backgroundOffset.x, _backgroundOffset.y, _backgroundOffset.x, _backgroundOffset.y), true); + renderImageToScreen(*_currentBackground, _backgroundOffset.x, _backgroundOffset.y, true); } void RenderManager::setBackgroundPosition(int offset) { - if (_renderTable.getRenderState() == RenderTable::TILT) { - _backgroundOffset = Common::Point(0, offset); + RenderTable::RenderState state = _renderTable.getRenderState(); + if (state == RenderTable::TILT) { + _backgroundOffset.x = 0; + _backgroundOffset.y = _screenCenterY - offset; + } else if (state == RenderTable::PANORAMA) { + _backgroundOffset.x = _screenCenterX - offset; + _backgroundOffset.y = 0; } else { - _backgroundOffset = Common::Point(offset, 0); + _backgroundOffset.x = 0; + _backgroundOffset.y = 0; } } @@ -305,25 +284,20 @@ void RenderManager::setBackgroundVelocity(int velocity) { } void RenderManager::moveBackground(int offset) { - if (_renderTable.getRenderState() == RenderTable::TILT) { + _currentBackground->seek(0); + + RenderTable::RenderState state = _renderTable.getRenderState(); + if (state == RenderTable::TILT) { _backgroundOffset += Common::Point(0, offset); - } else { - _backgroundOffset += Common::Point(offset, 0); - } - // Make sure the offset is within image bounds - if (_backgroundOffset.x < 0) - _backgroundOffset.x += _backgroundWidth; - if (_backgroundOffset.x > _backgroundWidth) - _backgroundOffset.x -= _backgroundWidth; - if (_backgroundOffset.y < 0) - _backgroundOffset.y += _backgroundHeight; - if (_backgroundOffset.y > _backgroundHeight) - _backgroundOffset.y -= _backgroundHeight; + renderImageToScreen(*_currentBackground, 0, _backgroundOffset.y, true); + } else if (state == RenderTable::PANORAMA) { + _backgroundOffset += Common::Point(offset, 0); - _currentBackground->seek(0); - // Purposely make the subRectangle empty. renderImageToScreen will then set the width and height automatically. - renderImageToBackbuffer(*_currentBackground, 0, 0, Common::Rect(_backgroundOffset.x, _backgroundOffset.y, _backgroundOffset.x, _backgroundOffset.y), true); + renderImageToScreen(*_currentBackground, _backgroundOffset.x, 0, true); + } else { + renderImageToScreen(*_currentBackground, 0, 0); + } } } // End of namespace ZVision diff --git a/engines/zvision/render_manager.h b/engines/zvision/render_manager.h index f59f50d4d7..cdcd52b67d 100644 --- a/engines/zvision/render_manager.h +++ b/engines/zvision/render_manager.h @@ -52,13 +52,17 @@ private: OSystem *_system; const Graphics::PixelFormat _pixelFormat; - Graphics::Surface _backbuffer; - uint16 *_warpedBackbuffer; + uint16 *_warpedBuffer; /** Width of the working window. Saved to prevent extraneous calls to _workingWindow.width() */ const int _workingWidth; /** Height of the working window. Saved to prevent extraneous calls to _workingWindow.height() */ const int _workingHeight; + /** Center of the screen in the x direction */ + const int _screenCenterX; + /** Center of the screen in the y direction */ + const int _screenCenterY; + /** * A Rectangle centered inside the actual window. All in-game coordinates * are given in this coordinate space. Also, all images are clipped to the @@ -102,9 +106,8 @@ public: * @param fileName Name of the image file * @param destinationX X position where the image should be put. Coords are in working window space, not screen space! * @param destinationY Y position where the image should be put. Coords are in working window space, not screen space! - * @param subRectangle The subrectangle of the image that should be rendered. If this is an empty rectangle, it will blit the entire image. Coords are in working window space, not screen space! */ - void renderImageToBackbuffer(const Common::String &fileName, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle = Common::Rect(0, 0, 0, 0), bool wrap = false); + void renderImageToScreen(const Common::String &fileName, uint32 destinationX, uint32 destinationY, bool wrap = false); /** * Blits the image or a portion of the image to the backbuffer. Actual screen updates won't happen until the end of the frame. @@ -113,9 +116,8 @@ public: * @param stream Stream to read the image data from * @param destinationX X position where the image should be put. Coords are in working window space, not screen space! * @param destinationY Y position where the image should be put. Coords are in working window space, not screen space! - * @param subRectangle The subrectangle of the image that should be rendered. If this is an empty rectangle, it will blit the entire image. Coords are in working window space, not screen space! */ - void renderImageToBackbuffer(Common::SeekableReadStream &stream, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle = Common::Rect(0, 0, 0, 0), bool wrap = false); + void renderImageToScreen(Common::SeekableReadStream &stream, uint32 destinationX, uint32 destinationY, bool wrap = false); /** * Sets the current background image to be used by the RenderManager and immediately @@ -169,9 +171,7 @@ private: * @param subRectangle A rectangle representing the part of the image that should be rendered * @param wrap Should the image wrap (tile) if it doesn't completely fill the screen? */ - void renderSubRectToBackbuffer(Graphics::Surface &surface, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle, bool wrap, bool isTransposed); - - void copyTransposedRectToBackbuffer(const uint16 *buffer, int imageWidth, int destinationX, int destinationY, int width, int height, const Common::Rect &subRect); + void renderSubRectToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap, bool isTransposed); void moveBackground(int offset); }; diff --git a/engines/zvision/render_table.cpp b/engines/zvision/render_table.cpp index a28f82baa6..23394b7bc2 100644 --- a/engines/zvision/render_table.cpp +++ b/engines/zvision/render_table.cpp @@ -98,22 +98,46 @@ uint16 mixTwoRGB(uint16 colorOne, uint16 colorTwo, float percentColorOne) { return returnColor; } -void RenderTable::mutateImage(uint16 *sourceBuffer, uint16* destBuffer, uint32 imageWidth, uint32 imageHeight) { - for (uint32 y = 0; y < imageHeight; y++) { - for (uint32 x = 0; x < imageWidth; x++) { - uint32 index = y * _numColumns + x; - - // RenderTable only stores offsets from the original coordinates - uint32 sourceYIndex = y + _internalBuffer[index].y; - uint32 sourceXIndex = x + _internalBuffer[index].x; +void RenderTable::mutateImage(uint16 *sourceBuffer, uint16* destBuffer, int16 imageWidth, int16 imageHeight, int16 destinationX, int16 destinationY, const Common::Rect &subRect, bool wrap, bool isTransposed) { + for (int16 y = subRect.top; y < subRect.bottom; y++) { + uint16 normalizedY = y - subRect.top; + uint32 internalColumnIndex = (normalizedY + destinationY) * _numColumns; + uint32 destColumnIndex = normalizedY * _numColumns; - // Clamp the yIndex to the size of the image - sourceYIndex = CLIP<uint32>(sourceYIndex, 0, imageHeight - 1); + for (int16 x = subRect.left; x < subRect.right; x++) { + uint16 normalizedX = x - subRect.left; - // Clamp the xIndex to the size of the image - sourceXIndex = CLIP<uint32>(sourceXIndex, 0, imageWidth - 1); + uint32 index = internalColumnIndex + normalizedX + destinationX; - destBuffer[index] = sourceBuffer[sourceYIndex * imageWidth + sourceXIndex]; + // RenderTable only stores offsets from the original coordinates + uint16 sourceYIndex = y + _internalBuffer[index].y; + uint16 sourceXIndex = x + _internalBuffer[index].x; + + if (wrap) { + if (sourceXIndex >= imageWidth) { + sourceXIndex -= imageWidth; + } else if (sourceXIndex < 0) { + sourceXIndex += imageWidth; + } + + if (sourceYIndex >= imageHeight) { + sourceYIndex -= imageHeight; + } else if (sourceYIndex < 0) { + sourceYIndex += imageHeight; + } + } else { + // Clamp the yIndex to the size of the image + sourceYIndex = CLIP<uint32>(sourceYIndex, 0, imageHeight - 1); + + // Clamp the xIndex to the size of the image + sourceXIndex = CLIP<uint32>(sourceXIndex, 0, imageWidth - 1); + } + + if (isTransposed) { + destBuffer[destColumnIndex + normalizedX] = sourceBuffer[sourceXIndex * imageHeight + sourceYIndex]; + } else { + destBuffer[destColumnIndex + normalizedX] = sourceBuffer[sourceYIndex * imageWidth + sourceXIndex]; + } } } } diff --git a/engines/zvision/render_table.h b/engines/zvision/render_table.h index 7c04564cd0..bbf5e1b22a 100644 --- a/engines/zvision/render_table.h +++ b/engines/zvision/render_table.h @@ -66,7 +66,7 @@ public: const Common::Point convertWarpedCoordToFlatCoord(const Common::Point &point); - void mutateImage(uint16 *sourceBuffer, uint16* destBuffer, uint32 imageWidth, uint32 imageHeight); + void mutateImage(uint16 *sourceBuffer, uint16* destBuffer, int16 imageWidth, int16 imageHeight, int16 destinationX, int16 destinationY, const Common::Rect &subRect, bool wrap, bool isTransposed); void generateRenderTable(); void setPanoramaFoV(float fov); |