scummvm/saga/isomap.cpp

487 lines
12 KiB
C++
Raw Normal View History

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004-2005 The ScummVM project
*
* The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
2004-05-01 13:04:31 +00:00
// Isometric level module
2004-08-02 16:20:35 +00:00
#include "saga/saga.h"
2004-08-02 16:20:35 +00:00
#include "saga/gfx.h"
2004-08-02 16:20:35 +00:00
#include "saga/isomap.h"
#include "saga/stream.h"
namespace Saga {
IsoMap::IsoMap(SagaEngine *vm) : _vm(vm) {
_tileData = NULL;
_tilesCount = 0;
_tilePlatformList = NULL;
_tilePlatformsCount = 0;
_metaTileList = NULL;
_metaTilesCount = 0;
_multiTable = NULL;
_multiCount = 0;
_viewScroll.x = (128 - 8) * 16;
_viewScroll.x = (128 - 8) * 16 - 64;
2005-02-11 22:18:37 +00:00
_viewDiff = 1;
}
void IsoMap::loadImages(const byte *resourcePointer, size_t resourceLength) {
IsoTileData *tileData;
uint16 i;
if (resourceLength == 0) {
error("IsoMap::loadImages wrong resourceLength");
}
_tileData = (byte*)malloc(resourceLength);
_tileDataLength = resourceLength;
memcpy(_tileData, resourcePointer, resourceLength);
MemoryReadStreamEndian readS(_tileData, _tileDataLength, IS_BIG_ENDIAN);
readS.readUint16(); // skip
_tilesCount = readS.readUint16();
_tilesCount = _tilesCount / SAGA_ISOTILEDATA_LEN;
readS.seek(0);
_tilesTable = (IsoTileData *)malloc(_tilesCount * sizeof(*_tilesTable));
if (_tilesTable == NULL) {
memoryError("IsoMap::loadImages");
}
for (i = 0; i < _tilesCount; i++) {
tileData = &_tilesTable[i];
tileData->height = readS.readByte();
tileData->attributes = readS.readByte();
tileData->offset = readS.readUint16();
tileData->terrainMask = readS.readSint16();
tileData->FGBGAttr = readS.readByte();
readS.readByte(); //skip
}
}
void IsoMap::loadPlatforms(const byte * resourcePointer, size_t resourceLength) {
TilePlatformData *tilePlatformData;
uint16 i, x, y;
if (resourceLength == 0) {
error("IsoMap::loadPlatforms wrong resourceLength");
}
MemoryReadStreamEndian readS(resourcePointer, resourceLength, IS_BIG_ENDIAN);
_tilePlatformsCount = resourceLength / SAGA_TILEPLATFORMDATA_LEN;
_tilePlatformList = (TilePlatformData *)malloc(_tilePlatformsCount * sizeof(*_tilePlatformList));
if (_tilePlatformList == NULL) {
memoryError("IsoMap::loadPlatforms");
}
for (i = 0; i < _tilePlatformsCount; i++) {
tilePlatformData = &_tilePlatformList[i];
tilePlatformData->metaTile = readS.readSint16();
tilePlatformData->height = readS.readSint16();
tilePlatformData->highestPixel = readS.readSint16();
tilePlatformData->vBits = readS.readByte();
tilePlatformData->uBits = readS.readByte();
for (x = 0; x < SAGA_PLATFORM_W; x++) {
for (y = 0; y < SAGA_PLATFORM_W; y++) {
tilePlatformData->tiles[x][y] = readS.readSint16();
}
}
}
}
void IsoMap::loadMap(const byte * resourcePointer, size_t resourceLength) {
uint16 x, y;
if (resourceLength != SAGA_TILEMAP_LEN) {
error("IsoMap::loadMap wrong resourceLength");
}
MemoryReadStreamEndian readS(resourcePointer, resourceLength, IS_BIG_ENDIAN);
_tileMap.edgeType = readS.readByte();
readS.readByte(); //skip
for (x = 0; x < SAGA_TILEMAP_W; x++) {
for (y = 0; y < SAGA_TILEMAP_H; y++) {
_tileMap.tilePlatforms[x][y] = readS.readSint16();
}
}
}
void IsoMap::loadMetaTiles(const byte * resourcePointer, size_t resourceLength) {
MetaTileData *metaTileData;
uint16 i, j;
if (resourceLength == 0) {
error("IsoMap::loadMetaTiles wrong resourceLength");
}
MemoryReadStreamEndian readS(resourcePointer, resourceLength, IS_BIG_ENDIAN);
_metaTilesCount = resourceLength / SAGA_METATILEDATA_LEN;
_metaTileList = (MetaTileData *)malloc(_metaTilesCount * sizeof(*_metaTileList));
if (_metaTileList == NULL) {
memoryError("IsoMap::loadMetaTiles");
}
for (i = 0; i < _metaTilesCount; i++) {
metaTileData = &_metaTileList[i];
metaTileData->highestPlatform = readS.readUint16();
metaTileData->highestPixel = readS.readUint16();
for (j = 0; j < SAGA_MAX_PLATFORM_H; j++) {
metaTileData->stack[j] = readS.readSint16();
}
}
}
void IsoMap::loadMulti(const byte * resourcePointer, size_t resourceLength) {
MultiTileEntryData *multiTileEntryData;
uint16 i;
if (resourceLength < 2) {
error("IsoMap::loadMetaTiles wrong resourceLength");
}
MemoryReadStreamEndian readS(resourcePointer, resourceLength, IS_BIG_ENDIAN);
_multiCount = readS.readUint16();
_multiTable = (MultiTileEntryData *)malloc(_multiCount * sizeof(*_multiTable));
if (_multiTable == NULL) {
memoryError("IsoMap::loadMulti");
}
debug(0,"resourceLength=%d but should be %d",resourceLength, 14*_multiCount + 2);
for (i = 0; i < _multiCount; i++) {
multiTileEntryData = &_multiTable[i];
readS.readUint32();//skip
multiTileEntryData->offset = readS.readSint16();
multiTileEntryData->u = readS.readByte();
multiTileEntryData->v = readS.readByte();
multiTileEntryData->h = readS.readByte();
multiTileEntryData->uSize = readS.readByte();
multiTileEntryData->vSize = readS.readByte();
multiTileEntryData->numStates = readS.readByte();
multiTileEntryData->currentState = readS.readByte();
readS.readByte();//skip
}
}
void IsoMap::freeMem() {
free(_tileData);
_tilesCount = 0;
free(_tilePlatformList);
_tilePlatformsCount = 0;
free(_metaTileList);
_metaTilesCount = 0;
free(_multiTable);
_multiCount = 0;
}
int IsoMap::draw(SURFACE *ds) {
Rect isoRect(_vm->getDisplayWidth(), _vm->getDisplayInfo().sceneHeight);
drawRect(ds, &isoRect, 0);
_tileClip = isoRect;
drawTiles(ds);
return SUCCESS;
}
void IsoMap::drawTiles(SURFACE *ds) {
Point view1;
2005-02-11 22:18:37 +00:00
Point fineScroll;
Point metaTileY;
Point metaTileX;
int16 u0, v0,
u1, v1,
u2, v2,
uc, vc;
int16 workAreaWidth;
int16 workAreaHeight;
uint16 metaTileIndex;
_tileScroll.x = _viewScroll.x >> 4;
_tileScroll.y = _viewScroll.y >> 4;
2005-02-11 22:18:37 +00:00
fineScroll.x = _viewScroll.x & 0xf;
fineScroll.y = _viewScroll.y & 0xf;
view1.x = _tileScroll.x - (8 * SAGA_TILEMAP_W);
view1.y = (8 * SAGA_TILEMAP_W) - _tileScroll.y;
u0 = ((view1.y + 64) * 2 + view1.x) >> 4;
v0 = ((view1.y + 64) * 2 - view1.x) >> 4;
2005-02-11 22:18:37 +00:00
metaTileY.x = (u0 - v0) * 128 - (view1.x * 16 + fineScroll.x);
metaTileY.y = (view1.y * 16 - fineScroll.y) - (u0 + v0) * 64;
workAreaWidth = _vm->getDisplayWidth() + 128;
workAreaHeight = _vm->getDisplayInfo().sceneHeight + 128 + 80;
for (u1 = u0, v1 = v0; metaTileY.y < workAreaHeight; u1--, v1-- ) {
metaTileX = metaTileY;
for (u2 = u1, v2 = v1; metaTileX.x < workAreaWidth; u2++, v2--, metaTileX.x += 256) {
uc = u2 & (SAGA_TILEMAP_W - 1);
vc = v2 & (SAGA_TILEMAP_W - 1);
if (uc != u2 || vc != v2) {
metaTileIndex = 0;
switch ( _tileMap.edgeType) {
case kEdgeTypeBlack:
continue;
case kEdgeTypeFill0:
break;
case kEdgeTypeFill1:
metaTileIndex = 1;
break;
case kEdgeTypeRpt:
uc = clamp( 0, u2, SAGA_TILEMAP_W - 1);
vc = clamp( 0, v2, SAGA_TILEMAP_W - 1);
metaTileIndex = _tileMap.tilePlatforms[uc][vc];
break;
case kEdgeTypeWrap:
metaTileIndex = _tileMap.tilePlatforms[uc][vc];
break;
}
} else {
metaTileIndex = _tileMap.tilePlatforms[uc][vc];
}
drawMetaTile(ds, metaTileIndex, metaTileX, u2 << 3, v2 << 3);
}
metaTileY.y += 64;
metaTileX = metaTileY;
metaTileX.x -= 128;
for (u2 = u1 - 1, v2 = v1; metaTileX.x < workAreaWidth; u2++, v2--, metaTileX.x += 256) {
uc = u2 & (SAGA_TILEMAP_W - 1);
vc = v2 & (SAGA_TILEMAP_W - 1);
if (uc != u2 || vc != v2) {
metaTileIndex = 0;
switch ( _tileMap.edgeType) {
case kEdgeTypeBlack:
continue;
case kEdgeTypeFill0:
break;
case kEdgeTypeFill1:
metaTileIndex = 1;
break;
case kEdgeTypeRpt:
uc = clamp( 0, u2, SAGA_TILEMAP_W - 1);
vc = clamp( 0, v2, SAGA_TILEMAP_W - 1);
metaTileIndex = _tileMap.tilePlatforms[uc][vc];
break;
case kEdgeTypeWrap:
metaTileIndex = _tileMap.tilePlatforms[uc][vc];
break;
}
} else {
metaTileIndex = _tileMap.tilePlatforms[uc][vc];
}
drawMetaTile(ds, metaTileIndex, metaTileX, u2 << 3, v2 << 3);
}
metaTileY.y += 64;
}
}
void IsoMap::drawMetaTile(SURFACE *ds, uint16 metaTileIndex, const Point &point, int16 absU, int16 absV) {
MetaTileData * metaTile;
uint16 high;
int16 platformIndex;
Point platformPoint;
platformPoint = point;
if (_metaTilesCount <= metaTileIndex) {
error("IsoMap::drawMetaTile wrong metaTileIndex");
}
metaTile = &_metaTileList[metaTileIndex];
if (metaTile->highestPlatform > 18) {
metaTile->highestPlatform = 0;
}
for (high = 0; high <= metaTile->highestPlatform; high++, platformPoint.y -= 8) {
assert(SAGA_MAX_PLATFORM_H > high);
platformIndex = metaTile->stack[high];
if (platformIndex >= 0) {
drawPlatform( ds, platformIndex, platformPoint, absU, absV, high );
}
}
}
void IsoMap::drawPlatform(SURFACE *ds, uint16 platformIndex, const Point &point, int16 absU, int16 absV, int16 absH) {
TilePlatformData *tilePlatform;
int16 u, v;
Point s;
Point s0;
int16 tileIndex;
if (_tilePlatformsCount <= platformIndex) {
error("IsoMap::drawPlatform wrong platformIndex");
}
tilePlatform = &_tilePlatformList[platformIndex];
if ((point.y <= _tileClip.top) || (point.y - SAGA_MAX_TILE_H - SAGA_PLATFORM_W * SAGA_TILE_NOMINAL_H >= _tileClip.bottom)) {
return;
}
s0 = point;
s0.y -= (((SAGA_PLATFORM_W - 1) + (SAGA_PLATFORM_W - 1)) * 8);
for (v = SAGA_PLATFORM_W - 1; v >= 0 && s0.y - SAGA_MAX_TILE_H < _tileClip.bottom && s0.x - 128 < _tileClip.right; v--, s0.x += 16, s0.y += 8) {
if ((tilePlatform->vBits & (1 << v)) == 0) {
continue;
}
if (s0.x + 128 + 32 < _tileClip.left) {
continue;
}
s = s0;
for (u = SAGA_PLATFORM_W - 1; u >= 0 && s.x + 32 > _tileClip.left && s.y - SAGA_MAX_TILE_H < _tileClip.bottom; u--, s.x -= 16, s.y += 8 ) {
if (s.x < _tileClip.right && s.y > _tileClip.top) {
tileIndex = tilePlatform->tiles[u][v];
if (tileIndex > 1) {
if (tileIndex & SAGA_MULTI_TILE) {
warning("SAGA_MULTI_TILE"); //TODO: do it !
}
drawTile(ds, tileIndex, s);
}
}
}
}
}
void IsoMap::drawTile(SURFACE *ds, uint16 tileIndex, const Point &point) {
const byte *tilePointer;
const byte *readPointer;
byte *drawPointer;
Point drawPoint;
int height;
int widthCount = 0;
int row, col, count, lowBound;
int bgRunCount;
int fgRunCount;
if (tileIndex >= _tilesCount) {
error("IsoMap::drawTile wrong tileIndex");
}
if (point.x + SAGA_ISOTILE_WIDTH < _tileClip.left) {
return;
}
if (point.x - SAGA_ISOTILE_WIDTH >= _tileClip.right) {
return;
}
tilePointer = _tileData + _tilesTable[tileIndex].offset;
height = _tilesTable[tileIndex].height;
if ((height <= 8) || (height > 64)) {
return;
}
drawPoint = point;
drawPoint.y -= height;
if (drawPoint.y >= _tileClip.bottom) {
return;
}
readPointer = tilePointer;
lowBound = MIN((int)(drawPoint.y + height), (int)_tileClip.bottom);
for (row = drawPoint.y; row < lowBound; row++) {
widthCount = 0;
if (row >= _tileClip.top) {
drawPointer = (byte *)ds->pixels + drawPoint.x + (row * ds->pitch);
col = drawPoint.x;
for (;;) {
bgRunCount = *readPointer++;
widthCount += bgRunCount;
if (widthCount >= SAGA_ISOTILE_WIDTH) {
break;
}
drawPointer += bgRunCount;
col += bgRunCount;
fgRunCount = *readPointer++;
widthCount += fgRunCount;
count = 0;
while ((col < _tileClip.left) && (count < fgRunCount)) {
count++;
col++;
}
while ((col < _tileClip.right) && (count < fgRunCount)) {
2005-02-11 22:18:37 +00:00
assert((uint)ds->pixels <= (uint)(drawPointer + count));
assert(((uint)ds->pixels + (ds->pitch * _vm->getDisplayWidth())) > (uint)(drawPointer + count));
drawPointer[count] = readPointer[count];
count++;
col++;
}
readPointer += fgRunCount;
drawPointer += fgRunCount;
}
} else {
for (;;) {
bgRunCount = *readPointer++;
widthCount += bgRunCount;
if (widthCount >= SAGA_ISOTILE_WIDTH) {
break;
}
fgRunCount = *readPointer++;
widthCount += fgRunCount;
readPointer += fgRunCount;
}
}
}
}
} // End of namespace Saga