1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/ultima4/core/config.h"
24 #include "ultima/ultima4/gfx/image.h"
25 #include "ultima/ultima4/gfx/imagemgr.h"
26 #include "ultima/ultima4/core/settings.h"
27 #include "ultima/ultima4/core/utils.h"
28 #include "ultima/ultima4/gfx/screen.h"
29 #include "ultima/ultima4/map/tile.h"
30 #include "ultima/ultima4/map/tileanim.h"
31 #include "ultima/ultima4/map/tileset.h"
32 #include "ultima/ultima4/views/tileview.h"
33 #include "ultima/ultima4/ultima4.h"
34
35 namespace Ultima {
36 namespace Ultima4 {
37
TileView(int x,int y,int columns,int rows)38 TileView::TileView(int x, int y, int columns, int rows) :
39 View(x, y, columns * TILE_WIDTH, rows * TILE_HEIGHT) {
40 _columns = columns;
41 _rows = rows;
42 _tileWidth = TILE_WIDTH;
43 _tileHeight = TILE_HEIGHT;
44 _tileSet = g_tileSets->get("base");
45 _animated = Image::create(SCALED(_tileWidth), SCALED(_tileHeight), false, Image::HARDWARE);
46 _dest = nullptr;
47 }
48
TileView(int x,int y,int columns,int rows,const Common::String & tileset)49 TileView::TileView(int x, int y, int columns, int rows, const Common::String &tileset) :
50 View(x, y, columns * TILE_WIDTH, rows * TILE_HEIGHT) {
51 _columns = columns;
52 _rows = rows;
53 _tileWidth = TILE_WIDTH;
54 _tileHeight = TILE_HEIGHT;
55 _tileSet = g_tileSets->get(tileset);
56 _animated = Image::create(SCALED(_tileWidth), SCALED(_tileHeight), false, Image::HARDWARE);
57 _dest = nullptr;
58 }
59
~TileView()60 TileView::~TileView() {
61 delete _animated;
62 }
63
reinit()64 void TileView::reinit() {
65 View::reinit();
66 _tileSet = g_tileSets->get("base");
67
68 // Scratchpad needs to be re-inited if we rescale...
69 if (_animated) {
70 delete _animated;
71 _animated = nullptr;
72 }
73 _animated = Image::create(SCALED(_tileWidth), SCALED(_tileHeight), false, Image::HARDWARE);
74 }
75
loadTile(MapTile & mapTile)76 void TileView::loadTile(MapTile &mapTile) {
77 // This attempts to preload tiles in advance
78 Tile *tile = _tileSet->get(mapTile._id);
79 if (tile) {
80 tile->getImage();
81 }
82 // But may fail if the tiles don't exist directly in the expected imagesets
83 }
84
drawTile(MapTile & mapTile,bool focus,int x,int y)85 void TileView::drawTile(MapTile &mapTile, bool focus, int x, int y) {
86 Tile *tile = _tileSet->get(mapTile._id);
87 Image *image = tile->getImage();
88
89 assertMsg(x < _columns, "x value of %d out of range", x);
90 assertMsg(y < _rows, "y value of %d out of range", y);
91
92 // Blank scratch pad
93 _animated->fillRect(0, 0, SCALED(_tileWidth), SCALED(_tileHeight), 0, 0, 0, 255);
94
95 // Draw blackness on the tile.
96 _animated->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
97 SCALED(y * _tileHeight + _bounds.top), 0, 0,
98 SCALED(_tileWidth), SCALED(_tileHeight));
99
100 // Draw the tile to the screen
101 if (tile->getAnim()) {
102 // First, create our animated version of the tile
103 #ifdef IOS_ULTIMA4
104 animated->clearImageContents();
105 #endif
106 tile->getAnim()->draw(_animated, tile, mapTile, DIR_NONE);
107
108 // Then draw it to the screen
109 _animated->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
110 SCALED(y * _tileHeight + _bounds.top), 0, 0,
111 SCALED(_tileWidth), SCALED(_tileHeight));
112 } else {
113 image->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
114 SCALED(y * _tileHeight + _bounds.top),
115 0, SCALED(_tileHeight * mapTile._frame),
116 SCALED(_tileWidth), SCALED(_tileHeight));
117 }
118
119 // Draw the focus around the tile if it has the focus
120 if (focus)
121 drawFocus(x, y);
122 }
123
drawTile(Std::vector<MapTile> & tiles,bool focus,int x,int y)124 void TileView::drawTile(Std::vector<MapTile> &tiles, bool focus, int x, int y) {
125 assertMsg(x < _columns, "x value of %d out of range", x);
126 assertMsg(y < _rows, "y value of %d out of range", y);
127
128 // Clear tile contents
129 _animated->fillRect(0, 0, SCALED(_tileWidth), SCALED(_tileHeight), 0, 0, 0, 255);
130 _animated->drawSubRectOn(_dest,
131 SCALED(x * _tileWidth + _bounds.left), SCALED(y * _tileHeight + _bounds.top),
132 0, 0,
133 SCALED(_tileWidth), SCALED(_tileHeight)
134 );
135
136 // Iterate through rendering each of the needed tiles
137 for (Std::vector<MapTile>::reverse_iterator t = tiles.rbegin(); t != tiles.rend(); ++t) {
138 MapTile &frontTile = *t;
139 Tile *frontTileType = _tileSet->get(frontTile._id);
140
141 if (!frontTileType) {
142 // TODO: This leads to an error. It happens after graphics mode changes.
143 return;
144 }
145
146 // Get the image for the tile
147 Image *image = frontTileType->getImage();
148
149 // Draw the tile to the screen
150 if (frontTileType->getAnim()) {
151 // First, create our animated version of the tile
152 frontTileType->getAnim()->draw(_animated, frontTileType, frontTile, DIR_NONE);
153 } else {
154 if (!image)
155 // FIXME: This is a problem, error message it.
156 return;
157 image->drawSubRectOn(_animated, 0, 0,
158 0, SCALED(_tileHeight * frontTile._frame),
159 SCALED(_tileWidth), SCALED(_tileHeight)
160 );
161 }
162
163 // Then draw it to the screen
164 _animated->drawSubRectOn(_dest, SCALED(x * _tileWidth + _bounds.left),
165 SCALED(y * _tileHeight + _bounds.top), 0, 0,
166 SCALED(_tileWidth), SCALED(_tileHeight)
167 );
168 }
169
170 // Draw the focus around the tile if it has the focus
171 if (focus)
172 drawFocus(x, y);
173 }
174
drawFocus(int x,int y)175 void TileView::drawFocus(int x, int y) {
176 assertMsg(x < _columns, "x value of %d out of range", x);
177 assertMsg(y < _rows, "y value of %d out of range", y);
178
179 // Draw the focus rectangle around the tile
180 if ((g_screen->_currentCycle * 4 / SCR_CYCLE_PER_SECOND) % 2) {
181 // left edge
182 _screen->fillRect(SCALED(x * _tileWidth + _bounds.left),
183 SCALED(y * _tileHeight + _bounds.top),
184 SCALED(2), SCALED(_tileHeight), 0xff, 0xff, 0xff);
185
186 // top edge
187 _screen->fillRect(SCALED(x * _tileWidth + _bounds.left),
188 SCALED(y * _tileHeight + _bounds.top),
189 SCALED(_tileWidth), SCALED(2),
190 0xff, 0xff, 0xff);
191
192 // Right edge
193 _screen->fillRect(SCALED((x + 1) * _tileWidth + _bounds.left - 2),
194 SCALED(y * _tileHeight + _bounds.top),
195 SCALED(2), SCALED(_tileHeight),
196 0xff, 0xff, 0xff);
197
198 // Bottom edge
199 _screen->fillRect(SCALED(x * _tileWidth + _bounds.left),
200 SCALED((y + 1) * _tileHeight + _bounds.top - 2),
201 SCALED(_tileWidth), SCALED(2),
202 0xff, 0xff, 0xff);
203 }
204 }
205
setTileset(Tileset * tileset)206 void TileView::setTileset(Tileset *tileset) {
207 this->_tileSet = tileset;
208 }
209
210 } // End of namespace Ultima4
211 } // End of namespace Ultima
212