aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision/graphics/render_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/zvision/graphics/render_manager.cpp')
-rw-r--r--engines/zvision/graphics/render_manager.cpp1333
1 files changed, 1012 insertions, 321 deletions
diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp
index aed30ea12c..ce0a02a1ad 100644
--- a/engines/zvision/graphics/render_manager.cpp
+++ b/engines/zvision/graphics/render_manager.cpp
@@ -1,30 +1,33 @@
/* 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.
- *
- */
+*
+* 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 "common/scummsys.h"
+#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
+#include "zvision/scripting/script_manager.h"
+#include "zvision/text/text.h"
-#include "zvision/utility/lzss_read_stream.h"
+#include "zvision/file/lzss_read_stream.h"
#include "common/file.h"
#include "common/system.h"
@@ -34,200 +37,153 @@
#include "image/tga.h"
-
namespace ZVision {
-RenderManager::RenderManager(OSystem *system, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat)
- : _system(system),
- _workingWidth(workingWindow.width()),
- _workingHeight(workingWindow.height()),
- _screenCenterX(_workingWidth / 2),
- _screenCenterY(_workingHeight / 2),
- _workingWindow(workingWindow),
- _pixelFormat(pixelFormat),
- _backgroundWidth(0),
- _backgroundHeight(0),
- _backgroundInverseVelocity(0),
- _backgroundOffset(0, 0),
- _accumulatedVelocityMilliseconds(0),
- _renderTable(_workingWidth, _workingHeight) {
-
- _workingWindowBuffer.create(_workingWidth, _workingHeight, _pixelFormat);
- _backBuffer.create(windowWidth, windowHeight, pixelFormat);
+RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat, bool doubleFPS)
+ : _engine(engine),
+ _system(engine->_system),
+ _screenCenterX(_workingWindow.width() / 2),
+ _screenCenterY(_workingWindow.height() / 2),
+ _workingWindow(workingWindow),
+ _pixelFormat(pixelFormat),
+ _backgroundWidth(0),
+ _backgroundHeight(0),
+ _backgroundOffset(0),
+ _renderTable(_workingWindow.width(), _workingWindow.height()),
+ _doubleFPS(doubleFPS),
+ _subid(0) {
+
+ _backgroundSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat);
+ _effectSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat);
+ _warpedSceneSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat);
+ _menuSurface.create(windowWidth, workingWindow.top, _pixelFormat);
+
+ _menuArea = Common::Rect(0, 0, windowWidth, workingWindow.top);
+
+ initSubArea(windowWidth, windowHeight, workingWindow);
}
RenderManager::~RenderManager() {
- _workingWindowBuffer.free();
- _currentBackground.free();
- _backBuffer.free();
-
- for (AlphaEntryMap::iterator iter = _alphaDataEntries.begin(); iter != _alphaDataEntries.end(); ++iter) {
- iter->_value.data->free();
- delete iter->_value.data;
- }
-}
-
-void RenderManager::update(uint deltaTimeInMillis) {
- // An inverse velocity of 0 would be infinitely fast, so we'll let 0 mean no velocity.
- if (_backgroundInverseVelocity != 0) {
- _accumulatedVelocityMilliseconds += deltaTimeInMillis;
-
- uint absVelocity = uint(abs(_backgroundInverseVelocity));
-
- int numberOfSteps = 0;
- while (_accumulatedVelocityMilliseconds >= absVelocity) {
- _accumulatedVelocityMilliseconds -= absVelocity;
- numberOfSteps++;
- }
-
- // Choose the direction of movement using the sign of the velocity
- moveBackground(_backgroundInverseVelocity < 0 ? -numberOfSteps : numberOfSteps);
- }
+ _currentBackgroundImage.free();
+ _backgroundSurface.free();
+ _effectSurface.free();
+ _warpedSceneSurface.free();
+ _menuSurface.free();
+ _subtitleSurface.free();
}
-void RenderManager::renderBackbufferToScreen() {
- if (!_workingWindowDirtyRect.isEmpty()) {
- RenderTable::RenderState state = _renderTable.getRenderState();
- if (state == RenderTable::PANORAMA || state == RenderTable::TILT) {
- _renderTable.mutateImage((uint16 *)_workingWindowBuffer.getPixels(), (uint16 *)_backBuffer.getBasePtr(_workingWindow.left + _workingWindowDirtyRect.left, _workingWindow.top + _workingWindowDirtyRect.top), _backBuffer.w, _workingWindowDirtyRect);
- } else {
- _backBuffer.copyRectToSurface(_workingWindowBuffer.getBasePtr(_workingWindowDirtyRect.left, _workingWindowDirtyRect.top), _workingWindowBuffer.pitch, _workingWindow.left + _workingWindowDirtyRect.left, _workingWindow.top + _workingWindowDirtyRect.top, _workingWindowDirtyRect.width(), _workingWindowDirtyRect.height());
- }
-
- // Translate the working window dirty rect to screen coords
- _workingWindowDirtyRect.translate(_workingWindow.left, _workingWindow.top);
- // Then extend the backbuffer dirty rect to contain it
- if (_backBufferDirtyRect.isEmpty()) {
- _backBufferDirtyRect = _workingWindowDirtyRect;
- } else {
- _backBufferDirtyRect.extend(_workingWindowDirtyRect);
- }
-
- // Clear the dirty rect
- _workingWindowDirtyRect = Common::Rect();
- }
-
- // TODO: Add menu rendering
+void RenderManager::renderSceneToScreen() {
+ Graphics::Surface *out = &_warpedSceneSurface;
+ Graphics::Surface *in = &_backgroundSurface;
+ Common::Rect outWndDirtyRect;
- // Render alpha entries
- processAlphaEntries();
+ // If we have graphical effects, we apply them using a temporary buffer
+ if (!_effects.empty()) {
+ bool copied = false;
+ Common::Rect windowRect(_workingWindow.width(), _workingWindow.height());
- if (!_backBufferDirtyRect.isEmpty()) {
- _system->copyRectToScreen(_backBuffer.getBasePtr(_backBufferDirtyRect.left, _backBufferDirtyRect.top), _backBuffer.pitch, _backBufferDirtyRect.left, _backBufferDirtyRect.top, _backBufferDirtyRect.width(), _backBufferDirtyRect.height());
- _backBufferDirtyRect = Common::Rect();
- }
-}
+ for (EffectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
+ Common::Rect rect = (*it)->getRegion();
+ Common::Rect screenSpaceLocation = rect;
-void RenderManager::processAlphaEntries() {
- // TODO: Add dirty rectangling support. AKA only draw an entry if the _backbufferDirtyRect intersects/contains the entry Rect
-
- for (AlphaEntryMap::iterator iter = _alphaDataEntries.begin(); iter != _alphaDataEntries.end(); ++iter) {
- uint32 destOffset = 0;
- uint32 sourceOffset = 0;
- uint16 *backbufferPtr = (uint16 *)_backBuffer.getBasePtr(iter->_value.destX + _workingWindow.left, iter->_value.destY + _workingWindow.top);
- uint16 *entryPtr = (uint16 *)iter->_value.data->getPixels();
+ if ((*it)->isPort()) {
+ screenSpaceLocation = transformBackgroundSpaceRectToScreenSpace(screenSpaceLocation);
+ }
- for (int32 y = 0; y < iter->_value.height; ++y) {
- for (int32 x = 0; x < iter->_value.width; ++x) {
- uint16 color = entryPtr[sourceOffset + x];
- if (color != iter->_value.alphaColor) {
- backbufferPtr[destOffset + x] = color;
+ if (windowRect.intersects(screenSpaceLocation)) {
+ if (!copied) {
+ copied = true;
+ _effectSurface.copyFrom(_backgroundSurface);
+ in = &_effectSurface;
+ }
+ const Graphics::Surface *post;
+ if ((*it)->isPort())
+ post = (*it)->draw(_currentBackgroundImage.getSubArea(rect));
+ else
+ post = (*it)->draw(_effectSurface.getSubArea(rect));
+ Common::Rect empty;
+ blitSurfaceToSurface(*post, empty, _effectSurface, screenSpaceLocation.left, screenSpaceLocation.top);
+ screenSpaceLocation.clip(windowRect);
+ if (_backgroundSurfaceDirtyRect .isEmpty()) {
+ _backgroundSurfaceDirtyRect = screenSpaceLocation;
+ } else {
+ _backgroundSurfaceDirtyRect.extend(screenSpaceLocation);
}
}
-
- destOffset += _backBuffer.w;
- sourceOffset += iter->_value.width;
}
+ }
- if (_backBufferDirtyRect.isEmpty()) {
- _backBufferDirtyRect = Common::Rect(iter->_value.destX + _workingWindow.left, iter->_value.destY + _workingWindow.top, iter->_value.destX + _workingWindow.left + iter->_value.width, iter->_value.destY + _workingWindow.top + iter->_value.height);
- } else {
- _backBufferDirtyRect.extend(Common::Rect(iter->_value.destX + _workingWindow.left, iter->_value.destY + _workingWindow.top, iter->_value.destX + _workingWindow.left + iter->_value.width, iter->_value.destY + _workingWindow.top + iter->_value.height));
+ RenderTable::RenderState state = _renderTable.getRenderState();
+ if (state == RenderTable::PANORAMA || state == RenderTable::TILT) {
+ if (!_backgroundSurfaceDirtyRect.isEmpty()) {
+ _renderTable.mutateImage(&_warpedSceneSurface, in);
+ out = &_warpedSceneSurface;
+ outWndDirtyRect = Common::Rect(_workingWindow.width(), _workingWindow.height());
}
+ } else {
+ out = in;
+ outWndDirtyRect = _backgroundSurfaceDirtyRect;
}
-}
-void RenderManager::clearWorkingWindowTo555Color(uint16 color) {
- uint32 workingWindowSize = _workingWidth * _workingHeight;
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(color, r, g, b);
- uint16 colorIn565 = _pixelFormat.RGBToColor(r, g, b);
- uint16 *bufferPtr = (uint16 *)_workingWindowBuffer.getPixels();
-
- for (uint32 i = 0; i < workingWindowSize; ++i) {
- bufferPtr[i] = colorIn565;
+ if (!outWndDirtyRect.isEmpty()) {
+ Common::Rect rect(
+ outWndDirtyRect.left + _workingWindow.left,
+ outWndDirtyRect.top + _workingWindow.top,
+ outWndDirtyRect.left + _workingWindow.left + outWndDirtyRect.width(),
+ outWndDirtyRect.top + _workingWindow.top + outWndDirtyRect.height()
+ );
+ copyToScreen(*out, rect, outWndDirtyRect.left, outWndDirtyRect.top);
}
}
-void RenderManager::renderSubRectToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap) {
- int16 subRectX = 0;
- int16 subRectY = 0;
-
- // Take care of negative destinations
- if (destinationX < 0) {
- subRectX = -destinationX;
- destinationX = 0;
- } else if (destinationX >= surface.w) {
- // Take care of extreme positive destinations
- destinationX -= surface.w;
- }
-
- // Take care of negative destinations
- if (destinationY < 0) {
- subRectY = -destinationY;
- destinationY = 0;
- } else if (destinationY >= surface.h) {
- // Take care of extreme positive destinations
- destinationY -= surface.h;
- }
-
- if (wrap) {
- _backgroundWidth = surface.w;
- _backgroundHeight = surface.h;
-
- if (destinationX > 0) {
- // Move destinationX to 0
- subRectX = surface.w - destinationX;
- destinationX = 0;
- }
-
- if (destinationY > 0) {
- // Move destinationY to 0
- subRectY = surface.h - destinationY;
- destinationY = 0;
- }
- }
+void RenderManager::copyToScreen(const Graphics::Surface &surface, Common::Rect &rect, int16 srcLeft, int16 srcTop) {
+ // Convert the surface to RGB565, if needed
+ Graphics::Surface *outSurface = surface.convertTo(_engine->_screenPixelFormat);
+ _system->copyRectToScreen(outSurface->getBasePtr(srcLeft, srcTop),
+ outSurface->pitch,
+ rect.left,
+ rect.top,
+ rect.width(),
+ rect.height());
+ outSurface->free();
+ delete outSurface;
+}
- // Clip subRect to working window bounds
- Common::Rect subRect(subRectX, subRectY, subRectX + _workingWidth, subRectY + _workingHeight);
+void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY) {
+ Graphics::Surface surface;
+ readImageToSurface(fileName, surface);
- if (!wrap) {
- // Clip to image bounds
- subRect.clip(surface.w, surface.h);
- }
+ blitSurfaceToBkg(surface, destX, destY);
+ surface.free();
+}
- // Check destRect for validity
- if (!subRect.isValidRect() || subRect.isEmpty())
- return;
+void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY, uint32 keycolor) {
+ Graphics::Surface surface;
+ readImageToSurface(fileName, surface);
- copyRectToWorkingWindow((const uint16 *)surface.getBasePtr(subRect.left, subRect.top), destinationX, destinationY, surface.w, subRect.width(), subRect.height());
+ blitSurfaceToBkg(surface, destX, destY, keycolor);
+ surface.free();
}
-void RenderManager::renderImageToScreen(const Common::String &fileName, int16 destinationX, int16 destinationY, bool wrap) {
+void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY, int16 keyX, int16 keyY) {
Graphics::Surface surface;
readImageToSurface(fileName, surface);
- renderSubRectToScreen(surface, destinationX, destinationY, wrap);
-}
+ uint16 keycolor = *(uint16 *)surface.getBasePtr(keyX, keyY);
-void RenderManager::renderImageToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap) {
- renderSubRectToScreen(surface, destinationX, destinationY, wrap);
+ blitSurfaceToBkg(surface, destX, destY, keycolor);
+ surface.free();
}
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) {
+ bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA;
+ readImageToSurface(fileName, destination, isTransposed);
+}
+
+void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed) {
Common::File file;
- if (!file.open(fileName)) {
+ if (!_engine->getSearchManager()->openFile(file, fileName)) {
warning("Could not open file %s", fileName.c_str());
return;
}
@@ -240,10 +196,8 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
uint32 imageHeight;
Image::TGADecoder tga;
uint16 *buffer;
- bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA;
// All ZVision images are in RGB 555
- Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
- destination.format = pixelFormat555;
+ destination.format = _engine->_resourcePixelFormat;
bool isTGZ;
@@ -252,13 +206,17 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
isTGZ = true;
// TGZ files have a header and then Bitmap data that is compressed with LZSS
- uint32 decompressedSize = file.readSint32LE();
+ uint32 decompressedSize = file.readSint32LE() / 2;
imageWidth = file.readSint32LE();
imageHeight = file.readSint32LE();
LzssReadStream lzssStream(&file);
buffer = (uint16 *)(new uint16[decompressedSize]);
- lzssStream.read(buffer, decompressedSize);
+ lzssStream.read(buffer, 2 * decompressedSize);
+#ifndef SCUMM_LITTLE_ENDIAN
+ for (uint32 i = 0; i < decompressedSize; ++i)
+ buffer[i] = FROM_LE_16(buffer[i]);
+#endif
} else {
isTGZ = false;
@@ -279,7 +237,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
}
// Flip the width and height if transposed
- if (isTransposed) {
+ if (transposed) {
uint16 temp = imageHeight;
imageHeight = imageWidth;
imageWidth = temp;
@@ -288,12 +246,12 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
// If the destination internal buffer is the same size as what we're copying into it,
// there is no need to free() and re-create
if (imageWidth != destination.w || imageHeight != destination.h) {
- destination.create(imageWidth, imageHeight, pixelFormat555);
+ destination.create(imageWidth, imageHeight, _engine->_resourcePixelFormat);
}
// If transposed, 'un-transpose' the data while copying it to the destination
// Otherwise, just do a simple copy
- if (isTransposed) {
+ if (transposed) {
uint16 *dest = (uint16 *)destination.getPixels();
for (uint32 y = 0; y < imageHeight; ++y) {
@@ -304,7 +262,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
}
}
} else {
- memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel);
+ memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * destination.format.bytesPerPixel);
}
// Cleanup
@@ -313,214 +271,947 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
} else {
tga.destroy();
}
-
- // Convert in place to RGB 565 from RGB 555
- destination.convertToInPlace(_pixelFormat);
}
-void RenderManager::copyRectToWorkingWindow(const uint16 *buffer, int32 destX, int32 destY, int32 imageWidth, int32 width, int32 height) {
- uint32 destOffset = 0;
- uint32 sourceOffset = 0;
- uint16 *workingWindowBufferPtr = (uint16 *)_workingWindowBuffer.getBasePtr(destX, destY);
+const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &point) {
+ if (_workingWindow.contains(point)) {
+ // Convert from screen space to working window space
+ Common::Point newPoint(point - Common::Point(_workingWindow.left, _workingWindow.top));
+
+ RenderTable::RenderState state = _renderTable.getRenderState();
+ if (state == RenderTable::PANORAMA || state == RenderTable::TILT) {
+ newPoint = _renderTable.convertWarpedCoordToFlatCoord(newPoint);
+ }
- for (int32 y = 0; y < height; ++y) {
- for (int32 x = 0; x < width; ++x) {
- workingWindowBufferPtr[destOffset + x] = buffer[sourceOffset + x];
+ if (state == RenderTable::PANORAMA) {
+ newPoint += (Common::Point(_backgroundOffset - _screenCenterX, 0));
+ } else if (state == RenderTable::TILT) {
+ newPoint += (Common::Point(0, _backgroundOffset - _screenCenterY));
}
- destOffset += _workingWidth;
- sourceOffset += imageWidth;
+ if (_backgroundWidth)
+ newPoint.x %= _backgroundWidth;
+ if (_backgroundHeight)
+ newPoint.y %= _backgroundHeight;
+
+ if (newPoint.x < 0)
+ newPoint.x += _backgroundWidth;
+ if (newPoint.y < 0)
+ newPoint.y += _backgroundHeight;
+
+ return newPoint;
+ } else {
+ return Common::Point(0, 0);
}
+}
+
+RenderTable *RenderManager::getRenderTable() {
+ return &_renderTable;
+}
+
+void RenderManager::setBackgroundImage(const Common::String &fileName) {
+ readImageToSurface(fileName, _currentBackgroundImage);
+ _backgroundWidth = _currentBackgroundImage.w;
+ _backgroundHeight = _currentBackgroundImage.h;
+ _backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
+}
+
+void RenderManager::setBackgroundPosition(int offset) {
+ RenderTable::RenderState state = _renderTable.getRenderState();
+ if (state == RenderTable::TILT || state == RenderTable::PANORAMA)
+ if (_backgroundOffset != offset)
+ _backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
+ _backgroundOffset = offset;
- if (_workingWindowDirtyRect.isEmpty()) {
- _workingWindowDirtyRect = Common::Rect(destX, destY, destX + width, destY + height);
+ _engine->getScriptManager()->setStateValue(StateKey_ViewPos, offset);
+}
+
+uint32 RenderManager::getCurrentBackgroundOffset() {
+ RenderTable::RenderState state = _renderTable.getRenderState();
+
+ if (state == RenderTable::PANORAMA) {
+ return _backgroundOffset;
+ } else if (state == RenderTable::TILT) {
+ return _backgroundOffset;
} else {
- _workingWindowDirtyRect.extend(Common::Rect(destX, destY, destX + width, destY + height));
+ return 0;
+ }
+}
+
+Graphics::Surface *RenderManager::tranposeSurface(const Graphics::Surface *surface) {
+ Graphics::Surface *tranposedSurface = new Graphics::Surface();
+ tranposedSurface->create(surface->h, surface->w, surface->format);
+
+ const uint16 *source = (const uint16 *)surface->getPixels();
+ uint16 *dest = (uint16 *)tranposedSurface->getPixels();
+
+ for (uint32 y = 0; y < tranposedSurface->h; ++y) {
+ uint32 columnIndex = y * tranposedSurface->w;
+
+ for (uint32 x = 0; x < tranposedSurface->w; ++x) {
+ dest[columnIndex + x] = source[x * surface->w + y];
+ }
}
- // TODO: Remove this from release. It's here to make sure code that uses this function clips their destinations correctly
- assert(_workingWindowDirtyRect.width() <= _workingWidth && _workingWindowDirtyRect.height() <= _workingHeight);
+ return tranposedSurface;
}
-void RenderManager::copyRectToWorkingWindow(const uint16 *buffer, int32 destX, int32 destY, int32 imageWidth, int32 width, int32 height, int16 alphaColor, uint32 idNumber) {
- AlphaDataEntry entry;
- entry.alphaColor = alphaColor;
- entry.data = new Graphics::Surface();
- entry.data->create(width, height, _pixelFormat);
- entry.destX = destX;
- entry.destY = destY;
- entry.width = width;
- entry.height = height;
+void RenderManager::scaleBuffer(const void *src, void *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint32 dstWidth, uint32 dstHeight) {
+ assert(bytesPerPixel == 1 || bytesPerPixel == 2);
- uint32 sourceOffset = 0;
- uint32 destOffset = 0;
- uint16 *surfacePtr = (uint16 *)entry.data->getPixels();
+ const float xscale = (float)srcWidth / (float)dstWidth;
+ const float yscale = (float)srcHeight / (float)dstHeight;
- for (int32 y = 0; y < height; ++y) {
- for (int32 x = 0; x < width; ++x) {
- surfacePtr[destOffset + x] = buffer[sourceOffset + x];
+ if (bytesPerPixel == 1) {
+ const byte *srcPtr = (const byte *)src;
+ byte *dstPtr = (byte *)dst;
+ for (uint32 y = 0; y < dstHeight; ++y) {
+ for (uint32 x = 0; x < dstWidth; ++x) {
+ *dstPtr = srcPtr[(int)(x * xscale) + (int)(y * yscale) * srcWidth];
+ dstPtr++;
+ }
}
+ } else if (bytesPerPixel == 2) {
+ const uint16 *srcPtr = (const uint16 *)src;
+ uint16 *dstPtr = (uint16 *)dst;
+ for (uint32 y = 0; y < dstHeight; ++y) {
+ for (uint32 x = 0; x < dstWidth; ++x) {
+ *dstPtr = srcPtr[(int)(x * xscale) + (int)(y * yscale) * srcWidth];
+ dstPtr++;
+ }
+ }
+ }
+}
+
+void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y) {
+ Common::Rect srcRect = _srcRect;
+ if (srcRect.isEmpty())
+ srcRect = Common::Rect(src.w, src.h);
+ srcRect.clip(src.w, src.h);
+ Common::Rect dstRect = Common::Rect(-_x + srcRect.left , -_y + srcRect.top, -_x + srcRect.left + dst.w, -_y + srcRect.top + dst.h);
+ srcRect.clip(dstRect);
+
+ if (srcRect.isEmpty() || !srcRect.isValidRect())
+ return;
+
+ Graphics::Surface *srcAdapted = src.convertTo(dst.format);
+
+ // Copy srcRect from src surface to dst surface
+ const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);
+
+ int xx = _x;
+ int yy = _y;
+
+ if (xx < 0)
+ xx = 0;
+ if (yy < 0)
+ yy = 0;
+
+ if (_x >= dst.w || _y >= dst.h) {
+ srcAdapted->free();
+ delete srcAdapted;
+ return;
+ }
+
+ byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);
- destOffset += width;
- sourceOffset += imageWidth;
+ int32 w = srcRect.width();
+ int32 h = srcRect.height();
+
+ for (int32 y = 0; y < h; y++) {
+ memcpy(dstBuffer, srcBuffer, w * srcAdapted->format.bytesPerPixel);
+ srcBuffer += srcAdapted->pitch;
+ dstBuffer += dst.pitch;
}
- _alphaDataEntries[idNumber] = entry;
+ srcAdapted->free();
+ delete srcAdapted;
}
-Common::Rect RenderManager::renderTextToWorkingWindow(uint32 idNumber, const Common::String &text, TruetypeFont *font, int destX, int destY, uint16 textColor, int maxWidth, int maxHeight, Graphics::TextAlign align, bool wrap) {
- AlphaDataEntry entry;
- entry.alphaColor = 0;
- entry.destX = destX;
- entry.destY = destY;
+void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey) {
+ Common::Rect srcRect = _srcRect;
+ if (srcRect.isEmpty())
+ srcRect = Common::Rect(src.w, src.h);
+ srcRect.clip(src.w, src.h);
+ Common::Rect dstRect = Common::Rect(-_x + srcRect.left , -_y + srcRect.top, -_x + srcRect.left + dst.w, -_y + srcRect.top + dst.h);
+ srcRect.clip(dstRect);
+
+ if (srcRect.isEmpty() || !srcRect.isValidRect())
+ return;
- // Draw the text to the working window
- entry.data = font->drawTextToSurface(text, textColor, maxWidth, maxHeight, align, wrap);
- entry.width = entry.data->w;
- entry.height = entry.data->h;
+ Graphics::Surface *srcAdapted = src.convertTo(dst.format);
+ uint32 keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);
- _alphaDataEntries[idNumber] = entry;
+ // Copy srcRect from src surface to dst surface
+ const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);
- return Common::Rect(destX, destY, destX + entry.width, destY + entry.height);
-}
+ int xx = _x;
+ int yy = _y;
-const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &point) {
- // Convert from screen space to working window space
- Common::Point newPoint(point - Common::Point(_workingWindow.left, _workingWindow.top));
+ if (xx < 0)
+ xx = 0;
+ if (yy < 0)
+ yy = 0;
- RenderTable::RenderState state = _renderTable.getRenderState();
- if (state == RenderTable::PANORAMA || state == RenderTable::TILT) {
- newPoint = _renderTable.convertWarpedCoordToFlatCoord(newPoint);
+ if (_x >= dst.w || _y >= dst.h) {
+ srcAdapted->free();
+ delete srcAdapted;
+ return;
}
- if (state == RenderTable::PANORAMA) {
- newPoint -= (Common::Point(_screenCenterX, 0) - _backgroundOffset);
- } else if (state == RenderTable::TILT) {
- newPoint -= (Common::Point(0, _screenCenterY) - _backgroundOffset);
+ byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);
+
+ int32 w = srcRect.width();
+ int32 h = srcRect.height();
+
+ for (int32 y = 0; y < h; y++) {
+ switch (srcAdapted->format.bytesPerPixel) {
+ case 1: {
+ const uint *srcTemp = (const uint *)srcBuffer;
+ uint *dstTemp = (uint *)dstBuffer;
+ for (int32 x = 0; x < w; x++) {
+ if (*srcTemp != keycolor)
+ *dstTemp = *srcTemp;
+ srcTemp++;
+ dstTemp++;
+ }
+ }
+ break;
+
+ case 2: {
+ const uint16 *srcTemp = (const uint16 *)srcBuffer;
+ uint16 *dstTemp = (uint16 *)dstBuffer;
+ for (int32 x = 0; x < w; x++) {
+ if (*srcTemp != keycolor)
+ *dstTemp = *srcTemp;
+ srcTemp++;
+ dstTemp++;
+ }
+ }
+ break;
+
+ case 4: {
+ const uint32 *srcTemp = (const uint32 *)srcBuffer;
+ uint32 *dstTemp = (uint32 *)dstBuffer;
+ for (int32 x = 0; x < w; x++) {
+ if (*srcTemp != keycolor)
+ *dstTemp = *srcTemp;
+ srcTemp++;
+ dstTemp++;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ srcBuffer += srcAdapted->pitch;
+ dstBuffer += dst.pitch;
}
- if (newPoint.x < 0)
- newPoint.x += _backgroundWidth;
- else if (newPoint.x >= _backgroundWidth)
- newPoint.x -= _backgroundWidth;
- if (newPoint.y < 0)
- newPoint.y += _backgroundHeight;
- else if (newPoint.y >= _backgroundHeight)
- newPoint.y -= _backgroundHeight;
+ srcAdapted->free();
+ delete srcAdapted;
+}
+
+void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, int32 colorkey) {
+ Common::Rect empt;
+ if (colorkey >= 0)
+ blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y, colorkey);
+ else
+ blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y);
+ Common::Rect dirty(src.w, src.h);
+ dirty.translate(x, y);
+ if (_backgroundDirtyRect.isEmpty())
+ _backgroundDirtyRect = dirty;
+ else
+ _backgroundDirtyRect.extend(dirty);
+}
+
+void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, int32 colorkey) {
+ if (src.w == _dstRect.width() && src.h == _dstRect.height()) {
+ blitSurfaceToBkg(src, _dstRect.left, _dstRect.top, colorkey);
+ } else {
+ Graphics::Surface *tmp = new Graphics::Surface;
+ tmp->create(_dstRect.width(), _dstRect.height(), src.format);
+ scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height());
+ blitSurfaceToBkg(*tmp, _dstRect.left, _dstRect.top, colorkey);
+ tmp->free();
+ delete tmp;
+ }
+}
- return newPoint;
+void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, int32 colorkey) {
+ Common::Rect empt;
+ if (colorkey >= 0)
+ blitSurfaceToSurface(src, empt, _menuSurface, x, y, colorkey);
+ else
+ blitSurfaceToSurface(src, empt, _menuSurface, x, y);
+ Common::Rect dirty(src.w, src.h);
+ dirty.translate(x, y);
+ if (_menuSurfaceDirtyRect.isEmpty())
+ _menuSurfaceDirtyRect = dirty;
+ else
+ _menuSurfaceDirtyRect.extend(dirty);
}
-const Common::Point RenderManager::imageSpaceToWorkingWindowSpace(const Common::Point &point) {
- Common::Point newPoint(point);
+Graphics::Surface *RenderManager::getBkgRect(Common::Rect &rect) {
+ Common::Rect dst = rect;
+ dst.clip(_backgroundWidth, _backgroundHeight);
+
+ if (dst.isEmpty() || !dst.isValidRect())
+ return NULL;
+ Graphics::Surface *srf = new Graphics::Surface;
+ srf->create(dst.width(), dst.height(), _currentBackgroundImage.format);
+
+ srf->copyRectToSurface(_currentBackgroundImage, 0, 0, Common::Rect(dst));
+
+ return srf;
+}
+
+Graphics::Surface *RenderManager::loadImage(Common::String file) {
+ Graphics::Surface *tmp = new Graphics::Surface;
+ readImageToSurface(file, *tmp);
+ return tmp;
+}
+
+Graphics::Surface *RenderManager::loadImage(Common::String file, bool transposed) {
+ Graphics::Surface *tmp = new Graphics::Surface;
+ readImageToSurface(file, *tmp, transposed);
+ return tmp;
+}
+
+void RenderManager::prepareBackground() {
+ _backgroundDirtyRect.clip(_backgroundWidth, _backgroundHeight);
RenderTable::RenderState state = _renderTable.getRenderState();
+
if (state == RenderTable::PANORAMA) {
- newPoint += (Common::Point(_screenCenterX, 0) - _backgroundOffset);
+ // Calculate the visible portion of the background
+ Common::Rect viewPort(_workingWindow.width(), _workingWindow.height());
+ viewPort.translate(-(_screenCenterX - _backgroundOffset), 0);
+ Common::Rect drawRect = _backgroundDirtyRect;
+ drawRect.clip(viewPort);
+
+ // Render the visible portion
+ if (!drawRect.isEmpty()) {
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - _backgroundOffset + drawRect.left, drawRect.top);
+ }
+
+ // Mark the dirty portion of the surface
+ _backgroundSurfaceDirtyRect = _backgroundDirtyRect;
+ _backgroundSurfaceDirtyRect.translate(_screenCenterX - _backgroundOffset, 0);
+
+ // Panorama mode allows the user to spin in circles. Therefore, we need to render
+ // the portion of the image that wrapped to the other side of the screen
+ if (_backgroundOffset < _screenCenterX) {
+ viewPort.moveTo(-(_screenCenterX - (_backgroundOffset + _backgroundWidth)), 0);
+ drawRect = _backgroundDirtyRect;
+ drawRect.clip(viewPort);
+
+ if (!drawRect.isEmpty())
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - (_backgroundOffset + _backgroundWidth) + drawRect.left, drawRect.top);
+
+ Common::Rect tmp = _backgroundDirtyRect;
+ tmp.translate(_screenCenterX - (_backgroundOffset + _backgroundWidth), 0);
+ if (!tmp.isEmpty())
+ _backgroundSurfaceDirtyRect.extend(tmp);
+
+ } else if (_backgroundWidth - _backgroundOffset < _screenCenterX) {
+ viewPort.moveTo(-(_screenCenterX + _backgroundWidth - _backgroundOffset), 0);
+ drawRect = _backgroundDirtyRect;
+ drawRect.clip(viewPort);
+
+ if (!drawRect.isEmpty())
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX + _backgroundWidth - _backgroundOffset + drawRect.left, drawRect.top);
+
+ Common::Rect tmp = _backgroundDirtyRect;
+ tmp.translate(_screenCenterX + _backgroundWidth - _backgroundOffset, 0);
+ if (!tmp.isEmpty())
+ _backgroundSurfaceDirtyRect.extend(tmp);
+
+ }
} else if (state == RenderTable::TILT) {
- newPoint += (Common::Point(0, _screenCenterY) - _backgroundOffset);
+ // Tilt doesn't allow wrapping, so we just do a simple clip
+ Common::Rect viewPort(_workingWindow.width(), _workingWindow.height());
+ viewPort.translate(0, -(_screenCenterY - _backgroundOffset));
+ Common::Rect drawRect = _backgroundDirtyRect;
+ drawRect.clip(viewPort);
+ if (!drawRect.isEmpty())
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, drawRect.left, _screenCenterY - _backgroundOffset + drawRect.top);
+
+ // Mark the dirty portion of the surface
+ _backgroundSurfaceDirtyRect = _backgroundDirtyRect;
+ _backgroundSurfaceDirtyRect.translate(0, _screenCenterY - _backgroundOffset);
+
+ } else {
+ if (!_backgroundDirtyRect.isEmpty())
+ blitSurfaceToSurface(_currentBackgroundImage, _backgroundDirtyRect, _backgroundSurface, _backgroundDirtyRect.left, _backgroundDirtyRect.top);
+ _backgroundSurfaceDirtyRect = _backgroundDirtyRect;
}
- return newPoint;
+ // Clear the dirty rect since everything is clean now
+ _backgroundDirtyRect = Common::Rect();
+
+ _backgroundSurfaceDirtyRect.clip(_workingWindow.width(), _workingWindow.height());
+}
+
+void RenderManager::clearMenuSurface() {
+ _menuSurfaceDirtyRect = Common::Rect(0, 0, _menuSurface.w, _menuSurface.h);
+ _menuSurface.fillRect(_menuSurfaceDirtyRect, 0);
}
-bool RenderManager::clipRectToWorkingWindow(Common::Rect &rect) {
- if (!_workingWindow.contains(rect)) {
- return false;
+void RenderManager::clearMenuSurface(const Common::Rect &r) {
+ if (_menuSurfaceDirtyRect.isEmpty())
+ _menuSurfaceDirtyRect = r;
+ else
+ _menuSurfaceDirtyRect.extend(r);
+ _menuSurface.fillRect(r, 0);
+}
+
+void RenderManager::renderMenuToScreen() {
+ if (!_menuSurfaceDirtyRect.isEmpty()) {
+ _menuSurfaceDirtyRect.clip(Common::Rect(_menuSurface.w, _menuSurface.h));
+ if (!_menuSurfaceDirtyRect.isEmpty()) {
+ Common::Rect rect(
+ _menuSurfaceDirtyRect.left + _menuArea.left,
+ _menuSurfaceDirtyRect.top + _menuArea.top,
+ _menuSurfaceDirtyRect.left + _menuArea.left + _menuSurfaceDirtyRect.width(),
+ _menuSurfaceDirtyRect.top + _menuArea.top + _menuSurfaceDirtyRect.height()
+ );
+ copyToScreen(_menuSurface, rect, _menuSurfaceDirtyRect.left, _menuSurfaceDirtyRect.top);
+ }
+ _menuSurfaceDirtyRect = Common::Rect();
}
+}
- // We can't clip against the actual working window rect because it's in screen space
- // But rect is in working window space
- rect.clip(_workingWidth, _workingHeight);
- return true;
+void RenderManager::initSubArea(uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow) {
+ _workingWindow = workingWindow;
+
+ _subtitleSurface.free();
+
+ _subtitleSurface.create(windowWidth, windowHeight - workingWindow.bottom, _pixelFormat);
+ _subtitleArea = Common::Rect(0, workingWindow.bottom, windowWidth, windowHeight);
}
-RenderTable *RenderManager::getRenderTable() {
- return &_renderTable;
+uint16 RenderManager::createSubArea(const Common::Rect &area) {
+ _subid++;
+
+ OneSubtitle sub;
+ sub.redraw = false;
+ sub.timer = -1;
+ sub.todelete = false;
+ sub.r = area;
+
+ _subsList[_subid] = sub;
+
+ return _subid;
}
-void RenderManager::setBackgroundImage(const Common::String &fileName) {
- readImageToSurface(fileName, _currentBackground);
+uint16 RenderManager::createSubArea() {
+ Common::Rect r(_subtitleArea.left, _subtitleArea.top, _subtitleArea.right, _subtitleArea.bottom);
+ r.translate(-_workingWindow.left, -_workingWindow.top);
+ return createSubArea(r);
+}
- moveBackground(0);
+void RenderManager::deleteSubArea(uint16 id) {
+ if (_subsList.contains(id))
+ _subsList[id].todelete = true;
}
-void RenderManager::setBackgroundPosition(int offset) {
- RenderTable::RenderState state = _renderTable.getRenderState();
- if (state == RenderTable::TILT) {
- _backgroundOffset.x = 0;
- _backgroundOffset.y = offset;
- } else if (state == RenderTable::PANORAMA) {
- _backgroundOffset.x = offset;
- _backgroundOffset.y = 0;
- } else {
- _backgroundOffset.x = 0;
- _backgroundOffset.y = 0;
+void RenderManager::deleteSubArea(uint16 id, int16 delay) {
+ if (_subsList.contains(id))
+ _subsList[id].timer = delay;
+}
+
+void RenderManager::updateSubArea(uint16 id, const Common::String &txt) {
+ if (_subsList.contains(id)) {
+ OneSubtitle *sub = &_subsList[id];
+ sub->txt = txt;
+ sub->redraw = true;
}
}
-void RenderManager::setBackgroundVelocity(int velocity) {
- // setBackgroundVelocity(0) will be called quite often, so make sure
- // _backgroundInverseVelocity isn't already 0 to prevent an extraneous assignment
- if (velocity == 0) {
- if (_backgroundInverseVelocity != 0) {
- _backgroundInverseVelocity = 0;
+void RenderManager::processSubs(uint16 deltatime) {
+ bool redraw = false;
+ for (SubtitleMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) {
+ if (it->_value.timer != -1) {
+ it->_value.timer -= deltatime;
+ if (it->_value.timer <= 0)
+ it->_value.todelete = true;
+ }
+ if (it->_value.todelete) {
+ _subsList.erase(it);
+ redraw = true;
+ } else if (it->_value.redraw) {
+ redraw = true;
}
- } else {
- _backgroundInverseVelocity = 1000 / velocity;
}
-}
-void RenderManager::moveBackground(int offset) {
- RenderTable::RenderState state = _renderTable.getRenderState();
- if (state == RenderTable::TILT) {
- _backgroundOffset += Common::Point(0, offset);
+ if (redraw) {
+ _subtitleSurface.fillRect(Common::Rect(_subtitleSurface.w, _subtitleSurface.h), 0);
+
+ for (SubtitleMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) {
+ OneSubtitle *sub = &it->_value;
+ if (sub->txt.size()) {
+ Graphics::Surface subtitleSurface;
+ subtitleSurface.create(sub->r.width(), sub->r.height(), _engine->_resourcePixelFormat);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(sub->txt, subtitleSurface);
+ Common::Rect empty;
+ blitSurfaceToSurface(subtitleSurface, empty, _subtitleSurface, sub->r.left - _subtitleArea.left + _workingWindow.left, sub->r.top - _subtitleArea.top + _workingWindow.top);
+ subtitleSurface.free();
+ }
+ sub->redraw = false;
+ }
- _backgroundOffset.y = CLIP<int16>(_backgroundOffset.y, _screenCenterY, (int16)_backgroundHeight - _screenCenterY);
+ Common::Rect rect(
+ _subtitleArea.left,
+ _subtitleArea.top,
+ _subtitleArea.left + _subtitleSurface.w,
+ _subtitleArea.top + _subtitleSurface.h
+ );
+ copyToScreen(_subtitleSurface, rect, 0, 0);
+ }
+}
- renderImageToScreen(_currentBackground, 0, _screenCenterY - _backgroundOffset.y, true);
- } else if (state == RenderTable::PANORAMA) {
- _backgroundOffset += Common::Point(offset, 0);
+Common::Point RenderManager::getBkgSize() {
+ return Common::Point(_backgroundWidth, _backgroundHeight);
+}
- if (_backgroundOffset.x <= -_backgroundWidth)
- _backgroundOffset.x += _backgroundWidth;
- else if (_backgroundOffset.x >= _backgroundWidth)
- _backgroundOffset.x -= _backgroundWidth;
+void RenderManager::addEffect(GraphicsEffect *_effect) {
+ _effects.push_back(_effect);
+}
- renderImageToScreen(_currentBackground, _screenCenterX - _backgroundOffset.x, 0, true);
- } else {
- renderImageToScreen(_currentBackground, 0, 0);
+void RenderManager::deleteEffect(uint32 ID) {
+ for (EffectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
+ if ((*it)->getKey() == ID) {
+ delete *it;
+ it = _effects.erase(it);
+ }
}
}
-uint32 RenderManager::getCurrentBackgroundOffset() {
+Common::Rect RenderManager::transformBackgroundSpaceRectToScreenSpace(const Common::Rect &src) {
+ Common::Rect tmp = src;
RenderTable::RenderState state = _renderTable.getRenderState();
if (state == RenderTable::PANORAMA) {
- return _backgroundOffset.x;
+ if (_backgroundOffset < _screenCenterX) {
+ Common::Rect rScreen(_screenCenterX + _backgroundOffset, _workingWindow.height());
+ Common::Rect lScreen(_workingWindow.width() - rScreen.width(), _workingWindow.height());
+ lScreen.translate(_backgroundWidth - lScreen.width(), 0);
+ lScreen.clip(src);
+ rScreen.clip(src);
+ if (rScreen.width() < lScreen.width()) {
+ tmp.translate(_screenCenterX - _backgroundOffset - _backgroundWidth, 0);
+ } else {
+ tmp.translate(_screenCenterX - _backgroundOffset, 0);
+ }
+ } else if (_backgroundWidth - _backgroundOffset < _screenCenterX) {
+ Common::Rect rScreen(_screenCenterX - (_backgroundWidth - _backgroundOffset), _workingWindow.height());
+ Common::Rect lScreen(_workingWindow.width() - rScreen.width(), _workingWindow.height());
+ lScreen.translate(_backgroundWidth - lScreen.width(), 0);
+ lScreen.clip(src);
+ rScreen.clip(src);
+ if (lScreen.width() < rScreen.width()) {
+ tmp.translate(_screenCenterX + (_backgroundWidth - _backgroundOffset), 0);
+ } else {
+ tmp.translate(_screenCenterX - _backgroundOffset, 0);
+ }
+ } else {
+ tmp.translate(_screenCenterX - _backgroundOffset, 0);
+ }
} else if (state == RenderTable::TILT) {
- return _backgroundOffset.y;
- } else {
- return 0;
+ tmp.translate(0, (_screenCenterY - _backgroundOffset));
}
+
+ return tmp;
}
-Graphics::Surface *RenderManager::tranposeSurface(const Graphics::Surface *surface) {
- Graphics::Surface *tranposedSurface = new Graphics::Surface();
- tranposedSurface->create(surface->h, surface->w, surface->format);
+EffectMap *RenderManager::makeEffectMap(const Common::Point &xy, int16 depth, const Common::Rect &rect, int8 *_minComp, int8 *_maxComp) {
+ Common::Rect bkgRect(_backgroundWidth, _backgroundHeight);
+ if (!bkgRect.contains(xy))
+ return NULL;
+
+ if (!bkgRect.intersects(rect))
+ return NULL;
+
+ uint16 color = *(uint16 *)_currentBackgroundImage.getBasePtr(xy.x, xy.y);
+ uint8 stC1, stC2, stC3;
+ _currentBackgroundImage.format.colorToRGB(color, stC1, stC2, stC3);
+ EffectMap *newMap = new EffectMap;
+
+ EffectMapUnit unit;
+ unit.count = 0;
+ unit.inEffect = false;
+
+ int16 w = rect.width();
+ int16 h = rect.height();
+
+ bool first = true;
+
+ uint8 minComp = MIN(MIN(stC1, stC2), stC3);
+ uint8 maxComp = MAX(MAX(stC1, stC2), stC3);
+
+ uint8 depth8 = depth << 3;
+
+ for (int16 j = 0; j < h; j++) {
+ uint16 *pix = (uint16 *)_currentBackgroundImage.getBasePtr(rect.left, rect.top + j);
+ for (int16 i = 0; i < w; i++) {
+ uint16 curClr = pix[i];
+ uint8 cC1, cC2, cC3;
+ _currentBackgroundImage.format.colorToRGB(curClr, cC1, cC2, cC3);
+
+ bool use = false;
+
+ if (curClr == color)
+ use = true;
+ else if (curClr > color) {
+ if ((cC1 - stC1 < depth8) &&
+ (cC2 - stC2 < depth8) &&
+ (cC3 - stC3 < depth8))
+ use = true;
+ } else { /* if (curClr < color) */
+ if ((stC1 - cC1 < depth8) &&
+ (stC2 - cC2 < depth8) &&
+ (stC3 - cC3 < depth8))
+ use = true;
+ }
- const uint16 *source = (const uint16 *)surface->getPixels();
- uint16 *dest = (uint16 *)tranposedSurface->getPixels();
+ if (first) {
+ unit.inEffect = use;
+ first = false;
+ }
- for (uint32 y = 0; y < tranposedSurface->h; ++y) {
- uint32 columnIndex = y * tranposedSurface->w;
+ if (use) {
+ uint8 cMinComp = MIN(MIN(cC1, cC2), cC3);
+ uint8 cMaxComp = MAX(MAX(cC1, cC2), cC3);
+ if (cMinComp < minComp)
+ minComp = cMinComp;
+ if (cMaxComp > maxComp)
+ maxComp = cMaxComp;
+ }
- for (uint32 x = 0; x < tranposedSurface->w; ++x) {
- dest[columnIndex + x] = source[x * surface->w + y];
+ if (unit.inEffect == use)
+ unit.count++;
+ else {
+ newMap->push_back(unit);
+ unit.count = 1;
+ unit.inEffect = use;
+ }
}
}
+ newMap->push_back(unit);
- return tranposedSurface;
+ if (_minComp) {
+ if (minComp - depth8 < 0)
+ *_minComp = -(minComp >> 3);
+ else
+ *_minComp = -depth;
+ }
+ if (_maxComp) {
+ if ((int16)maxComp + (int16)depth8 > 255)
+ *_maxComp = (255 - maxComp) >> 3;
+ else
+ *_maxComp = depth;
+ }
+
+ return newMap;
+}
+
+EffectMap *RenderManager::makeEffectMap(const Graphics::Surface &surf, uint16 transp) {
+ EffectMapUnit unit;
+ unit.count = 0;
+ unit.inEffect = false;
+
+ int16 w = surf.w;
+ int16 h = surf.h;
+
+ EffectMap *newMap = new EffectMap;
+
+ bool first = true;
+
+ for (int16 j = 0; j < h; j++) {
+ const uint16 *pix = (const uint16 *)surf.getBasePtr(0, j);
+ for (int16 i = 0; i < w; i++) {
+ bool use = false;
+ if (pix[i] != transp)
+ use = true;
+
+ if (first) {
+ unit.inEffect = use;
+ first = false;
+ }
+
+ if (unit.inEffect == use)
+ unit.count++;
+ else {
+ newMap->push_back(unit);
+ unit.count = 1;
+ unit.inEffect = use;
+ }
+ }
+ }
+ newMap->push_back(unit);
+
+ return newMap;
+}
+
+void RenderManager::markDirty() {
+ _backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
+}
+
+#if 0
+void RenderManager::bkgFill(uint8 r, uint8 g, uint8 b) {
+ _currentBackgroundImage.fillRect(Common::Rect(_currentBackgroundImage.w, _currentBackgroundImage.h), _currentBackgroundImage.format.RGBToColor(r, g, b));
+ markDirty();
+}
+#endif
+
+void RenderManager::timedMessage(const Common::String &str, uint16 milsecs) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ deleteSubArea(msgid, milsecs);
+}
+
+bool RenderManager::askQuestion(const Common::String &str) {
+ Graphics::Surface textSurface;
+ textSurface.create(_subtitleArea.width(), _subtitleArea.height(), _engine->_resourcePixelFormat);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(str, textSurface);
+ copyToScreen(textSurface, _subtitleArea, 0, 0);
+
+ _engine->stopClock();
+
+ int result = 0;
+
+ while (result == 0) {
+ Common::Event evnt;
+ while (_engine->getEventManager()->pollEvent(evnt)) {
+ if (evnt.type == Common::EVENT_KEYDOWN) {
+ // English: yes/no
+ // German: ja/nein
+ // Spanish: si/no
+ // French Nemesis: F4/any other key
+ // French ZGI: oui/non
+ switch (evnt.kbd.keycode) {
+ case Common::KEYCODE_y:
+ if (_engine->getLanguage() == Common::EN_ANY)
+ result = 2;
+ break;
+ case Common::KEYCODE_j:
+ if (_engine->getLanguage() == Common::DE_DEU)
+ result = 2;
+ break;
+ case Common::KEYCODE_s:
+ if (_engine->getLanguage() == Common::ES_ESP)
+ result = 2;
+ break;
+ case Common::KEYCODE_o:
+ if (_engine->getLanguage() == Common::FR_FRA && _engine->getGameId() == GID_GRANDINQUISITOR)
+ result = 2;
+ break;
+ case Common::KEYCODE_F4:
+ if (_engine->getLanguage() == Common::FR_FRA && _engine->getGameId() == GID_NEMESIS)
+ result = 2;
+ break;
+ case Common::KEYCODE_n:
+ result = 1;
+ break;
+ default:
+ if (_engine->getLanguage() == Common::FR_FRA && _engine->getGameId() == GID_NEMESIS)
+ result = 1;
+ break;
+ }
+ }
+ }
+ _system->updateScreen();
+ if (_doubleFPS)
+ _system->delayMillis(33);
+ else
+ _system->delayMillis(66);
+ }
+
+ // Draw over the text in order to clear it
+ textSurface.fillRect(Common::Rect(_subtitleArea.width(), _subtitleArea.height()), 0);
+ copyToScreen(textSurface, _subtitleArea, 0, 0);
+
+ // Free the surface
+ textSurface.free();
+
+ _engine->startClock();
+ return result == 2;
+}
+
+void RenderManager::delayedMessage(const Common::String &str, uint16 milsecs) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ processSubs(0);
+ renderSceneToScreen();
+ _engine->stopClock();
+
+ uint32 stopTime = _system->getMillis() + milsecs;
+ while (_system->getMillis() < stopTime) {
+ Common::Event evnt;
+ while (_engine->getEventManager()->pollEvent(evnt)) {
+ if (evnt.type == Common::EVENT_KEYDOWN &&
+ (evnt.kbd.keycode == Common::KEYCODE_SPACE ||
+ evnt.kbd.keycode == Common::KEYCODE_RETURN ||
+ evnt.kbd.keycode == Common::KEYCODE_ESCAPE))
+ break;
+ }
+ _system->updateScreen();
+ if (_doubleFPS)
+ _system->delayMillis(33);
+ else
+ _system->delayMillis(66);
+ }
+ deleteSubArea(msgid);
+ _engine->startClock();
+}
+
+void RenderManager::showDebugMsg(const Common::String &msg, int16 delay) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, msg);
+ deleteSubArea(msgid, delay);
+}
+
+void RenderManager::updateRotation() {
+ int16 _velocity = _engine->getMouseVelocity() + _engine->getKeyboardVelocity();
+ ScriptManager *scriptManager = _engine->getScriptManager();
+
+ if (_doubleFPS)
+ _velocity /= 2;
+
+ if (_velocity) {
+ RenderTable::RenderState renderState = _renderTable.getRenderState();
+ if (renderState == RenderTable::PANORAMA) {
+ int16 startPosition = scriptManager->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition + (_renderTable.getPanoramaReverse() ? -_velocity : _velocity);
+
+ int16 zeroPoint = _renderTable.getPanoramaZeroPoint();
+ if (startPosition >= zeroPoint && newPosition < zeroPoint)
+ scriptManager->setStateValue(StateKey_Rounds, scriptManager->getStateValue(StateKey_Rounds) - 1);
+ if (startPosition <= zeroPoint && newPosition > zeroPoint)
+ scriptManager->setStateValue(StateKey_Rounds, scriptManager->getStateValue(StateKey_Rounds) + 1);
+
+ int16 screenWidth = getBkgSize().x;
+ if (screenWidth)
+ newPosition %= screenWidth;
+
+ if (newPosition < 0)
+ newPosition += screenWidth;
+
+ setBackgroundPosition(newPosition);
+ } else if (renderState == RenderTable::TILT) {
+ int16 startPosition = scriptManager->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition + _velocity;
+
+ int16 screenHeight = getBkgSize().y;
+ int16 tiltGap = (int16)_renderTable.getTiltGap();
+
+ if (newPosition >= (screenHeight - tiltGap))
+ newPosition = screenHeight - tiltGap;
+ if (newPosition <= tiltGap)
+ newPosition = tiltGap;
+
+ setBackgroundPosition(newPosition);
+ }
+ }
+}
+
+void RenderManager::checkBorders() {
+ RenderTable::RenderState renderState = _renderTable.getRenderState();
+ if (renderState == RenderTable::PANORAMA) {
+ int16 startPosition = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition;
+
+ int16 screenWidth = getBkgSize().x;
+
+ if (screenWidth)
+ newPosition %= screenWidth;
+
+ if (newPosition < 0)
+ newPosition += screenWidth;
+
+ if (startPosition != newPosition)
+ setBackgroundPosition(newPosition);
+ } else if (renderState == RenderTable::TILT) {
+ int16 startPosition = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition;
+
+ int16 screenHeight = getBkgSize().y;
+ int16 tiltGap = (int16)_renderTable.getTiltGap();
+
+ if (newPosition >= (screenHeight - tiltGap))
+ newPosition = screenHeight - tiltGap;
+ if (newPosition <= tiltGap)
+ newPosition = tiltGap;
+
+ if (startPosition != newPosition)
+ setBackgroundPosition(newPosition);
+ }
+}
+
+void RenderManager::rotateTo(int16 _toPos, int16 _time) {
+ if (_renderTable.getRenderState() != RenderTable::PANORAMA)
+ return;
+
+ if (_time == 0)
+ _time = 1;
+
+ int32 maxX = getBkgSize().x;
+ int32 curX = getCurrentBackgroundOffset();
+ int32 dx = 0;
+
+ if (curX == _toPos)
+ return;
+
+ if (curX > _toPos) {
+ if (curX - _toPos > maxX / 2)
+ dx = (_toPos + (maxX - curX)) / _time;
+ else
+ dx = -(curX - _toPos) / _time;
+ } else {
+ if (_toPos - curX > maxX / 2)
+ dx = -((maxX - _toPos) + curX) / _time;
+ else
+ dx = (_toPos - curX) / _time;
+ }
+
+ _engine->stopClock();
+
+ for (int16 i = 0; i <= _time; i++) {
+ if (i == _time)
+ curX = _toPos;
+ else
+ curX += dx;
+
+ if (curX < 0)
+ curX = maxX - curX;
+ else if (curX >= maxX)
+ curX %= maxX;
+
+ setBackgroundPosition(curX);
+
+ prepareBackground();
+ renderSceneToScreen();
+
+ _system->updateScreen();
+
+ _system->delayMillis(500 / _time);
+ }
+
+ _engine->startClock();
+}
+
+void RenderManager::upscaleRect(Common::Rect &rect) {
+ rect.top = rect.top * HIRES_WINDOW_HEIGHT / WINDOW_HEIGHT;
+ rect.left = rect.left * HIRES_WINDOW_WIDTH / WINDOW_WIDTH;
+ rect.bottom = rect.bottom * HIRES_WINDOW_HEIGHT / WINDOW_HEIGHT;
+ rect.right = rect.right * HIRES_WINDOW_WIDTH / WINDOW_WIDTH;
}
} // End of namespace ZVision