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
24
25 #ifdef ENABLE_AGOS2
26
27 #include "common/endian.h"
28 #include "common/events.h"
29 #include "common/file.h"
30 #include "common/system.h"
31 #include "common/textconsole.h"
32 #include "common/translation.h"
33
34 #include "graphics/cursorman.h"
35 #include "graphics/palette.h"
36 #include "graphics/surface.h"
37
38 #include "agos/animation.h"
39 #include "agos/intern.h"
40 #include "agos/agos.h"
41
42 #include "audio/audiostream.h"
43 #include "audio/decoders/wave.h"
44
45 #include "gui/message.h"
46
47 namespace AGOS {
48
MoviePlayer(AGOSEngine_Feeble * vm)49 MoviePlayer::MoviePlayer(AGOSEngine_Feeble *vm)
50 : _vm(vm) {
51 _mixer = _vm->_mixer;
52
53 _leftButtonDown = false;
54 _rightButtonDown = false;
55 _skipMovie = false;
56
57 memset(baseName, 0, sizeof(baseName));
58
59 _ticks = 0;
60 _bgSoundStream = nullptr;
61 }
62
~MoviePlayer()63 MoviePlayer::~MoviePlayer() {
64 }
65
play()66 void MoviePlayer::play() {
67 if (_vm->getBitFlag(40)) {
68 _vm->setBitFlag(42, false);
69 startSound();
70 return;
71 }
72
73 _leftButtonDown = false;
74 _rightButtonDown = false;
75 _skipMovie = false;
76
77 _vm->_mixer->stopAll();
78
79 _ticks = _vm->_system->getMillis();
80
81 startSound();
82
83 playVideo();
84 stopVideo();
85
86 _vm->o_killAnimate();
87
88 if (_vm->getBitFlag(41)) {
89 _vm->fillBackFromFront();
90 } else {
91 uint8 palette[768];
92 memset(palette, 0, sizeof(palette));
93 _vm->clearSurfaces();
94 _vm->_system->getPaletteManager()->setPalette(palette, 0, 256);
95 }
96
97 _vm->fillBackGroundFromBack();
98 _vm->_fastFadeOutFlag = true;
99 }
100
handleNextFrame()101 void MoviePlayer::handleNextFrame() {
102 Common::Event event;
103 Common::EventManager *eventMan = _vm->_system->getEventManager();
104 while (eventMan->pollEvent(event)) {
105 switch (event.type) {
106 case Common::EVENT_KEYDOWN:
107 if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
108 _leftButtonDown = true;
109 _rightButtonDown = true;
110 } else if (event.kbd.keycode == Common::KEYCODE_PAUSE) {
111 _vm->pause();
112 }
113 break;
114 case Common::EVENT_LBUTTONDOWN:
115 _leftButtonDown = true;
116 break;
117 case Common::EVENT_RBUTTONDOWN:
118 _rightButtonDown = true;
119 break;
120 case Common::EVENT_LBUTTONUP:
121 _leftButtonDown = false;
122 break;
123 case Common::EVENT_RBUTTONUP:
124 _rightButtonDown = false;
125 break;
126 default:
127 break;
128 }
129 }
130
131 if (_leftButtonDown && _rightButtonDown && !_vm->getBitFlag(41)) {
132 _skipMovie = true;
133 _mixer->stopHandle(_bgSound);
134 }
135 }
136
137 ///////////////////////////////////////////////////////////////////////////////
138 // Movie player for DXA movies
139 ///////////////////////////////////////////////////////////////////////////////
140
141 const char *const MoviePlayerDXA::_sequenceList[90] = {
142 "agent32",
143 "Airlock",
144 "Badluck",
145 "bentalk1",
146 "bentalk2",
147 "bentalk3",
148 "BigFight",
149 "BLOWLAB",
150 "breakdown",
151 "bridge",
152 "button2",
153 "cargo",
154 "COACH",
155 "Colatalk",
156 "cygnus2",
157 "dream",
158 "escape2",
159 "FASALL",
160 "fbikewurb",
161 "feebdel",
162 "Feebohno",
163 "feebpump",
164 "feefone1",
165 "feefone2",
166 "founder2",
167 "founder3",
168 "founder4",
169 "fxmadsam",
170 "fxwakeup",
171 "gate",
172 "Get Car",
173 "getaxe",
174 "getlift",
175 "icetrench",
176 "intomb1",
177 "intomb2",
178 "Jackpot",
179 "knockout",
180 "labocto",
181 "longfeeb",
182 "Mainmin",
183 "maznat",
184 "meetsquid",
185 "mflirt",
186 "mfxHappy",
187 "Mix_Feeb1",
188 "Mix_Feeb2",
189 "Mix_Feeb3",
190 "Mix_Guardscn",
191 "Mlights1",
192 "MLights2",
193 "MProtest",
194 "mudman",
195 "munlock",
196 "MUS5P2",
197 "MUSOSP1",
198 "Omenter",
199 "Omnicofe",
200 "OUTMIN~1",
201 "Readbook",
202 "Rebelhq",
203 "RebelHQ2",
204 "Reedin",
205 "rescue1",
206 "rescue2",
207 "samcar",
208 "Samdead",
209 "scanner",
210 "Sleepy",
211 "spitbrai",
212 "statue1",
213 "statue2",
214 "sva1",
215 "sva2",
216 "Teeter",
217 "Temple2",
218 "Temple3",
219 "Temple4",
220 "Temple5",
221 "Temple6",
222 "Temple7",
223 "Temple8",
224 "Tic-tac2",
225 "torture",
226 "transmit",
227 "Typey",
228 "ventfall",
229 "ventoff",
230 "wasting",
231 "wurbatak"
232 };
233
MoviePlayerDXA(AGOSEngine_Feeble * vm,const char * name)234 MoviePlayerDXA::MoviePlayerDXA(AGOSEngine_Feeble *vm, const char *name)
235 : MoviePlayer(vm) {
236 debug(0, "Creating DXA cutscene player");
237
238 memset(baseName, 0, sizeof(baseName));
239 memcpy(baseName, name, strlen(name));
240
241 _sequenceNum = 0;
242 }
243
load()244 bool MoviePlayerDXA::load() {
245 if ((_vm->getPlatform() == Common::kPlatformAmiga || _vm->getPlatform() == Common::kPlatformMacintosh) &&
246 _vm->_language != Common::EN_ANY) {
247 _sequenceNum = 0;
248 for (uint i = 0; i < 90; i++) {
249 if (!scumm_stricmp(baseName, _sequenceList[i]))
250 _sequenceNum = i;
251 }
252 }
253
254 Common::String videoName = Common::String::format("%s.dxa", baseName);
255 Common::File *videoStream = new Common::File();
256 if (!videoStream->open(videoName))
257 error("Failed to load video file %s", videoName.c_str());
258 if (!loadStream(videoStream))
259 error("Failed to load video stream from file %s", videoName.c_str());
260
261 debug(0, "Playing video %s", videoName.c_str());
262
263 CursorMan.showMouse(false);
264 return true;
265 }
266
copyFrameToBuffer(byte * dst,uint x,uint y,uint pitch)267 void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
268 uint h = getHeight();
269 uint w = getWidth();
270
271 const Graphics::Surface *surface = decodeNextFrame();
272
273 if (!surface)
274 return;
275
276 const byte *src = (const byte *)surface->getPixels();
277 dst += y * pitch + x;
278
279 do {
280 memcpy(dst, src, w);
281 dst += pitch;
282 src += w;
283 } while (--h);
284
285 if (hasDirtyPalette())
286 g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
287 }
288
playVideo()289 void MoviePlayerDXA::playVideo() {
290 // Most of the videos included in the Amiga version, reduced the
291 // resolution to 384 x 280, so require the screen to be cleared,
292 // before starting playing those videos.
293 if (getWidth() == 384 && getHeight() == 280) {
294 _vm->clearSurfaces();
295 }
296
297 while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit())
298 handleNextFrame();
299 }
300
stopVideo()301 void MoviePlayerDXA::stopVideo() {
302 close();
303 _mixer->stopHandle(_bgSound);
304 }
305
startSound()306 void MoviePlayerDXA::startSound() {
307 start();
308
309 if (_bgSoundStream != NULL) {
310 _vm->_mixer->stopHandle(_bgSound);
311 _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream, -1, getVolume(), getBalance());
312 }
313 }
314
nextFrame()315 void MoviePlayerDXA::nextFrame() {
316 if (_bgSoundStream && _vm->_mixer->isSoundHandleActive(_bgSound) && needsUpdate()) {
317 copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
318 return;
319 }
320
321 if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) {
322 rewind();
323 startSound();
324 }
325
326 if (!endOfVideo()) {
327 if (_vm->_interactiveVideo == TYPE_OMNITV) {
328 copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
329 } else if (_vm->_interactiveVideo == TYPE_LOOPING) {
330 copyFrameToBuffer(_vm->getBackBuf(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
331 }
332 } else if (_vm->_interactiveVideo == TYPE_OMNITV) {
333 close();
334 _vm->_interactiveVideo = 0;
335 _vm->_variableArray[254] = 6747;
336 }
337 }
338
handleNextFrame()339 void MoviePlayerDXA::handleNextFrame() {
340 if (processFrame())
341 _vm->_system->updateScreen();
342
343 MoviePlayer::handleNextFrame();
344 }
345
processFrame()346 bool MoviePlayerDXA::processFrame() {
347 Graphics::Surface *screen = _vm->getBackendSurface();
348 copyFrameToBuffer((byte *)screen->getPixels(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch);
349 _vm->updateBackendSurface();
350
351 uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound);
352 uint32 nextFrameStartTime = ((Video::VideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime();
353
354 if ((_bgSoundStream == NULL) || soundTime < nextFrameStartTime) {
355
356 if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) {
357 while (_mixer->isSoundHandleActive(_bgSound) && soundTime < nextFrameStartTime) {
358 _vm->_system->delayMillis(10);
359 soundTime = _mixer->getSoundElapsedTime(_bgSound);
360 }
361 // In case the background sound ends prematurely, update
362 // _ticks so that we can still fall back on the no-sound
363 // sync case for the subsequent frames.
364 _ticks = _vm->_system->getMillis();
365 } else {
366 _ticks += getTimeToNextFrame();
367 while (_vm->_system->getMillis() < _ticks)
368 _vm->_system->delayMillis(10);
369 }
370
371 return true;
372 }
373
374 warning("dropped frame %i", getCurFrame());
375 return false;
376 }
377
readSoundData(Common::SeekableReadStream * stream)378 void MoviePlayerDXA::readSoundData(Common::SeekableReadStream *stream) {
379 uint32 tag = stream->readUint32BE();
380
381 if (tag == MKTAG('W','A','V','E')) {
382 uint32 size = stream->readUint32BE();
383
384 if (_sequenceNum) {
385 Common::File in;
386
387 stream->skip(size);
388
389 in.open("audio.wav");
390 if (!in.isOpen()) {
391 error("Can't read offset file 'audio.wav'");
392 }
393
394 in.seek(_sequenceNum * 8, SEEK_SET);
395 uint32 offset = in.readUint32LE();
396 size = in.readUint32LE();
397
398 in.seek(offset, SEEK_SET);
399 _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES);
400 in.close();
401 } else {
402 _bgSoundStream = Audio::makeWAVStream(stream->readStream(size), DisposeAfterUse::YES);
403 }
404 } else {
405 _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName);
406 }
407 }
408
409 ///////////////////////////////////////////////////////////////////////////////
410 // Movie player for Smacker movies
411 ///////////////////////////////////////////////////////////////////////////////
412
413
MoviePlayerSMK(AGOSEngine_Feeble * vm,const char * name)414 MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name)
415 : MoviePlayer(vm), SmackerDecoder() {
416 debug(0, "Creating SMK cutscene player");
417
418 memset(baseName, 0, sizeof(baseName));
419 memcpy(baseName, name, strlen(name));
420 }
421
load()422 bool MoviePlayerSMK::load() {
423 Common::String videoName = Common::String::format("%s.smk", baseName);
424
425 Common::File *videoStream = new Common::File();
426 if (!videoStream->open(videoName))
427 error("Failed to load video file %s", videoName.c_str());
428 if (!loadStream(videoStream))
429 error("Failed to load video stream from file %s", videoName.c_str());
430
431 debug(0, "Playing video %s", videoName.c_str());
432
433 CursorMan.showMouse(false);
434
435 return true;
436 }
437
copyFrameToBuffer(byte * dst,uint x,uint y,uint pitch)438 void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
439 uint h = getHeight();
440 uint w = getWidth();
441
442 const Graphics::Surface *surface = decodeNextFrame();
443
444 if (!surface)
445 return;
446
447 const byte *src = (const byte *)surface->getPixels();
448 dst += y * pitch + x;
449
450 do {
451 memcpy(dst, src, w);
452 dst += pitch;
453 src += w;
454 } while (--h);
455
456 if (hasDirtyPalette())
457 g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
458 }
459
playVideo()460 void MoviePlayerSMK::playVideo() {
461 while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit())
462 handleNextFrame();
463 }
464
stopVideo()465 void MoviePlayerSMK::stopVideo() {
466 close();
467 }
468
startSound()469 void MoviePlayerSMK::startSound() {
470 start();
471 }
472
handleNextFrame()473 void MoviePlayerSMK::handleNextFrame() {
474 processFrame();
475
476 MoviePlayer::handleNextFrame();
477 }
478
nextFrame()479 void MoviePlayerSMK::nextFrame() {
480 if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo())
481 rewind();
482
483 if (!endOfVideo()) {
484 decodeNextFrame();
485 if (_vm->_interactiveVideo == TYPE_OMNITV) {
486 copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
487 } else if (_vm->_interactiveVideo == TYPE_LOOPING) {
488 copyFrameToBuffer(_vm->getBackBuf(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
489 }
490 } else if (_vm->_interactiveVideo == TYPE_OMNITV) {
491 close();
492 _vm->_interactiveVideo = 0;
493 _vm->_variableArray[254] = 6747;
494 }
495 }
496
processFrame()497 bool MoviePlayerSMK::processFrame() {
498 Graphics::Surface *screen = _vm->getBackendSurface();
499 copyFrameToBuffer((byte *)screen->getPixels(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch);
500 _vm->updateBackendSurface();
501
502 uint32 waitTime = getTimeToNextFrame();
503
504 if (!waitTime && !endOfVideoTracks()) {
505 warning("dropped frame %i", getCurFrame());
506 return false;
507 }
508
509 _vm->_system->updateScreen();
510
511 // Wait before showing the next frame
512 _vm->_system->delayMillis(waitTime);
513 return true;
514 }
515
516 ///////////////////////////////////////////////////////////////////////////////
517 // Factory function for creating the appropriate cutscene player
518 ///////////////////////////////////////////////////////////////////////////////
519
makeMoviePlayer(AGOSEngine_Feeble * vm,const char * name)520 MoviePlayer *makeMoviePlayer(AGOSEngine_Feeble *vm, const char *name) {
521 char baseName[40];
522 char filename[45];
523
524 int baseLen = strlen(name) - 4;
525 memset(baseName, 0, sizeof(baseName));
526 memcpy(baseName, name, baseLen);
527
528 if (vm->getLanguage() == Common::DE_DEU && baseLen >= 8) {
529 // Check short filename to work around
530 // bug in a German Windows 2CD version.
531 char shortName[10];
532 memset(shortName, 0, sizeof(shortName));
533 memcpy(shortName, baseName, 6);
534
535 sprintf(filename, "%s~1.dxa", shortName);
536 if (Common::File::exists(filename)) {
537 memset(baseName, 0, sizeof(baseName));
538 memcpy(baseName, filename, 8);
539 }
540
541 sprintf(filename, "%s~1.smk", shortName);
542 if (Common::File::exists(filename)) {
543 memset(baseName, 0, sizeof(baseName));
544 memcpy(baseName, filename, 8);
545 }
546 }
547
548 sprintf(filename, "%s.dxa", baseName);
549 if (Common::File::exists(filename)) {
550 return new MoviePlayerDXA(vm, baseName);
551 }
552
553 sprintf(filename, "%s.smk", baseName);
554 if (Common::File::exists(filename)) {
555 return new MoviePlayerSMK(vm, baseName);
556 }
557
558 Common::U32String buf = Common::U32String::format(_("Cutscene file '%s' not found!"), baseName);
559 GUI::MessageDialog dialog(buf, _("OK"));
560 dialog.runModal();
561
562 return NULL;
563 }
564
565 } // End of namespace AGOS
566
567 #endif // ENABLE_AGOS2
568