diff options
author | Eugene Sandulenko | 2008-08-04 11:28:57 +0000 |
---|---|---|
committer | Willem Jan Palenstijn | 2011-11-20 22:43:05 +0100 |
commit | 7c2835313ee3c68e6ac753782b63a9dd485b0a60 (patch) | |
tree | 86049438fa48c2a9fee1c40e0eacb2cfb0bb9962 /engines/toltecs/segmap.cpp | |
parent | 528c1173d7b9d15d9b7e36f25a876c8952357f26 (diff) | |
download | scummvm-rg350-7c2835313ee3c68e6ac753782b63a9dd485b0a60.tar.gz scummvm-rg350-7c2835313ee3c68e6ac753782b63a9dd485b0a60.tar.bz2 scummvm-rg350-7c2835313ee3c68e6ac753782b63a9dd485b0a60.zip |
TOLTECS: Initial checkin
Diffstat (limited to 'engines/toltecs/segmap.cpp')
-rw-r--r-- | engines/toltecs/segmap.cpp | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/engines/toltecs/segmap.cpp b/engines/toltecs/segmap.cpp new file mode 100644 index 0000000000..6c4796f76a --- /dev/null +++ b/engines/toltecs/segmap.cpp @@ -0,0 +1,535 @@ +/* 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. + * + * + */ + +#include "common/events.h" +#include "common/keyboard.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" +#include "common/stream.h" + +#include "graphics/primitives.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "sound/mixer.h" + +#include "toltecs/toltecs.h" +#include "toltecs/resource.h" +#include "toltecs/screen.h" +#include "toltecs/segmap.h" + +namespace Toltecs { + +SegmentMap::SegmentMap(ToltecsEngine *vm) : _vm(vm) { + _maskRectData = new byte[32768]; +} + +SegmentMap::~SegmentMap() { + delete[] _maskRectData; +} + +void SegmentMap::load(byte *source) { + + // TODO: Use MemoryReadStream + + _maskRects.clear(); + _pathRects.clear(); + _infoRects.clear(); + + // Load mask rects + uint16 maskSize = READ_LE_UINT16(source); + source += 2; + uint16 maskRectCount = READ_LE_UINT16(source); + source += 2; + uint16 maskRectDataSize = maskRectCount * 12 + 2; + + debug(0, "SegmentMap::load() maskRectCount = %d", maskRectCount); + + for (uint16 i = 0; i < maskRectCount; i++) { + SegmapMaskRect maskRect; + maskRect.y = READ_LE_UINT16(source); + maskRect.x = READ_LE_UINT16(source + 2); + maskRect.height = READ_LE_UINT16(source + 4); + maskRect.width = READ_LE_UINT16(source + 6); + maskRect.maskOffset = READ_LE_UINT16(source + 8); + maskRect.maskOffset -= maskRectDataSize; + maskRect.ybottom = READ_LE_UINT16(source + 10); + + debug(0, "SegmentMap::load() (%d, %d, %d, %d, %04X, %d)", + maskRect.x, maskRect.y, maskRect.width, maskRect.height, maskRect.maskOffset, maskRect.ybottom); + + source += 12; + _maskRects.push_back(maskRect); + } + + memcpy(_maskRectData, source, maskSize - maskRectDataSize); + source += maskSize - maskRectDataSize; + + // Load path rects + + source += 2; // skip rects array size + + uint16 pathRectCount = READ_LE_UINT16(source); + source += 2; + + debug(0, "SegmentMap::load() pathRectCount = %d", pathRectCount); + + for (uint16 i = 0; i < pathRectCount; i++) { + SegmapPathRect pathRect; + pathRect.y = READ_LE_UINT16(source); + pathRect.x = READ_LE_UINT16(source + 2); + pathRect.height = READ_LE_UINT16(source + 4); + pathRect.width = READ_LE_UINT16(source + 6); + + debug(0, "SegmentMap::load() (%d, %d, %d, %d)", pathRect.x, pathRect.y, pathRect.width, pathRect.height); + + source += 8; + _pathRects.push_back(pathRect); + } + + // Load info rects + + source += 2; // skip rects array size + + uint16 infoRectCount = READ_LE_UINT16(source); + source += 2; + debug(0, "SegmentMap::load() infoRectCount = %d", infoRectCount); + for (uint16 i = 0; i < infoRectCount; i++) { + SegmapInfoRect infoRect; + infoRect.y = READ_LE_UINT16(source); + infoRect.x = READ_LE_UINT16(source + 2); + infoRect.height = READ_LE_UINT16(source + 4); + infoRect.width = READ_LE_UINT16(source + 6); + infoRect.id = source[8]; + infoRect.a = source[9]; + infoRect.b = source[10]; + infoRect.c = source[11]; + + debug(0, "SegmentMap::load() (%d, %d, %d, %d) (%d, %d, %d, %d)", + infoRect.x, infoRect.y, infoRect.width, infoRect.height, + infoRect.id, (int8)infoRect.a, (int8)infoRect.b, (int8)infoRect.c); + + source += 12; + _infoRects.push_back(infoRect); + } + + // TODO Other stuff + + +} + +int SegmentMap::findPathRectAtPoint(int x, int y) { + for (uint rectIndex = 0; rectIndex < _pathRects.size(); rectIndex++) { + if (y >= _pathRects[rectIndex].y && y <= _pathRects[rectIndex].y + _pathRects[rectIndex].height && + x >= _pathRects[rectIndex].x && x <= _pathRects[rectIndex].x + _pathRects[rectIndex].width) { + return rectIndex; + } + } + return -1; +} + +void SegmentMap::adjustPathPoint(int x, int y) { + + if (findPathRectAtPoint(x, y) != -1) + return; + + uint32 minDistance = 0xFFFFFFFF, distance; + int x2, y2; + + for (uint rectIndex = 0; rectIndex < _pathRects.size(); rectIndex++) { + + if (ABS(x - _pathRects[rectIndex].x) >= ABS((x - (_pathRects[rectIndex].x + _pathRects[rectIndex].width)))) { + x2 = _pathRects[rectIndex].x + _pathRects[rectIndex].width; + } else { + x2 = _pathRects[rectIndex].x; + } + + if (ABS(y - _pathRects[rectIndex].y) >= ABS((y - (_pathRects[rectIndex].y + _pathRects[rectIndex].height)))) { + y2 = _pathRects[rectIndex].y + _pathRects[rectIndex].height; + } else { + y2 = _pathRects[rectIndex].y; + } + + if (x >= _pathRects[rectIndex].x && x < _pathRects[rectIndex].x + _pathRects[rectIndex].width) { + x2 = x; + } + + distance = ABS(y - y2) + ABS(x - x2); + if (distance < minDistance) { + if (y >= _pathRects[rectIndex].y && y <= _pathRects[rectIndex].y + _pathRects[rectIndex].height) + _y = y; + else + _y = y2; + if (x >= _pathRects[rectIndex].x && x <= _pathRects[rectIndex].x + _pathRects[rectIndex].width) + _x = x; + else + _x = x2; + minDistance = distance; + } + + } + +} + +int SegmentMap::findNextPathRect(int srcRectIndex) { + + uint v28; + int result; + int minDistance, distance; + int x1, y1, x2, y2; + int nx1, nx2, nx3; + int ny, ny2, ny3; + + result = -1; + minDistance = 65535; + + x1 = _pathRects[srcRectIndex].x; + y1 = _pathRects[srcRectIndex].y; + + x2 = x1 + _pathRects[srcRectIndex].width; + y2 = y1 + _pathRects[srcRectIndex].height; + + for (uint rectIndex = 0; rectIndex < _pathRects.size(); ++rectIndex) { + + if ( y1 == _pathRects[rectIndex].height + _pathRects[rectIndex].y && x1 < _pathRects[rectIndex].x + _pathRects[rectIndex].width && x2 > _pathRects[rectIndex].x ) { + ny = y1; + +LABEL_28: + if ( x1 >= _pathRects[rectIndex].x ) { + nx1 = x1; + } else { + nx1 = _pathRects[rectIndex].x; + } + if ( x2 <= _pathRects[rectIndex].x + _pathRects[rectIndex].width ) { + nx2 = x2 - 1; + } else { + nx2 = _pathRects[rectIndex].x + _pathRects[rectIndex].width - 1; + } + if ( ABS(_x - nx1) >= ABS(_x - nx2) ) { + nx3 = nx2 - 1; + } else { + nx3 = nx1; + } + if ( _x > nx1 && _x < nx2 ) { + nx3 = _x; + } + goto LABEL_55; + } + if ( y2 == _pathRects[rectIndex].y && x1 < _pathRects[rectIndex].x + _pathRects[rectIndex].width && x2 > _pathRects[rectIndex].x ) { + ny = y2 - 1; + goto LABEL_28; + } + if ( x1 == _pathRects[rectIndex].x + _pathRects[rectIndex].width && y1 < _pathRects[rectIndex].y + _pathRects[rectIndex].height && y2 > _pathRects[rectIndex].y ) { + nx3 = x1; + } else { + if ( x2 != _pathRects[rectIndex].x || y1 >= _pathRects[rectIndex].y + _pathRects[rectIndex].height || y2 <= _pathRects[rectIndex].y ) + continue; + nx3 = x2 - 1; + } + if ( y1 >= _pathRects[rectIndex].y ) { + ny3 = y1; + } else { + ny3 = _pathRects[rectIndex].y; + } + if ( y2 <= _pathRects[rectIndex].y + _pathRects[rectIndex].height ) { + ny2 = y2 - 1; + } else { + ny2 = _pathRects[rectIndex].y + _pathRects[rectIndex].height - 1; + } + if ( ABS(_y - ny3) >= ABS(_y - ny2) ) { + ny = ny2 - 1; + } else { + ny = ny3; + } + if ( _y > ny3 && _y < ny2 ) { + ny = _y; + } + +LABEL_55: + distance = ABS(_x - nx3) + ABS(_y - ny); + v28 = 0; + while ( v28 < _rectIndexArray2Count ) { + if ( rectIndex == _rectIndexArray2[v28] ) { + distance = minDistance; + break; + } + ++v28; + } + + v28 = 0; + while ( v28 < _rectIndexArray1Count ) { + if ( rectIndex == _rectIndexArray1[v28] ) { + distance = minDistance; + break; + } + ++v28; + } + + if ( distance < minDistance ) { + result = rectIndex; + minDistance = distance; + _pointsArray[_pointsCount].y = ny; + _pointsArray[_pointsCount].x = nx3; + } + + } + + return result; +} + +struct LineData { + int pitch; + byte *surf; +}; + +void plotProc(int x, int y, int color, void *data) { + LineData *ld = (LineData*)data; + ld->surf[x + y * ld->pitch] = color; +} + +void SegmentMap::findPath(int16 *pointsArray, int destX, int destY, int x, int y) { + + int index; + int sourceRectIndex, destRectIndex; + int pointsCount; + + pointsCount = 2; + index = 0; + + debug(0, "SegmentMap::findPath(fromX: %d; fromY: %d; toX: %d; toY: %d)", x, y, destX, destY); + + sourceRectIndex = findPathRectAtPoint(x, y); + if ( sourceRectIndex == -1 ) { + adjustPathPoint(x, y); + x = _x; + y = _y; + } + + _rectIndexArray1Count = 0; + _rectIndexArray2Count = 0; + _pointsCount = 0; + + _x = destX; + _y = destY; + + adjustPathPoint(_x, _y); + destRectIndex = findPathRectAtPoint(_x, _y); + sourceRectIndex = findPathRectAtPoint(x, y); + if ( sourceRectIndex != -1 ) { + if ( destRectIndex != sourceRectIndex ) { + while ( 1 ) { + do { + _rectIndexArray2[_rectIndexArray2Count++] = sourceRectIndex; + sourceRectIndex = findNextPathRect(sourceRectIndex); + _pointsCount++; + } while ( sourceRectIndex != -1 && sourceRectIndex != destRectIndex ); + if ( sourceRectIndex != -1 && sourceRectIndex == destRectIndex ) + break; + _rectIndexArray1[_rectIndexArray1Count++] = _rectIndexArray2[--_rectIndexArray2Count]; + _pointsCount -= 2; + sourceRectIndex = _rectIndexArray2[--_rectIndexArray2Count]; + } + sourceRectIndex = 0; + while ( sourceRectIndex < _pointsCount ) { + pointsArray[pointsCount++] = _pointsArray[sourceRectIndex].y; + pointsArray[pointsCount++] = _pointsArray[sourceRectIndex].x; + index++; + sourceRectIndex++; + } + } + + pointsArray[pointsCount++] = _y; + pointsArray[pointsCount++] = _x; + + pointsArray[0] = 0; + pointsArray[1] = index + 1; + } + + debug(0, "SegmentMap::findPath() count = %d", pointsArray[1]); + + /* + int sx = x, sy = y; + LineData ld; + ld.pitch = _vm->_sceneWidth; + ld.surf = _vm->_screen->_backScreen; + for (int16 i = 0; i < pointsArray[1] * 2; i+=2) { + debug(0, "x = %d; y = %d", pointsArray[3+i], pointsArray[2+i]); + Graphics::drawLine(sx, sy, pointsArray[3+i], pointsArray[2+i], 0xFF, plotProc, &ld); + sx = pointsArray[3+i]; + sy = pointsArray[2+i]; + } + */ + +} + +int8 SegmentMap::getScalingAtPoint(int16 x, int16 y) { + int8 scaling = 0; + for (uint i = 0; i < _infoRects.size(); i++) { + if (_infoRects[i].id == 0 && + y >= _infoRects[i].y && y <= _infoRects[i].y + _infoRects[i].height && + x >= _infoRects[i].x && x <= _infoRects[i].x + _infoRects[i].width) { + char topScaling = (char)_infoRects[i].b; + char bottomScaling = (char)_infoRects[i].c; + if (y - _infoRects[i].y > 0) { + scaling = (ABS(y - _infoRects[i].y) * (bottomScaling - topScaling) / _infoRects[i].height) + topScaling; + } + } + } + return scaling; +} + +void SegmentMap::getRgbModifiertAtPoint(int16 x, int16 y, int16 id, byte &r, byte &g, byte &b) { + r = 0; + g = 0; + b = 0; + for (uint i = 0; i < _infoRects.size(); i++) { + if (_infoRects[i].id == id && + y >= _infoRects[i].y && y <= _infoRects[i].y + _infoRects[i].height && + x >= _infoRects[i].x && x <= _infoRects[i].x + _infoRects[i].width) { + + r = _infoRects[i].a; + g = _infoRects[i].b; + b = _infoRects[i].c; + } + } + debug(0, "SegmentMap::getRgbModifiertAtPoint() r: %d; g: %d; b: %d", r, g, b); +} + +void SegmentMap::restoreMasksBySprite(SpriteDrawItem *sprite) { + // TODO: This needs more optimization + for (uint i = 0; i < _maskRects.size(); i++) { + +#if 0 + if ( *(__int16 *)((char *)&spriteDrawList[0].y2 + v5) <= (unsigned __int16)v3->ybottom ) + { + if ( (unsigned __int16)(*(__int16 *)((char *)&spriteDrawList[0].height + v5) + + *(__int16 *)((char *)&spriteDrawList[0].y + v5)) > v3->y ) + { + if ( (unsigned __int16)(v3->height + v3->y) > *(__int16 *)((char *)&spriteDrawList[0].y + v5) ) + { + if ( (unsigned __int16)(*(__int16 *)((char *)&spriteDrawList[0].width + v5) + + *(__int16 *)((char *)&spriteDrawList[0].x + v5)) > v3->x ) + { + if ( (unsigned __int16)(v3->width + v3->x) > *(__int16 *)((char *)&spriteDrawList[0].x + v5) ) + { + +#endif + + if (sprite->ybottom <= _maskRects[i].ybottom) { + restoreMask(i); + } + } + +} + +void SegmentMap::restoreMask(int16 index) { + // TODO: This needs more optimization + SegmapMaskRect *maskRect = &_maskRects[index]; + + int16 maskX = maskRect->x, maskY = maskRect->y; + int16 skipX = 0; + int16 x = maskRect->x - _vm->_cameraX; + int16 y = maskRect->y - _vm->_cameraY; + int16 width = maskRect->width; + int16 height = maskRect->height; + byte *mask = _maskRectData + maskRect->maskOffset; + + debug(0, "SegmentMap::restoreMask() screenX = %d; screenY = %d; maskX = %d; maskY = %d", + x, y, maskRect->x, maskRect->y); + + // Not on screen, skip + if (x + width < 0 || y + height < 0 || x >= 640 || y >= _vm->_cameraHeight) + return; + + if (x < 0) { + skipX = -x; + x = 0; + } + + if (y < 0) { + int16 skipY = -y; + for (int16 h = 0; h < skipY; h++) { + int16 w = width; + while (w > 0) { + w -= (*mask++) & 0x7F; + } + } + y = 0; + height -= skipY; + maskY += skipY; + } + + if (x + width >= 640) { + width -= x + width - 640; + } + + if (y + height >= _vm->_cameraHeight) { + height -= y + height - _vm->_cameraHeight; + } + + byte *backScreen = _vm->_screen->_backScreen + maskX + (maskY * _vm->_sceneWidth); + byte *frontScreen = _vm->_screen->_frontScreen + x + (y * 640); + + for (int16 h = 0; h < height; h++) { + byte *src = backScreen; + byte *dst = frontScreen; + byte maskLine[640], *maskLineP = maskLine; + + int16 w = width; + while (w > 0) { + byte m = *mask++; + byte count = m & 0x7F; + if (m & 0x80) + memset(maskLineP, 1, count); + else + memset(maskLineP, 0, count); + maskLineP += count; + w -= count; + } + + src += skipX; + for (int16 c = skipX; c < width; c++) { + if (maskLine[c] == 1) + *dst = *src; + dst++; + src++; + } + + backScreen += _vm->_sceneWidth; + frontScreen += 640; + } + +} + +void SegmentMap::debugDrawRects(Graphics::Surface *surf) { + for (uint16 i = 0; i < _pathRects.size(); i++) { + SegmapPathRect pathRect = _pathRects[i]; + surf->frameRect( + Common::Rect(pathRect.x, pathRect.y, pathRect.x + pathRect.width, pathRect.y + pathRect.height), + 255); + } +} + +} // End of namespace Toltecs |