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 "illusions/illusions.h"
24 #include "illusions/resources/backgroundresource.h"
25 #include "illusions/actor.h"
26 #include "illusions/camera.h"
27 #include "illusions/dictionary.h"
28 #include "illusions/resources/actorresource.h"
29 #include "illusions/screen.h"
30 #include "illusions/sequenceopcodes.h"
31 #include "common/str.h"
32 
33 namespace Illusions {
34 
35 // BackgroundResourceLoader
36 
load(Resource * resource)37 void BackgroundResourceLoader::load(Resource *resource) {
38 	resource->_instance = _vm->_backgroundInstances->createBackgroundInstance(resource);
39 }
40 
isFlag(int flag)41 bool BackgroundResourceLoader::isFlag(int flag) {
42 	return
43 		flag == kRlfLoadFile;
44 }
45 
46 // TileMap
47 
load(byte * dataStart,Common::SeekableReadStream & stream)48 void TileMap::load(byte *dataStart, Common::SeekableReadStream &stream) {
49 	_width = stream.readSint16LE();
50 	_height = stream.readSint16LE();
51 	stream.skip(4); // Unknown
52 	uint32 mapOffs = stream.pos();
53 	_map = dataStart + mapOffs;
54 	debug(0, "TileMap::load() _width: %d; _height: %d",
55 		_width, _height);
56 }
57 
58 // BgInfo
59 
load(byte * dataStart,Common::SeekableReadStream & stream)60 void BgInfo::load(byte *dataStart, Common::SeekableReadStream &stream) {
61 	_flags = stream.readUint32LE();
62 	uint16 unknown = stream.readUint16LE(); //	TODO Unknown
63 	_priorityBase = stream.readSint16LE();
64 	_surfInfo.load(stream);
65 	loadPoint(stream, _panPoint);
66 	uint32 tileMapOffs = stream.readUint32LE();
67 	uint32 tilePixelsOffs = stream.readUint32LE();
68 	stream.seek(tileMapOffs);
69 	_tileMap.load(dataStart, stream);
70 	_tilePixels = dataStart + tilePixelsOffs;
71 	debug(0, "BgInfo::load() _flags: %08X; unknown: %04X; _priorityBase: %d; tileMapOffs: %08X; tilePixelsOffs: %08X",
72 		_flags, unknown, _priorityBase, tileMapOffs, tilePixelsOffs);
73 }
74 
75 // PriorityLayer
76 
load(byte * dataStart,Common::SeekableReadStream & stream)77 void PriorityLayer::load(byte *dataStart, Common::SeekableReadStream &stream) {
78 	_width = stream.readUint16LE();
79 	_height = stream.readUint16LE();
80 	uint32 mapOffs = stream.readUint32LE();
81 	uint32 valuesOffs = stream.readUint32LE();
82 	_map = dataStart + mapOffs;
83 	_mapWidth = READ_LE_UINT16(_map + 0);
84 	_mapHeight = READ_LE_UINT16(_map + 2);
85 	_map += 8;
86 	_values = dataStart + valuesOffs;
87 	debug(0, "PriorityLayer::load() _width: %d; _height: %d; mapOffs: %08X; valuesOffs: %08X; _mapWidth: %d; _mapHeight: %d",
88 		_width, _height, mapOffs, valuesOffs, _mapWidth, _mapHeight);
89 }
90 
getPriority(Common::Point pos)91 int PriorityLayer::getPriority(Common::Point pos) {
92 	pos.x = CLIP<int16>(pos.x, 0, _width - 1);
93 	pos.y = CLIP<int16>(pos.y, 0, _height - 1);
94 	const int16 tx = pos.x / 32, sx = pos.x % 32;
95 	const int16 ty = pos.y / 8, sy = pos.y % 8;
96 	uint16 mapIndex = READ_LE_UINT16(_map + 2 * (tx + ty * _mapWidth)) - 1;
97 	return _values[mapIndex * 32 * 8 + sx + sy * 32];
98 }
99 
100 // ScaleLayer
101 
load(byte * dataStart,Common::SeekableReadStream & stream)102 void ScaleLayer::load(byte *dataStart, Common::SeekableReadStream &stream) {
103 	_height = stream.readUint16LE();
104 	stream.skip(2);
105 	uint32 valuesOffs = stream.readUint32LE();
106 	_values = dataStart + valuesOffs;
107 	debug(0, "ScaleLayer::load() _height: %d; valuesOffs: %08X",
108 		_height, valuesOffs);
109 }
110 
getScale(Common::Point pos)111 int ScaleLayer::getScale(Common::Point pos) {
112 	pos.y = CLIP<int16>(pos.y, 0, _height - 1);
113 	return _values[pos.y];
114 }
115 
116 // RegionLayer
117 
load(byte * dataStart,Common::SeekableReadStream & stream)118 void RegionLayer::load(byte *dataStart, Common::SeekableReadStream &stream) {
119 	_unk = stream.readUint32LE();
120 	uint32 regionSequenceIdsOffs = stream.readUint32LE();
121 	_width = stream.readUint16LE();
122 	_height = stream.readUint16LE();
123 	uint32 mapOffs = stream.readUint32LE();
124 	uint32 valuesOffs = stream.readUint32LE();
125 	_regionSequenceIds = dataStart + regionSequenceIdsOffs;
126 	_map = dataStart + mapOffs;
127 	_values = dataStart + valuesOffs;
128 	_mapWidth = READ_LE_UINT16(_map + 0);
129 	_mapHeight = READ_LE_UINT16(_map + 2);
130 	_map += 8;
131 	debug(1, "RegionLayer::load() %d; regionSequenceIdsOffs: %08X; _width: %d; _height: %d; mapOffs: %08X; valuesOffs: %08X",
132 		_unk, regionSequenceIdsOffs, _width, _height, mapOffs, valuesOffs);
133 }
134 
getRegionIndex(Common::Point pos)135 int RegionLayer::getRegionIndex(Common::Point pos) {
136 	pos.x = CLIP<int16>(pos.x, 0, _width - 1);
137 	pos.y = CLIP<int16>(pos.y, 0, _height - 1);
138 	const int16 tx = pos.x / 32, sx = pos.x % 32;
139 	const int16 ty = pos.y / 8, sy = pos.y % 8;
140 	uint16 mapIndex = READ_LE_UINT16(_map + 2 * (tx + ty * _mapWidth)) - 1;
141 	return _values[mapIndex * 32 * 8 + sx + sy * 32];
142 }
143 
getRegionSequenceId(int regionIndex)144 uint32 RegionLayer::getRegionSequenceId(int regionIndex) {
145 	return READ_LE_UINT32(_regionSequenceIds + 4 * regionIndex);
146 }
147 
148 // Palette
149 
load(byte * dataStart,Common::SeekableReadStream & stream)150 void Palette::load(byte *dataStart, Common::SeekableReadStream &stream) {
151 	_count = stream.readUint16LE();
152 	_unk = stream.readUint16LE();
153 	uint32 paletteOffs = stream.readUint32LE();
154 	_palette = dataStart + paletteOffs;
155 }
156 
157 // BackgroundObject
158 
load(byte * dataStart,Common::SeekableReadStream & stream)159 void BackgroundObject::load(byte *dataStart, Common::SeekableReadStream &stream) {
160 	_objectId = stream.readUint32LE();
161 	_flags = stream.readUint16LE();
162 	_priority = stream.readUint16LE();
163 	uint32 pointsConfigOffs = stream.readUint32LE();
164 	_pointsConfig = dataStart + pointsConfigOffs;
165 	debug(0, "BackgroundObject::load() _objectId: %08X; _flags: %04X; _priority: %d; pointsConfigOffs: %08X",
166 		_objectId, _flags, _priority, pointsConfigOffs);
167 }
168 
169 // PathWalkPoints
170 
load(byte * dataStart,Common::SeekableReadStream & stream)171 void PathWalkPoints::load(byte *dataStart, Common::SeekableReadStream &stream) {
172 	_points = new PointArray();
173 	uint count = stream.readUint32LE();
174 	uint32 pointsOffs = stream.readUint32LE();
175 	_points->reserve(count);
176 	stream.seek(pointsOffs);
177 	for (uint i = 0; i < count; ++i) {
178 		Common::Point pt;
179 		loadPoint(stream, pt);
180 		_points->push_back(pt);
181 	}
182 	debug(0, "PathWalkPoints::load() count: %d; pointsOffs: %08X",
183 		count, pointsOffs);
184 }
185 
186 // PathWalkRects
187 
load(byte * dataStart,Common::SeekableReadStream & stream)188 void PathWalkRects::load(byte *dataStart, Common::SeekableReadStream &stream) {
189 	_rects = new PathLines();
190 	uint count = stream.readUint32LE();
191 	uint32 rectsOffs = stream.readUint32LE();
192 	_rects->reserve(count);
193 	stream.seek(rectsOffs);
194 	for (uint i = 0; i < count; ++i) {
195 		PathLine rect;
196 		loadPoint(stream, rect.p0);
197 		loadPoint(stream, rect.p1);
198 		_rects->push_back(rect);
199 	}
200 	debug(0, "PathWalkRects::load() count: %d; rectsOffs: %08X",
201 		count, rectsOffs);
202 }
203 
204 // BackgroundResource
205 
BackgroundResource()206 BackgroundResource::BackgroundResource()
207 	: _bgInfos(0), _scaleLayers(0), _priorityLayers(0), _regionLayers(0),
208 	_regionSequences(0), _backgroundObjects(0), _pathWalkPoints(0),
209 	_pathWalkRects(0), _palettes(0) {
210 }
211 
~BackgroundResource()212 BackgroundResource::~BackgroundResource() {
213 	delete[] _bgInfos;
214 	delete[] _scaleLayers;
215 	delete[] _priorityLayers;
216 	delete[] _regionLayers;
217 	delete[] _regionSequences;
218 	delete[] _backgroundObjects;
219 	delete[] _pathWalkPoints;
220 	delete[] _pathWalkRects;
221 	delete[] _palettes;
222 }
223 
load(byte * data,uint32 dataSize)224 void BackgroundResource::load(byte *data, uint32 dataSize) {
225 	Common::MemoryReadStream stream(data, dataSize, DisposeAfterUse::NO);
226 
227 	stream.seek(8);
228 	_paletteIndex = stream.readUint16LE();
229 
230 	// Load background pixels
231 	stream.seek(0x0A);
232 	_bgInfosCount = stream.readUint16LE();
233 	_bgInfos = new BgInfo[_bgInfosCount];
234 	stream.seek(0x20);
235 	uint32 bgInfosOffs = stream.readUint32LE();
236 	for (uint i = 0; i < _bgInfosCount; ++i) {
237 		stream.seek(bgInfosOffs + i * 0x1C);
238 		_bgInfos[i].load(data, stream);
239 	}
240 
241 	// Load scale layers
242 	stream.seek(0x10);
243 	_scaleLayersCount = stream.readUint16LE();
244 	_scaleLayers = new ScaleLayer[_scaleLayersCount];
245 	stream.seek(0x2C);
246 	uint32 scaleLayersOffs = stream.readUint32LE();
247 	debug(0, "_scaleLayersCount: %d", _scaleLayersCount);
248 	for (uint i = 0; i < _scaleLayersCount; ++i) {
249 		stream.seek(scaleLayersOffs + i * 8);
250 		_scaleLayers[i].load(data, stream);
251 	}
252 
253 	// Load priority layers
254 	stream.seek(0x14);
255 	_priorityLayersCount = stream.readUint16LE();
256 	_priorityLayers = new PriorityLayer[_priorityLayersCount];
257 	stream.seek(0x34);
258 	uint32 priorityLayersOffs = stream.readUint32LE();
259 	debug(1, "_priorityLayersCount: %d", _priorityLayersCount);
260 	for (uint i = 0; i < _priorityLayersCount; ++i) {
261 		stream.seek(priorityLayersOffs + i * 12);
262 		_priorityLayers[i].load(data, stream);
263 	}
264 
265 	// Load region layers
266 	stream.seek(0x16);
267 	_regionLayersCount = stream.readUint16LE();
268 	_regionLayers = new RegionLayer[_regionLayersCount];
269 	stream.seek(0x38);
270 	uint32 regionLayersOffs = stream.readUint32LE();
271 	debug(1, "_regionLayersCount: %d", _regionLayersCount);
272 	for (uint i = 0; i < _regionLayersCount; ++i) {
273 		stream.seek(regionLayersOffs + i * 20);
274 		_regionLayers[i].load(data, stream);
275 	}
276 
277 	// Load region sequences
278 	stream.seek(0x1E);
279 	_regionSequencesCount = stream.readUint16LE();
280 	_regionSequences = new Sequence[_regionSequencesCount];
281 	stream.seek(0x48);
282 	uint32 regionSequencesOffs = stream.readUint32LE();
283 	stream.seek(regionSequencesOffs);
284 	for (uint i = 0; i < _regionSequencesCount; ++i) {
285 		_regionSequences[i].load(data, stream);
286 	}
287 
288 	// Load background objects
289 	stream.seek(0x1C);
290 	_backgroundObjectsCount = stream.readUint16LE();
291 	_backgroundObjects = new BackgroundObject[_backgroundObjectsCount];
292 	stream.seek(0x44);
293 	uint32 backgroundObjectsOffs = stream.readUint32LE();
294 	debug(0, "_backgroundObjectsCount: %d", _backgroundObjectsCount);
295 	for (uint i = 0; i < _backgroundObjectsCount; ++i) {
296 		stream.seek(backgroundObjectsOffs + i * 12);
297 		_backgroundObjects[i].load(data, stream);
298 	}
299 
300 	// Load path walk points
301 	stream.seek(0x0E);
302 	_pathWalkPointsCount = stream.readUint16LE();
303 	debug(1, "_pathWalkPointsCount: %d", _pathWalkPointsCount);
304 	_pathWalkPoints = new PathWalkPoints[_pathWalkPointsCount];
305 	stream.seek(0x28);
306 	uint32 pathWalkPointsOffs = stream.readUint32LE();
307 	for (uint i = 0; i < _pathWalkPointsCount; ++i) {
308 		stream.seek(pathWalkPointsOffs + i * 8);
309 		_pathWalkPoints[i].load(data, stream);
310 	}
311 
312 	// Load path walk rects
313 	stream.seek(0x12);
314 	_pathWalkRectsCount = stream.readUint16LE();
315 	debug(1, "_pathWalkRectsCount: %d", _pathWalkRectsCount);
316 	_pathWalkRects = new PathWalkRects[_pathWalkRectsCount];
317 	stream.seek(0x30);
318 	uint32 pathWalkRectsOffs = stream.readUint32LE();
319 	for (uint i = 0; i < _pathWalkRectsCount; ++i) {
320 		stream.seek(pathWalkRectsOffs + i * 8);
321 		_pathWalkRects[i].load(data, stream);
322 	}
323 
324 	// Load named points
325 	stream.seek(0xC);
326 	uint namedPointsCount = stream.readUint16LE();
327 	stream.seek(0x24);
328 	uint32 namedPointsOffs = stream.readUint32LE();
329 	stream.seek(namedPointsOffs);
330 	_namedPoints.load(namedPointsCount, stream);
331 
332 	// Load palettes
333 	stream.seek(0x18);
334 	_palettesCount = stream.readUint16LE();
335 	_palettes = new Palette[_palettesCount];
336 	stream.seek(0x3C);
337 	uint32 palettesOffs = stream.readUint32LE();
338 	debug(0, "_palettesCount: %d", _palettesCount);
339 	for (uint i = 0; i < _palettesCount; ++i) {
340 		stream.seek(palettesOffs + i * 8);
341 		_palettes[i].load(data, stream);
342 	}
343 
344 }
345 
findMasterBgIndex()346 int BackgroundResource::findMasterBgIndex() {
347 	int index = 1;
348 	while (!(_bgInfos[index - 1]._flags & 1)) { // TODO check if this is correct
349 		++index;
350 	}
351 	return index;
352 }
353 
getPriorityLayer(uint index)354 PriorityLayer *BackgroundResource::getPriorityLayer(uint index) {
355 	return &_priorityLayers[index];
356 }
357 
getScaleLayer(uint index)358 ScaleLayer *BackgroundResource::getScaleLayer(uint index) {
359 	return &_scaleLayers[index];
360 }
361 
getRegionLayer(uint index)362 RegionLayer *BackgroundResource::getRegionLayer(uint index) {
363 	return &_regionLayers[index];
364 }
365 
getPathWalkPoints(uint index)366 PathWalkPoints *BackgroundResource::getPathWalkPoints(uint index) {
367 	return &_pathWalkPoints[index];
368 }
369 
getPathWalkRects(uint index)370 PathWalkRects *BackgroundResource::getPathWalkRects(uint index) {
371 	return &_pathWalkRects[index];
372 }
373 
getPalette(uint index)374 Palette *BackgroundResource::getPalette(uint index) {
375 	return &_palettes[index];
376 }
377 
findNamedPoint(uint32 namedPointId,Common::Point & pt)378 bool BackgroundResource::findNamedPoint(uint32 namedPointId, Common::Point &pt) {
379 	return _namedPoints.findNamedPoint(namedPointId, pt);
380 }
381 
382 // BackgroundInstance
383 
BackgroundInstance(IllusionsEngine * vm)384 BackgroundInstance::BackgroundInstance(IllusionsEngine *vm)
385 	: _vm(vm), _sceneId(0), _pauseCtr(0), _bgRes(0), _savedPalette(0) {
386 }
387 
load(Resource * resource)388 void BackgroundInstance::load(Resource *resource) {
389 	debug(1, "BackgroundResourceLoader::load() Loading background %08X from %s...", resource->_resId, resource->_filename.c_str());
390 
391 	BackgroundResource *backgroundResource = new BackgroundResource();
392 	backgroundResource->load(resource->_data, resource->_dataSize);
393 
394 	_bgRes = backgroundResource;
395 	_sceneId = resource->_sceneId;
396 	initSurface();
397 
398 	// Insert background objects
399 	for (uint i = 0; i < backgroundResource->_backgroundObjectsCount; ++i) {
400 		_vm->_controls->placeBackgroundObject(&backgroundResource->_backgroundObjects[i]);
401 	}
402 
403 	registerResources();
404 
405 	_vm->clearFader();
406 
407 	int index = _bgRes->findMasterBgIndex();
408 	_vm->_camera->set(_bgRes->_bgInfos[index - 1]._panPoint, _bgRes->_bgInfos[index - 1]._surfInfo._dimensions);
409 
410 	if (_bgRes->_palettesCount > 0) {
411 		Palette *palette = _bgRes->getPalette(_bgRes->_paletteIndex - 1);
412 		_vm->_screenPalette->setPalette(palette->_palette, 1, palette->_count);
413 	}
414 
415 }
416 
unload()417 void BackgroundInstance::unload() {
418 	debug(1, "BackgroundInstance::unload()");
419 	freeSurface();
420 	unregisterResources();
421 	delete _bgRes;
422 	_vm->_backgroundInstances->removeBackgroundInstance(this);
423 	_vm->setDefaultTextCoords();
424 }
425 
pause()426 void BackgroundInstance::pause() {
427 	++_pauseCtr;
428 	if (_pauseCtr <= 1) {
429 		unregisterResources();
430 		_vm->setDefaultTextCoords();
431 		_vm->_camera->getActiveState(_savedCameraState);
432 		_savedPalette = new byte[1024];
433 		_vm->_screenPalette->getPalette(_savedPalette);
434 		freeSurface();
435 	}
436 }
437 
unpause()438 void BackgroundInstance::unpause() {
439 	--_pauseCtr;
440 	if (_pauseCtr <= 0) {
441 		registerResources();
442 		initSurface();
443 		_vm->_screenPalette->setPalette(_savedPalette, 1, 256);
444 		delete[] _savedPalette;
445 		_savedPalette = 0;
446 		_vm->clearFader();
447 		_vm->_camera->setActiveState(_savedCameraState);
448 		_vm->_backgroundInstances->refreshPan();
449 	}
450 }
451 
registerResources()452 void BackgroundInstance::registerResources() {
453 	for (uint i = 0; i < _bgRes->_regionSequencesCount; ++i) {
454 		Sequence *sequence = &_bgRes->_regionSequences[i];
455 		_vm->_dict->addSequence(sequence->_sequenceId, sequence);
456 	}
457 }
458 
unregisterResources()459 void BackgroundInstance::unregisterResources() {
460 	for (uint i = 0; i < _bgRes->_regionSequencesCount; ++i) {
461 		Sequence *sequence = &_bgRes->_regionSequences[i];
462 		_vm->_dict->removeSequence(sequence->_sequenceId);
463 	}
464 }
465 
initSurface()466 void BackgroundInstance::initSurface() {
467 	for (uint i = 0; i < kMaxBackgroundItemSurfaces; ++i) {
468 		_surfaces[i] = 0;
469 	}
470 	for (uint i = 0; i < _bgRes->_bgInfosCount; ++i) {
471 		BgInfo *bgInfo = &_bgRes->_bgInfos[i];
472 		_panPoints[i] = bgInfo->_panPoint;
473 		_surfaces[i] = _vm->_screen->allocSurface(bgInfo->_surfInfo);
474 		drawTiles(_surfaces[i], bgInfo->_tileMap, bgInfo->_tilePixels);
475 #if 0
476 		if (_bgRes->_pathWalkRectsCount > 0) {
477 			PathLines *pl = _bgRes->_pathWalkRects->_rects;
478 			for (int j=0; j < pl->size(); j++) {
479 				PathLine pathLine = (*pl)[j];
480 				debug(0, "walk path rect line[%d]. (%d,%d)->(%d,%d)", j, pathLine.p0.x, pathLine.p0.y, pathLine.p1.x, pathLine.p1.y);
481 				_surfaces[i]->drawLine(pathLine.p0.x, pathLine.p0.y, pathLine.p1.x, pathLine.p1.y, 5);
482 			}
483 		}
484 #endif
485 	}
486 }
487 
freeSurface()488 void BackgroundInstance::freeSurface() {
489 	for (uint i = 0; i < _bgRes->_bgInfosCount; ++i) {
490 		if (_surfaces[i]) {
491 			_surfaces[i]->free();
492 			delete _surfaces[i];
493 			_surfaces[i] = 0;
494 		}
495 	}
496 }
497 
drawTiles(Graphics::Surface * surface,TileMap & tileMap,byte * tilePixels)498 void BackgroundInstance::drawTiles(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels) {
499 	switch (_vm->getGameId()) {
500 	case kGameIdDuckman:
501 		drawTiles8(surface, tileMap, tilePixels);
502 		break;
503 	case kGameIdBBDOU:
504 		drawTiles16(surface, tileMap, tilePixels);
505 		break;
506 	default:
507 		break;
508 	}
509 }
510 
drawTiles8(Graphics::Surface * surface,TileMap & tileMap,byte * tilePixels)511 void BackgroundInstance::drawTiles8(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels) {
512 	const int kTileWidth = 32;
513 	const int kTileHeight = 8;
514 	const int kTileSize = kTileWidth * kTileHeight;
515 	uint tileMapIndex = 0;
516 	for (int tileY = 0; tileY < tileMap._height; ++tileY) {
517 		int tileDestY = tileY * kTileHeight;
518 		int tileDestH = MIN(kTileHeight, surface->h - tileDestY);
519 		for (int tileX = 0; tileX < tileMap._width; ++tileX) {
520 			int tileDestX = tileX * kTileWidth;
521 			int tileDestW = MIN(kTileWidth, surface->w - tileDestX);
522 			uint16 tileIndex = READ_LE_UINT16(tileMap._map + 2 * tileMapIndex);
523 			++tileMapIndex;
524 			byte *src = tilePixels + (tileIndex - 1) * kTileSize;
525 			byte *dst = (byte*)surface->getBasePtr(tileDestX, tileDestY);
526 			for (int h = 0; h < tileDestH; ++h) {
527 				memcpy(dst, src, tileDestW);
528 				dst += surface->pitch;
529 				src += kTileWidth;
530 			}
531 		}
532 	}
533 }
534 
drawTiles16(Graphics::Surface * surface,TileMap & tileMap,byte * tilePixels)535 void BackgroundInstance::drawTiles16(Graphics::Surface *surface, TileMap &tileMap, byte *tilePixels) {
536 	const int kTileWidth = 32;
537 	const int kTileHeight = 8;
538 	const int kTileSize = kTileWidth * kTileHeight * 2;
539 	uint tileMapIndex = 0;
540 	for (int tileY = 0; tileY < tileMap._height; ++tileY) {
541 		int tileDestY = tileY * kTileHeight;
542 		int tileDestH = MIN(kTileHeight, surface->h - tileDestY);
543 		for (int tileX = 0; tileX < tileMap._width; ++tileX) {
544 			int tileDestX = tileX * kTileWidth;
545 			int tileDestW = MIN(kTileWidth, surface->w - tileDestX);
546 			uint16 tileIndex = READ_LE_UINT16(tileMap._map + 2 * tileMapIndex);
547 			++tileMapIndex;
548 			byte *src = tilePixels + (tileIndex - 1) * kTileSize;
549 			byte *dst = (byte*)surface->getBasePtr(tileDestX, tileDestY);
550 			for (int h = 0; h < tileDestH; ++h) {
551 				for (int w = 0; w < tileDestW; ++w) {
552 					uint16 pixel = READ_LE_UINT16(src + w * 2);
553 					WRITE_LE_UINT16(dst + w * 2, pixel);
554 				}
555 				dst += surface->pitch;
556 				src += kTileWidth * 2;
557 			}
558 		}
559 	}
560 }
561 
562 // BackgroundInstanceList
563 
BackgroundInstanceList(IllusionsEngine * vm)564 BackgroundInstanceList::BackgroundInstanceList(IllusionsEngine *vm)
565 	: _vm(vm) {
566 }
567 
~BackgroundInstanceList()568 BackgroundInstanceList::~BackgroundInstanceList() {
569 }
570 
createBackgroundInstance(Resource * resource)571 BackgroundInstance *BackgroundInstanceList::createBackgroundInstance(Resource *resource) {
572 	BackgroundInstance *backgroundInstance = new BackgroundInstance(_vm);
573 	backgroundInstance->load(resource);
574 	_items.push_back(backgroundInstance);
575 	return backgroundInstance;
576 }
577 
removeBackgroundInstance(BackgroundInstance * backgroundInstance)578 void BackgroundInstanceList::removeBackgroundInstance(BackgroundInstance *backgroundInstance) {
579 	_items.remove(backgroundInstance);
580 }
581 
pauseBySceneId(uint32 sceneId)582 void BackgroundInstanceList::pauseBySceneId(uint32 sceneId) {
583 	for (ItemsIterator it = _items.begin(); it != _items.end(); ++it) {
584 		if ((*it)->_sceneId == sceneId)
585 			(*it)->pause();
586 	}
587 }
588 
unpauseBySceneId(uint32 sceneId)589 void BackgroundInstanceList::unpauseBySceneId(uint32 sceneId) {
590 	for (ItemsIterator it = _items.begin(); it != _items.end(); ++it) {
591 		if ((*it)->_sceneId == sceneId)
592 			(*it)->unpause();
593 	}
594 }
595 
findActiveBackgroundInstance()596 BackgroundInstance *BackgroundInstanceList::findActiveBackgroundInstance() {
597 	for (ItemsIterator it = _items.begin(); it != _items.end(); ++it) {
598 		if ((*it)->_pauseCtr == 0)
599 			return (*it);
600 	}
601 	return 0;
602 }
603 
findBackgroundByResource(BackgroundResource * backgroundResource)604 BackgroundInstance *BackgroundInstanceList::findBackgroundByResource(BackgroundResource *backgroundResource) {
605 	for (ItemsIterator it = _items.begin(); it != _items.end(); ++it) {
606 		if ((*it)->_bgRes == backgroundResource)
607 			return (*it);
608 	}
609 	return 0;
610 }
611 
getActiveBgResource()612 BackgroundResource *BackgroundInstanceList::getActiveBgResource() {
613 	BackgroundInstance *background = findActiveBackgroundInstance();
614 	if (background)
615 		return background->_bgRes;
616 	return 0;
617 }
618 
getMasterBgDimensions()619 WidthHeight BackgroundInstanceList::getMasterBgDimensions() {
620 	BackgroundInstance *backgroundInstance = findActiveBackgroundInstance();
621 	int16 index = backgroundInstance->_bgRes->findMasterBgIndex();
622 	return backgroundInstance->_bgRes->_bgInfos[index - 1]._surfInfo._dimensions;
623 }
624 
refreshPan()625 void BackgroundInstanceList::refreshPan() {
626 	BackgroundInstance *backgroundInstance = findActiveBackgroundInstance();
627 	if (backgroundInstance) {
628 		WidthHeight dimensions = getMasterBgDimensions();
629 		_vm->_camera->refreshPan(backgroundInstance, dimensions);
630 	}
631 }
632 
findActiveBackgroundNamedPoint(uint32 namedPointId,Common::Point & pt)633 bool BackgroundInstanceList::findActiveBackgroundNamedPoint(uint32 namedPointId, Common::Point &pt) {
634 	BackgroundResource *backgroundResource = getActiveBgResource();
635 	return backgroundResource ? backgroundResource->findNamedPoint(namedPointId, pt) : false;
636 }
637 
638 } // End of namespace Illusions
639