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 /** \file
24  * @todo Make resource manager class and make load* functions its members
25  */
26 
27 #include "common/endian.h"
28 #include "common/memstream.h"
29 #include "common/textconsole.h"
30 
31 #include "cine/cine.h"
32 #include "cine/anim.h"
33 #include "cine/gfx.h"
34 #include "cine/pal.h"
35 #include "cine/part.h"
36 #include "cine/various.h"
37 
38 namespace Cine {
39 
40 struct AnimHeader2Struct {
41 	uint32 field_0;
42 	uint16 width;
43 	uint16 height;
44 	uint16 type;
45 	uint16 field_A;
46 	uint16 field_C;
47 	uint16 field_E;
48 };
49 
50 static const AnimDataEntry transparencyData[] = {
51 	{"ALPHA", 0xF},
52 	{"TITRE2", 0xF},
53 	{"ET", 0xC},
54 	{"L311", 0x3},
55 	{"L405", 0x1},
56 	{"L515", 0xC},
57 	{"L009", 0xE},
58 	{"L010", 0xE},
59 	{"FUTUR", 0x6},
60 	{"PAYSAN3", 0xB},
61 	{"L801", 0xC},
62 	{"L802", 0xC},
63 	{"L803", 0xC},
64 	{"L901", 0xD},
65 	{"L902", 0x8},
66 	{"L903", 0xD},
67 	{"L904", 0xD},
68 	{"L905", 0xD},
69 	{"L906", 0xD},
70 	{"L907", 0xD},
71 	{"LA03", 0x4},
72 	{"MOINE", 0xB},
73 	{"L908", 0x8},
74 	{"L909", 0x8},
75 	{"L807", 0xC},
76 	{"L808", 0xC},
77 	{"LA01", 0xB},
78 	{"L1201", 0xC},
79 	{"L1202", 0xC},
80 	{"L1203", 0xC},
81 	{"L1210", 0x5},
82 	{"L1211", 0xC},
83 	{"L1214", 0xC},
84 	{"L1215", 0xC},
85 	{"L1216", 0xC},
86 	{"L1217", 0xC},
87 	{"L1218", 0xC},
88 	{"L1219", 0xC},
89 	{"L1220", 0xC},
90 	{"SEIGNEUR", 0x6},
91 	{"PERE0", 0xD},
92 	{"L1302", 0x4},
93 	{"L1303", 0x4},
94 	{"L1304", 0x4},
95 	{"L1401", 0xF},
96 	{"L1402", 0xF},
97 	{"L1501", 0x8},
98 	{"L1503", 0x8},
99 	{"L1504", 0x4},
100 	{"L1505", 0x8},
101 	{"L1506", 0x8},
102 	{"L1601", 0xB},
103 	{"L1602", 0xB},
104 	{"L1603", 0xB},
105 	{"L1604", 0x4},
106 	{"L1605", 0x4},
107 	{"L1701", 0x4},
108 	{"L1702", 0x4},
109 	{"L1801", 0x6},
110 	{"L1904", 0x8},
111 	{"L2002", 0x8},
112 	{"L2003", 0x8},
113 	{"L2101", 0x4},
114 	{"L2102", 0x4},
115 	{"L2201", 0x7},
116 	{"L2202", 0x7},
117 	{"L2203", 0xE},
118 	{"L2305", 0x9},
119 	{"L2306", 0x9},
120 	{"GARDE1", 0x7},
121 	{"L2402", 0x7},
122 	{"L2407", 0x7},
123 	{"L2408", 0x7},
124 	{"GARDE2", 0x6},
125 	{"L2601", 0x6},
126 	{"L2602", 0x6},
127 	{"L2603", 0x6},
128 	{"L2604", 0x6},
129 	{"L2605", 0x8},
130 	{"L2606", 0x8},
131 	{"L2607", 0x8},
132 	{"L2610", 0x6},
133 	{"L2611", 0x6},
134 	{"L2612", 0x6},
135 	{"L2613", 0x8},
136 	{"L2614", 0x6},
137 	{"VOYAGEUR", 0x6},
138 	{"L2701", 0xD},
139 	{"L2702", 0xD},
140 	{"L2703", 0x6},
141 	{"L2801", 0xD},
142 	{"L2802", 0xD},
143 	{"L2803", 0xD},
144 	{"L2804", 0xD},
145 	{"L2807", 0xD},
146 	{"L2902", 0x8},
147 	{"L2903", 0x8},
148 	{"L3101", 0xA},
149 	{"L3102", 0xA},
150 	{"L3103", 0xA},
151 	{"L3203", 0xF},
152 	{"L3204", 0xF},
153 	{"L3001", 0x7},
154 	{"L3002", 0x7},
155 	{"L3416", 0xC},
156 	{"L3601", 0x5},
157 	{"L3602", 0x5},
158 	{"L3603", 0x5},
159 	{"L3607", 0x5},
160 	{"L3701", 0x8},
161 	{"L3702", 0x8},
162 	{"L3703", 0x8},
163 	{"L4001", 0xD},
164 	{"L4002", 0xD},
165 	{"L4103", 0xF},
166 	{"L4106", 0xF},
167 	{"CRUGHON1", 0xC},
168 	{"L4203", 0xC},
169 	{"L4301", 0xC},
170 	{"L4302", 0xC},
171 	{"L4303", 0xC},
172 	{"FUTUR2", 0x6},
173 	{"L4601", 0xE},
174 	{"L4603", 0x1},
175 	{"L4106", 0xF},
176 	{"L4801", 0xD},
177 	{"L4802", 0xD},
178 	{"FIN01", 0xB},
179 	{"FIN02", 0xB},
180 	{"FIN03", 0xB},
181 	{"FIN", 0x9},
182 };
183 
184 void convertMask(byte *dest, const byte *source, int16 width, int16 height);
185 void convert8BBP(byte *dest, const byte *source, int16 width, int16 height);
186 void convert8BBP2(byte *dest, byte *source, int16 width, int16 height);
187 
AnimData()188 AnimData::AnimData() : _width(0), _height(0), _bpp(0), _var1(0), _data(NULL),
189 	_mask(NULL), _fileIdx(-1), _frameIdx(-1), _realWidth(0), _size(0) {
190 
191 	memset(_name, 0, sizeof(_name));
192 }
193 
194 /**
195  * Copy constructor
196  */
AnimData(const AnimData & src)197 AnimData::AnimData(const AnimData &src) : _width(src._width),
198 	_height(src._height), _bpp(src._bpp), _var1(src._var1),
199 	_data(NULL), _mask(NULL), _fileIdx(src._fileIdx),
200 	_frameIdx(src._frameIdx), _realWidth(src._realWidth), _size(src._size) {
201 
202 	if (src._data) {
203 		_data = new byte[_size];
204 		assert(_data);
205 		memcpy(_data, src._data, _size * sizeof(byte));
206 	}
207 
208 	if (src._mask) {
209 		_mask = new byte[_size];
210 		assert(_mask);
211 		memcpy(_mask, src._mask, _size * sizeof(byte));
212 	}
213 
214 	memset(_name, 0, sizeof(_name));
215 	strcpy(_name, src._name);
216 }
217 
218 /**
219  * Destructor
220  */
~AnimData()221 AnimData::~AnimData() {
222 	clear();
223 }
224 
225 /**
226  * Assingment operator
227  */
operator =(const AnimData & src)228 AnimData &AnimData::operator=(const AnimData &src) {
229 	AnimData tmp = src;
230 	byte *ptr;
231 
232 	_width = tmp._width;
233 	_height = tmp._height;
234 	_bpp = tmp._bpp;
235 	_var1 = tmp._var1;
236 
237 	ptr = _data;
238 	_data = tmp._data;
239 	tmp._data = ptr;
240 
241 	ptr = _mask;
242 	_mask = tmp._mask;
243 	tmp._mask = ptr;
244 
245 	_fileIdx = tmp._fileIdx;
246 	_frameIdx = tmp._frameIdx;
247 	memset(_name, 0, sizeof(_name));
248 	strcpy(_name, tmp._name);
249 	_realWidth = tmp._realWidth;
250 	_size = tmp._size;
251 
252 	return *this;
253 }
254 
getColor(int x,int y)255 byte AnimData::getColor(int x, int y) {
256 	assert(_data);
257 	assert(x >= 0 && x < _realWidth && y >= 0 && y <= _height);
258 	assert(x + y * _realWidth < _size);
259 
260 	return _data[x + y * _realWidth];
261 }
262 
263 /**
264  * Load and decode image frame
265  * @param d Encoded image data
266  * @param type Encoding type
267  * @param w Image width
268  * @param h Image height
269  * @param file Data file index in bundle
270  * @param frame Image frame index
271  * @param n Part name
272  * @param transparent Transparent color (for ANIM_MASKSPRITE)
273  */
load(byte * d,int type,uint16 w,uint16 h,int16 file,int16 frame,const char * n,byte transparent)274 void AnimData::load(byte *d, int type, uint16 w, uint16 h, int16 file,
275                     int16 frame, const char *n, byte transparent) {
276 	assert(d);
277 
278 	if (_data) {
279 		clear();
280 	}
281 
282 	_width = w * 2;
283 	_height = h;
284 	_var1 = _width >> 3;
285 	_data = NULL;
286 	_mask = NULL;
287 	_fileIdx = file;
288 	_frameIdx = frame;
289 	memset(_name, 0, sizeof(_name));
290 	Common::strlcpy(_name, n, sizeof(_name));
291 	_realWidth = w;
292 
293 	switch (type) {
294 	case ANIM_RAW:
295 		_width = w;
296 		_var1 = w >> 3;
297 		_bpp = 4;
298 		_size = w * h;
299 		_data = new byte[_size];
300 		assert(_data);
301 		memcpy(_data, d, _size * sizeof(byte));
302 		break;
303 
304 	case ANIM_MASK:
305 		_bpp = 1;
306 		_size = w * h * 8;
307 		_data = new byte[_size];
308 		_realWidth = w * 8;
309 		assert(_data);
310 		convertMask(_data, d, w, h);
311 		break;
312 
313 	case ANIM_SPRITE:
314 		_bpp = 4;
315 		_size = w * h * 2;
316 		_data = new byte[_size];
317 		_realWidth = w * 2;
318 		assert(_data);
319 		gfxConvertSpriteToRaw(_data, d, w, h);
320 		break;
321 
322 	case ANIM_MASKSPRITE:
323 		_bpp = 4;
324 		_size = w * h * 2;
325 		_data = new byte[_size];
326 		_mask = new byte[_size];
327 		_realWidth = w * 2;
328 		assert(_data && _mask);
329 		gfxConvertSpriteToRaw(_data, d, w, h);
330 		generateMask(_data, _mask, _size, transparent);
331 		break;
332 
333 	case ANIM_PALSPRITE:
334 		_bpp = 5;
335 		_size = w * h * 2;
336 		_data = new byte[_size];
337 		_realWidth = w * 2;
338 		assert(_data);
339 		convert8BBP(_data, d, w, h);
340 		break;
341 
342 	case ANIM_FULLSPRITE:
343 		_bpp = 8;
344 		_var1 = _width >> 4;
345 		_size = w * h;
346 		_data = new byte[_size];
347 		assert(_data);
348 		convert8BBP2(_data, d, w, h);
349 		break;
350 
351 	default:
352 		error("AnimData::load: unknown image type");
353 	}
354 }
355 
356 /**
357  * Reset image
358  */
clear()359 void AnimData::clear() {
360 	delete[] _data;
361 	delete[] _mask;
362 
363 	_width = 0;
364 	_height = 0;
365 	_bpp = 0;
366 	_var1 = 0;
367 	_data = NULL;
368 	_mask = NULL;
369 	_fileIdx = -1;
370 	_frameIdx = -1;
371 	memset(_name, 0, sizeof(_name));
372 	_size = 0;
373 }
374 
375 /**
376  * Write image identifiers to savefile
377  * @param fHandle Savefile open for writing
378  */
save(Common::OutSaveFile & fHandle) const379 void AnimData::save(Common::OutSaveFile &fHandle) const {
380 	fHandle.writeUint16BE(_width);
381 	fHandle.writeUint16BE(_var1);
382 	fHandle.writeUint16BE(_bpp);
383 	fHandle.writeUint16BE(_height);
384 	fHandle.writeUint32BE(_data != NULL); // _data
385 	fHandle.writeUint32BE(_mask != NULL); // _mask
386 	fHandle.writeUint16BE(_fileIdx);
387 	fHandle.writeUint16BE(_frameIdx);
388 	fHandle.write(_name, sizeof(_name));
389 }
390 
391 /**
392  * Clear part of animDataTable
393  * @param startIdx First image frame to be cleared
394  * @param numIdx Number of image frames to be cleared
395  */
freeAnimDataRange(byte startIdx,byte numIdx)396 void freeAnimDataRange(byte startIdx, byte numIdx) {
397 	for (byte i = 0; i < numIdx; i++) {
398 		g_cine->_animDataTable[startIdx + i].clear();
399 	}
400 }
401 
402 /**
403  * Clear whole animDataTable
404  */
freeAnimDataTable()405 void freeAnimDataTable() {
406 	freeAnimDataRange(0, NUM_MAX_ANIMDATA);
407 }
408 
409 /**
410  * Find transparent color index for image
411  * @param animName Image file name
412  */
getAnimTransparentColor(const char * animName)413 static byte getAnimTransparentColor(const char *animName) {
414 	char name[15];
415 
416 	removeExtention(name, animName);
417 
418 	for (int i = 0; i < ARRAYSIZE(transparencyData); i++) {
419 		if (!strcmp(name, transparencyData[i].name)) {
420 			return transparencyData[i].color;
421 		}
422 	}
423 	return 0;
424 }
425 
426 /**
427  * Generate mask for image
428  * @param[in] sprite Image data
429  * @param[out] mask Image mask
430  * @param size Image data length
431  * @param transparency Transparent color index
432  */
generateMask(const byte * sprite,byte * mask,uint16 size,byte transparency)433 void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency) {
434 	for (uint16 i = 0; i < size; i++) {
435 		if (*(sprite++) != transparency) {
436 			*(mask++) = 0;
437 		} else {
438 			*(mask++) = 1;
439 		}
440 	}
441 }
442 
443 /**
444  * Decode 1bpp mask
445  * @param[out] dest Decoded mask
446  * @param[in] source Encoded mask
447  * @param width Mask width
448  * @param height Mask height
449  */
convertMask(byte * dest,const byte * source,int16 width,int16 height)450 void convertMask(byte *dest, const byte *source, int16 width, int16 height) {
451 	int16 i, j;
452 	byte maskEntry;
453 
454 	for (i = 0; i < width * height; i++) {
455 		maskEntry = *(source++);
456 		for (j = 0; j < 8; j++) {
457 			*(dest++) = (maskEntry & 0x80) ? 0 : 1;
458 			maskEntry <<= 1;
459 		}
460 	}
461 }
462 
463 /**
464  * Decode 4bpp sprite
465  * @param[out] dest Decoded image
466  * @param[in] source Encoded image
467  * @param width Image width
468  * @param height Image height
469  */
convert4BBP(byte * dest,const byte * source,int16 width,int16 height)470 void convert4BBP(byte *dest, const byte *source, int16 width, int16 height) {
471 	byte maskEntry;
472 
473 	for (int16 i = 0; i < width * height; i++) {
474 		maskEntry = *(source++);
475 		*(dest++) = (maskEntry & 0xF0) >> 4;
476 		*(dest++) = (maskEntry & 0xF);
477 	}
478 }
479 
480 /**
481  * Read image header
482  * @param[out] animHeader Image header reference
483  * @param readS Input stream open for reading
484  */
loadAnimHeader(AnimHeaderStruct & animHeader,Common::SeekableReadStream & readS)485 void loadAnimHeader(AnimHeaderStruct &animHeader, Common::SeekableReadStream &readS) {
486 	animHeader.field_0 = readS.readByte();
487 	animHeader.field_1 = readS.readByte();
488 	animHeader.field_2 = readS.readByte();
489 	animHeader.field_3 = readS.readByte();
490 	animHeader.frameWidth = readS.readUint16BE();
491 	animHeader.frameHeight = readS.readUint16BE();
492 	animHeader.field_8 = readS.readByte();
493 	animHeader.field_9 = readS.readByte();
494 	animHeader.field_A = readS.readByte();
495 	animHeader.field_B = readS.readByte();
496 	animHeader.field_C = readS.readByte();
497 	animHeader.field_D = readS.readByte();
498 	animHeader.numFrames = readS.readUint16BE();
499 	animHeader.field_10 = readS.readByte();
500 	animHeader.field_11 = readS.readByte();
501 	animHeader.field_12 = readS.readByte();
502 	animHeader.field_13 = readS.readByte();
503 	animHeader.field_14 = readS.readUint16BE();
504 }
505 
506 /**
507  * Find next empty space animDataTable
508  * @param start First index to check
509  */
emptyAnimSpace(int start=0)510 int emptyAnimSpace(int start = 0) {
511 	for (; start < NUM_MAX_ANIMDATA; start++) {
512 		if (!g_cine->_animDataTable[start].data()) {
513 			return start;
514 		}
515 	}
516 
517 	return -1;
518 }
519 
520 /**
521  * Load SPL data into animDataTable
522  * @param resourceName SPL filename
523  * @param idx Target index in animDataTable (-1 if any empty space will do)
524  * @return The number of the animDataTable entry after the loaded SPL data (-1 if error)
525  */
loadSpl(const char * resourceName,int16 idx)526 int loadSpl(const char *resourceName, int16 idx) {
527 	int16 foundFileIdx = findFileInBundle(resourceName);
528 	int entry;
529 
530 	if (foundFileIdx < 0) {
531 		return -1;
532 	}
533 
534 	byte *dataPtr = readBundleFile(foundFileIdx);
535 
536 	entry = idx < 0 ? emptyAnimSpace() : idx;
537 	assert(entry >= 0);
538 	g_cine->_animDataTable[entry].load(dataPtr, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName);
539 
540 	free(dataPtr);
541 	return entry + 1;
542 }
543 
544 /**
545  * Load 1bpp mask
546  * @param resourceName Mask filename
547  * @param idx Target index in animDataTable (-1 if any empty space will do)
548  * @param frameIndex frame of animation to load (-1 for all frames)
549  * @return The number of the animDataTable entry after the loaded mask (-1 if error)
550  */
loadMsk(const char * resourceName,int16 idx,int16 frameIndex)551 int loadMsk(const char *resourceName, int16 idx, int16 frameIndex) {
552 	int16 foundFileIdx = findFileInBundle(resourceName);
553 	if (foundFileIdx < 0) {
554 		return -1;
555 	}
556 
557 	int entry = 0;
558 	byte *dataPtr = readBundleFile(foundFileIdx);
559 	byte *ptr;
560 	AnimHeaderStruct animHeader;
561 
562 	Common::MemoryReadStream readS(dataPtr, 0x16);
563 	loadAnimHeader(animHeader, readS);
564 	ptr = dataPtr + 0x16;
565 
566 	int16 startFrame = 0;
567 	int16 endFrame = animHeader.numFrames;
568 
569 	if (frameIndex >= 0) {
570 		startFrame = frameIndex;
571 		endFrame = frameIndex + 1;
572 		ptr += frameIndex * animHeader.frameWidth * animHeader.frameHeight;
573 	}
574 
575 	entry = idx < 0 ? emptyAnimSpace() : idx;
576 	assert(entry >= 0);
577 	for (int16 i = startFrame; i < endFrame; i++, entry++) {
578 		g_cine->_animDataTable[entry].load(ptr, ANIM_MASK, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName);
579 		ptr += animHeader.frameWidth * animHeader.frameHeight;
580 	}
581 
582 	free(dataPtr);
583 	return entry;
584 }
585 
586 /**
587  * Load animation
588  * @param resourceName Animation filename
589  * @param idx Target index in animDataTable (-1 if any empty space will do)
590  * @param frameIndex frame of animation to load (-1 for all frames)
591  * @return The number of the animDataTable entry after the loaded animation (-1 if error)
592  */
loadAni(const char * resourceName,int16 idx,int16 frameIndex)593 int loadAni(const char *resourceName, int16 idx, int16 frameIndex) {
594 	int16 foundFileIdx = findFileInBundle(resourceName);
595 	if (foundFileIdx < 0) {
596 		return -1;
597 	}
598 
599 	int entry = 0;
600 	byte *dataPtr = readBundleFile(foundFileIdx);
601 	byte *ptr;
602 	byte transparentColor;
603 	AnimHeaderStruct animHeader;
604 
605 	Common::MemoryReadStream readS(dataPtr, 0x16);
606 	loadAnimHeader(animHeader, readS);
607 	ptr = dataPtr + 0x16;
608 
609 	int16 startFrame = 0;
610 	int16 endFrame = animHeader.numFrames;
611 
612 	if (frameIndex >= 0) {
613 		startFrame = frameIndex;
614 		endFrame = frameIndex + 1;
615 		ptr += frameIndex * animHeader.frameWidth * animHeader.frameHeight;
616 	}
617 
618 	transparentColor = getAnimTransparentColor(resourceName);
619 
620 	// TODO: Merge this special case hack into getAnimTransparentColor somehow.
621 	// HACK: Versions of TITRE.ANI with height 37 use color 0xF for transparency.
622 	//       Versions of TITRE.ANI with height 57 use color 0x0 for transparency.
623 	//       Fixes bug #2057619: FW: Glitches in title display of demo (regression).
624 	if (scumm_stricmp(resourceName, "TITRE.ANI") == 0 && animHeader.frameHeight == 37) {
625 		transparentColor = 0xF;
626 	}
627 
628 	entry = idx < 0 ? emptyAnimSpace() : idx;
629 	assert(entry >= 0);
630 
631 	for (int16 i = startFrame; i < endFrame; i++, entry++) {
632 		// special case transparency handling
633 		if (!strcmp(resourceName, "L2202.ANI")) {
634 			transparentColor = i < 2 ? 0 : 7;
635 		} else if (!strcmp(resourceName, "L4601.ANI")) {
636 			transparentColor = i < 1 ? 0xE : 0;
637 		}
638 
639 		g_cine->_animDataTable[entry].load(ptr, ANIM_MASKSPRITE, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName, transparentColor);
640 		ptr += animHeader.frameWidth * animHeader.frameHeight;
641 	}
642 
643 	free(dataPtr);
644 	return entry;
645 }
646 
647 /**
648  * Decode 16 color image with palette
649  * @param[out] dest Decoded image
650  * @param[in] source Encoded image
651  * @param width Image width
652  * @param height Image height
653  */
convert8BBP(byte * dest,const byte * source,int16 width,int16 height)654 void convert8BBP(byte *dest, const byte *source, int16 width, int16 height) {
655 	const byte *table = source;
656 	byte color;
657 
658 	source += 16;
659 
660 	for (uint16 i = 0; i < width * height; i++) {
661 		color = *(source++);
662 
663 		*(dest++) = table[color >> 4];
664 		*(dest++) = table[color & 0xF];
665 	}
666 }
667 
668 /**
669  * Decode 8bit image
670  * @param[out] dest Decoded image
671  * @param[in] source Encoded image
672  * @param width Image width
673  * @param height Image height
674  * \attention Data in source are destroyed during decoding
675  */
convert8BBP2(byte * dest,byte * source,int16 width,int16 height)676 void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
677 	uint16 i, j;
678 	int k, m;
679 	byte color;
680 
681 	for (j = 0; j < (width * height) / 16; j++) {
682 		// m = 0: even bits, m = 1: odd bits
683 		for (m = 0; m <= 1; m++) {
684 			for (i = 0; i < 8; i++) {
685 				color = 0;
686 				for (k = 14 + m; k >= 0; k -= 2) {
687 					color |= ((*(source + k) & 0x080) >> 7);
688 					*(source + k) <<= 1;
689 					if (k > 0 + m)
690 						color <<= 1;
691 				} // end k
692 				*(dest++) = color;
693 			} // end i
694 		} // end m
695 
696 		source += 0x10;
697 	} // end j
698 }
699 
700 /**
701  * Load image set
702  * @param resourceName Image set filename
703  * @param idx Target index in animDataTable (-1 if any empty space will do)
704  * @param frameIndex frame of animation to load (-1 for all frames)
705  * @return The number of the animDataTable entry after the loaded image set (-1 if error)
706  */
loadSet(const char * resourceName,int16 idx,int16 frameIndex=-1)707 int loadSet(const char *resourceName, int16 idx, int16 frameIndex = -1) {
708 	AnimHeader2Struct header2;
709 	uint16 numSpriteInAnim;
710 	int16 foundFileIdx = findFileInBundle(resourceName);
711 	int16 entry;
712 	byte *ptr, *startOfDataPtr, *dataPtr, *origDataPtr;
713 	int type;
714 
715 	if (foundFileIdx < 0) {
716 		return -1;
717 	}
718 
719 	origDataPtr = dataPtr = readBundleFile(foundFileIdx);
720 	assert(!memcmp(dataPtr, "SET", 3));
721 	ptr = dataPtr + 4;
722 
723 	numSpriteInAnim = READ_BE_UINT16(ptr);
724 	ptr += 2;
725 
726 	startOfDataPtr = ptr + numSpriteInAnim * 0x10;
727 
728 	entry = idx < 0 ? emptyAnimSpace() : idx;
729 	assert(entry >= 0);
730 
731 	int16 startFrame = 0;
732 	int16 endFrame = numSpriteInAnim;
733 
734 	if (frameIndex >= 0) {
735 		startFrame = frameIndex;
736 		endFrame = frameIndex + 1;
737 		ptr += 0x10 * frameIndex;
738 	}
739 
740 	for (int16 i = startFrame; i < endFrame; i++, entry++) {
741 		Common::MemoryReadStream readS(ptr, 0x10);
742 
743 		header2.field_0 = readS.readUint32BE();
744 		header2.width = readS.readUint16BE();
745 		header2.height = readS.readUint16BE();
746 		header2.type = readS.readUint16BE();
747 		header2.field_A = readS.readUint16BE();
748 		header2.field_C = readS.readUint16BE();
749 		header2.field_E = readS.readUint16BE();
750 
751 		ptr += 0x10;
752 
753 		dataPtr = startOfDataPtr + header2.field_0;
754 
755 		if (header2.type == 1) {
756 			type = ANIM_MASK;
757 		} else if (header2.type == 4) {
758 			type = ANIM_SPRITE;
759 		} else if (header2.type == 5) {
760 			type = ANIM_PALSPRITE;
761 		} else {
762 			type = ANIM_FULLSPRITE;
763 		}
764 
765 		g_cine->_animDataTable[entry].load(dataPtr, type, header2.width, header2.height, foundFileIdx, i, currentPartName);
766 	}
767 
768 	free(origDataPtr);
769 	return entry;
770 }
771 
772 /**
773  * Load SEQ data into animDataTable
774  * @param resourceName SEQ data filename
775  * @param idx Target index in animDataTable (-1 if any empty space will do)
776  * @return The number of the animDataTable entry after the loaded SEQ data (-1 if error)
777  */
loadSeq(const char * resourceName,int16 idx)778 int loadSeq(const char *resourceName, int16 idx) {
779 	int16 foundFileIdx = findFileInBundle(resourceName);
780 	if (foundFileIdx < 0) {
781 		return -1;
782 	}
783 
784 	byte *dataPtr = readBundleFile(foundFileIdx);
785 	int entry = idx < 0 ? emptyAnimSpace() : idx;
786 
787 	g_cine->_animDataTable[entry].load(dataPtr + 0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize - 0x16, 1, foundFileIdx, 0, currentPartName);
788 	free(dataPtr);
789 	return entry + 1;
790 }
791 
792 /**
793  * Load a resource into animDataTable
794  * @param resourceName Resource's filename
795  * @param idx Target index in animDataTable (-1 if any empty space will do)
796  * @return The number of the animDataTable entry after the loaded resource (-1 if error)
797  * @todo Implement loading of all resource types
798  */
loadResource(const char * resourceName,int16 idx,int16 frameIndex)799 int loadResource(const char *resourceName, int16 idx, int16 frameIndex) {
800 	int result = -1; // Return an error by default
801 	if (strstr(resourceName, ".SPL")) {
802 		result = loadSpl(resourceName, idx);
803 	} else if (strstr(resourceName, ".MSK")) {
804 		result = loadMsk(resourceName, idx, frameIndex);
805 	} else if (strstr(resourceName, ".ANI")) {
806 		result = loadAni(resourceName, idx, frameIndex);
807 	} else if (strstr(resourceName, ".ANM")) {
808 		result = loadAni(resourceName, idx, frameIndex);
809 	} else if (strstr(resourceName, ".SET")) {
810 		result = loadSet(resourceName, idx, frameIndex);
811 	} else if (strstr(resourceName, ".SEQ")) {
812 		result = loadSeq(resourceName, idx);
813 	} else if (strstr(resourceName, ".H32")) {
814 		warning("loadResource: Ignoring file '%s' (Load at %d)", resourceName, idx);
815 	} else if (strstr(resourceName, ".AMI")) {
816 		warning("loadResource: Ignoring file '%s' (Load at %d)", resourceName, idx);
817 	} else if (strstr(resourceName, "ECHEC")) { // Echec (French) means failure
818 		g_cine->quitGame();
819 	} else {
820 		error("loadResource: Cannot determine type for '%s'", resourceName);
821 	}
822 
823 	return result;
824 }
825 
826 } // End of namespace Cine
827