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