Ticket #8948: sword_smk_latest.patch
File sword_smk_latest.patch, 52.8 KB (added by , 16 years ago) |
---|
-
engines/sword1/animation.cpp
27 27 #include "common/file.h" 28 28 #include "sword1/sword1.h" 29 29 #include "sword1/animation.h" 30 #include "sword1/credits.h"31 30 #include "sword1/text.h" 32 31 #include "sound/vorbis.h" 33 32 … … 36 35 #include "common/str.h" 37 36 #include "common/events.h" 38 37 #include "common/system.h" 38 #include "common/list.h" 39 39 #include "graphics/surface.h" 40 40 41 #include "gui/message.h" 42 41 43 namespace Sword1 { 42 44 43 45 static const char *sequenceList[20] = { … … 67 69 // Basic movie player 68 70 /////////////////////////////////////////////////////////////////////////////// 69 71 70 MoviePlayer::MoviePlayer(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)71 : _vm(vm), _ screen(screen), _textMan(textMan), _snd(snd), _system(system) {72 MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType) 73 : _vm(vm), _textMan(textMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system), VideoPlayer(decoder) { 72 74 _bgSoundStream = NULL; 73 _ticks = 0; 74 _black = 1; 75 _white = 255; 76 _currentFrame = 0; 77 _forceFrame = false; 78 _framesSkipped = 0; 75 _decoderType = decoderType; 79 76 } 80 77 81 78 MoviePlayer::~MoviePlayer(void) { 79 delete(_decoder); 82 80 } 83 81 84 void MoviePlayer::updatePalette(byte *pal, bool packed) {85 byte palette[4 * 256];86 byte *p = palette;87 88 uint32 maxWeight = 0;89 uint32 minWeight = 0xFFFFFFFF;90 91 for (int i = 0; i < 256; i++) {92 int r = *pal++;93 int g = *pal++;94 int b = *pal++;95 96 if (!packed)97 pal++;98 99 uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b;100 101 if (weight >= maxWeight) {102 _white = i;103 maxWeight = weight;104 }105 106 if (weight <= minWeight) {107 _black = i;108 minWeight = i;109 }110 111 *p++ = r;112 *p++ = g;113 *p++ = b;114 *p++ = 0;115 }116 117 _system->setPalette(palette, 0, 256);118 _forceFrame = true;119 }120 121 void MoviePlayer::handleScreenChanged(void) {122 }123 124 bool MoviePlayer::initOverlays(uint32 id) {125 return true;126 }127 128 bool MoviePlayer::checkSkipFrame(void) {129 if (_forceFrame) {130 _forceFrame = false;131 return false;132 }133 if (_framesSkipped > 10) {134 warning("Forced frame %d to be displayed", _currentFrame);135 _framesSkipped = 0;136 return false;137 }138 if (_bgSoundStream) {139 if ((_snd->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame + 1)140 return false;141 } else {142 if (_system->getMillis() <= _ticks)143 return false;144 }145 _framesSkipped++;146 return true;147 }148 149 bool MoviePlayer::syncFrame(void) {150 _ticks += 83;151 if (checkSkipFrame()) {152 warning("Skipped frame %d", _currentFrame);153 return false;154 }155 if (_bgSoundStream) {156 while (_snd->isSoundHandleActive(_bgSoundHandle) && (_snd->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame) {157 _system->delayMillis(10);158 }159 160 // In case the background sound ends prematurely, update _ticks161 // so that we can still fall back on the no-sound sync case for162 // the subsequent frames.163 164 _ticks = _system->getMillis();165 } else {166 while (_system->getMillis() < _ticks) {167 _system->delayMillis(10);168 }169 }170 return true;171 }172 173 82 /** 174 83 * Plays an animated cutscene. 175 84 * @param id the id of the file … … 178 87 Common::File f; 179 88 char fileName[20]; 180 89 181 _id = id; 182 _bgSoundStream = NULL; 90 if (_decoderType == kVideoDecoderDXA) { 91 _bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[id]); 92 } else { 93 _bgSoundStream = NULL; 94 } 183 95 184 96 if (SwordEngine::_systemVars.showText) { 185 97 sprintf(fileName, "%s.txt", sequenceList[id]); … … 221 133 } 222 134 } 223 135 224 if (SwordEngine::_systemVars.cutscenePackVersion == 1) { 225 if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) { 226 #ifdef USE_VORBIS 227 // these sequences are language specific 228 sprintf(fileName, "%s.snd", sequenceList[id]); 229 Common::File *oggSource = new Common::File(); 230 if (oggSource->open(fileName)) { 231 SplittedAudioStream *sStream = new SplittedAudioStream(); 232 uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2. 233 // for each segment and each of the 7 languages, we've got fileoffset and size 234 uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4); 235 for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++) 236 header[cnt] = oggSource->readUint32LE(); 237 for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) { 238 oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]); 239 uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14]; 240 Common::MemoryReadStream *stream = oggSource->readStream(segSize); 241 Audio::AudioStream *apStream = Audio::makeVorbisStream(stream, true); 242 if (!apStream) 243 error("Can't create Vorbis Stream from file %s", fileName); 244 sStream->appendStream(apStream); 245 } 246 free(header); 247 _bgSoundStream = sStream; 248 } else 249 warning("Sound file \"%s\" not found", fileName); 250 delete oggSource; 136 char filename[20]; 137 switch (_decoderType) { 138 case kVideoDecoderDXA: 139 snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]); 140 break; 141 #ifdef USE_SWORD_SMACKS 142 case kVideoDecoderSMK: 143 snprintf(filename, sizeof(filename), "%s.smk", sequenceList[id]); 144 break; 251 145 #endif 252 initOverlays(id);253 }254 146 } 147 148 if (_decoder->loadFile(filename)) { 149 // The Broken Sword games always use external audio tracks. 150 if (_decoder->readSoundHeader() != MKID_BE('NULL')) 151 return false; 152 } else { 153 return false; 154 } 155 255 156 return true; 256 157 } 257 158 258 159 void MoviePlayer::play(void) { 259 _screen->clearScreen();260 _framesSkipped = 0;261 _ticks = _system->getMillis();262 _bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[_id]);263 160 if (_bgSoundStream) { 264 _snd->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSoundHandle, _bgSoundStream);161 _snd->playInputStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); 265 162 } 266 _currentFrame = 0;267 163 bool terminated = false; 268 Common::EventManager *eventMan = _system->getEventManager();269 while (!terminated && decodeFrame()) {270 if (!_movieTexts.empty()) {271 if (_currentFrame == _movieTexts[0]->_startFrame) {272 _textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL);273 164 274 FrameHeader *frame = _textMan->giveSpriteData(2); 275 _textWidth = frame->width; 276 _textHeight = frame->height; 277 _textX = 320 - _textWidth / 2; 278 _textY = 420 - _textHeight; 279 } 280 if (_currentFrame == _movieTexts[0]->_endFrame) { 281 _textMan->releaseText(2, false); 282 delete _movieTexts.remove_at(0); 283 } 284 } 285 processFrame(); 286 if (syncFrame()) 287 updateScreen(); 288 _currentFrame++; 289 Common::Event event; 290 while (eventMan->pollEvent(event)) { 291 switch (event.type) { 292 case Common::EVENT_SCREEN_CHANGED: 293 handleScreenChanged(); 294 break; 295 case Common::EVENT_KEYDOWN: 296 if (event.kbd.keycode == Common::KEYCODE_ESCAPE) 297 terminated = true; 298 break; 299 default: 300 break; 301 } 302 } 303 if (_vm->shouldQuit()) 304 terminated = true; 305 } 165 Common::List<Common::Event> stopEvents; 166 Common::Event stopEvent; 167 stopEvents.clear(); 168 stopEvent.type = Common::EVENT_KEYDOWN; 169 stopEvent.kbd = Common::KEYCODE_ESCAPE; 170 stopEvents.push_back(stopEvent); 306 171 172 terminated = !playVideo(&stopEvents); 173 307 174 if (terminated) 308 _snd->stopHandle( _bgSoundHandle);175 _snd->stopHandle(*_bgSoundHandle); 309 176 310 177 _textMan->releaseText(2, false); 311 178 312 179 while (!_movieTexts.empty()) 313 180 delete _movieTexts.remove_at(_movieTexts.size() - 1); 314 181 315 while (_snd->isSoundHandleActive( _bgSoundHandle))182 while (_snd->isSoundHandleActive(*_bgSoundHandle)) 316 183 _system->delayMillis(100); 317 184 318 185 // It's tempting to call _screen->fullRefresh() here to restore the old … … 322 189 323 190 byte pal[3 * 256]; 324 191 memset(pal, 0, sizeof(pal)); 325 updatePalette(pal, true);192 _system->setPalette(pal, 0, 255); 326 193 } 327 194 328 SplittedAudioStream::SplittedAudioStream(void) { 329 _queue = NULL; 330 } 195 void MoviePlayer::performPostProcessing(byte *screen) { 196 if (!_movieTexts.empty()) { 197 if (_decoder->getCurFrame() == _movieTexts[0]->_startFrame) { 198 _textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL); 331 199 332 SplittedAudioStream::~SplittedAudioStream(void) { 333 while (_queue) { 334 delete _queue->stream; 335 FileQueue *que = _queue->next; 336 delete _queue; 337 _queue = que; 338 } 339 } 340 341 int SplittedAudioStream::getRate(void) const { 342 if (_queue) 343 return _queue->stream->getRate(); 344 else 345 return 22050; 346 } 347 348 void SplittedAudioStream::appendStream(Audio::AudioStream *stream) { 349 FileQueue **que = &_queue; 350 while (*que) 351 que = &((*que)->next); 352 *que = new FileQueue; 353 (*que)->stream = stream; 354 (*que)->next = NULL; 355 } 356 357 bool SplittedAudioStream::endOfData(void) const { 358 if (_queue) 359 return _queue->stream->endOfData(); 360 else 361 return true; 362 } 363 364 bool SplittedAudioStream::isStereo(void) const { 365 if (_queue) 366 return _queue->stream->isStereo(); 367 else 368 return false; // all the BS1 files are mono, anyways. 369 } 370 371 int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) { 372 int retVal = 0; 373 int needSamples = numSamples; 374 while (needSamples && _queue) { 375 int retSmp = _queue->stream->readBuffer(buffer, needSamples); 376 needSamples -= retSmp; 377 retVal += retSmp; 378 buffer += retSmp; 379 if (_queue->stream->endOfData()) { 380 delete _queue->stream; 381 FileQueue *que = _queue->next; 382 delete _queue; 383 _queue = que; 200 FrameHeader *frame = _textMan->giveSpriteData(2); 201 _textWidth = frame->width; 202 _textHeight = frame->height; 203 _textX = 320 - _textWidth / 2; 204 _textY = 420 - _textHeight; 384 205 } 206 if (_decoder->getCurFrame() == _movieTexts[0]->_endFrame) { 207 _textMan->releaseText(2, false); 208 delete _movieTexts.remove_at(0); 209 } 385 210 } 386 return retVal;387 }388 211 389 #ifdef USE_ZLIB390 391 ///////////////////////////////////////////////////////////////////////////////392 // Movie player for the new DXA movies393 ///////////////////////////////////////////////////////////////////////////////394 395 MoviePlayerDXA::MoviePlayerDXA(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)396 : MoviePlayer(vm, screen, textMan, snd, system) {397 debug(0, "Creating DXA cutscene player");398 }399 400 MoviePlayerDXA::~MoviePlayerDXA(void) {401 closeFile();402 }403 404 bool MoviePlayerDXA::load(uint32 id) {405 if (!MoviePlayer::load(id))406 return false;407 408 char filename[20];409 snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]);410 if (loadFile(filename)) {411 // The Broken Sword games always use external audio tracks.412 if (_fileStream->readUint32BE() != MKID_BE('NULL'))413 return false;414 _frameWidth = getWidth();415 _frameHeight = getHeight();416 _frameX = (640 - _frameWidth) / 2;417 _frameY = (480 - _frameHeight) / 2;418 return true;419 }420 return false;421 }422 423 bool MoviePlayerDXA::initOverlays(uint32 id) {424 // TODO425 return true;426 }427 428 void MoviePlayerDXA::setPalette(byte *pal) {429 updatePalette(pal, true);430 }431 432 bool MoviePlayerDXA::decodeFrame(void) {433 if ((uint32)_currentFrame < (uint32)getFrameCount()) {434 decodeNextFrame();435 return true;436 }437 return false;438 }439 440 void MoviePlayerDXA::processFrame(void) {441 }442 443 void MoviePlayerDXA::updateScreen(void) {444 Graphics::Surface *frameBuffer = _system->lockScreen();445 copyFrameToBuffer((byte *)frameBuffer->pixels, _frameX, _frameY, 640);446 447 // TODO: Handle the advanced cutscene packs. Do they really exist?448 449 // We cannot draw the text to _drawBuffer, since that's one of the450 // decoder's internal buffers, and besides it may be much smaller than451 // the screen, so it's possible that the subtitles don't fit on it.452 // Instead, we get the frame buffer from the backend, after copying the453 // frame to it, and draw on that.454 455 212 if (_textMan->giveSpriteData(2)) { 456 213 byte *src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader); 457 byte *dst = (byte *)frameBuffer->getBasePtr(_textX, _textY);214 byte *dst = screen + _textY * _decoder->getWidth() + _textX * 1; 458 215 459 216 for (int y = 0; y < _textHeight; y++) { 460 217 for (int x = 0; x < _textWidth; x++) { 461 218 switch (src[x]) { 462 219 case BORDER_COL: 463 dst[x] = _ black;220 dst[x] = _decoder->getBlack(); 464 221 break; 465 222 case LETTER_COL: 466 dst[x] = _ white;223 dst[x] = _decoder->getWhite(); 467 224 break; 468 225 } 469 226 } 470 227 src += _textWidth; 471 dst += frameBuffer->pitch;228 dst += _decoder->getWidth(); 472 229 } 473 474 230 } 475 476 _system->unlockScreen();477 478 _system->updateScreen();479 231 } 480 232 481 #endif 482 483 #ifdef USE_MPEG2 484 485 /////////////////////////////////////////////////////////////////////////////// 486 // Movie player for the old MPEG movies 487 /////////////////////////////////////////////////////////////////////////////// 488 489 MoviePlayerMPEG::MoviePlayerMPEG(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) 490 : MoviePlayer(vm, screen, textMan, snd, system) { 491 #ifdef BACKEND_8BIT 492 debug(0, "Creating MPEG cutscene player (8-bit)"); 493 #else 494 debug(0, "Creating MPEG cutscene player (16-bit)"); 495 #endif 496 for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) 497 _logoOvls[cnt] = NULL; 498 _introPal = NULL; 499 _anim = NULL; 233 DXAPlayerWithSound::DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) 234 : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { 500 235 } 501 236 502 MoviePlayerMPEG::~MoviePlayerMPEG(void) { 503 free(_introPal); 504 for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) 505 free(_logoOvls[cnt]); 506 delete _anim; 507 } 237 int32 DXAPlayerWithSound::getAudioLag() { 238 if (!_fileStream) 239 return 0; 508 240 509 void MoviePlayerMPEG::handleScreenChanged(void) { 510 _anim->handleScreenChanged();511 } 241 int32 frameDelay = getFrameDelay(); 242 int32 videoTime = _videoInfo.currentFrame * frameDelay; 243 int32 audioTime; 512 244 513 void MoviePlayerMPEG::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) { 514 if (ovl != NULL) 515 for (uint32 cnt = 0; cnt < 640 * 400; cnt++) 516 if (ovl[cnt]) 517 buf[cnt] = pal[ovl[cnt]]; 518 } 245 audioTime = (((int32) _mixer->getSoundElapsedTime(*_bgSoundHandle)) * 100); 519 246 520 bool MoviePlayerMPEG::load(uint32 id) { 521 if (MoviePlayer::load(id)) { 522 _anim = new AnimationState(this, _screen, _system); 523 return _anim->init(sequenceList[id]); 524 } 525 return false; 247 return videoTime - audioTime; 526 248 } 527 249 528 bool MoviePlayerMPEG::initOverlays(uint32 id) {529 if (id == SEQ_INTRO) {530 ArcFile ovlFile;531 if (!ovlFile.open("intro.dat")) {532 warning("\"intro.dat\" not found");533 return false;534 }535 ovlFile.enterPath(SwordEngine::_systemVars.language);536 for (uint8 fcnt = 0; fcnt < 12; fcnt++) {537 _logoOvls[fcnt] = ovlFile.decompressFile(fcnt);538 if (fcnt > 0)539 for (uint32 cnt = 0; cnt < 640 * 400; cnt++)540 if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt])541 _logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt];542 }543 uint8 *pal = ovlFile.fetchFile(12);544 _introPal = (OverlayColor *)malloc(256 * sizeof(OverlayColor));545 Graphics::PixelFormat format = _system->getOverlayFormat();546 for (uint16 cnt = 0; cnt < 256; cnt++)547 _introPal[cnt] = format.RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]);548 }549 550 return true;551 }552 553 bool MoviePlayerMPEG::decodeFrame(void) {554 return _anim->decodeFrame();555 }556 557 void MoviePlayerMPEG::updateScreen(void) {558 _anim->updateScreen();559 }560 561 void MoviePlayerMPEG::processFrame(void) {562 #ifndef BACKEND_8BIT563 if ((_id != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0))564 return;565 OverlayColor *buf = _anim->giveRgbBuffer();566 if ((_currentFrame > 397) && (_currentFrame < 444)) { // Broken Sword Logo567 if (_currentFrame <= 403)568 insertOverlay(buf, _logoOvls[_currentFrame - 398], _introPal); // fade up569 else if (_currentFrame <= 437)570 insertOverlay(buf, _logoOvls[(_currentFrame - 404) % 6 + 6], _introPal); // animation571 else {572 insertOverlay(buf, _logoOvls[5 - (_currentFrame - 438)], _introPal); // fade down573 }574 }575 #endif576 }577 578 AnimationState::AnimationState(MoviePlayer *player, Screen *screen, OSystem *system)579 : BaseAnimationState(system, 640, 400), _player(player), _screen(screen) {580 }581 582 AnimationState::~AnimationState(void) {583 }584 585 #ifdef BACKEND_8BIT586 void AnimationState::setPalette(byte *pal) {587 _player->updatePalette(pal, false);588 }589 #endif590 591 void AnimationState::drawYUV(int width, int height, byte *const *dat) {592 _frameWidth = width;593 _frameHeight = height;594 595 #ifdef BACKEND_8BIT596 _screen->plotYUV(_lut, width, height, dat);597 #else598 plotYUV(width, height, dat);599 #endif600 }601 602 OverlayColor *AnimationState::giveRgbBuffer(void) {603 #ifdef BACKEND_8BIT604 return NULL;605 #else606 return _overlay;607 #endif608 }609 610 Audio::AudioStream *AnimationState::createAudioStream(const char *name, void *arg) {611 if (arg)612 return (Audio::AudioStream*)arg;613 else614 return Audio::AudioStream::openStreamFile(name);615 }616 617 #endif618 619 250 /////////////////////////////////////////////////////////////////////////////// 620 251 // Factory function for creating the appropriate cutscene player 621 252 /////////////////////////////////////////////////////////////////////////////// 622 253 623 MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) { 624 #if defined(USE_ZLIB) || defined(USE_MPEG2) 254 MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system) { 625 255 char filename[20]; 256 char buf[60]; 257 Audio::SoundHandle bgSoundHandle; 258 259 #ifdef USE_SWORD_SMACKS 260 snprintf(filename, sizeof(filename), "%s.smk", sequenceList[id]); 261 262 if (Common::File::exists(filename)) { 263 Graphics::SMKPlayer *smkDecoder = new Graphics::SMKPlayer(snd); 264 return new MoviePlayer(vm, textMan, snd, system, &bgSoundHandle, smkDecoder, kVideoDecoderSMK); 265 } 626 266 #endif 627 267 628 #ifdef USE_ZLIB629 268 snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]); 630 269 631 270 if (Common::File::exists(filename)) { 632 return new MoviePlayerDXA(vm, screen, textMan, snd, system); 633 } 271 #ifdef USE_ZLIB 272 DXAPlayerWithSound *dxaDecoder = new DXAPlayerWithSound(snd, &bgSoundHandle); 273 return new MoviePlayer(vm, textMan, snd, system, &bgSoundHandle, dxaDecoder, kVideoDecoderDXA); 274 #else 275 GUI::MessageDialog dialog("DXA cutscenes found but ScummVM has been built without zlib support", "OK"); 276 dialog.runModal(); 277 return NULL; 634 278 #endif 279 } 635 280 636 #ifdef USE_MPEG2 281 // Old MPEG2 cutscenes 637 282 snprintf(filename, sizeof(filename), "%s.mp2", sequenceList[id]); 638 283 639 284 if (Common::File::exists(filename)) { 640 return new MoviePlayerMPEG(vm, screen, textMan, snd, system); 285 GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK"); 286 dialog.runModal(); 287 return NULL; 641 288 } 642 #endif643 289 290 sprintf(buf, "Cutscene '%s' not found", sequenceList[id]); 291 GUI::MessageDialog dialog(buf, "OK"); 292 dialog.runModal(); 293 644 294 return NULL; 645 295 } 646 296 -
engines/sword1/animation.h
27 27 #define SWORD1_ANIMATION_H 28 28 29 29 #include "graphics/video/dxa_player.h" 30 #include "graphics/video/mpeg_player.h" 30 #ifdef USE_SWORD_SMACKS 31 #include "graphics/video/smk_player.h" 32 #endif 33 #include "graphics/video/video_player.h" 31 34 32 35 #include "sword1/screen.h" 33 36 #include "sword1/sound.h" … … 35 38 36 39 namespace Sword1 { 37 40 38 enum { 39 SEQ_FERRARI = 0, 40 SEQ_LADDER, 41 SEQ_STEPS, 42 SEQ_SEWER, 43 SEQ_INTRO, 44 SEQ_RIVER, 45 SEQ_TRUCK, 46 SEQ_GRAVE, 47 SEQ_MONTFCON, 48 SEQ_TAPESTRY, 49 SEQ_IRELAND, 50 SEQ_FINALE, 51 SEQ_HISTORY, 52 SEQ_SPANISH, 53 SEQ_WELL, 54 SEQ_CANDLE, 55 SEQ_GEODROP, 56 SEQ_VULTURE, 57 SEQ_ENDDEMO, 58 SEQ_CREDITS 41 enum DecoderType { 42 kVideoDecoderDXA = 0, 43 kVideoDecoderSMK = 1 59 44 }; 60 45 61 #define INTRO_LOGO_OVLS 1262 #define INTRO_TEXT_OVLS 863 64 46 class MovieText { 65 47 public: 66 48 uint16 _startFrame; … … 76 58 } 77 59 }; 78 60 79 class MoviePlayer {61 class DXAPlayerWithSound : public Graphics::DXAPlayer { 80 62 public: 81 MoviePlayer(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system); 63 DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); 64 ~DXAPlayerWithSound() {} 65 66 int32 getAudioLag(); 67 private: 68 Audio::Mixer *_mixer; 69 Audio::SoundHandle *_bgSoundHandle; 70 }; 71 72 class MoviePlayer : public Graphics::VideoPlayer { 73 public: 74 MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType); 82 75 virtual ~MoviePlayer(void); 83 virtualbool load(uint32 id);76 bool load(uint32 id); 84 77 void play(void); 85 void updatePalette(byte *pal, bool packed = true);86 private:87 bool checkSkipFrame(void);88 78 protected: 89 79 SwordEngine *_vm; 90 Screen *_screen;91 80 Text *_textMan; 92 81 Audio::Mixer *_snd; 93 82 OSystem *_system; 94 83 Common::Array<MovieText *> _movieTexts; 95 84 int _textX, _textY, _textWidth, _textHeight; 96 byte _black, _white;85 DecoderType _decoderType; 97 86 98 uint32 _id; 99 100 uint _currentFrame; 101 int _framesSkipped; 102 bool _forceFrame; 103 104 int _frameWidth, _frameHeight; 105 int _frameX, _frameY; 106 107 Audio::SoundHandle _bgSoundHandle; 87 Audio::SoundHandle *_bgSoundHandle; 108 88 Audio::AudioStream *_bgSoundStream; 109 uint32 _ticks;110 89 111 virtual void handleScreenChanged(void); 112 virtual bool initOverlays(uint32 id); 113 virtual bool decodeFrame(void) = 0; 114 virtual void processFrame(void) = 0; 115 virtual bool syncFrame(void); 116 virtual void updateScreen(void) = 0; 90 void performPostProcessing(byte *screen); 117 91 }; 118 92 119 #ifdef USE_ZLIB 93 MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system); 120 94 121 class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer {122 protected:123 virtual void setPalette(byte *pal);124 public:125 MoviePlayerDXA(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);126 virtual ~MoviePlayerDXA(void);127 bool load(uint32 id);128 protected:129 bool initOverlays(uint32 id);130 bool decodeFrame(void);131 void processFrame(void);132 void updateScreen(void);133 };134 135 #endif136 137 #ifdef USE_MPEG2138 139 class AnimationState : public Graphics::BaseAnimationState {140 private:141 MoviePlayer *_player;142 Screen *_screen;143 144 public:145 AnimationState(MoviePlayer *player, Screen *screen, OSystem *system);146 ~AnimationState(void);147 OverlayColor *giveRgbBuffer(void);148 149 private:150 void drawYUV(int width, int height, byte *const *dat);151 152 #ifdef BACKEND_8BIT153 void setPalette(byte *pal);154 #endif155 156 protected:157 virtual Audio::AudioStream *createAudioStream(const char *name, void *arg);158 };159 160 class MoviePlayerMPEG : public MoviePlayer {161 public:162 MoviePlayerMPEG(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);163 virtual ~MoviePlayerMPEG(void);164 bool load(uint32 id);165 protected:166 void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal);167 AnimationState *_anim;168 OverlayColor *_introPal;169 uint8 *_logoOvls[INTRO_LOGO_OVLS];170 171 bool initOverlays(uint32 id);172 bool decodeFrame(void);173 void processFrame(void);174 void updateScreen(void);175 void handleScreenChanged(void);176 };177 178 #endif179 180 struct FileQueue {181 Audio::AudioStream *stream;182 FileQueue *next;183 };184 185 class SplittedAudioStream : public Audio::AudioStream {186 public:187 SplittedAudioStream(void);188 ~SplittedAudioStream(void);189 void appendStream(Audio::AudioStream *stream);190 virtual int readBuffer(int16 *buffer, const int numSamples);191 virtual bool isStereo(void) const;192 virtual bool endOfData(void) const;193 virtual int getRate(void) const;194 private:195 FileQueue *_queue;196 };197 198 MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);199 200 95 } // End of namespace Sword1 201 96 202 97 #endif -
engines/sword1/credits.cpp
1 /* ScummVM - Graphic Adventure Engine2 *3 * ScummVM is the legal property of its developers, whose names4 * are too numerous to list here. Please refer to the COPYRIGHT5 * file distributed with this source distribution.6 *7 * This program is free software; you can redistribute it and/or8 * modify it under the terms of the GNU General Public License9 * as published by the Free Software Foundation; either version 210 * 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 of14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 * GNU General Public License for more details.16 17 * You should have received a copy of the GNU General Public License18 * along with this program; if not, write to the Free Software19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.20 *21 * $URL$22 * $Id$23 *24 */25 26 27 #include "common/endian.h"28 29 #include "sword1/credits.h"30 #include "sword1/screen.h"31 #include "sword1/sword1.h"32 33 #include "sound/audiostream.h"34 #include "sound/mixer.h"35 36 #include "common/file.h"37 #include "common/util.h"38 #include "common/events.h"39 #include "common/system.h"40 41 42 #define CREDITS_X 48043 #define CREDITS_Y 30044 #define BUFSIZE_Y 64045 46 #define START_X ((640 - CREDITS_X) / 2)47 #define START_Y ((480 - CREDITS_Y) / 2)48 49 #define SCROLL_TIMING (2000 / 59) // 29.5 frames per second50 51 #define LOGO_FADEUP_TIME (133 * 1000)52 #define LOGO_FADEDOWN_TIME (163 * 1000)53 54 namespace Sword1 {55 56 enum {57 FONT_PAL = 0,58 FONT,59 TEXT,60 REVO_PAL,61 REVO_LOGO,62 F_EOF63 };64 65 enum {66 FNT_LFT = 0, // left column67 FNT_RGT, // right column68 FNT_CEN, // centered69 FNT_BIG = 64, // big font70 FNT_EOL = 128, // linebreak71 FNT_EOB = 255 // end of textblock72 };73 74 75 CreditsPlayer::CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer) {76 _system = pSystem;77 _mixer = pMixer;78 _smlFont = _bigFont = NULL;79 }80 81 bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) {82 if (blitEnd > blitSta) {83 if ((renderDest > blitEnd) || (renderDest + 15 < blitSta))84 return true;85 } else {86 if ((renderDest > blitEnd) && (renderDest + 15 < blitSta))87 return true;88 }89 return false;90 }91 92 void CreditsPlayer::play(void) {93 Audio::AudioStream *bgSoundStream = Audio::AudioStream::openStreamFile("credits");94 if (bgSoundStream == NULL) {95 warning("\"credits.ogg\" not found, skipping credits sequence");96 return;97 }98 ArcFile credFile;99 if (!credFile.open("credits.dat")) {100 warning("\"credits.dat\" not found, skipping credits sequence");101 return;102 }103 104 uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen);105 for (uint32 cnt = 0; cnt < _palLen; cnt++)106 _palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt];107 _palLen /= 3;108 109 generateFonts(&credFile);110 111 uint8 *textData = credFile.fetchFile(TEXT);112 textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4);113 114 uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y);115 memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y);116 _system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480);117 _system->setPalette(_palette, 0, _palLen);118 119 // everything's initialized, time to render and show the credits.120 Audio::SoundHandle bgSound;121 _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &bgSound, bgSoundStream, 0);122 123 int relDelay = 0;124 uint16 scrollY = 0;125 uint16 renderY = BUFSIZE_Y / 2;126 uint16 clearY = 0xFFFF;127 bool clearLine = false;128 while (((*textData != FNT_EOB) || (scrollY != renderY)) && !Engine::shouldQuit()) {129 if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio130 if (scrollY < BUFSIZE_Y - CREDITS_Y)131 _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y);132 else {133 _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY);134 _system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY));135 }136 _system->updateScreen();137 } else138 warning("frame skipped");139 140 while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) {141 if (*textData & FNT_EOL) {142 renderY = (renderY + 16) % BUFSIZE_Y; // linebreak143 clearLine = true;144 *textData &= ~FNT_EOL;145 }146 if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) {147 if (clearLine)148 memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X);149 clearLine = false;150 renderLine(screenBuf, textData + 1, renderY, *textData);151 if (*textData & FNT_BIG)152 renderY += 16;153 while (*++textData != 0) // search for the start of next string154 ;155 textData++;156 }157 if (*textData == FNT_EOB)158 clearY = renderY;159 }160 if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) {161 memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X);162 clearY = (clearY + 16) % BUFSIZE_Y;163 }164 165 relDelay += SCROLL_TIMING;166 delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound));167 scrollY = (scrollY + 1) % BUFSIZE_Y;168 }169 free(_smlFont);170 free(_bigFont);171 _smlFont = _bigFont = NULL;172 free(screenBuf);173 174 // credits done, now show the revolution logo175 uint8 *revoBuf = credFile.decompressFile(REVO_LOGO);176 uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen);177 _palLen /= 3;178 while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !Engine::shouldQuit()) {179 delay(100);180 }181 memset(_palette, 0, 256 * 4);182 _system->setPalette(_palette, 0, 256);183 _system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y);184 _system->updateScreen();185 186 fadePalette(revoPal, true, _palLen);187 while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !Engine::shouldQuit()) {188 delay(100);189 }190 fadePalette(revoPal, false, _palLen);191 delay(3000);192 193 if (Engine::shouldQuit())194 _mixer->stopAll();195 free(revoBuf);196 }197 198 void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) {199 int8 fadeDir = fadeup ? 1 : -1;200 int fadeStart = fadeup ? 0 : 12;201 202 int relDelay = _system->getMillis();203 for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !Engine::shouldQuit(); fadeStep += fadeDir) {204 for (uint16 cnt = 0; cnt < len * 3; cnt++)205 _palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12;206 _system->setPalette(_palette, 0, 256);207 relDelay += 1000 / 12;208 delay(relDelay - _system->getMillis());209 }210 }211 212 void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) {213 uint8 *font;214 uint16 fntSize = 16;215 if (flags & FNT_BIG) {216 font = _bigFont;217 fntSize = 32;218 flags &= ~FNT_BIG;219 } else220 font = _smlFont;221 222 uint16 width = getWidth(font, line);223 uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255);224 uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos;225 while (*line) {226 uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize;227 for (uint16 cnty = 0; cnty < fntSize; cnty++) {228 for (uint16 cntx = 0; cntx < fntSize; cntx++)229 bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx];230 chrSrc += fntSize;231 }232 bufDest += font[*line++ - 1];233 }234 }235 236 uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) {237 uint16 width = 0;238 while (*line)239 width += font[*line++ - 1];240 return width;241 }242 243 void CreditsPlayer::generateFonts(ArcFile *arcFile) {244 _bigFont = arcFile->decompressFile(FONT);245 _numChars = *_bigFont;246 memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1));247 _smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1));248 uint8 *src = _bigFont + _numChars;249 uint8 *dst = _smlFont + _numChars;250 for (uint16 cnt = 0; cnt < _numChars; cnt++) {251 _smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table252 for (uint16 cnty = 0; cnty < 16; cnty++) {253 for (uint16 cntx = 0; cntx < 16; cntx++) {254 uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2);255 uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2);256 uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2);257 *dst++ = getPalIdx(resR, resG, resB);258 src += 2;259 }260 src += 32;261 }262 }263 }264 265 uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) {266 for (uint16 cnt = 0; cnt < _palLen; cnt++)267 if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b))268 return (uint8)cnt;269 assert(_palLen < 256);270 _palette[_palLen * 4 + 0] = r;271 _palette[_palLen * 4 + 1] = g;272 _palette[_palLen * 4 + 2] = b;273 return (uint8)_palLen++;274 }275 276 void CreditsPlayer::delay(int msecs) {277 278 Common::Event event;279 uint32 start = _system->getMillis();280 do {281 Common::EventManager *eventMan = _system->getEventManager();282 while (eventMan->pollEvent(event)) {283 #if 0284 switch (event.type) {285 default:286 break;287 }288 #endif289 }290 291 _system->updateScreen();292 293 if (msecs > 0)294 _system->delayMillis(10);295 296 } while ((_system->getMillis() < start + msecs) && !Engine::shouldQuit());297 }298 299 ArcFile::ArcFile(void) {300 _buf = NULL;301 }302 303 ArcFile::~ArcFile(void) {304 if (_buf)305 free(_buf);306 }307 308 bool ArcFile::open(const char *name) {309 Common::File arc;310 if (!arc.open(name))311 return false;312 _bufPos = _buf = (uint8*)malloc(arc.size());313 arc.read(_buf, arc.size());314 arc.close();315 return true;316 }317 318 void ArcFile::enterPath(uint32 id) {319 _bufPos += READ_LE_UINT32(_bufPos + id * 4);320 }321 322 uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) {323 if (size)324 *size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4);325 return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4);326 }327 328 uint8 *ArcFile::decompressFile(uint32 fileId) {329 uint32 size;330 uint8 *srcBuf = fetchFile(fileId, &size);331 uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf));332 uint8 *srcPos = srcBuf + 4;333 uint8 *dstPos = dstBuf;334 while (srcPos < srcBuf + size) {335 uint16 len = READ_LE_UINT16(srcPos);336 memset(dstPos, 0, len);337 dstPos += len;338 srcPos += 2;339 if (srcPos < srcBuf + size) {340 len = *srcPos++;341 memcpy(dstPos, srcPos, len);342 dstPos += len;343 srcPos += len;344 }345 }346 return dstBuf;347 }348 349 } // end of namespace Sword1 -
engines/sword1/credits.h
1 /* ScummVM - Graphic Adventure Engine2 *3 * ScummVM is the legal property of its developers, whose names4 * are too numerous to list here. Please refer to the COPYRIGHT5 * file distributed with this source distribution.6 *7 * This program is free software; you can redistribute it and/or8 * modify it under the terms of the GNU General Public License9 * as published by the Free Software Foundation; either version 210 * 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 of14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 * GNU General Public License for more details.16 17 * You should have received a copy of the GNU General Public License18 * along with this program; if not, write to the Free Software19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.20 *21 * $URL$22 * $Id$23 *24 */25 26 #ifndef SWORD1_CREDITS_H27 #define SWORD1_CREDITS_H28 29 #include "common/util.h"30 31 namespace Audio {32 class Mixer;33 }34 class OSystem;35 36 namespace Sword1 {37 38 class ArcFile {39 public:40 ArcFile(void);41 ~ArcFile(void);42 bool open(const char *name);43 uint8 *fetchFile(uint32 fileId, uint32 *size = NULL);44 uint8 *decompressFile(uint32 fileId);45 void enterPath(uint32 id);46 void backToRoot(void) { _bufPos = _buf; }47 private:48 uint8 *_bufPos;49 uint8 *_buf;50 };51 52 class CreditsPlayer {53 public:54 CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer);55 void play(void);56 private:57 void generateFonts(ArcFile *arcFile);58 void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags);59 void fadePalette(uint8 *srcPal, bool fadeup, uint16 len);60 void delay(int msecs);61 uint16 getWidth(uint8 *font, uint8 *line);62 uint8 getPalIdx(uint8 r, uint8 g, uint8 b);63 uint8 _palette[256 * 4];64 uint32 _palLen;65 uint8 _numChars;66 67 OSystem *_system;68 Audio::Mixer *_mixer;69 70 uint8 *_smlFont, *_bigFont;71 };72 73 } // end of namespace Sword174 75 #endif // BS1CREDITS_H -
engines/sword1/logic.cpp
41 41 #include "sword1/music.h" 42 42 #include "sword1/swordres.h" 43 43 #include "sword1/animation.h" 44 #include "sword1/credits.h"45 44 46 45 #include "sword1/debug.h" 47 46 … … 960 959 // meantime, we don't want any looping sound effects still playing. 961 960 _sound->quitScreen(); 962 961 963 if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) { 964 CreditsPlayer player(_system, _mixer); 965 player.play(); 966 } else { 967 MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _screen, _textMan, _mixer, _system); 968 if (player) { 969 if (player->load(sequenceId)) 970 player->play(); 971 delete player; 972 } 962 MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _mixer, _system); 963 if (player) { 964 _screen->clearScreen(); 965 if (player->load(sequenceId)) 966 player->play(); 967 delete player; 973 968 } 974 969 return SCRIPT_CONT; 975 970 } -
engines/sword1/module.mk
3 3 MODULE_OBJS := \ 4 4 animation.o \ 5 5 control.o \ 6 credits.o \7 6 debug.o \ 8 7 detection.o \ 9 8 eventman.o \ -
engines/sword1/sword1.cpp
58 58 Common::File::addDefaultDirectory(_gameDataDir.getChild("MUSIC")); 59 59 Common::File::addDefaultDirectory(_gameDataDir.getChild("SPEECH")); 60 60 Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); 61 Common::File::addDefaultDirectory(_gameDataDir.getChild("SMACKSHI")); 61 62 Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters")); 62 63 Common::File::addDefaultDirectory(_gameDataDir.getChild("music")); 63 64 Common::File::addDefaultDirectory(_gameDataDir.getChild("speech")); 64 65 Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); 66 Common::File::addDefaultDirectory(_gameDataDir.getChild("smackshi")); 65 67 } 66 68 67 69 SwordEngine::~SwordEngine() { … … 475 477 */ 476 478 // make the demo flag depend on the Gamesettings for now, and not on what the datafiles look like 477 479 _systemVars.isDemo = (_features & GF_DEMO) != 0; 478 _systemVars.cutscenePackVersion = 0;479 #ifdef USE_MPEG2480 if (Common::File::exists("intro.snd")) {481 _systemVars.cutscenePackVersion = 1;482 }483 #endif484 480 } 485 481 486 482 Common::Error SwordEngine::go() { -
engines/sword1/sword1.h
67 67 uint8 language; 68 68 bool isDemo; 69 69 bool isMac; 70 71 uint8 cutscenePackVersion;72 70 }; 73 71 74 72 class SwordEngine : public Engine { -
engines/sword2/animation.cpp
42 42 #include "sword2/sound.h" 43 43 #include "sword2/animation.h" 44 44 45 #include "gui/message.h" 46 45 47 namespace Sword2 { 46 48 47 49 /////////////////////////////////////////////////////////////////////////////// … … 91 93 _leadOutFrame = (uint)-1; 92 94 _seamless = false; 93 95 _framesSkipped = 0; 94 _forceFrame = false;95 96 _currentText = 0; 96 97 } 97 98 … … 103 104 return _system->getMillis() - _pauseTicks; 104 105 } 105 106 106 void MoviePlayer::updatePalette(byte *pal, bool packed) {107 byte palette[4 * 256];108 byte *p = palette;109 110 uint32 maxWeight = 0;111 uint32 minWeight = 0xFFFFFFFF;112 113 for (int i = 0; i < 256; i++) {114 int r = *pal++;115 int g = *pal++;116 int b = *pal++;117 118 if (!packed)119 pal++;120 121 uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b;122 123 if (weight >= maxWeight) {124 _white = i;125 maxWeight = weight;126 }127 128 if (weight <= minWeight) {129 _black = i;130 minWeight = i;131 }132 133 *p++ = r;134 *p++ = g;135 *p++ = b;136 *p++ = 0;137 }138 139 _vm->_screen->setPalette(0, 256, palette, RDPAL_INSTANT);140 _forceFrame = true;141 }142 143 107 void MoviePlayer::savePalette() { 144 108 memcpy(_originalPalette, _vm->_screen->getPalette(), sizeof(_originalPalette)); 145 109 } … … 157 121 } 158 122 159 123 bool MoviePlayer::checkSkipFrame() { 160 if (_forceFrame) {161 _forceFrame = false;162 return false;163 }164 165 124 if (_framesSkipped > 10) { 166 125 warning("Forced frame %d to be displayed", _currentFrame); 167 126 _framesSkipped = 0; … … 512 471 } 513 472 } 514 473 515 #ifdef USE_ ZLIB474 #ifdef USE_SWORD_SMACKS 516 475 517 476 /////////////////////////////////////////////////////////////////////////////// 518 // Movie player for the new DXAmovies477 // Movie player for the original SMK movies 519 478 /////////////////////////////////////////////////////////////////////////////// 520 479 521 MoviePlayer DXA::MoviePlayerDXA(Sword2Engine *vm, const char *name)522 : MoviePlayer(vm, name) {523 debug(0, "Creating DXAcutscene player");480 MoviePlayerSMK::MoviePlayerSMK(Sword2Engine *vm, const char *name) 481 : MoviePlayer(vm, name), SMKPlayer(vm->_mixer) { 482 debug(0, "Creating SMK cutscene player"); 524 483 } 525 484 526 MoviePlayer DXA::~MoviePlayerDXA() {485 MoviePlayerSMK::~MoviePlayerSMK() { 527 486 closeFile(); 528 487 } 529 488 530 void MoviePlayerDXA::setPalette(byte *pal) { 531 updatePalette(pal); 532 } 533 534 bool MoviePlayerDXA::decodeFrame() { 489 bool MoviePlayerSMK::decodeFrame() { 535 490 decodeNextFrame(); 536 491 copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide()); 537 492 return true; 538 493 } 539 494 540 bool MoviePlayer DXA::load() {495 bool MoviePlayerSMK::load() { 541 496 if (!MoviePlayer::load()) 542 497 return false; 543 498 544 499 char filename[20]; 545 500 546 snprintf(filename, sizeof(filename), "%s. dxa", _name);501 snprintf(filename, sizeof(filename), "%s.smk", _name); 547 502 548 503 if (loadFile(filename)) { 549 // The Broken Sword games always use external audio tracks.550 if (_fileStream->readUint32BE() != MKID_BE('NULL'))551 return false;552 553 504 _frameBuffer = _vm->_screen->getScreen(); 554 505 555 506 _frameWidth = getWidth(); … … 566 517 567 518 #endif 568 519 569 #ifdef USE_ MPEG2520 #ifdef USE_ZLIB 570 521 571 522 /////////////////////////////////////////////////////////////////////////////// 572 // Movie player for the old MPEGmovies523 // Movie player for the new DXA movies 573 524 /////////////////////////////////////////////////////////////////////////////// 574 525 575 MoviePlayer MPEG::MoviePlayerMPEG(Sword2Engine *vm, const char *name)526 MoviePlayerDXA::MoviePlayerDXA(Sword2Engine *vm, const char *name) 576 527 : MoviePlayer(vm, name) { 577 #ifdef BACKEND_8BIT 578 debug(0, "Creating MPEG cutscene player (8-bit)"); 579 #else 580 debug(0, "Creating MPEG cutscene player (16-bit)"); 581 #endif 528 debug(0, "Creating DXA cutscene player"); 582 529 } 583 530 584 MoviePlayerMPEG::~MoviePlayerMPEG() { 585 delete _anim; 586 _anim = NULL; 531 MoviePlayerDXA::~MoviePlayerDXA() { 532 closeFile(); 587 533 } 588 534 589 bool MoviePlayerMPEG::load() { 590 if (!MoviePlayer::load()) 591 return false; 592 593 _anim = new AnimationState(_vm, this); 594 595 if (!_anim->init(_name)) { 596 delete _anim; 597 _anim = NULL; 598 return false; 599 } 600 601 #ifdef BACKEND_8BIT 602 _frameBuffer = _vm->_screen->getScreen(); 603 #endif 604 535 bool MoviePlayerDXA::decodeFrame() { 536 decodeNextFrame(); 537 copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide()); 605 538 return true; 606 539 } 607 540 608 bool MoviePlayerMPEG::decodeFrame() { 609 bool result = _anim->decodeFrame(); 541 bool MoviePlayerDXA::load() { 542 if (!MoviePlayer::load()) 543 return false; 610 544 611 #ifdef BACKEND_8BIT 612 _frameWidth = _anim->getFrameWidth(); 613 _frameHeight = _anim->getFrameHeight(); 545 char filename[20]; 614 546 615 _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2; 616 _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2; 617 #endif 547 snprintf(filename, sizeof(filename), "%s.dxa", _name); 618 548 619 return result; 620 } 549 if (loadFile(filename)) { 550 // The Broken Sword games always use external audio tracks. 551 if (_fileStream->readUint32BE() != MKID_BE('NULL')) 552 return false; 621 553 622 AnimationState::AnimationState(Sword2Engine *vm, MoviePlayer *player) 623 : BaseAnimationState(vm->_system, 640, 480) { 624 _vm = vm; 625 _player = player; 626 } 554 _frameBuffer = _vm->_screen->getScreen(); 627 555 628 AnimationState::~AnimationState() { 629 } 556 _frameWidth = getWidth(); 557 _frameHeight = getHeight(); 630 558 631 #ifdef BACKEND_8BIT 559 _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2; 560 _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2; 632 561 633 void AnimationState::setPalette(byte *pal) { 634 _player->updatePalette(pal, false); 635 } 636 637 #else 638 639 void MoviePlayerMPEG::handleScreenChanged() { 640 _anim->handleScreenChanged(); 641 } 642 643 void MoviePlayerMPEG::clearFrame() { 644 _anim->clearFrame(); 645 } 646 647 void MoviePlayerMPEG::drawFrame() { 648 } 649 650 void MoviePlayerMPEG::updateScreen() { 651 _anim->updateScreen(); 652 } 653 654 void MoviePlayerMPEG::drawTextObject() { 655 if (_textObject.textMem && _textSurface) { 656 _anim->drawTextObject(&_textObject.textSprite, _textSurface); 562 return true; 657 563 } 658 }659 564 660 void MoviePlayerMPEG::undrawTextObject() { 661 // As long as we only have subtitles for full-sized cutscenes, we don't 662 // really need to implement this function. 565 return false; 663 566 } 664 567 665 void AnimationState::drawTextObject(SpriteInfo *s, byte *src) {666 int moviePitch = _movieScale * _movieWidth;667 int textX = _movieScale * s->x;668 int textY = _movieScale * (_frameHeight - s->h - 12);669 670 OverlayColor *dst = _overlay + textY * moviePitch + textX;671 672 Graphics::PixelFormat format = _sys->getOverlayFormat();673 OverlayColor pen = format.RGBToColor(255, 255, 255);674 OverlayColor border = format.RGBToColor(0, 0, 0);675 676 // TODO: Use the AdvMame scalers for the text? Pre-scale it?677 678 for (int y = 0; y < s->h; y++) {679 OverlayColor *ptr = dst;680 681 for (int x = 0; x < s->w; x++) {682 switch (src[x]) {683 case 1:684 *ptr++ = border;685 if (_movieScale > 1) {686 *ptr++ = border;687 if (_movieScale > 2)688 *ptr++ = border;689 }690 break;691 case 255:692 *ptr++ = pen;693 if (_movieScale > 1) {694 *ptr++ = pen;695 if (_movieScale > 2)696 *ptr++ = pen;697 }698 break;699 default:700 ptr += _movieScale;701 break;702 }703 }704 705 if (_movieScale > 1) {706 memcpy(dst + moviePitch, dst, _movieScale * s->w * sizeof(OverlayColor));707 if (_movieScale > 2)708 memcpy(dst + 2 * moviePitch, dst, _movieScale * s->w * sizeof(OverlayColor));709 }710 711 dst += _movieScale * moviePitch;712 src += s->w;713 }714 }715 568 #endif 716 569 717 void AnimationState::clearFrame() {718 #ifdef BACKEND_8BIT719 memset(_vm->_screen->getScreen(), 0, _movieWidth * _movieHeight);720 #else721 Graphics::PixelFormat format = _sys->getOverlayFormat();722 OverlayColor black = format.RGBToColor(0, 0, 0);723 724 for (int i = 0; i < _movieScale * _movieWidth * _movieScale * _movieHeight; i++)725 _overlay[i] = black;726 #endif727 }728 729 void AnimationState::drawYUV(int width, int height, byte *const *dat) {730 _frameWidth = width;731 _frameHeight = height;732 733 #ifdef BACKEND_8BIT734 byte *buf = _vm->_screen->getScreen() + ((480 - height) / 2) * RENDERWIDE + (640 - width) / 2;735 736 int x, y;737 738 int ypos = 0;739 int cpos = 0;740 int linepos = 0;741 742 for (y = 0; y < height; y += 2) {743 for (x = 0; x < width; x += 2) {744 int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * (BITDEPTH + 1)) + ((dat[1][cpos] + ROUNDADD) >> SHIFT)) * (BITDEPTH + 1);745 cpos++;746 747 buf[linepos ] = _lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)];748 buf[RENDERWIDE + linepos++] = _lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)];749 buf[linepos ] = _lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)];750 buf[RENDERWIDE + linepos++] = _lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)];751 }752 linepos += (2 * RENDERWIDE - width);753 ypos += width;754 }755 #else756 plotYUV(width, height, dat);757 #endif758 }759 760 #endif761 762 570 /////////////////////////////////////////////////////////////////////////////// 763 571 // Dummy player for subtitled speech only 764 572 /////////////////////////////////////////////////////////////////////////////// … … 802 610 803 611 byte msgNoCutscenesRU[] = "Po\344uk - to\344\345ko pev\345: hagmute k\344abuwy Ucke\343n, u\344u nocetute ca\343t npoekta u ckava\343te budeo po\344uku"; 804 612 805 #if defined(USE_ MPEG2) || defined(USE_ZLIB)613 #if defined(USE_ZLIB) 806 614 byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos"; 807 615 #else 808 byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with MPEG2 orZLib support";616 byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with ZLib support"; 809 617 #endif 810 618 811 619 byte *msg; … … 885 693 MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) { 886 694 static char filename[20]; 887 695 696 #ifdef USE_SWORD_SMACKS 697 snprintf(filename, sizeof(filename), "%s.smk", name); 698 699 if (Common::File::exists(filename)) { 700 return new MoviePlayerSMK(vm, name); 701 } 702 #endif 703 888 704 #ifdef USE_ZLIB 889 705 snprintf(filename, sizeof(filename), "%s.dxa", name); 890 706 … … 893 709 } 894 710 #endif 895 711 896 #ifdef USE_MPEG2897 712 snprintf(filename, sizeof(filename), "%s.mp2", name); 898 713 899 714 if (Common::File::exists(filename)) { 900 return new MoviePlayerMPEG(vm, name); 715 GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK"); 716 dialog.runModal(); 901 717 } 902 #endif903 718 904 719 return new MoviePlayerDummy(vm, name); 905 720 } -
engines/sword2/animation.h
29 29 #define SWORD2_ANIMATION_H 30 30 31 31 #include "graphics/video/dxa_player.h" 32 #include "graphics/video/mpeg_player.h" 32 #ifdef USE_SWORD_SMACKS 33 #include "graphics/video/smk_player.h" 34 #endif 33 35 #include "sound/mixer.h" 34 36 35 37 #include "sword2/screen.h" … … 97 99 bool _seamless; 98 100 99 101 int _framesSkipped; 100 bool _forceFrame;101 102 102 103 static const MovieInfo _movies[]; 103 104 … … 126 127 MoviePlayer(Sword2Engine *vm, const char *name); 127 128 virtual ~MoviePlayer(); 128 129 129 void updatePalette(byte *pal, bool packed = true);130 130 virtual bool load(); 131 131 bool userInterrupt(); 132 132 void play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut); … … 148 148 bool load(); 149 149 }; 150 150 151 #ifdef USE_MPEG2 152 class AnimationState : public ::Graphics::BaseAnimationState { 153 private: 154 Sword2Engine *_vm; 155 MoviePlayer *_player; 156 157 public: 158 AnimationState(Sword2Engine *vm, MoviePlayer *player); 159 ~AnimationState(); 160 161 #ifndef BACKEND_8BIT 162 void drawTextObject(SpriteInfo *s, byte *src); 163 #endif 164 165 void clearFrame(); 166 167 private: 168 void drawYUV(int width, int height, byte *const *dat); 169 170 #ifdef BACKEND_8BIT 171 void setPalette(byte *pal); 172 #endif 173 }; 174 175 class MoviePlayerMPEG : public MoviePlayer { 151 #ifdef USE_SWORD_SMACKS 152 class MoviePlayerSMK : public MoviePlayer, ::Graphics::SMKPlayer { 176 153 protected: 177 AnimationState *_anim;154 bool decodeFrame(); 178 155 179 virtual bool decodeFrame();180 181 #ifndef BACKEND_8BIT182 void handleScreenChanged();183 void clearFrame();184 void drawFrame();185 void updateScreen();186 void drawTextObject();187 void undrawTextObject();188 #endif189 190 156 public: 191 MoviePlayer MPEG(Sword2Engine *vm, const char *name);192 ~MoviePlayer MPEG();157 MoviePlayerSMK(Sword2Engine *vm, const char *name); 158 ~MoviePlayerSMK(); 193 159 194 160 bool load(); 195 161 }; … … 198 164 #ifdef USE_ZLIB 199 165 class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer { 200 166 protected: 201 void setPalette(byte *pal);202 167 bool decodeFrame(); 203 168 204 169 public: -
engines/sword2/sword2.cpp
252 252 Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS")); 253 253 Common::File::addDefaultDirectory(_gameDataDir.getChild("SWORD2")); 254 254 Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); 255 Common::File::addDefaultDirectory(_gameDataDir.getChild("SMACKS")); 255 256 Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters")); 256 257 Common::File::addDefaultDirectory(_gameDataDir.getChild("sword2")); 257 258 Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); 259 Common::File::addDefaultDirectory(_gameDataDir.getChild("smacks")); 258 260 259 261 if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo")) 260 262 _features = GF_DEMO; -
graphics/video/video_player.h
141 141 */ 142 142 virtual bool decodeNextFrame() = 0; 143 143 144 /** 145 * Used to read the sound header from DXA files. It's not pretty, 146 * but it's slightly better than exposing _fileStream 147 */ 148 uint32 readSoundHeader() { return _fileStream->readUint32BE(); } 149 144 150 protected: 145 151 struct { 146 152 uint32 width;