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 #include "common/memstream.h"
23 #include "common/endian.h"
24 #include "dragons/background.h"
25 #include "dragons/screen.h"
26 
27 namespace Dragons {
28 
29 #define TILE_WIDTH 32
30 #define TILE_HEIGHT 8
31 #define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT)
32 
33 
load(TileMap & tileMap,byte * tiles)34 void PriorityLayer::load(TileMap &tileMap, byte *tiles) {
35 	_width = tileMap.w * TILE_WIDTH;
36 	_height = tileMap.h * TILE_HEIGHT;
37 	_mapWidth = tileMap.w;
38 	_mapHeight = tileMap.h;
39 	size_t tileSize = (size_t)tileMap.tileIndexOffset * TILE_SIZE;
40 	_map = new byte[tileMap.size];
41 	_mapBase = new byte[tileMap.size];
42 	_values = new byte[tileSize];
43 
44 	memcpy(_map, tileMap.map, tileMap.size);
45 	memcpy(_mapBase, tileMap.map, tileMap.size);
46 	memcpy(_values, tiles, tileSize);
47 }
48 
getPriority(Common::Point pos)49 int16 PriorityLayer::getPriority(Common::Point pos) {
50 	pos.x = CLIP<int16>(pos.x, 0, _width - 1);
51 	pos.y = CLIP<int16>(pos.y, 0, _height - 1);
52 	const int16 tx = pos.x / TILE_WIDTH, sx = pos.x % TILE_WIDTH;
53 	const int16 ty = pos.y / TILE_HEIGHT, sy = pos.y % TILE_HEIGHT;
54 	uint16 mapIndex = READ_LE_UINT16(_map + 2 * (tx + ty * _mapWidth));
55 
56 //
57 //	byte priority = *(byte *)((((uint)*(uint16 *)
58 //			(((int)pos.x / 32) * 2 +
59 //			 ((int)pos.y / 8) * (uint)_mapWidth * 2 +
60 //					_map) * 32) * 8) +
61 //			_values + (((int)pos.y % 8) * 32) +
62 //						 ((int)pos.x % 32));
63 	return _values[mapIndex * TILE_WIDTH * TILE_HEIGHT + sx + sy * TILE_WIDTH] + 1;
64 }
65 
overlayTileMap(byte * data,int16 x,int16 y,int16 w,int16 h)66 void PriorityLayer::overlayTileMap(byte *data, int16 x, int16 y, int16 w, int16 h) {
67 	byte *ptr = _map + (x + y * _mapWidth) * 2;
68 	byte *src = data;
69 	for (int i = 0; i < h; i++) {
70 		memcpy(ptr, src, w * 2);
71 		src += w * 2;
72 		ptr += _mapWidth * 2;
73 	}
74 }
75 
restoreTileMap(int16 x,int16 y,int16 w,int16 h)76 void PriorityLayer::restoreTileMap(int16 x, int16 y, int16 w, int16 h) {
77 	byte *ptr = _map + (x + y * _mapWidth) * 2;
78 	byte *src = _mapBase + (x + y * _mapWidth) * 2;
79 	for (int i = 0; i < h; i++) {
80 		memcpy(ptr, src, w * 2);
81 		src += _mapWidth * 2;
82 		ptr += _mapWidth * 2;
83 	}
84 
85 }
86 
Background()87 Background::Background() : _priorityLayer(0), _points2(0), _data(0) {
88 	_layerSurface[0] = nullptr;
89 	_layerSurface[1] = nullptr;
90 	_layerSurface[2] = nullptr;
91 	_layerOffset[0] = Common::Point(0, 0);
92 	_layerOffset[1] = Common::Point(0, 0);
93 	_layerOffset[2] = Common::Point(0, 0);
94 	_layerAlphaMode[0] = NONE;
95 	_layerAlphaMode[1] = NONE;
96 	_layerAlphaMode[2] = NONE;
97 
98 	_tileDataOffset = nullptr;
99 }
100 
~Background()101 Background::~Background() {
102 	if (_data) {
103 		delete _data;
104 	}
105 
106 	for (int i = 0; i < 3; i++) {
107 		if (_layerSurface[i]) {
108 			_layerSurface[i]->free();
109 			delete _layerSurface[i];
110 		}
111 	}
112 
113 }
114 
load(byte * dataStart,uint32 size)115 bool Background::load(byte *dataStart, uint32 size) {
116 	Common::MemoryReadStream stream(dataStart, size, DisposeAfterUse::NO);
117 	_data = dataStart;
118 
119 	stream.read(_palette, 512);
120 	_palette[0] = 0x00; //FIXME update palette
121 	_palette[1] = 0x00;
122 
123 	_scaleLayer.load(stream); // 0x200
124 	_points2 = loadPoints(stream); // 0x280
125 	stream.seek(0x305);
126 	uint8 tileindexOffset = stream.readByte();
127 	stream.seek(0x308);
128 
129 	uint32 tilemapOffset = 0x324;
130 	for (int i = 0; i < 3; i++) {
131 		_tileMap[i].w = stream.readUint16LE();
132 		_tileMap[i].h = stream.readUint16LE();
133 		_tileMap[i].size = stream.readUint32LE();
134 		_tileMap[i].map = dataStart + tilemapOffset;
135 		_tileMap[i].tileIndexOffset = tileindexOffset;
136 		debug(3, "Tilemap (%d, %d) map: %X", _tileMap[i].w, _tileMap[i].h, tilemapOffset);
137 
138 		tilemapOffset += _tileMap[i].size;
139 	}
140 
141 	uint32 finalSize = stream.readUint32LE();
142 
143 	TileMap priorityTilemap;
144 
145 	priorityTilemap.w = _tileMap[0].w;
146 	priorityTilemap.h = _tileMap[0].h;
147 	priorityTilemap.size = _tileMap[0].size;
148 	priorityTilemap.map = dataStart + tilemapOffset;
149 	priorityTilemap.tileIndexOffset = tileindexOffset;
150 
151 	uint32 tilesOffset = tilemapOffset + finalSize;
152 
153 	_tileDataOffset = _data + tilesOffset;
154 
155 	_priorityLayer = new PriorityLayer();
156 	_priorityLayer->load(priorityTilemap, _tileDataOffset);
157 
158 	debug(3, "Tiles: %X", tilesOffset);
159 	debug(3, "tileIndexOffset: %d", _tileMap[0].tileIndexOffset);
160 
161 	for (int i = 0; i < 3; i++) {
162 		_layerSurface[i] = initGfxLayer(_tileMap[i]);
163 		loadGfxLayer(_layerSurface[i], _tileMap[i], _tileDataOffset);
164 	}
165 
166 	_layerPriority[0] = 1;
167 	_layerPriority[1] = 2;
168 	_layerPriority[2] = 3;
169 
170 	return false;
171 }
172 
loadPoints(Common::SeekableReadStream & stream)173 Common::Point *Background::loadPoints(Common::SeekableReadStream &stream) {
174 	Common::Point *points = new Common::Point[0x20];
175 
176 	for (int i = 0; i < 0x20; i++) {
177 		points[i].x = stream.readUint16LE();
178 		points[i].y = stream.readUint16LE();
179 	}
180 
181 	return points;
182 }
183 
initGfxLayer(TileMap & tileMap)184 Graphics::Surface *Background::initGfxLayer(TileMap &tileMap) {
185 	Graphics::Surface *surface = new Graphics::Surface();
186 	surface->create(tileMap.w * TILE_WIDTH, tileMap.h * TILE_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
187 	return surface;
188 }
189 
loadGfxLayer(Graphics::Surface * surface,TileMap & tileMap,byte * tiles)190 void Background::loadGfxLayer(Graphics::Surface *surface, TileMap &tileMap, byte *tiles) {
191 	for (int y = 0; y < tileMap.h; y++) {
192 		for (int x = 0; x < tileMap.w; x++) {
193 			uint16 idx = READ_LE_UINT16(&tileMap.map[(y * tileMap.w + x) * 2]) + tileMap.tileIndexOffset;
194 			//debug("tileIdx: %d", idx);
195 			drawTileToSurface(surface, _palette, tiles + idx * 0x100, x * TILE_WIDTH, y * TILE_HEIGHT);
196 		}
197 	}
198 }
199 
drawTileToSurface(Graphics::Surface * surface,byte * palette,byte * tile,uint32 x,uint32 y)200 void drawTileToSurface(Graphics::Surface *surface, byte *palette, byte *tile, uint32 x, uint32 y) {
201 	byte *pixels = (byte *)surface->getPixels();
202 	if (surface->format.bpp() == 16) {
203 		for (int ty = 0; ty < TILE_HEIGHT; ty++) {
204 			for (int tx = 0; tx < TILE_WIDTH; tx++) {
205 				uint32 cidx = *tile;
206 				uint32 offset = (y + ty) * surface->pitch + (x + tx) * 2;
207 				pixels[offset] = palette[cidx * 2];
208 				pixels[offset + 1] = palette[cidx * 2 + 1];
209 				tile++;
210 			}
211 		}
212 	} else {
213 		for (int ty = 0; ty < TILE_HEIGHT; ty++) {
214 			memcpy(&pixels[(y + ty) * surface->pitch + x], tile, TILE_WIDTH);
215 			tile += TILE_WIDTH;
216 		}
217 	}
218 }
219 
getPoint2(uint32 pointIndex)220 Common::Point Background::getPoint2(uint32 pointIndex) {
221 	assert (pointIndex < 0x20);
222 	return _points2[pointIndex];
223 }
224 
getWidth()225 uint16 Background::getWidth() {
226 	assert (_layerSurface[1]);
227 	return _layerSurface[1]->w;
228 }
229 
getHeight()230 uint16 Background::getHeight() {
231 	assert (_layerSurface[1]);
232 	return _layerSurface[1]->h;
233 }
234 
getPriorityAtPoint(Common::Point pos)235 int16 Background::getPriorityAtPoint(Common::Point pos) {
236 	if (pos.x < 0 || pos.x >= getWidth() || pos.y < 0 || pos.y >= getHeight()) {
237 		return -1;
238 	}
239 	int16 priority = _priorityLayer->getPriority(pos);
240 	return priority < 0x11 ? priority : 0;
241 }
242 
overlayImage(uint16 layerNum,byte * data,int16 x,int16 y,int16 w,int16 h)243 void Background::overlayImage(uint16 layerNum, byte *data, int16 x, int16 y, int16 w, int16 h) {
244 	for (int i = 0; i < h; i++) {
245 		for (int j = 0; j < w; j++) {
246 			int16 idx = READ_LE_UINT16(data) + _tileMap[layerNum].tileIndexOffset;
247 			drawTileToSurface(_layerSurface[layerNum],
248 					_palette,
249 					_tileDataOffset + idx * 0x100,
250 					(j + x) * TILE_WIDTH,
251 					(i + y) * TILE_HEIGHT);
252 			data += 2;
253 		}
254 	}
255 }
256 
restoreTiles(uint16 layerNum,int16 x1,int16 y1,int16 w,int16 h)257 void Background::restoreTiles(uint16 layerNum, int16 x1, int16 y1, int16 w, int16 h) {
258 	int16 tmw = x1 + w;
259 	int16 tmh = y1 + h;
260 	for (int y = y1; y < tmh; y++) {
261 		for (int x = x1; x < tmw; x++) {
262 			uint16 idx = READ_LE_UINT16(&_tileMap[layerNum].map[(y * _tileMap[layerNum].w + x) * 2]) + _tileMap[layerNum].tileIndexOffset;
263 			//debug("tileIdx: %d", idx);
264 			drawTileToSurface(_layerSurface[layerNum], _palette, _tileDataOffset + idx * 0x100, x * TILE_WIDTH, y * TILE_HEIGHT);
265 		}
266 	}
267 }
268 
overlayPriorityTileMap(byte * data,int16 x,int16 y,int16 w,int16 h)269 void Background::overlayPriorityTileMap(byte *data, int16 x, int16 y, int16 w, int16 h) {
270 	_priorityLayer->overlayTileMap(data, x, y, w, h);
271 }
272 
restorePriorityTileMap(int16 x,int16 y,int16 w,int16 h)273 void Background::restorePriorityTileMap(int16 x, int16 y, int16 w, int16 h) {
274 	_priorityLayer->restoreTileMap(x, y, w, h);
275 }
276 
setPalette(byte * newPalette)277 void Background::setPalette(byte *newPalette) {
278 	memcpy(_palette, newPalette, 512);
279 	for (int i = 0; i < 3; i++) {
280 		loadGfxLayer(_layerSurface[i], _tileMap[i], _tileDataOffset);
281 	}
282 }
283 
setLayerOffset(uint8 layerNumber,Common::Point offset)284 void Background::setLayerOffset(uint8 layerNumber, Common::Point offset) {
285 	assert(layerNumber < 4);
286 	_layerOffset[layerNumber] = offset;
287 }
288 
getLayerOffset(uint8 layerNumber)289 Common::Point Background::getLayerOffset(uint8 layerNumber) {
290 	assert(layerNumber < 4);
291 	return _layerOffset[layerNumber];
292 }
293 
getLayerAlphaMode(uint8 layerNumber)294 AlphaBlendMode Background::getLayerAlphaMode(uint8 layerNumber) {
295 	assert(layerNumber < 4);
296 	return _layerAlphaMode[layerNumber];
297 }
298 
setLayerAlphaMode(uint8 layerNumber,AlphaBlendMode mode)299 void Background::setLayerAlphaMode(uint8 layerNumber, AlphaBlendMode mode) {
300 	assert(layerNumber < 4);
301 	_layerAlphaMode[layerNumber] = mode;
302 }
303 
BackgroundResourceLoader(BigfileArchive * bigFileArchive,DragonRMS * dragonRMS)304 BackgroundResourceLoader::BackgroundResourceLoader(BigfileArchive *bigFileArchive, DragonRMS *dragonRMS) : _bigFileArchive(
305 	bigFileArchive), _dragonRMS(dragonRMS) {}
306 
load(uint32 sceneId)307 Background *BackgroundResourceLoader::load(uint32 sceneId) {
308 	char filename[] = "nnnn.scr";
309 	memcpy(filename, _dragonRMS->getSceneName(sceneId), 4);
310 	return load(filename);
311 }
312 
load(const char * filename)313 Background *BackgroundResourceLoader::load(const char *filename) {
314 	debug(1, "Loading %s", filename);
315 	uint32 size;
316 	byte *scrData = _bigFileArchive->load(filename, size);
317 	Background *bg = new Background();
318 	bg->load(scrData, size);
319 	return bg;
320 }
321 
load(Common::SeekableReadStream & stream)322 void ScaleLayer::load(Common::SeekableReadStream &stream) {
323 	for (int i = 0; i < 32; i++) {
324 		_bands[i]._y = stream.readSint16LE();
325 		_bands[i]._priority = stream.readSint16LE();
326 	}
327 }
328 
getScale(uint16 y)329 uint16 ScaleLayer::getScale(uint16 y) {
330 	short yBand;
331 	uint uVar1;
332 	short local_v0_368;
333 	int iVar3;
334 	short lowerYBandIdx;
335 	ScaleBand *pSVar4;
336 	short upperYBandIdx;
337 	uint uVar5;
338 	ScaleBand *pSVar6;
339 	int uVar7;
340 
341 
342 	upperYBandIdx = -1;
343 	for (int16 i = 0x1f; i >= 0; i--) {
344 		yBand = _bands[i]._y;
345 		if (yBand != -1 && yBand <= y) {
346 			upperYBandIdx = i;
347 			break;
348 		}
349 	}
350 //	iVar3 = 0x1f0000;
351 //	do {
352 //		yBand = *(uint16 *)((int)&scaleBandTbl->y + (iVar3 >> 0xe));
353 //		if ((yBand != 0xffff) && (yBand <= y)) break;
354 //		i = i + -1;
355 //		iVar3 = i * 0x10000;
356 //	} while (-1 < i * 0x10000);
357 	lowerYBandIdx = 32;
358 	for (int i = 0; i < 32; i++) {
359 		yBand = _bands[i]._y;
360 		if (yBand != -1 && y <= yBand) {
361 			lowerYBandIdx = i;
362 			break;
363 		}
364 	}
365 //	j = 0;
366 //	iVar3 = 0;
367 //	do {
368 //		lowerYBandIdx = (short)j;
369 //		yBand = *(uint16 *)((int)&scaleBandTbl->y + (iVar3 >> 0xe));
370 //		if ((yBand != 0xffff) && (y <= yBand)) break;
371 //		j = j + 1;
372 //		lowerYBandIdx = (short)j;
373 //		iVar3 = j * 0x10000;
374 //	} while (j * 0x10000 >> 0x10 < 0x20);
375 	if ((upperYBandIdx == -1) && (lowerYBandIdx == 0x20)) {
376 		return 0x100;
377 	}
378 	if (upperYBandIdx < 0 || lowerYBandIdx >= 32) {
379 		if (upperYBandIdx >= 0) {
380 			lowerYBandIdx = upperYBandIdx;
381 		}
382 		upperYBandIdx = lowerYBandIdx;
383 	}
384 
385 
386 	pSVar6 = &_bands[upperYBandIdx];  //scaleBandTbl + (int)upperYBandIdx;
387 	uVar7 = (0x21 - (uint)pSVar6->_priority) * 8;
388 	uVar1 = uVar7;
389 	if (y != pSVar6->_y) {
390 		pSVar4 = &_bands[lowerYBandIdx]; //scaleBandTbl + (int)lowerYBandIdx;
391 		uVar5 = (0x21 - (uint)pSVar4->_priority) * 8;
392 		uVar1 = uVar5;
393 		if ((y != pSVar4->_y) && (uVar1 = uVar7, (int)upperYBandIdx != (int)lowerYBandIdx)) {
394 			local_v0_368 = pSVar4->_y - pSVar6->_y;
395 			uVar1 = uVar5;
396 			if (local_v0_368 != 0) {
397 				iVar3 = ((uVar5 & 0xffffu) - (uVar7 & 0xffffu)) * (uint)(uint16)(y - pSVar6->_y);
398 
399 				assert(((uint16)local_v0_368 != 0xffffu) || (iVar3 != (int)-0x80000000));
400 
401 				return (uVar7 + iVar3 / (int)(uint)(uint16)local_v0_368) & 0xffff;
402 			}
403 		}
404 	}
405 	return uVar1 & 0xfff8u;
406 }
407 
ScaleLayer()408 ScaleLayer::ScaleLayer(): _savedBands(nullptr) {
409 	for (int i = 0; i < 32; i++) {
410 		_bands[i]._y = -1;
411 		_bands[i]._priority = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
412 	}
413 }
414 
~ScaleLayer()415 ScaleLayer::~ScaleLayer() {
416 	delete _savedBands;
417 }
418 
backup()419 void ScaleLayer::backup() {
420 	delete _savedBands;
421 	_savedBands = new ScaleBand[32];
422 	memcpy(_savedBands, _bands, sizeof(_bands));
423 }
424 
restore()425 void ScaleLayer::restore() {
426 	assert(_savedBands);
427 	memcpy(_bands, _savedBands, sizeof(_bands));
428 }
429 
clearAll()430 void ScaleLayer::clearAll() {
431 	for (int i = 0; i < 32; i++) {
432 		_bands[i]._y = -1;
433 	}
434 }
435 
setValue(uint8 index,int16 y,int16 value)436 void ScaleLayer::setValue(uint8 index, int16 y, int16 value) {
437 	assert(index < 32);
438 	_bands[index]._y = y;
439 	_bands[index]._priority = value;
440 }
441 
442 } // End of namespace Dragons
443