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