mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
1215 lines
36 KiB
C++
1215 lines
36 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#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/file/lzss_read_stream.h"
|
|
|
|
#include "common/file.h"
|
|
#include "common/system.h"
|
|
#include "common/stream.h"
|
|
|
|
#include "engines/util.h"
|
|
|
|
#include "image/tga.h"
|
|
|
|
namespace ZVision {
|
|
|
|
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() {
|
|
_currentBackgroundImage.free();
|
|
_backgroundSurface.free();
|
|
_effectSurface.free();
|
|
_warpedSceneSurface.free();
|
|
_menuSurface.free();
|
|
_subtitleSurface.free();
|
|
}
|
|
|
|
void RenderManager::renderSceneToScreen() {
|
|
Graphics::Surface *out = &_warpedSceneSurface;
|
|
Graphics::Surface *in = &_backgroundSurface;
|
|
Common::Rect outWndDirtyRect;
|
|
|
|
// 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());
|
|
|
|
for (EffectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
|
|
Common::Rect rect = (*it)->getRegion();
|
|
Common::Rect screenSpaceLocation = rect;
|
|
|
|
if ((*it)->isPort()) {
|
|
screenSpaceLocation = transformBackgroundSpaceRectToScreenSpace(screenSpaceLocation);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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::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;
|
|
}
|
|
|
|
void RenderManager::renderImageToBackground(const Common::Path &fileName, int16 destX, int16 destY) {
|
|
Graphics::Surface surface;
|
|
readImageToSurface(fileName, surface);
|
|
|
|
blitSurfaceToBkg(surface, destX, destY);
|
|
surface.free();
|
|
}
|
|
|
|
void RenderManager::renderImageToBackground(const Common::Path &fileName, int16 destX, int16 destY, uint32 keycolor) {
|
|
Graphics::Surface surface;
|
|
readImageToSurface(fileName, surface);
|
|
|
|
blitSurfaceToBkg(surface, destX, destY, keycolor);
|
|
surface.free();
|
|
}
|
|
|
|
void RenderManager::renderImageToBackground(const Common::Path &fileName, int16 destX, int16 destY, int16 keyX, int16 keyY) {
|
|
Graphics::Surface surface;
|
|
readImageToSurface(fileName, surface);
|
|
|
|
uint16 keycolor = *(uint16 *)surface.getBasePtr(keyX, keyY);
|
|
|
|
blitSurfaceToBkg(surface, destX, destY, keycolor);
|
|
surface.free();
|
|
}
|
|
|
|
void RenderManager::readImageToSurface(const Common::Path &fileName, Graphics::Surface &destination) {
|
|
bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA;
|
|
readImageToSurface(fileName, destination, isTransposed);
|
|
}
|
|
|
|
void RenderManager::readImageToSurface(const Common::Path &fileName, Graphics::Surface &destination, bool transposed) {
|
|
Common::File file;
|
|
|
|
if (!_engine->getSearchManager()->openFile(file, fileName)) {
|
|
warning("Could not open file %s", fileName.toString().c_str());
|
|
return;
|
|
}
|
|
|
|
// Read the magic number
|
|
// Some files are true TGA, while others are TGZ
|
|
uint32 fileType = file.readUint32BE();
|
|
|
|
int imageWidth;
|
|
int imageHeight;
|
|
Image::TGADecoder tga;
|
|
uint16 *buffer;
|
|
// All Z-Vision images are in RGB 555
|
|
destination.format = _engine->_resourcePixelFormat;
|
|
|
|
bool isTGZ;
|
|
|
|
// Check for TGZ files
|
|
if (fileType == MKTAG('T', 'G', 'Z', '\0')) {
|
|
isTGZ = true;
|
|
|
|
// TGZ files have a header and then Bitmap data that is compressed with LZSS
|
|
uint32 decompressedSize = file.readSint32LE() / 2;
|
|
imageWidth = file.readSint32LE();
|
|
imageHeight = file.readSint32LE();
|
|
|
|
LzssReadStream lzssStream(&file);
|
|
buffer = (uint16 *)(new uint16[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;
|
|
|
|
// Reset the cursor
|
|
file.seek(0);
|
|
|
|
// Decode
|
|
if (!tga.loadStream(file)) {
|
|
warning("Error while reading TGA image");
|
|
return;
|
|
}
|
|
|
|
Graphics::Surface tgaSurface = *(tga.getSurface());
|
|
imageWidth = tgaSurface.w;
|
|
imageHeight = tgaSurface.h;
|
|
|
|
buffer = (uint16 *)tgaSurface.getPixels();
|
|
}
|
|
|
|
// Flip the width and height if transposed
|
|
if (transposed) {
|
|
SWAP(imageWidth, imageHeight);
|
|
}
|
|
|
|
// 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, _engine->_resourcePixelFormat);
|
|
}
|
|
|
|
// If transposed, 'un-transpose' the data while copying it to the destination
|
|
// Otherwise, just do a simple copy
|
|
if (transposed) {
|
|
uint16 *dest = (uint16 *)destination.getPixels();
|
|
|
|
for (int y = 0; y < imageHeight; ++y) {
|
|
uint32 columnIndex = y * imageWidth;
|
|
|
|
for (int x = 0; x < imageWidth; ++x) {
|
|
dest[columnIndex + x] = buffer[x * imageHeight + y];
|
|
}
|
|
}
|
|
} else {
|
|
memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * destination.format.bytesPerPixel);
|
|
}
|
|
|
|
// Cleanup
|
|
if (isTGZ) {
|
|
delete[] buffer;
|
|
} else {
|
|
tga.destroy();
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
if (state == RenderTable::PANORAMA) {
|
|
newPoint += (Common::Point(_backgroundOffset - _screenCenterX, 0));
|
|
} else if (state == RenderTable::TILT) {
|
|
newPoint += (Common::Point(0, _backgroundOffset - _screenCenterY));
|
|
}
|
|
|
|
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::Path &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;
|
|
|
|
_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 {
|
|
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 (int y = 0; y < tranposedSurface->h; ++y) {
|
|
int columnIndex = y * tranposedSurface->w;
|
|
|
|
for (int x = 0; x < tranposedSurface->w; ++x) {
|
|
dest[columnIndex + x] = source[x * surface->w + y];
|
|
}
|
|
}
|
|
|
|
return tranposedSurface;
|
|
}
|
|
|
|
void RenderManager::scaleBuffer(const void *src, void *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint32 dstWidth, uint32 dstHeight) {
|
|
assert(bytesPerPixel == 1 || bytesPerPixel == 2);
|
|
|
|
const float xscale = (float)srcWidth / (float)dstWidth;
|
|
const float yscale = (float)srcHeight / (float)dstHeight;
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
srcAdapted->free();
|
|
delete srcAdapted;
|
|
}
|
|
|
|
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;
|
|
|
|
Graphics::Surface *srcAdapted = src.convertTo(dst.format);
|
|
uint32 keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);
|
|
|
|
// 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);
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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(const Common::Path &file) {
|
|
Graphics::Surface *tmp = new Graphics::Surface;
|
|
readImageToSurface(file, *tmp);
|
|
return tmp;
|
|
}
|
|
|
|
Graphics::Surface *RenderManager::loadImage(const Common::Path &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) {
|
|
// 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) {
|
|
// 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;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
uint16 RenderManager::createSubArea() {
|
|
Common::Rect r(_subtitleArea.left, _subtitleArea.top, _subtitleArea.right, _subtitleArea.bottom);
|
|
r.translate(-_workingWindow.left, -_workingWindow.top);
|
|
return createSubArea(r);
|
|
}
|
|
|
|
void RenderManager::deleteSubArea(uint16 id) {
|
|
if (_subsList.contains(id))
|
|
_subsList[id].todelete = true;
|
|
}
|
|
|
|
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::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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
Common::Rect rect(
|
|
_subtitleArea.left,
|
|
_subtitleArea.top,
|
|
_subtitleArea.left + _subtitleSurface.w,
|
|
_subtitleArea.top + _subtitleSurface.h
|
|
);
|
|
copyToScreen(_subtitleSurface, rect, 0, 0);
|
|
}
|
|
}
|
|
|
|
Common::Point RenderManager::getBkgSize() {
|
|
return Common::Point(_backgroundWidth, _backgroundHeight);
|
|
}
|
|
|
|
void RenderManager::addEffect(GraphicsEffect *_effect) {
|
|
_effects.push_back(_effect);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
Common::Rect RenderManager::transformBackgroundSpaceRectToScreenSpace(const Common::Rect &src) {
|
|
Common::Rect tmp = src;
|
|
RenderTable::RenderState state = _renderTable.getRenderState();
|
|
|
|
if (state == RenderTable::PANORAMA) {
|
|
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) {
|
|
tmp.translate(0, (_screenCenterY - _backgroundOffset));
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (first) {
|
|
unit.inEffect = use;
|
|
first = false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (unit.inEffect == use)
|
|
unit.count++;
|
|
else {
|
|
newMap->push_back(unit);
|
|
unit.count = 1;
|
|
unit.inEffect = use;
|
|
}
|
|
}
|
|
}
|
|
newMap->push_back(unit);
|
|
|
|
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
|
|
// TODO: Handle this using the keymapper
|
|
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
|