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 "common/substream.h"
24
25 #include "director/director.h"
26 #include "director/frame.h"
27 #include "director/score.h"
28 #include "director/movie.h"
29 #include "director/sprite.h"
30 #include "director/util.h"
31
32 namespace Director {
33
Frame(Score * score,int numChannels)34 Frame::Frame(Score *score, int numChannels) {
35 _score = score;
36 _vm = score->getMovie()->getVM();
37 _transDuration = 0;
38 _transType = kTransNone;
39 _transArea = 0;
40 _transChunkSize = 0;
41 _tempo = 0;
42
43 _numChannels = numChannels;
44
45 _sound1 = CastMemberID(0, 0);
46 _sound2 = CastMemberID(0, 0);
47 _soundType1 = 0;
48 _soundType2 = 0;
49
50 _actionId = CastMemberID(0, 0);
51 _skipFrameFlag = 0;
52 _blend = 0;
53
54 _colorTempo = 0;
55 _colorSound1 = 0;
56 _colorSound2 = 0;
57 _colorScript = 0;
58 _colorTrans = 0;
59
60 _sprites.resize(_numChannels + 1);
61
62 for (uint16 i = 0; i < _sprites.size(); i++) {
63 Sprite *sp = new Sprite(this);
64 _sprites[i] = sp;
65 }
66 }
67
Frame(const Frame & frame)68 Frame::Frame(const Frame &frame) {
69 _vm = frame._vm;
70 _numChannels = frame._numChannels;
71 _actionId = frame._actionId;
72 _transArea = frame._transArea;
73 _transDuration = frame._transDuration;
74 _transType = frame._transType;
75 _transChunkSize = frame._transChunkSize;
76 _tempo = frame._tempo;
77 _sound1 = frame._sound1;
78 _sound2 = frame._sound2;
79 _soundType1 = frame._soundType1;
80 _soundType2 = frame._soundType2;
81 _skipFrameFlag = frame._skipFrameFlag;
82 _blend = frame._blend;
83
84 _colorTempo = frame._colorTempo;
85 _colorSound1 = frame._colorSound1;
86 _colorSound2 = frame._colorSound2;
87 _colorScript = frame._colorScript;
88 _colorTrans = frame._colorTrans;
89
90 _palette = frame._palette;
91
92 _score = frame._score;
93
94 debugC(1, kDebugLoading, "Frame. action: %s transType: %d transDuration: %d", _actionId.asString().c_str(), _transType, _transDuration);
95
96 _sprites.resize(_numChannels + 1);
97
98 for (uint16 i = 0; i <= _numChannels; i++) {
99 _sprites[i] = new Sprite(*frame._sprites[i]);
100 }
101 }
102
~Frame()103 Frame::~Frame() {
104 for (uint16 i = 0; i < _sprites.size(); i++)
105 delete _sprites[i];
106 }
107
readChannel(Common::SeekableReadStreamEndian & stream,uint16 offset,uint16 size)108 void Frame::readChannel(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size) {
109 if (offset >= 32) {
110 if (size <= 16)
111 readSprite(stream, offset, size);
112 else {
113 // read > 1 sprites channel
114 while (size > 16) {
115 byte spritePosition = (offset - 32) / 16;
116 uint16 nextStart = (spritePosition + 1) * 16 + 32;
117 uint16 needSize = nextStart - offset;
118 readSprite(stream, offset, needSize);
119 offset += needSize;
120 size -= needSize;
121 }
122 readSprite(stream, offset, size);
123 }
124 } else {
125 readMainChannels(stream, offset, size);
126 }
127 }
128
readChannels(Common::ReadStreamEndian * stream,uint16 version)129 void Frame::readChannels(Common::ReadStreamEndian *stream, uint16 version) {
130 byte unk[48];
131
132 if (version < kFileVer400) {
133 // Sound/Tempo/Transition
134 _actionId = CastMemberID(stream->readByte(), 0);
135 _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
136 uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
137
138 if (transFlags & 0x80)
139 _transArea = 1;
140 else
141 _transArea = 0;
142 _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
143
144 _transChunkSize = stream->readByte();
145 _tempo = stream->readByte();
146 _transType = static_cast<TransitionType>(stream->readByte());
147 _sound1 = CastMemberID(stream->readUint16(), 0);
148 _sound2 = CastMemberID(stream->readUint16(), 0);
149 _soundType2 = stream->readByte();
150
151 _skipFrameFlag = stream->readByte();
152 _blend = stream->readByte();
153
154 if (_vm->getPlatform() == Common::kPlatformWindows) {
155 _sound2 = CastMemberID(stream->readUint16(), 0);
156 _soundType2 = stream->readByte();
157 }
158
159 // palette
160 if (_vm->getPlatform() == Common::kPlatformWindows) {
161 _palette.paletteId = stream->readUint16();
162 _palette.firstColor = stream->readByte(); // for cycles. note: these start at 0x80 (for pal entry 0)!
163 _palette.lastColor = stream->readByte();
164 _palette.flags = stream->readByte();
165 _palette.speed = stream->readByte();
166 _palette.frameCount = stream->readUint16();
167 _palette.cycleCount = stream->readUint16();
168
169 stream->read(unk, 6);
170 } else {
171 stream->read(unk, 4);
172
173 _palette.paletteId = stream->readByte();
174 _palette.firstColor = stream->readByte(); // for cycles. note: these start at 0x80 (for pal entry 0)!
175 _palette.lastColor = stream->readByte();
176 _palette.flags = stream->readByte();
177 _palette.cycleCount = stream->readByte();
178 _palette.speed = stream->readByte();
179 _palette.frameCount = stream->readByte();
180 _palette.cycleLength = stream->readByte();
181
182 stream->read(unk, 4);
183 }
184
185 debugC(8, kDebugLoading, "Frame::readChannels(): %d %d %d %d %d %d %d %d %d %d %d", _actionId.member, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1.member, _skipFrameFlag, _blend, _sound2.member, _soundType2);
186
187 if (_vm->getPlatform() == Common::kPlatformMacintosh || _vm->getPlatform() == Common::kPlatformMacintoshII)
188 stream->read(unk, 3);
189 } else if (version >= kFileVer400 && version < kFileVer500) {
190 // Sound/Tempo/Transition
191 int unk1 = stream->readByte();
192 if (unk1) {
193 warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
194 }
195 _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
196 uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
197
198 if (transFlags & 0x80)
199 _transArea = 1;
200 else
201 _transArea = 0;
202 _transDuration = (transFlags & 0x7f) * 250; // Duration is 1/4 secs
203
204 _transChunkSize = stream->readByte();
205 _tempo = stream->readByte();
206 _transType = static_cast<TransitionType>(stream->readByte());
207 _sound1 = CastMemberID(stream->readUint16(), 0);
208
209 _sound2 = CastMemberID(stream->readUint16(), 0);
210 _soundType2 = stream->readByte();
211
212 _skipFrameFlag = stream->readByte();
213 _blend = stream->readByte();
214
215 _colorTempo = stream->readByte();
216 _colorSound1 = stream->readByte();
217 _colorSound2 = stream->readByte();
218
219 _actionId = CastMemberID(stream->readUint16(), 0);
220
221 _colorScript = stream->readByte();
222 _colorTrans = stream->readByte();
223
224 // palette
225 _palette.paletteId = stream->readSint16();
226 _palette.firstColor = stream->readByte(); // for cycles. note: these start at 0x80 (for pal entry 0)!
227 _palette.lastColor = stream->readByte();
228 _palette.flags = stream->readByte();
229 _palette.speed = stream->readByte();
230 _palette.frameCount = stream->readUint16();
231 _palette.cycleCount = stream->readUint16();
232 _palette.fade = stream->readByte();
233 _palette.delay = stream->readByte();
234 _palette.style = stream->readByte();
235
236 stream->readByte();
237 stream->readUint16();
238 stream->readUint16();
239
240 _palette.colorCode = stream->readByte();
241
242 stream->readByte();
243
244 debugC(8, kDebugLoading, "Frame::readChannels(): %d %d %d %d %d %d %d %d %d %d %d", _actionId.member, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1.member, _skipFrameFlag, _blend, _sound2.member, _soundType2);
245 } else if (version >= kFileVer500 && version < kFileVer600) {
246 // Sound/Tempo/Transition channel
247 stream->read(unk, 24);
248
249 // palette
250 stream->read(unk, 24);
251 } else {
252 // Sound[2]
253 // palette
254 // Transition
255 // Tempo
256 // Script
257 }
258
259 _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
260 _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
261
262 for (int i = 0; i < _numChannels; i++) {
263 Sprite &sprite = *_sprites[i + 1];
264
265 if (version < kFileVer500) {
266 sprite._scriptId = CastMemberID(stream->readByte(), 0);
267 sprite._spriteType = (SpriteType)stream->readByte();
268 sprite._enabled = sprite._spriteType != kInactiveSprite;
269 if (version >= kFileVer400) {
270 sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
271 sprite._backColor = _vm->transformColor((uint8)stream->readByte());
272 } else {
273 // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
274 sprite._foreColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
275 sprite._backColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
276 }
277
278 sprite._thickness = stream->readByte();
279 sprite._inkData = stream->readByte();
280
281 if (sprite.isQDShape()) {
282 sprite._pattern = stream->readUint16();
283 } else {
284 sprite._castId = CastMemberID(stream->readUint16(), 0);
285 }
286
287 sprite._startPoint.y = (int16)stream->readUint16();
288 sprite._startPoint.x = (int16)stream->readUint16();
289
290 sprite._height = (int16)stream->readUint16();
291 sprite._width = (int16)stream->readUint16();
292
293 if (version >= kFileVer400) {
294 sprite._scriptId = CastMemberID(stream->readUint16(), 0);
295 // & 0x0f scorecolor
296 // 0x10 forecolor is rgb
297 // 0x20 bgcolor is rgb
298 // 0x40 editable
299 // 0x80 moveable
300 sprite._colorcode = stream->readByte();
301 sprite._blendAmount = stream->readByte();
302 }
303 } else if (version >= kFileVer500 && version < kFileVer600) {
304 sprite._spriteType = (SpriteType)stream->readByte();
305 sprite._inkData = stream->readByte();
306
307 uint16 castLib = stream->readUint16();
308 uint16 memberID = stream->readUint16();
309 sprite._castId = CastMemberID(memberID, castLib);
310
311 uint16 scriptCastLib = stream->readUint16();
312 uint16 scriptMemberID = stream->readUint16();
313 sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
314
315 sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
316 sprite._backColor = _vm->transformColor((uint8)stream->readByte());
317
318 sprite._startPoint.y = (int16)stream->readUint16();
319 sprite._startPoint.x = (int16)stream->readUint16();
320
321 sprite._height = (int16)stream->readUint16();
322 sprite._width = (int16)stream->readUint16();
323
324 sprite._colorcode = stream->readByte();
325 sprite._blendAmount = stream->readByte();
326 sprite._thickness = stream->readByte();
327 stream->readByte(); // unused
328 } else if (version >= kFileVer600 && version < kFileVer700) {
329 sprite._spriteType = (SpriteType)stream->readByte();
330 sprite._inkData = stream->readByte();
331
332 sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
333 sprite._backColor = _vm->transformColor((uint8)stream->readByte());
334
335 uint16 castLib = stream->readUint16();
336 uint16 memberID = stream->readUint16();
337 sprite._castId = CastMemberID(memberID, castLib);
338
339 /* uint32 spriteId = */stream->readUint32();
340
341 sprite._startPoint.y = (int16)stream->readUint16();
342 sprite._startPoint.x = (int16)stream->readUint16();
343
344 sprite._height = (int16)stream->readUint16();
345 sprite._width = (int16)stream->readUint16();
346
347 sprite._colorcode = stream->readByte();
348 sprite._blendAmount = stream->readByte();
349 sprite._thickness = stream->readByte();
350 stream->readByte(); // unused
351 }
352
353 // Sometimes removed sprites leave garbage in the channel
354 // We set it to zero, so then could skip
355 if (sprite._width <= 0 || sprite._height <= 0)
356 sprite._width = sprite._height = 0;
357
358 sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
359 sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
360 sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
361
362 if (sprite._inkData & 0x40)
363 sprite._trails = 1;
364 else
365 sprite._trails = 0;
366
367 sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
368
369 if (sprite._castId.member) {
370 debugC(4, kDebugLoading, "CH: %-3d castId: %s [flags:%04x [ink: %x trails: %d line: %d], %dx%d@%d,%d type: %d fg: %d bg: %d] script: %s, flags2: %x, unk2: %x, unk3: %x",
371 i + 1, sprite._castId.asString().c_str(), sprite._inkData,
372 sprite._ink, sprite._trails, sprite._thickness, sprite._width, sprite._height,
373 sprite._startPoint.x, sprite._startPoint.y,
374 sprite._spriteType, sprite._foreColor, sprite._backColor, sprite._scriptId.asString().c_str(), sprite._colorcode, sprite._blendAmount, sprite._unk3);
375 } else {
376 debugC(4, kDebugLoading, "CH: %-3d castId: 000", i + 1);
377 }
378 }
379 }
380
readMainChannels(Common::SeekableReadStreamEndian & stream,uint16 offset,uint16 size)381 void Frame::readMainChannels(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size) {
382 uint16 finishPosition = offset + size;
383
384 while (offset < finishPosition) {
385 switch(offset) {
386 case kScriptIdPosition:
387 _actionId = CastMemberID(stream.readByte(), 0);
388 offset++;
389 break;
390 case kSoundType1Position:
391 _soundType1 = stream.readByte();
392 offset++;
393 break;
394 case kTransFlagsPosition: {
395 uint8 transFlags = stream.readByte();
396 if (transFlags & 0x80)
397 _transArea = 1;
398 else
399 _transArea = 0;
400 _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
401 offset++;
402 }
403 break;
404 case kTransChunkSizePosition:
405 _transChunkSize = stream.readByte();
406 offset++;
407 break;
408 case kTempoPosition:
409 _tempo = stream.readByte();
410 offset++;
411 break;
412 case kTransTypePosition:
413 _transType = static_cast<TransitionType>(stream.readByte());
414 offset++;
415 break;
416 case kSound1Position:
417 _sound1 = CastMemberID(stream.readUint16(), 0);
418 offset+=2;
419 break;
420 case kSkipFrameFlagsPosition:
421 _skipFrameFlag = stream.readByte();
422 offset++;
423 break;
424 case kBlendPosition:
425 _blend = stream.readByte();
426 offset++;
427 break;
428 case kSound2Position:
429 _sound2 = CastMemberID(stream.readUint16(), 0);
430 offset += 2;
431 break;
432 case kSound2TypePosition:
433 _soundType2 = stream.readByte();
434 offset += 1;
435 break;
436 case kPalettePosition:
437 if (stream.readUint16())
438 readPaletteInfo(stream);
439 offset += 16;
440 break;
441 default:
442 offset++;
443 stream.readByte();
444 debugC(1, kDebugLoading, "Frame::readMainChannels: Field Position %d, Finish Position %d", offset, finishPosition);
445 break;
446 }
447 }
448
449 debugC(1, kDebugLoading, "Frame::readChannels(): %d %d %d %d %d %d %d %d %d %d %d", _actionId.member, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1.member, _skipFrameFlag, _blend, _sound2.member, _soundType2);
450 }
451
readPaletteInfo(Common::SeekableReadStreamEndian & stream)452 void Frame::readPaletteInfo(Common::SeekableReadStreamEndian &stream) {
453 _palette.firstColor = stream.readByte();
454 _palette.lastColor = stream.readByte();
455 _palette.flags = stream.readByte();
456 _palette.speed = stream.readByte();
457 _palette.frameCount = stream.readUint16();
458 stream.skip(8); // unknown
459 }
460
readSprite(Common::SeekableReadStreamEndian & stream,uint16 offset,uint16 size)461 void Frame::readSprite(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size) {
462 uint16 spritePosition = (offset - 32) / 16;
463 uint16 spriteStart = spritePosition * 16 + 32;
464
465 uint16 fieldPosition = offset - spriteStart;
466 uint16 finishPosition = fieldPosition + size;
467
468 Sprite &sprite = *_sprites[spritePosition];
469 int x1 = 0;
470 int x2 = 0;
471
472 while (fieldPosition < finishPosition) {
473 switch (fieldPosition) {
474 case kSpritePositionUnk1:
475 x1 = stream.readByte();
476 fieldPosition++;
477 break;
478 case kSpritePositionEnabled:
479 sprite._enabled = (stream.readByte() != 0);
480 fieldPosition++;
481 break;
482 case kSpritePositionUnk2:
483 x2 = stream.readUint16();
484 fieldPosition += 2;
485 break;
486 case kSpritePositionFlags:
487 sprite._thickness = stream.readByte();
488 sprite._inkData = stream.readByte();
489 sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
490
491 if (sprite._inkData & 0x40)
492 sprite._trails = 1;
493 else
494 sprite._trails = 0;
495
496 fieldPosition += 2;
497 break;
498 case kSpritePositionCastId:
499 sprite._castId = CastMemberID(stream.readUint16(), 0);
500 fieldPosition += 2;
501 break;
502 case kSpritePositionY:
503 sprite._startPoint.y = stream.readUint16();
504 fieldPosition += 2;
505 break;
506 case kSpritePositionX:
507 sprite._startPoint.x = stream.readUint16();
508 fieldPosition += 2;
509 break;
510 case kSpritePositionWidth:
511 sprite._width = stream.readUint16();
512 fieldPosition += 2;
513 break;
514 case kSpritePositionHeight:
515 sprite._height = stream.readUint16();
516 fieldPosition += 2;
517 break;
518 default:
519 // end of channel, go to next sprite channel
520 readSprite(stream, spriteStart + 16, finishPosition - fieldPosition);
521 fieldPosition = finishPosition;
522 break;
523 }
524 }
525 warning("Frame::readSprite(): %s(%d)[%x,%x,%02x %02x,%d/%d/%d/%d]", sprite._castId.asString().c_str(), sprite._enabled, x1, x2, sprite._thickness, sprite._inkData, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
526
527 }
528
529 } // End of namespace Director
530