Files
2026-02-02 04:50:13 +01:00

212 lines
6.6 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 "ultima/ultima4/core/config.h"
#include "ultima/ultima4/gfx/image.h"
#include "ultima/ultima4/gfx/imagemgr.h"
#include "ultima/ultima4/core/settings.h"
#include "ultima/ultima4/core/utils.h"
#include "ultima/ultima4/gfx/screen.h"
#include "ultima/ultima4/map/tile.h"
#include "ultima/ultima4/map/tileanim.h"
#include "ultima/ultima4/map/tileset.h"
#include "ultima/ultima4/views/tileview.h"
#include "ultima/ultima4/ultima4.h"
#include "common/system.h"
namespace Ultima {
namespace Ultima4 {
TileView::TileView(int x, int y, int columns, int rows) :
View(x, y, columns * TILE_WIDTH, rows * TILE_HEIGHT) {
_columns = columns;
_rows = rows;
_tileWidth = TILE_WIDTH;
_tileHeight = TILE_HEIGHT;
_tileSet = g_tileSets->get("base");
_animated = Image::create(SCALED(_tileWidth), SCALED(_tileHeight), g_system->getScreenFormat());
_dest = nullptr;
}
TileView::TileView(int x, int y, int columns, int rows, const Common::String &tileset) :
View(x, y, columns * TILE_WIDTH, rows * TILE_HEIGHT) {
_columns = columns;
_rows = rows;
_tileWidth = TILE_WIDTH;
_tileHeight = TILE_HEIGHT;
_tileSet = g_tileSets->get(tileset);
_animated = Image::create(SCALED(_tileWidth), SCALED(_tileHeight), g_system->getScreenFormat());
_dest = nullptr;
}
TileView::~TileView() {
delete _animated;
}
void TileView::reinit() {
View::reinit();
_tileSet = g_tileSets->get("base");
// Scratchpad needs to be re-inited if we rescale...
if (_animated) {
delete _animated;
_animated = nullptr;
}
_animated = Image::create(SCALED(_tileWidth), SCALED(_tileHeight), _dest ? _dest->format() : g_system->getScreenFormat());
}
void TileView::loadTile(MapTile &mapTile) {
// This attempts to preload tiles in advance
Tile *tile = _tileSet->get(mapTile._id);
if (tile) {
tile->getImage();
}
// But may fail if the tiles don't exist directly in the expected imagesets
}
void TileView::drawTile(MapTile &mapTile, bool focus, int x, int y) {
Tile *tile = _tileSet->get(mapTile._id);
Image *image = tile->getImage();
assertMsg(x < _columns, "x value of %d out of range", x);
assertMsg(y < _rows, "y value of %d out of range", y);
// Blank scratch pad
_animated->fillRect(0, 0, SCALED(_tileWidth), SCALED(_tileHeight), 0, 0, 0, 255);
// Draw blackness on the tile.
_animated->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
SCALED(y * _tileHeight + _bounds.top), 0, 0,
SCALED(_tileWidth), SCALED(_tileHeight));
// Draw the tile to the screen
if (tile->getAnim()) {
// First, create our animated version of the tile
#ifdef IOS_ULTIMA4
animated->clearImageContents();
#endif
tile->getAnim()->draw(_animated, tile, mapTile, DIR_NONE);
// Then draw it to the screen
_animated->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
SCALED(y * _tileHeight + _bounds.top), 0, 0,
SCALED(_tileWidth), SCALED(_tileHeight));
} else {
image->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
SCALED(y * _tileHeight + _bounds.top),
0, SCALED(_tileHeight * mapTile._frame),
SCALED(_tileWidth), SCALED(_tileHeight));
}
// Draw the focus around the tile if it has the focus
if (focus)
drawFocus(x, y);
}
void TileView::drawTile(Std::vector<MapTile> &tiles, bool focus, int x, int y) {
assertMsg(x < _columns, "x value of %d out of range", x);
assertMsg(y < _rows, "y value of %d out of range", y);
// Clear tile contents
_animated->fillRect(0, 0, SCALED(_tileWidth), SCALED(_tileHeight), 0, 0, 0, 255);
_animated->drawSubRectOn(_dest,
SCALED(x * _tileWidth + _bounds.left), SCALED(y * _tileHeight + _bounds.top),
0, 0,
SCALED(_tileWidth), SCALED(_tileHeight)
);
// Iterate through rendering each of the needed tiles
for (int t = tiles.size() - 1; t >= 0; --t) {
MapTile &frontTile = tiles[t];
Tile *frontTileType = _tileSet->get(frontTile._id);
if (!frontTileType) {
// TODO: This leads to an error. It happens after graphics mode changes.
return;
}
// Get the image for the tile
Image *image = frontTileType->getImage();
// Draw the tile to the screen
if (frontTileType->getAnim()) {
// First, create our animated version of the tile
frontTileType->getAnim()->draw(_animated, frontTileType, frontTile, DIR_NONE);
} else {
if (!image)
// FIXME: This is a problem, error message it.
return;
image->drawSubRectOn(_animated, 0, 0,
0, SCALED(_tileHeight * frontTile._frame),
SCALED(_tileWidth), SCALED(_tileHeight)
);
}
// Then draw it to the screen
_animated->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
SCALED(y * _tileHeight + _bounds.top), 0, 0,
SCALED(_tileWidth), SCALED(_tileHeight)
);
}
// Draw the focus around the tile if it has the focus
if (focus)
drawFocus(x, y);
}
void TileView::drawFocus(int x, int y) {
assertMsg(x < _columns, "x value of %d out of range", x);
assertMsg(y < _rows, "y value of %d out of range", y);
// Draw the focus rectangle around the tile
if ((g_screen->_currentCycle * 4 / SCR_CYCLE_PER_SECOND) % 2) {
// left edge
_screen->fillRect(SCALED(x * _tileWidth + _bounds.left),
SCALED(y * _tileHeight + _bounds.top),
SCALED(2), SCALED(_tileHeight), 0xff, 0xff, 0xff);
// top edge
_screen->fillRect(SCALED(x * _tileWidth + _bounds.left),
SCALED(y * _tileHeight + _bounds.top),
SCALED(_tileWidth), SCALED(2),
0xff, 0xff, 0xff);
// Right edge
_screen->fillRect(SCALED((x + 1) * _tileWidth + _bounds.left - 2),
SCALED(y * _tileHeight + _bounds.top),
SCALED(2), SCALED(_tileHeight),
0xff, 0xff, 0xff);
// Bottom edge
_screen->fillRect(SCALED(x * _tileWidth + _bounds.left),
SCALED((y + 1) * _tileHeight + _bounds.top - 2),
SCALED(_tileWidth), SCALED(2),
0xff, 0xff, 0xff);
}
}
void TileView::setTileset(Tileset *tileset) {
this->_tileSet = tileset;
}
} // End of namespace Ultima4
} // End of namespace Ultima