2018-11-07 22:27:05 +11:00
|
|
|
/* 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/memstream.h>
|
|
|
|
#include "graphics/screen.h"
|
|
|
|
#include "common/endian.h"
|
|
|
|
#include "background.h"
|
|
|
|
|
|
|
|
namespace Dragons {
|
|
|
|
|
|
|
|
#define TILE_WIDTH 32
|
|
|
|
#define TILE_HEIGHT 8
|
2019-04-14 14:44:56 +10:00
|
|
|
#define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT)
|
2018-11-07 22:27:05 +11:00
|
|
|
|
|
|
|
|
|
|
|
void Dragons::PriorityLayer::load(TileMap &tileMap, byte *tiles) {
|
|
|
|
_width = tileMap.w * TILE_WIDTH;
|
|
|
|
_height = tileMap.h * TILE_HEIGHT;
|
|
|
|
_mapWidth = tileMap.w;
|
|
|
|
_mapHeight = tileMap.h;
|
|
|
|
size_t tileSize = (size_t)tileMap.tileIndexOffset * TILE_SIZE;
|
|
|
|
_map = new byte[tileMap.size];
|
2019-04-18 09:00:32 +10:00
|
|
|
_mapBase = new byte[tileMap.size];
|
2018-11-07 22:27:05 +11:00
|
|
|
_values = new byte[tileSize];
|
|
|
|
|
|
|
|
memcpy(_map, tileMap.map, tileMap.size);
|
2019-04-18 09:00:32 +10:00
|
|
|
memcpy(_mapBase, tileMap.map, tileMap.size);
|
2018-11-07 22:27:05 +11:00
|
|
|
memcpy(_values, tiles, tileSize);
|
|
|
|
}
|
|
|
|
|
2019-01-05 13:26:55 +11:00
|
|
|
int16 PriorityLayer::getPriority(Common::Point pos) {
|
2018-11-07 22:27:05 +11:00
|
|
|
pos.x = CLIP<int16>(pos.x, 0, _width - 1);
|
|
|
|
pos.y = CLIP<int16>(pos.y, 0, _height - 1);
|
2019-01-15 07:19:54 +11:00
|
|
|
const int16 tx = pos.x / TILE_WIDTH, sx = pos.x % TILE_WIDTH;
|
|
|
|
const int16 ty = pos.y / TILE_HEIGHT, sy = pos.y % TILE_HEIGHT;
|
|
|
|
uint16 mapIndex = READ_LE_UINT16(_map + 2 * (tx + ty * _mapWidth));
|
2018-11-07 22:27:05 +11:00
|
|
|
|
2019-04-14 14:44:56 +10:00
|
|
|
//
|
|
|
|
// byte priority = *(byte *)((((uint)*(ushort *)
|
|
|
|
// (((int)pos.x / 32) * 2 +
|
|
|
|
// ((int)pos.y / 8) * (uint)_mapWidth * 2 +
|
|
|
|
// _map) * 32) * 8) +
|
|
|
|
// _values + (((int)pos.y % 8) * 32) +
|
|
|
|
// ((int)pos.x % 32));
|
|
|
|
return _values[mapIndex * TILE_WIDTH * TILE_HEIGHT + sx + sy * TILE_WIDTH] + 1;
|
2018-11-07 22:27:05 +11:00
|
|
|
}
|
|
|
|
|
2019-04-18 09:00:32 +10:00
|
|
|
void PriorityLayer::overlayTileMap(byte *data, int16 x, int16 y, int16 w, int16 h) {
|
|
|
|
byte *ptr = _map + (x + y * _mapWidth) * 2;
|
|
|
|
byte *src = data;
|
|
|
|
for (int i=0;i < h; i++) {
|
|
|
|
memcpy(ptr, src, w * 2);
|
|
|
|
src += w * 2;
|
|
|
|
ptr += _mapWidth * 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PriorityLayer::restoreTileMap(int16 x, int16 y, int16 w, int16 h) {
|
|
|
|
byte *ptr = _map + (x + y * _mapWidth) * 2;
|
|
|
|
byte *src = _mapBase + (x + y * _mapWidth) * 2;
|
|
|
|
for (int i=0;i < h; i++) {
|
|
|
|
memcpy(ptr, src, w * 2);
|
|
|
|
src += _mapWidth * 2;
|
|
|
|
ptr += _mapWidth * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-03-01 20:04:38 +11:00
|
|
|
Background::Background() : _priorityLayer(0), _points1(0), _points2(0), _data(0) {
|
2019-07-28 14:48:34 +10:00
|
|
|
_layerSurface[0] = NULL;
|
|
|
|
_layerSurface[1] = NULL;
|
|
|
|
_layerSurface[2] = NULL;
|
2019-11-01 21:13:37 +11:00
|
|
|
_xOffset = 0;
|
2019-03-01 20:04:38 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
Background::~Background() {
|
|
|
|
if(_data) {
|
|
|
|
delete _data;
|
|
|
|
}
|
2019-07-28 14:48:34 +10:00
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
if (_layerSurface[i]) {
|
|
|
|
_layerSurface[i]->free();
|
|
|
|
delete _layerSurface[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-01 20:04:38 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Background::load(byte *dataStart, uint32 size) {
|
|
|
|
Common::MemoryReadStream stream(dataStart, size, DisposeAfterUse::NO);
|
|
|
|
_data = dataStart;
|
|
|
|
|
2018-11-07 22:27:05 +11:00
|
|
|
stream.read(_palette, 512);
|
2019-10-12 10:07:24 +11:00
|
|
|
_palette[0] = 0x00; //FIXME update palette
|
|
|
|
_palette[1] = 0x00;
|
2018-11-07 22:27:05 +11:00
|
|
|
|
2019-02-13 20:46:14 +11:00
|
|
|
_points1 = loadPoints(stream); // 0x200
|
|
|
|
_points2 = loadPoints(stream); // 0x280
|
2018-11-07 22:27:05 +11:00
|
|
|
stream.seek(0x305);
|
|
|
|
uint8 tileindexOffset = stream.readByte();
|
|
|
|
stream.seek(0x308);
|
|
|
|
|
|
|
|
uint32 tilemapOffset = 0x324;
|
|
|
|
for(int i=0;i< 3;i++) {
|
2019-03-01 20:04:38 +11:00
|
|
|
_tileMap[i].w = stream.readUint16LE();
|
|
|
|
_tileMap[i].h = stream.readUint16LE();
|
|
|
|
_tileMap[i].size = stream.readUint32LE();
|
|
|
|
_tileMap[i].map = dataStart + tilemapOffset;
|
|
|
|
_tileMap[i].tileIndexOffset = tileindexOffset;
|
|
|
|
debug("Tilemap (%d,%d) map: %X", _tileMap[i].w, _tileMap[i].h, tilemapOffset);
|
|
|
|
|
|
|
|
tilemapOffset += _tileMap[i].size;
|
2018-11-07 22:27:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 finalSize = stream.readUint32LE();
|
|
|
|
|
2019-03-01 20:04:38 +11:00
|
|
|
TileMap priorityTilemap;
|
|
|
|
|
|
|
|
priorityTilemap.w = _tileMap[0].w;
|
|
|
|
priorityTilemap.h = _tileMap[0].h;
|
|
|
|
priorityTilemap.size = _tileMap[0].size;
|
|
|
|
priorityTilemap.map = dataStart + tilemapOffset;
|
|
|
|
priorityTilemap.tileIndexOffset = tileindexOffset;
|
2018-11-07 22:27:05 +11:00
|
|
|
|
|
|
|
uint32 tilesOffset = tilemapOffset + finalSize;
|
2019-01-15 07:19:54 +11:00
|
|
|
|
2019-03-01 20:04:38 +11:00
|
|
|
_tileDataOffset = _data + tilesOffset;
|
|
|
|
|
2019-01-15 07:19:54 +11:00
|
|
|
_priorityLayer = new PriorityLayer();
|
2019-03-01 20:04:38 +11:00
|
|
|
_priorityLayer->load(priorityTilemap, _tileDataOffset);
|
2019-01-15 07:19:54 +11:00
|
|
|
|
2018-11-07 22:27:05 +11:00
|
|
|
debug("Tiles: %X", tilesOffset);
|
2019-03-01 20:04:38 +11:00
|
|
|
debug("tileIndexOffset: %d", _tileMap[0].tileIndexOffset);
|
|
|
|
|
|
|
|
for(int i = 0; i < 3; i++) {
|
2019-07-28 14:48:34 +10:00
|
|
|
_layerSurface[i] = initGfxLayer(_tileMap[i]);
|
|
|
|
loadGfxLayer(_layerSurface[i], _tileMap[i], _tileDataOffset);
|
2019-03-01 20:04:38 +11:00
|
|
|
}
|
|
|
|
|
2019-07-27 16:46:37 +10:00
|
|
|
layerPriority[0] = 1;
|
|
|
|
layerPriority[1] = 2;
|
|
|
|
layerPriority[2] = 3;
|
|
|
|
|
2018-11-07 22:27:05 +11:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::Point *Background::loadPoints(Common::SeekableReadStream &stream) {
|
|
|
|
Common::Point *points = new Common::Point[0x20];
|
|
|
|
|
|
|
|
for (int i=0;i < 0x20;i++) {
|
|
|
|
points[i].x = stream.readUint16LE();
|
|
|
|
points[i].y = stream.readUint16LE();
|
|
|
|
}
|
|
|
|
|
|
|
|
return points;
|
|
|
|
}
|
|
|
|
|
2019-07-28 14:48:34 +10:00
|
|
|
Graphics::Surface *Background::initGfxLayer(TileMap &tileMap) {
|
2018-11-07 22:27:05 +11:00
|
|
|
Graphics::Surface *surface = new Graphics::Surface();
|
2019-10-25 23:17:02 +11:00
|
|
|
surface->create(tileMap.w * TILE_WIDTH, tileMap.h * TILE_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
|
2019-07-28 14:48:34 +10:00
|
|
|
return surface;
|
|
|
|
}
|
2018-11-07 22:27:05 +11:00
|
|
|
|
2019-07-28 14:48:34 +10:00
|
|
|
void Background::loadGfxLayer(Graphics::Surface *surface, TileMap &tileMap, byte *tiles) {
|
2018-11-07 22:27:05 +11:00
|
|
|
for(int y = 0; y < tileMap.h; y++) {
|
|
|
|
for(int x = 0; x < tileMap.w; x++) {
|
|
|
|
uint16 idx = READ_LE_UINT16(&tileMap.map[(y * tileMap.w + x) * 2]) + tileMap.tileIndexOffset;
|
2018-12-13 22:30:30 +11:00
|
|
|
//debug("tileIdx: %d", idx);
|
2019-05-02 22:12:04 +10:00
|
|
|
drawTileToSurface(surface, _palette, tiles + idx * 0x100, x * TILE_WIDTH, y * TILE_HEIGHT);
|
2018-11-07 22:27:05 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-02 22:12:04 +10:00
|
|
|
void drawTileToSurface(Graphics::Surface *surface, byte *palette, byte *tile, uint32 x, uint32 y) {
|
2018-11-07 22:27:05 +11:00
|
|
|
byte *pixels = (byte *)surface->getPixels();
|
2019-10-25 23:17:02 +11:00
|
|
|
if (surface->format.bpp() == 16) {
|
|
|
|
for(int ty = 0; ty < TILE_HEIGHT; ty++) {
|
|
|
|
for(int tx = 0; tx < TILE_WIDTH; tx++) {
|
|
|
|
uint32 cidx = *tile;
|
|
|
|
uint32 offset = (y + ty) * surface->pitch + (x + tx) * 2;
|
|
|
|
pixels[offset] = palette[cidx * 2];
|
|
|
|
pixels[offset + 1] = palette[cidx * 2 + 1];
|
|
|
|
tile++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int ty = 0; ty < TILE_HEIGHT; ty++) {
|
|
|
|
memcpy(&pixels[(y + ty) * surface->pitch + x], tile, TILE_WIDTH);
|
|
|
|
tile += TILE_WIDTH;
|
2018-11-07 22:27:05 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::Point Background::getPoint2(uint32 pointIndex) {
|
|
|
|
assert (pointIndex < 0x20);
|
|
|
|
return _points2[pointIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 Background::getWidth() {
|
2019-07-28 14:48:34 +10:00
|
|
|
assert (_layerSurface[0]);
|
|
|
|
return _layerSurface[0]->w;
|
2018-11-07 22:27:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16 Background::getHeight() {
|
2019-07-28 14:48:34 +10:00
|
|
|
assert (_layerSurface[0]);
|
|
|
|
return _layerSurface[0]->h;
|
2018-11-07 22:27:05 +11:00
|
|
|
}
|
|
|
|
|
2019-01-05 13:26:55 +11:00
|
|
|
int16 Background::getPriorityAtPoint(Common::Point pos) {
|
2019-03-01 20:04:38 +11:00
|
|
|
if (pos.x < 0 || pos.x >= getWidth() || pos.y < 0 || pos.y >= getHeight()) {
|
2019-01-05 13:26:55 +11:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
int16 priority = _priorityLayer->getPriority(pos);
|
2019-02-19 07:56:36 +11:00
|
|
|
return priority < 0x11 ? priority : 0;
|
2019-01-05 13:26:55 +11:00
|
|
|
}
|
|
|
|
|
2019-03-01 20:04:38 +11:00
|
|
|
void Background::overlayImage(uint16 layerNum, byte *data, int16 x, int16 y, int16 w, int16 h) {
|
|
|
|
for(int i = 0; i < h; i++ ) {
|
|
|
|
for(int j = 0; j < w; j++ ) {
|
|
|
|
int16 idx = READ_LE_UINT16(data) + _tileMap[layerNum].tileIndexOffset;
|
2019-07-28 14:48:34 +10:00
|
|
|
drawTileToSurface(_layerSurface[layerNum],
|
2019-05-02 22:12:04 +10:00
|
|
|
_palette,
|
2019-03-01 20:04:38 +11:00
|
|
|
_tileDataOffset + idx * 0x100,
|
|
|
|
(j + x) * TILE_WIDTH,
|
|
|
|
(i + y) * TILE_HEIGHT);
|
|
|
|
data += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-03 22:25:00 +11:00
|
|
|
void Background::restoreTiles(uint16 layerNum, int16 x, int16 y, int16 w, int16 h) {
|
|
|
|
int16 tmw = x + w;
|
|
|
|
int16 tmh = y + h;
|
|
|
|
for(int y = 0; y < tmh; y++) {
|
|
|
|
for(int x = 0; x < tmw; x++) {
|
|
|
|
uint16 idx = READ_LE_UINT16(&_tileMap[layerNum].map[(y * _tileMap[layerNum].w + x) * 2]) + _tileMap[layerNum].tileIndexOffset;
|
|
|
|
//debug("tileIdx: %d", idx);
|
2019-07-28 14:48:34 +10:00
|
|
|
drawTileToSurface(_layerSurface[layerNum], _palette, _tileDataOffset + idx * 0x100, x * TILE_WIDTH, y * TILE_HEIGHT);
|
2019-03-03 22:25:00 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-18 09:00:32 +10:00
|
|
|
void Background::overlayPriorityTileMap(byte *data, int16 x, int16 y, int16 w, int16 h) {
|
|
|
|
_priorityLayer->overlayTileMap(data, x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Background::restorePriorityTileMap(int16 x, int16 y, int16 w, int16 h) {
|
|
|
|
_priorityLayer->restoreTileMap(x, y, w, h);
|
|
|
|
}
|
|
|
|
|
2019-07-28 14:48:34 +10:00
|
|
|
void Background::setPalette(byte *newPalette) {
|
|
|
|
memcpy(_palette, newPalette, 512);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
loadGfxLayer(_layerSurface[i], _tileMap[i], _tileDataOffset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-01 21:13:37 +11:00
|
|
|
void Background::setXOffset(int16 xOffset) {
|
|
|
|
_xOffset = xOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
int16 Background::getXOffset() {
|
|
|
|
return _xOffset;
|
|
|
|
}
|
|
|
|
|
2018-11-07 22:27:05 +11:00
|
|
|
BackgroundResourceLoader::BackgroundResourceLoader(BigfileArchive *bigFileArchive, DragonRMS *dragonRMS) : _bigFileArchive(
|
2019-03-03 22:25:00 +11:00
|
|
|
bigFileArchive), _dragonRMS(dragonRMS) {}
|
2018-11-07 22:27:05 +11:00
|
|
|
|
|
|
|
Background *BackgroundResourceLoader::load(uint32 sceneId) {
|
|
|
|
char filename[] = "nnnn.scr";
|
|
|
|
memcpy(filename, _dragonRMS->getSceneName(sceneId), 4);
|
2019-05-02 22:12:04 +10:00
|
|
|
return load(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
Background *BackgroundResourceLoader::load(const char *filename) {
|
2018-11-07 22:27:05 +11:00
|
|
|
debug("Loading %s", filename);
|
|
|
|
uint32 size;
|
|
|
|
byte *scrData = _bigFileArchive->load(filename, size);
|
|
|
|
Background *bg = new Background();
|
2019-03-01 20:04:38 +11:00
|
|
|
bg->load(scrData, size);
|
2018-11-07 22:27:05 +11:00
|
|
|
return bg;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End of namespace Dragons
|