mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-30 21:00:39 +00:00
Applied my patch for the BS1/2 video player
- Support for the MPEG2 videos in BS1/2 has been dropped. The MPEG2 videos were lossy, and support for them complicated the code a lot. - Support for the non-existing enhanced MPEG cutscene packs for BS1 has been dropped. As a consequence, the credits player and the splitted audio stream players used for these packs has been removed - The original Smacker videos for both games are now supported, using our Smacker player (which is based off publically available specs and FFMPEG) - The animations now use the common video player code. Both the Smacker videos and our DXA video packs are supported svn-id: r38236
This commit is contained in:
parent
47a1cd7545
commit
781d7da6b1
@ -27,7 +27,6 @@
|
||||
#include "common/file.h"
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/animation.h"
|
||||
#include "sword1/credits.h"
|
||||
#include "sword1/text.h"
|
||||
#include "sound/vorbis.h"
|
||||
|
||||
@ -36,8 +35,11 @@
|
||||
#include "common/str.h"
|
||||
#include "common/events.h"
|
||||
#include "common/system.h"
|
||||
#include "common/list.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
static const char *sequenceList[20] = {
|
||||
@ -67,107 +69,14 @@ static const char *sequenceList[20] = {
|
||||
// Basic movie player
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayer::MoviePlayer(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)
|
||||
: _vm(vm), _screen(screen), _textMan(textMan), _snd(snd), _system(system) {
|
||||
MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType)
|
||||
: _vm(vm), _textMan(textMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system), VideoPlayer(decoder) {
|
||||
_bgSoundStream = NULL;
|
||||
_ticks = 0;
|
||||
_black = 1;
|
||||
_white = 255;
|
||||
_currentFrame = 0;
|
||||
_forceFrame = false;
|
||||
_framesSkipped = 0;
|
||||
_decoderType = decoderType;
|
||||
}
|
||||
|
||||
MoviePlayer::~MoviePlayer(void) {
|
||||
}
|
||||
|
||||
void MoviePlayer::updatePalette(byte *pal, bool packed) {
|
||||
byte palette[4 * 256];
|
||||
byte *p = palette;
|
||||
|
||||
uint32 maxWeight = 0;
|
||||
uint32 minWeight = 0xFFFFFFFF;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int r = *pal++;
|
||||
int g = *pal++;
|
||||
int b = *pal++;
|
||||
|
||||
if (!packed)
|
||||
pal++;
|
||||
|
||||
uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b;
|
||||
|
||||
if (weight >= maxWeight) {
|
||||
_white = i;
|
||||
maxWeight = weight;
|
||||
}
|
||||
|
||||
if (weight <= minWeight) {
|
||||
_black = i;
|
||||
minWeight = i;
|
||||
}
|
||||
|
||||
*p++ = r;
|
||||
*p++ = g;
|
||||
*p++ = b;
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
_system->setPalette(palette, 0, 256);
|
||||
_forceFrame = true;
|
||||
}
|
||||
|
||||
void MoviePlayer::handleScreenChanged(void) {
|
||||
}
|
||||
|
||||
bool MoviePlayer::initOverlays(uint32 id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MoviePlayer::checkSkipFrame(void) {
|
||||
if (_forceFrame) {
|
||||
_forceFrame = false;
|
||||
return false;
|
||||
}
|
||||
if (_framesSkipped > 10) {
|
||||
warning("Forced frame %d to be displayed", _currentFrame);
|
||||
_framesSkipped = 0;
|
||||
return false;
|
||||
}
|
||||
if (_bgSoundStream) {
|
||||
if ((_snd->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame + 1)
|
||||
return false;
|
||||
} else {
|
||||
if (_system->getMillis() <= _ticks)
|
||||
return false;
|
||||
}
|
||||
_framesSkipped++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MoviePlayer::syncFrame(void) {
|
||||
_ticks += 83;
|
||||
if (checkSkipFrame()) {
|
||||
warning("Skipped frame %d", _currentFrame);
|
||||
return false;
|
||||
}
|
||||
if (_bgSoundStream) {
|
||||
while (_snd->isSoundHandleActive(_bgSoundHandle) && (_snd->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame) {
|
||||
_system->delayMillis(10);
|
||||
}
|
||||
|
||||
// In case the background sound ends prematurely, update _ticks
|
||||
// so that we can still fall back on the no-sound sync case for
|
||||
// the subsequent frames.
|
||||
|
||||
_ticks = _system->getMillis();
|
||||
} else {
|
||||
while (_system->getMillis() < _ticks) {
|
||||
_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
delete(_decoder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,8 +87,11 @@ bool MoviePlayer::load(uint32 id) {
|
||||
Common::File f;
|
||||
char fileName[20];
|
||||
|
||||
_id = id;
|
||||
_bgSoundStream = NULL;
|
||||
if (_decoderType == kVideoDecoderDXA) {
|
||||
_bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[id]);
|
||||
} else {
|
||||
_bgSoundStream = NULL;
|
||||
}
|
||||
|
||||
if (SwordEngine::_systemVars.showText) {
|
||||
sprintf(fileName, "%s.txt", sequenceList[id]);
|
||||
@ -221,98 +133,51 @@ bool MoviePlayer::load(uint32 id) {
|
||||
}
|
||||
}
|
||||
|
||||
if (SwordEngine::_systemVars.cutscenePackVersion == 1) {
|
||||
if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) {
|
||||
#ifdef USE_VORBIS
|
||||
// these sequences are language specific
|
||||
sprintf(fileName, "%s.snd", sequenceList[id]);
|
||||
Common::File *oggSource = new Common::File();
|
||||
if (oggSource->open(fileName)) {
|
||||
SplittedAudioStream *sStream = new SplittedAudioStream();
|
||||
uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2.
|
||||
// for each segment and each of the 7 languages, we've got fileoffset and size
|
||||
uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4);
|
||||
for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++)
|
||||
header[cnt] = oggSource->readUint32LE();
|
||||
for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) {
|
||||
oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]);
|
||||
uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14];
|
||||
Common::MemoryReadStream *stream = oggSource->readStream(segSize);
|
||||
Audio::AudioStream *apStream = Audio::makeVorbisStream(stream, true);
|
||||
if (!apStream)
|
||||
error("Can't create Vorbis Stream from file %s", fileName);
|
||||
sStream->appendStream(apStream);
|
||||
}
|
||||
free(header);
|
||||
_bgSoundStream = sStream;
|
||||
} else
|
||||
warning("Sound file \"%s\" not found", fileName);
|
||||
delete oggSource;
|
||||
#endif
|
||||
initOverlays(id);
|
||||
}
|
||||
char filename[20];
|
||||
switch (_decoderType) {
|
||||
case kVideoDecoderDXA:
|
||||
snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]);
|
||||
break;
|
||||
case kVideoDecoderSMK:
|
||||
snprintf(filename, sizeof(filename), "%s.smk", sequenceList[id]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_decoder->loadFile(filename)) {
|
||||
// The Broken Sword games always use external audio tracks.
|
||||
if (_decoder->readSoundHeader() != MKID_BE('NULL'))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MoviePlayer::play(void) {
|
||||
_screen->clearScreen();
|
||||
_framesSkipped = 0;
|
||||
_ticks = _system->getMillis();
|
||||
_bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[_id]);
|
||||
if (_bgSoundStream) {
|
||||
_snd->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSoundHandle, _bgSoundStream);
|
||||
_snd->playInputStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
|
||||
}
|
||||
_currentFrame = 0;
|
||||
bool terminated = false;
|
||||
Common::EventManager *eventMan = _system->getEventManager();
|
||||
while (!terminated && decodeFrame()) {
|
||||
if (!_movieTexts.empty()) {
|
||||
if (_currentFrame == _movieTexts[0]->_startFrame) {
|
||||
_textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL);
|
||||
|
||||
FrameHeader *frame = _textMan->giveSpriteData(2);
|
||||
_textWidth = frame->width;
|
||||
_textHeight = frame->height;
|
||||
_textX = 320 - _textWidth / 2;
|
||||
_textY = 420 - _textHeight;
|
||||
}
|
||||
if (_currentFrame == _movieTexts[0]->_endFrame) {
|
||||
_textMan->releaseText(2, false);
|
||||
delete _movieTexts.remove_at(0);
|
||||
}
|
||||
}
|
||||
processFrame();
|
||||
if (syncFrame())
|
||||
updateScreen();
|
||||
_currentFrame++;
|
||||
Common::Event event;
|
||||
while (eventMan->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_SCREEN_CHANGED:
|
||||
handleScreenChanged();
|
||||
break;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
|
||||
terminated = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_vm->shouldQuit())
|
||||
terminated = true;
|
||||
}
|
||||
Common::List<Common::Event> stopEvents;
|
||||
Common::Event stopEvent;
|
||||
stopEvents.clear();
|
||||
stopEvent.type = Common::EVENT_KEYDOWN;
|
||||
stopEvent.kbd = Common::KEYCODE_ESCAPE;
|
||||
stopEvents.push_back(stopEvent);
|
||||
|
||||
terminated = !playVideo(&stopEvents);
|
||||
|
||||
if (terminated)
|
||||
_snd->stopHandle(_bgSoundHandle);
|
||||
_snd->stopHandle(*_bgSoundHandle);
|
||||
|
||||
_textMan->releaseText(2, false);
|
||||
|
||||
while (!_movieTexts.empty())
|
||||
delete _movieTexts.remove_at(_movieTexts.size() - 1);
|
||||
|
||||
while (_snd->isSoundHandleActive(_bgSoundHandle))
|
||||
while (_snd->isSoundHandleActive(*_bgSoundHandle))
|
||||
_system->delayMillis(100);
|
||||
|
||||
// It's tempting to call _screen->fullRefresh() here to restore the old
|
||||
@ -322,324 +187,105 @@ void MoviePlayer::play(void) {
|
||||
|
||||
byte pal[3 * 256];
|
||||
memset(pal, 0, sizeof(pal));
|
||||
updatePalette(pal, true);
|
||||
_system->setPalette(pal, 0, 255);
|
||||
}
|
||||
|
||||
SplittedAudioStream::SplittedAudioStream(void) {
|
||||
_queue = NULL;
|
||||
}
|
||||
void MoviePlayer::performPostProcessing(byte *screen) {
|
||||
if (!_movieTexts.empty()) {
|
||||
if (_decoder->getCurFrame() == _movieTexts[0]->_startFrame) {
|
||||
_textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL);
|
||||
|
||||
SplittedAudioStream::~SplittedAudioStream(void) {
|
||||
while (_queue) {
|
||||
delete _queue->stream;
|
||||
FileQueue *que = _queue->next;
|
||||
delete _queue;
|
||||
_queue = que;
|
||||
}
|
||||
}
|
||||
|
||||
int SplittedAudioStream::getRate(void) const {
|
||||
if (_queue)
|
||||
return _queue->stream->getRate();
|
||||
else
|
||||
return 22050;
|
||||
}
|
||||
|
||||
void SplittedAudioStream::appendStream(Audio::AudioStream *stream) {
|
||||
FileQueue **que = &_queue;
|
||||
while (*que)
|
||||
que = &((*que)->next);
|
||||
*que = new FileQueue;
|
||||
(*que)->stream = stream;
|
||||
(*que)->next = NULL;
|
||||
}
|
||||
|
||||
bool SplittedAudioStream::endOfData(void) const {
|
||||
if (_queue)
|
||||
return _queue->stream->endOfData();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SplittedAudioStream::isStereo(void) const {
|
||||
if (_queue)
|
||||
return _queue->stream->isStereo();
|
||||
else
|
||||
return false; // all the BS1 files are mono, anyways.
|
||||
}
|
||||
|
||||
int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) {
|
||||
int retVal = 0;
|
||||
int needSamples = numSamples;
|
||||
while (needSamples && _queue) {
|
||||
int retSmp = _queue->stream->readBuffer(buffer, needSamples);
|
||||
needSamples -= retSmp;
|
||||
retVal += retSmp;
|
||||
buffer += retSmp;
|
||||
if (_queue->stream->endOfData()) {
|
||||
delete _queue->stream;
|
||||
FileQueue *que = _queue->next;
|
||||
delete _queue;
|
||||
_queue = que;
|
||||
FrameHeader *frame = _textMan->giveSpriteData(2);
|
||||
_textWidth = frame->width;
|
||||
_textHeight = frame->height;
|
||||
_textX = 320 - _textWidth / 2;
|
||||
_textY = 420 - _textHeight;
|
||||
}
|
||||
if (_decoder->getCurFrame() == _movieTexts[0]->_endFrame) {
|
||||
_textMan->releaseText(2, false);
|
||||
delete _movieTexts.remove_at(0);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Movie player for the new DXA movies
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayerDXA::MoviePlayerDXA(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)
|
||||
: MoviePlayer(vm, screen, textMan, snd, system) {
|
||||
debug(0, "Creating DXA cutscene player");
|
||||
}
|
||||
|
||||
MoviePlayerDXA::~MoviePlayerDXA(void) {
|
||||
closeFile();
|
||||
}
|
||||
|
||||
bool MoviePlayerDXA::load(uint32 id) {
|
||||
if (!MoviePlayer::load(id))
|
||||
return false;
|
||||
|
||||
char filename[20];
|
||||
snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]);
|
||||
if (loadFile(filename)) {
|
||||
// The Broken Sword games always use external audio tracks.
|
||||
if (_fileStream->readUint32BE() != MKID_BE('NULL'))
|
||||
return false;
|
||||
_frameWidth = getWidth();
|
||||
_frameHeight = getHeight();
|
||||
_frameX = (640 - _frameWidth) / 2;
|
||||
_frameY = (480 - _frameHeight) / 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoviePlayerDXA::initOverlays(uint32 id) {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
void MoviePlayerDXA::setPalette(byte *pal) {
|
||||
updatePalette(pal, true);
|
||||
}
|
||||
|
||||
bool MoviePlayerDXA::decodeFrame(void) {
|
||||
if ((uint32)_currentFrame < (uint32)getFrameCount()) {
|
||||
decodeNextFrame();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MoviePlayerDXA::processFrame(void) {
|
||||
}
|
||||
|
||||
void MoviePlayerDXA::updateScreen(void) {
|
||||
Graphics::Surface *frameBuffer = _system->lockScreen();
|
||||
copyFrameToBuffer((byte *)frameBuffer->pixels, _frameX, _frameY, 640);
|
||||
|
||||
// TODO: Handle the advanced cutscene packs. Do they really exist?
|
||||
|
||||
// We cannot draw the text to _drawBuffer, since that's one of the
|
||||
// decoder's internal buffers, and besides it may be much smaller than
|
||||
// the screen, so it's possible that the subtitles don't fit on it.
|
||||
// Instead, we get the frame buffer from the backend, after copying the
|
||||
// frame to it, and draw on that.
|
||||
|
||||
if (_textMan->giveSpriteData(2)) {
|
||||
byte *src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader);
|
||||
byte *dst = (byte *)frameBuffer->getBasePtr(_textX, _textY);
|
||||
byte *dst = screen + _textY * _decoder->getWidth() + _textX * 1;
|
||||
|
||||
for (int y = 0; y < _textHeight; y++) {
|
||||
for (int x = 0; x < _textWidth; x++) {
|
||||
switch (src[x]) {
|
||||
case BORDER_COL:
|
||||
dst[x] = _black;
|
||||
dst[x] = _decoder->getBlack();
|
||||
break;
|
||||
case LETTER_COL:
|
||||
dst[x] = _white;
|
||||
dst[x] = _decoder->getWhite();
|
||||
break;
|
||||
}
|
||||
}
|
||||
src += _textWidth;
|
||||
dst += frameBuffer->pitch;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_system->unlockScreen();
|
||||
|
||||
_system->updateScreen();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Movie player for the old MPEG movies
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayerMPEG::MoviePlayerMPEG(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)
|
||||
: MoviePlayer(vm, screen, textMan, snd, system) {
|
||||
#ifdef BACKEND_8BIT
|
||||
debug(0, "Creating MPEG cutscene player (8-bit)");
|
||||
#else
|
||||
debug(0, "Creating MPEG cutscene player (16-bit)");
|
||||
#endif
|
||||
for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++)
|
||||
_logoOvls[cnt] = NULL;
|
||||
_introPal = NULL;
|
||||
_anim = NULL;
|
||||
}
|
||||
|
||||
MoviePlayerMPEG::~MoviePlayerMPEG(void) {
|
||||
free(_introPal);
|
||||
for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++)
|
||||
free(_logoOvls[cnt]);
|
||||
delete _anim;
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::handleScreenChanged(void) {
|
||||
_anim->handleScreenChanged();
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) {
|
||||
if (ovl != NULL)
|
||||
for (uint32 cnt = 0; cnt < 640 * 400; cnt++)
|
||||
if (ovl[cnt])
|
||||
buf[cnt] = pal[ovl[cnt]];
|
||||
}
|
||||
|
||||
bool MoviePlayerMPEG::load(uint32 id) {
|
||||
if (MoviePlayer::load(id)) {
|
||||
_anim = new AnimationState(this, _screen, _system);
|
||||
return _anim->init(sequenceList[id]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoviePlayerMPEG::initOverlays(uint32 id) {
|
||||
if (id == SEQ_INTRO) {
|
||||
ArcFile ovlFile;
|
||||
if (!ovlFile.open("intro.dat")) {
|
||||
warning("\"intro.dat\" not found");
|
||||
return false;
|
||||
}
|
||||
ovlFile.enterPath(SwordEngine::_systemVars.language);
|
||||
for (uint8 fcnt = 0; fcnt < 12; fcnt++) {
|
||||
_logoOvls[fcnt] = ovlFile.decompressFile(fcnt);
|
||||
if (fcnt > 0)
|
||||
for (uint32 cnt = 0; cnt < 640 * 400; cnt++)
|
||||
if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt])
|
||||
_logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt];
|
||||
}
|
||||
uint8 *pal = ovlFile.fetchFile(12);
|
||||
_introPal = (OverlayColor *)malloc(256 * sizeof(OverlayColor));
|
||||
Graphics::PixelFormat format = _system->getOverlayFormat();
|
||||
for (uint16 cnt = 0; cnt < 256; cnt++)
|
||||
_introPal[cnt] = format.RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MoviePlayerMPEG::decodeFrame(void) {
|
||||
return _anim->decodeFrame();
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::updateScreen(void) {
|
||||
_anim->updateScreen();
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::processFrame(void) {
|
||||
#ifndef BACKEND_8BIT
|
||||
if ((_id != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0))
|
||||
return;
|
||||
OverlayColor *buf = _anim->giveRgbBuffer();
|
||||
if ((_currentFrame > 397) && (_currentFrame < 444)) { // Broken Sword Logo
|
||||
if (_currentFrame <= 403)
|
||||
insertOverlay(buf, _logoOvls[_currentFrame - 398], _introPal); // fade up
|
||||
else if (_currentFrame <= 437)
|
||||
insertOverlay(buf, _logoOvls[(_currentFrame - 404) % 6 + 6], _introPal); // animation
|
||||
else {
|
||||
insertOverlay(buf, _logoOvls[5 - (_currentFrame - 438)], _introPal); // fade down
|
||||
dst += _decoder->getWidth();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
AnimationState::AnimationState(MoviePlayer *player, Screen *screen, OSystem *system)
|
||||
: BaseAnimationState(system, 640, 400), _player(player), _screen(screen) {
|
||||
DXAPlayerWithSound::DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
|
||||
: _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
|
||||
}
|
||||
|
||||
AnimationState::~AnimationState(void) {
|
||||
int32 DXAPlayerWithSound::getAudioLag() {
|
||||
if (!_fileStream)
|
||||
return 0;
|
||||
|
||||
int32 frameDelay = getFrameDelay();
|
||||
int32 videoTime = _videoInfo.currentFrame * frameDelay;
|
||||
int32 audioTime;
|
||||
|
||||
audioTime = (((int32) _mixer->getSoundElapsedTime(*_bgSoundHandle)) * 100);
|
||||
|
||||
return videoTime - audioTime;
|
||||
}
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
void AnimationState::setPalette(byte *pal) {
|
||||
_player->updatePalette(pal, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
void AnimationState::drawYUV(int width, int height, byte *const *dat) {
|
||||
_frameWidth = width;
|
||||
_frameHeight = height;
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
_screen->plotYUV(_lut, width, height, dat);
|
||||
#else
|
||||
plotYUV(width, height, dat);
|
||||
#endif
|
||||
}
|
||||
|
||||
OverlayColor *AnimationState::giveRgbBuffer(void) {
|
||||
#ifdef BACKEND_8BIT
|
||||
return NULL;
|
||||
#else
|
||||
return _overlay;
|
||||
#endif
|
||||
}
|
||||
|
||||
Audio::AudioStream *AnimationState::createAudioStream(const char *name, void *arg) {
|
||||
if (arg)
|
||||
return (Audio::AudioStream*)arg;
|
||||
else
|
||||
return Audio::AudioStream::openStreamFile(name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Factory function for creating the appropriate cutscene player
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) {
|
||||
#if defined(USE_ZLIB) || defined(USE_MPEG2)
|
||||
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system) {
|
||||
char filename[20];
|
||||
#endif
|
||||
char buf[60];
|
||||
Audio::SoundHandle bgSoundHandle;
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s.smk", sequenceList[id]);
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
Graphics::SMKPlayer *smkDecoder = new Graphics::SMKPlayer(snd);
|
||||
return new MoviePlayer(vm, textMan, snd, system, &bgSoundHandle, smkDecoder, kVideoDecoderSMK);
|
||||
}
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]);
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
return new MoviePlayerDXA(vm, screen, textMan, snd, system);
|
||||
}
|
||||
#ifdef USE_ZLIB
|
||||
DXAPlayerWithSound *dxaDecoder = new DXAPlayerWithSound(snd, &bgSoundHandle);
|
||||
return new MoviePlayer(vm, textMan, snd, system, &bgSoundHandle, dxaDecoder, kVideoDecoderDXA);
|
||||
#else
|
||||
GUI::MessageDialog dialog("DXA cutscenes found but ScummVM has been built without zlib support", "OK");
|
||||
dialog.runModal();
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
// Old MPEG2 cutscenes
|
||||
snprintf(filename, sizeof(filename), "%s.mp2", sequenceList[id]);
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
return new MoviePlayerMPEG(vm, screen, textMan, snd, system);
|
||||
GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK");
|
||||
dialog.runModal();
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
sprintf(buf, "Cutscene '%s' not found", sequenceList[id]);
|
||||
GUI::MessageDialog dialog(buf, "OK");
|
||||
dialog.runModal();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -27,7 +27,8 @@
|
||||
#define SWORD1_ANIMATION_H
|
||||
|
||||
#include "graphics/video/dxa_player.h"
|
||||
#include "graphics/video/mpeg_player.h"
|
||||
#include "graphics/video/smk_player.h"
|
||||
#include "graphics/video/video_player.h"
|
||||
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/sound.h"
|
||||
@ -35,32 +36,11 @@
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum {
|
||||
SEQ_FERRARI = 0,
|
||||
SEQ_LADDER,
|
||||
SEQ_STEPS,
|
||||
SEQ_SEWER,
|
||||
SEQ_INTRO,
|
||||
SEQ_RIVER,
|
||||
SEQ_TRUCK,
|
||||
SEQ_GRAVE,
|
||||
SEQ_MONTFCON,
|
||||
SEQ_TAPESTRY,
|
||||
SEQ_IRELAND,
|
||||
SEQ_FINALE,
|
||||
SEQ_HISTORY,
|
||||
SEQ_SPANISH,
|
||||
SEQ_WELL,
|
||||
SEQ_CANDLE,
|
||||
SEQ_GEODROP,
|
||||
SEQ_VULTURE,
|
||||
SEQ_ENDDEMO,
|
||||
SEQ_CREDITS
|
||||
enum DecoderType {
|
||||
kVideoDecoderDXA = 0,
|
||||
kVideoDecoderSMK = 1
|
||||
};
|
||||
|
||||
#define INTRO_LOGO_OVLS 12
|
||||
#define INTRO_TEXT_OVLS 8
|
||||
|
||||
class MovieText {
|
||||
public:
|
||||
uint16 _startFrame;
|
||||
@ -76,126 +56,39 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MoviePlayer {
|
||||
class DXAPlayerWithSound : public Graphics::DXAPlayer {
|
||||
public:
|
||||
MoviePlayer(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
|
||||
virtual ~MoviePlayer(void);
|
||||
virtual bool load(uint32 id);
|
||||
void play(void);
|
||||
void updatePalette(byte *pal, bool packed = true);
|
||||
DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle);
|
||||
~DXAPlayerWithSound() {}
|
||||
|
||||
int32 getAudioLag();
|
||||
private:
|
||||
bool checkSkipFrame(void);
|
||||
Audio::Mixer *_mixer;
|
||||
Audio::SoundHandle *_bgSoundHandle;
|
||||
};
|
||||
|
||||
class MoviePlayer : public Graphics::VideoPlayer {
|
||||
public:
|
||||
MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType);
|
||||
virtual ~MoviePlayer(void);
|
||||
bool load(uint32 id);
|
||||
void play(void);
|
||||
protected:
|
||||
SwordEngine *_vm;
|
||||
Screen *_screen;
|
||||
Text *_textMan;
|
||||
Audio::Mixer *_snd;
|
||||
OSystem *_system;
|
||||
Common::Array<MovieText *> _movieTexts;
|
||||
int _textX, _textY, _textWidth, _textHeight;
|
||||
byte _black, _white;
|
||||
DecoderType _decoderType;
|
||||
|
||||
uint32 _id;
|
||||
|
||||
uint _currentFrame;
|
||||
int _framesSkipped;
|
||||
bool _forceFrame;
|
||||
|
||||
int _frameWidth, _frameHeight;
|
||||
int _frameX, _frameY;
|
||||
|
||||
Audio::SoundHandle _bgSoundHandle;
|
||||
Audio::SoundHandle *_bgSoundHandle;
|
||||
Audio::AudioStream *_bgSoundStream;
|
||||
uint32 _ticks;
|
||||
|
||||
virtual void handleScreenChanged(void);
|
||||
virtual bool initOverlays(uint32 id);
|
||||
virtual bool decodeFrame(void) = 0;
|
||||
virtual void processFrame(void) = 0;
|
||||
virtual bool syncFrame(void);
|
||||
virtual void updateScreen(void) = 0;
|
||||
void performPostProcessing(byte *screen);
|
||||
};
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
|
||||
class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer {
|
||||
protected:
|
||||
virtual void setPalette(byte *pal);
|
||||
public:
|
||||
MoviePlayerDXA(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
|
||||
virtual ~MoviePlayerDXA(void);
|
||||
bool load(uint32 id);
|
||||
protected:
|
||||
bool initOverlays(uint32 id);
|
||||
bool decodeFrame(void);
|
||||
void processFrame(void);
|
||||
void updateScreen(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
|
||||
class AnimationState : public Graphics::BaseAnimationState {
|
||||
private:
|
||||
MoviePlayer *_player;
|
||||
Screen *_screen;
|
||||
|
||||
public:
|
||||
AnimationState(MoviePlayer *player, Screen *screen, OSystem *system);
|
||||
~AnimationState(void);
|
||||
OverlayColor *giveRgbBuffer(void);
|
||||
|
||||
private:
|
||||
void drawYUV(int width, int height, byte *const *dat);
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
void setPalette(byte *pal);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual Audio::AudioStream *createAudioStream(const char *name, void *arg);
|
||||
};
|
||||
|
||||
class MoviePlayerMPEG : public MoviePlayer {
|
||||
public:
|
||||
MoviePlayerMPEG(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
|
||||
virtual ~MoviePlayerMPEG(void);
|
||||
bool load(uint32 id);
|
||||
protected:
|
||||
void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal);
|
||||
AnimationState *_anim;
|
||||
OverlayColor *_introPal;
|
||||
uint8 *_logoOvls[INTRO_LOGO_OVLS];
|
||||
|
||||
bool initOverlays(uint32 id);
|
||||
bool decodeFrame(void);
|
||||
void processFrame(void);
|
||||
void updateScreen(void);
|
||||
void handleScreenChanged(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct FileQueue {
|
||||
Audio::AudioStream *stream;
|
||||
FileQueue *next;
|
||||
};
|
||||
|
||||
class SplittedAudioStream : public Audio::AudioStream {
|
||||
public:
|
||||
SplittedAudioStream(void);
|
||||
~SplittedAudioStream(void);
|
||||
void appendStream(Audio::AudioStream *stream);
|
||||
virtual int readBuffer(int16 *buffer, const int numSamples);
|
||||
virtual bool isStereo(void) const;
|
||||
virtual bool endOfData(void) const;
|
||||
virtual int getRate(void) const;
|
||||
private:
|
||||
FileQueue *_queue;
|
||||
};
|
||||
|
||||
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
|
||||
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system);
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
|
@ -1,349 +0,0 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "sword1/credits.h"
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
#include "sound/audiostream.h"
|
||||
#include "sound/mixer.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/util.h"
|
||||
#include "common/events.h"
|
||||
#include "common/system.h"
|
||||
|
||||
|
||||
#define CREDITS_X 480
|
||||
#define CREDITS_Y 300
|
||||
#define BUFSIZE_Y 640
|
||||
|
||||
#define START_X ((640 - CREDITS_X) / 2)
|
||||
#define START_Y ((480 - CREDITS_Y) / 2)
|
||||
|
||||
#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second
|
||||
|
||||
#define LOGO_FADEUP_TIME (133 * 1000)
|
||||
#define LOGO_FADEDOWN_TIME (163 * 1000)
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum {
|
||||
FONT_PAL = 0,
|
||||
FONT,
|
||||
TEXT,
|
||||
REVO_PAL,
|
||||
REVO_LOGO,
|
||||
F_EOF
|
||||
};
|
||||
|
||||
enum {
|
||||
FNT_LFT = 0, // left column
|
||||
FNT_RGT, // right column
|
||||
FNT_CEN, // centered
|
||||
FNT_BIG = 64, // big font
|
||||
FNT_EOL = 128, // linebreak
|
||||
FNT_EOB = 255 // end of textblock
|
||||
};
|
||||
|
||||
|
||||
CreditsPlayer::CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer) {
|
||||
_system = pSystem;
|
||||
_mixer = pMixer;
|
||||
_smlFont = _bigFont = NULL;
|
||||
}
|
||||
|
||||
bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) {
|
||||
if (blitEnd > blitSta) {
|
||||
if ((renderDest > blitEnd) || (renderDest + 15 < blitSta))
|
||||
return true;
|
||||
} else {
|
||||
if ((renderDest > blitEnd) && (renderDest + 15 < blitSta))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreditsPlayer::play(void) {
|
||||
Audio::AudioStream *bgSoundStream = Audio::AudioStream::openStreamFile("credits");
|
||||
if (bgSoundStream == NULL) {
|
||||
warning("\"credits.ogg\" not found, skipping credits sequence");
|
||||
return;
|
||||
}
|
||||
ArcFile credFile;
|
||||
if (!credFile.open("credits.dat")) {
|
||||
warning("\"credits.dat\" not found, skipping credits sequence");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen);
|
||||
for (uint32 cnt = 0; cnt < _palLen; cnt++)
|
||||
_palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt];
|
||||
_palLen /= 3;
|
||||
|
||||
generateFonts(&credFile);
|
||||
|
||||
uint8 *textData = credFile.fetchFile(TEXT);
|
||||
textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4);
|
||||
|
||||
uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y);
|
||||
memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y);
|
||||
_system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480);
|
||||
_system->setPalette(_palette, 0, _palLen);
|
||||
|
||||
// everything's initialized, time to render and show the credits.
|
||||
Audio::SoundHandle bgSound;
|
||||
_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &bgSound, bgSoundStream, 0);
|
||||
|
||||
int relDelay = 0;
|
||||
uint16 scrollY = 0;
|
||||
uint16 renderY = BUFSIZE_Y / 2;
|
||||
uint16 clearY = 0xFFFF;
|
||||
bool clearLine = false;
|
||||
while (((*textData != FNT_EOB) || (scrollY != renderY)) && !Engine::shouldQuit()) {
|
||||
if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio
|
||||
if (scrollY < BUFSIZE_Y - CREDITS_Y)
|
||||
_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y);
|
||||
else {
|
||||
_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY);
|
||||
_system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY));
|
||||
}
|
||||
_system->updateScreen();
|
||||
} else
|
||||
warning("frame skipped");
|
||||
|
||||
while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) {
|
||||
if (*textData & FNT_EOL) {
|
||||
renderY = (renderY + 16) % BUFSIZE_Y; // linebreak
|
||||
clearLine = true;
|
||||
*textData &= ~FNT_EOL;
|
||||
}
|
||||
if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) {
|
||||
if (clearLine)
|
||||
memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X);
|
||||
clearLine = false;
|
||||
renderLine(screenBuf, textData + 1, renderY, *textData);
|
||||
if (*textData & FNT_BIG)
|
||||
renderY += 16;
|
||||
while (*++textData != 0) // search for the start of next string
|
||||
;
|
||||
textData++;
|
||||
}
|
||||
if (*textData == FNT_EOB)
|
||||
clearY = renderY;
|
||||
}
|
||||
if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) {
|
||||
memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X);
|
||||
clearY = (clearY + 16) % BUFSIZE_Y;
|
||||
}
|
||||
|
||||
relDelay += SCROLL_TIMING;
|
||||
delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound));
|
||||
scrollY = (scrollY + 1) % BUFSIZE_Y;
|
||||
}
|
||||
free(_smlFont);
|
||||
free(_bigFont);
|
||||
_smlFont = _bigFont = NULL;
|
||||
free(screenBuf);
|
||||
|
||||
// credits done, now show the revolution logo
|
||||
uint8 *revoBuf = credFile.decompressFile(REVO_LOGO);
|
||||
uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen);
|
||||
_palLen /= 3;
|
||||
while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !Engine::shouldQuit()) {
|
||||
delay(100);
|
||||
}
|
||||
memset(_palette, 0, 256 * 4);
|
||||
_system->setPalette(_palette, 0, 256);
|
||||
_system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y);
|
||||
_system->updateScreen();
|
||||
|
||||
fadePalette(revoPal, true, _palLen);
|
||||
while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !Engine::shouldQuit()) {
|
||||
delay(100);
|
||||
}
|
||||
fadePalette(revoPal, false, _palLen);
|
||||
delay(3000);
|
||||
|
||||
if (Engine::shouldQuit())
|
||||
_mixer->stopAll();
|
||||
free(revoBuf);
|
||||
}
|
||||
|
||||
void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) {
|
||||
int8 fadeDir = fadeup ? 1 : -1;
|
||||
int fadeStart = fadeup ? 0 : 12;
|
||||
|
||||
int relDelay = _system->getMillis();
|
||||
for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !Engine::shouldQuit(); fadeStep += fadeDir) {
|
||||
for (uint16 cnt = 0; cnt < len * 3; cnt++)
|
||||
_palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12;
|
||||
_system->setPalette(_palette, 0, 256);
|
||||
relDelay += 1000 / 12;
|
||||
delay(relDelay - _system->getMillis());
|
||||
}
|
||||
}
|
||||
|
||||
void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) {
|
||||
uint8 *font;
|
||||
uint16 fntSize = 16;
|
||||
if (flags & FNT_BIG) {
|
||||
font = _bigFont;
|
||||
fntSize = 32;
|
||||
flags &= ~FNT_BIG;
|
||||
} else
|
||||
font = _smlFont;
|
||||
|
||||
uint16 width = getWidth(font, line);
|
||||
uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255);
|
||||
uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos;
|
||||
while (*line) {
|
||||
uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize;
|
||||
for (uint16 cnty = 0; cnty < fntSize; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < fntSize; cntx++)
|
||||
bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx];
|
||||
chrSrc += fntSize;
|
||||
}
|
||||
bufDest += font[*line++ - 1];
|
||||
}
|
||||
}
|
||||
|
||||
uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) {
|
||||
uint16 width = 0;
|
||||
while (*line)
|
||||
width += font[*line++ - 1];
|
||||
return width;
|
||||
}
|
||||
|
||||
void CreditsPlayer::generateFonts(ArcFile *arcFile) {
|
||||
_bigFont = arcFile->decompressFile(FONT);
|
||||
_numChars = *_bigFont;
|
||||
memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1));
|
||||
_smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1));
|
||||
uint8 *src = _bigFont + _numChars;
|
||||
uint8 *dst = _smlFont + _numChars;
|
||||
for (uint16 cnt = 0; cnt < _numChars; cnt++) {
|
||||
_smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table
|
||||
for (uint16 cnty = 0; cnty < 16; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < 16; cntx++) {
|
||||
uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2);
|
||||
uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2);
|
||||
uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2);
|
||||
*dst++ = getPalIdx(resR, resG, resB);
|
||||
src += 2;
|
||||
}
|
||||
src += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) {
|
||||
for (uint16 cnt = 0; cnt < _palLen; cnt++)
|
||||
if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b))
|
||||
return (uint8)cnt;
|
||||
assert(_palLen < 256);
|
||||
_palette[_palLen * 4 + 0] = r;
|
||||
_palette[_palLen * 4 + 1] = g;
|
||||
_palette[_palLen * 4 + 2] = b;
|
||||
return (uint8)_palLen++;
|
||||
}
|
||||
|
||||
void CreditsPlayer::delay(int msecs) {
|
||||
|
||||
Common::Event event;
|
||||
uint32 start = _system->getMillis();
|
||||
do {
|
||||
Common::EventManager *eventMan = _system->getEventManager();
|
||||
while (eventMan->pollEvent(event)) {
|
||||
#if 0
|
||||
switch (event.type) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_system->updateScreen();
|
||||
|
||||
if (msecs > 0)
|
||||
_system->delayMillis(10);
|
||||
|
||||
} while ((_system->getMillis() < start + msecs) && !Engine::shouldQuit());
|
||||
}
|
||||
|
||||
ArcFile::ArcFile(void) {
|
||||
_buf = NULL;
|
||||
}
|
||||
|
||||
ArcFile::~ArcFile(void) {
|
||||
if (_buf)
|
||||
free(_buf);
|
||||
}
|
||||
|
||||
bool ArcFile::open(const char *name) {
|
||||
Common::File arc;
|
||||
if (!arc.open(name))
|
||||
return false;
|
||||
_bufPos = _buf = (uint8*)malloc(arc.size());
|
||||
arc.read(_buf, arc.size());
|
||||
arc.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArcFile::enterPath(uint32 id) {
|
||||
_bufPos += READ_LE_UINT32(_bufPos + id * 4);
|
||||
}
|
||||
|
||||
uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) {
|
||||
if (size)
|
||||
*size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4);
|
||||
return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4);
|
||||
}
|
||||
|
||||
uint8 *ArcFile::decompressFile(uint32 fileId) {
|
||||
uint32 size;
|
||||
uint8 *srcBuf = fetchFile(fileId, &size);
|
||||
uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf));
|
||||
uint8 *srcPos = srcBuf + 4;
|
||||
uint8 *dstPos = dstBuf;
|
||||
while (srcPos < srcBuf + size) {
|
||||
uint16 len = READ_LE_UINT16(srcPos);
|
||||
memset(dstPos, 0, len);
|
||||
dstPos += len;
|
||||
srcPos += 2;
|
||||
if (srcPos < srcBuf + size) {
|
||||
len = *srcPos++;
|
||||
memcpy(dstPos, srcPos, len);
|
||||
dstPos += len;
|
||||
srcPos += len;
|
||||
}
|
||||
}
|
||||
return dstBuf;
|
||||
}
|
||||
|
||||
} // end of namespace Sword1
|
@ -1,75 +0,0 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD1_CREDITS_H
|
||||
#define SWORD1_CREDITS_H
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Audio {
|
||||
class Mixer;
|
||||
}
|
||||
class OSystem;
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class ArcFile {
|
||||
public:
|
||||
ArcFile(void);
|
||||
~ArcFile(void);
|
||||
bool open(const char *name);
|
||||
uint8 *fetchFile(uint32 fileId, uint32 *size = NULL);
|
||||
uint8 *decompressFile(uint32 fileId);
|
||||
void enterPath(uint32 id);
|
||||
void backToRoot(void) { _bufPos = _buf; }
|
||||
private:
|
||||
uint8 *_bufPos;
|
||||
uint8 *_buf;
|
||||
};
|
||||
|
||||
class CreditsPlayer {
|
||||
public:
|
||||
CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer);
|
||||
void play(void);
|
||||
private:
|
||||
void generateFonts(ArcFile *arcFile);
|
||||
void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags);
|
||||
void fadePalette(uint8 *srcPal, bool fadeup, uint16 len);
|
||||
void delay(int msecs);
|
||||
uint16 getWidth(uint8 *font, uint8 *line);
|
||||
uint8 getPalIdx(uint8 r, uint8 g, uint8 b);
|
||||
uint8 _palette[256 * 4];
|
||||
uint32 _palLen;
|
||||
uint8 _numChars;
|
||||
|
||||
OSystem *_system;
|
||||
Audio::Mixer *_mixer;
|
||||
|
||||
uint8 *_smlFont, *_bigFont;
|
||||
};
|
||||
|
||||
} // end of namespace Sword1
|
||||
|
||||
#endif // BS1CREDITS_H
|
@ -41,7 +41,6 @@
|
||||
#include "sword1/music.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/animation.h"
|
||||
#include "sword1/credits.h"
|
||||
|
||||
#include "sword1/debug.h"
|
||||
|
||||
@ -960,16 +959,12 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3
|
||||
// meantime, we don't want any looping sound effects still playing.
|
||||
_sound->quitScreen();
|
||||
|
||||
if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) {
|
||||
CreditsPlayer player(_system, _mixer);
|
||||
player.play();
|
||||
} else {
|
||||
MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _screen, _textMan, _mixer, _system);
|
||||
if (player) {
|
||||
if (player->load(sequenceId))
|
||||
player->play();
|
||||
delete player;
|
||||
}
|
||||
MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _mixer, _system);
|
||||
if (player) {
|
||||
_screen->clearScreen();
|
||||
if (player->load(sequenceId))
|
||||
player->play();
|
||||
delete player;
|
||||
}
|
||||
return SCRIPT_CONT;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ MODULE := engines/sword1
|
||||
MODULE_OBJS := \
|
||||
animation.o \
|
||||
control.o \
|
||||
credits.o \
|
||||
debug.o \
|
||||
detection.o \
|
||||
eventman.o \
|
||||
|
@ -58,10 +58,12 @@ SwordEngine::SwordEngine(OSystem *syst)
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("MUSIC"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("SPEECH"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("SMACKSHI"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("music"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("speech"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("video"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("smackshi"));
|
||||
}
|
||||
|
||||
SwordEngine::~SwordEngine() {
|
||||
@ -475,12 +477,6 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or
|
||||
*/
|
||||
// make the demo flag depend on the Gamesettings for now, and not on what the datafiles look like
|
||||
_systemVars.isDemo = (_features & GF_DEMO) != 0;
|
||||
_systemVars.cutscenePackVersion = 0;
|
||||
#ifdef USE_MPEG2
|
||||
if (Common::File::exists("intro.snd")) {
|
||||
_systemVars.cutscenePackVersion = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Common::Error SwordEngine::go() {
|
||||
|
@ -67,8 +67,6 @@ struct SystemVars {
|
||||
uint8 language;
|
||||
bool isDemo;
|
||||
bool isMac;
|
||||
|
||||
uint8 cutscenePackVersion;
|
||||
};
|
||||
|
||||
class SwordEngine : public Engine {
|
||||
|
@ -42,6 +42,8 @@
|
||||
#include "sword2/sound.h"
|
||||
#include "sword2/animation.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
namespace Sword2 {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -91,7 +93,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, const char *name) {
|
||||
_leadOutFrame = (uint)-1;
|
||||
_seamless = false;
|
||||
_framesSkipped = 0;
|
||||
_forceFrame = false;
|
||||
_currentText = 0;
|
||||
}
|
||||
|
||||
@ -103,43 +104,6 @@ uint32 MoviePlayer::getTick() {
|
||||
return _system->getMillis() - _pauseTicks;
|
||||
}
|
||||
|
||||
void MoviePlayer::updatePalette(byte *pal, bool packed) {
|
||||
byte palette[4 * 256];
|
||||
byte *p = palette;
|
||||
|
||||
uint32 maxWeight = 0;
|
||||
uint32 minWeight = 0xFFFFFFFF;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int r = *pal++;
|
||||
int g = *pal++;
|
||||
int b = *pal++;
|
||||
|
||||
if (!packed)
|
||||
pal++;
|
||||
|
||||
uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b;
|
||||
|
||||
if (weight >= maxWeight) {
|
||||
_white = i;
|
||||
maxWeight = weight;
|
||||
}
|
||||
|
||||
if (weight <= minWeight) {
|
||||
_black = i;
|
||||
minWeight = i;
|
||||
}
|
||||
|
||||
*p++ = r;
|
||||
*p++ = g;
|
||||
*p++ = b;
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
_vm->_screen->setPalette(0, 256, palette, RDPAL_INSTANT);
|
||||
_forceFrame = true;
|
||||
}
|
||||
|
||||
void MoviePlayer::savePalette() {
|
||||
memcpy(_originalPalette, _vm->_screen->getPalette(), sizeof(_originalPalette));
|
||||
}
|
||||
@ -157,11 +121,6 @@ void MoviePlayer::updateScreen() {
|
||||
}
|
||||
|
||||
bool MoviePlayer::checkSkipFrame() {
|
||||
if (_forceFrame) {
|
||||
_forceFrame = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_framesSkipped > 10) {
|
||||
warning("Forced frame %d to be displayed", _currentFrame);
|
||||
_framesSkipped = 0;
|
||||
@ -512,6 +471,48 @@ void MoviePlayer::pauseMovie(bool pause) {
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Movie player for the original SMK movies
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayerSMK::MoviePlayerSMK(Sword2Engine *vm, const char *name)
|
||||
: MoviePlayer(vm, name), SMKPlayer(vm->_mixer) {
|
||||
debug(0, "Creating SMK cutscene player");
|
||||
}
|
||||
|
||||
MoviePlayerSMK::~MoviePlayerSMK() {
|
||||
closeFile();
|
||||
}
|
||||
|
||||
bool MoviePlayerSMK::decodeFrame() {
|
||||
decodeNextFrame();
|
||||
copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MoviePlayerSMK::load() {
|
||||
if (!MoviePlayer::load())
|
||||
return false;
|
||||
|
||||
char filename[20];
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s.smk", _name);
|
||||
|
||||
if (loadFile(filename)) {
|
||||
_frameBuffer = _vm->_screen->getScreen();
|
||||
|
||||
_frameWidth = getWidth();
|
||||
_frameHeight = getHeight();
|
||||
|
||||
_frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2;
|
||||
_frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -527,10 +528,6 @@ MoviePlayerDXA::~MoviePlayerDXA() {
|
||||
closeFile();
|
||||
}
|
||||
|
||||
void MoviePlayerDXA::setPalette(byte *pal) {
|
||||
updatePalette(pal);
|
||||
}
|
||||
|
||||
bool MoviePlayerDXA::decodeFrame() {
|
||||
decodeNextFrame();
|
||||
copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide());
|
||||
@ -566,199 +563,6 @@ bool MoviePlayerDXA::load() {
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Movie player for the old MPEG movies
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayerMPEG::MoviePlayerMPEG(Sword2Engine *vm, const char *name)
|
||||
: MoviePlayer(vm, name) {
|
||||
#ifdef BACKEND_8BIT
|
||||
debug(0, "Creating MPEG cutscene player (8-bit)");
|
||||
#else
|
||||
debug(0, "Creating MPEG cutscene player (16-bit)");
|
||||
#endif
|
||||
}
|
||||
|
||||
MoviePlayerMPEG::~MoviePlayerMPEG() {
|
||||
delete _anim;
|
||||
_anim = NULL;
|
||||
}
|
||||
|
||||
bool MoviePlayerMPEG::load() {
|
||||
if (!MoviePlayer::load())
|
||||
return false;
|
||||
|
||||
_anim = new AnimationState(_vm, this);
|
||||
|
||||
if (!_anim->init(_name)) {
|
||||
delete _anim;
|
||||
_anim = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
_frameBuffer = _vm->_screen->getScreen();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MoviePlayerMPEG::decodeFrame() {
|
||||
bool result = _anim->decodeFrame();
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
_frameWidth = _anim->getFrameWidth();
|
||||
_frameHeight = _anim->getFrameHeight();
|
||||
|
||||
_frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2;
|
||||
_frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AnimationState::AnimationState(Sword2Engine *vm, MoviePlayer *player)
|
||||
: BaseAnimationState(vm->_system, 640, 480) {
|
||||
_vm = vm;
|
||||
_player = player;
|
||||
}
|
||||
|
||||
AnimationState::~AnimationState() {
|
||||
}
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
|
||||
void AnimationState::setPalette(byte *pal) {
|
||||
_player->updatePalette(pal, false);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void MoviePlayerMPEG::handleScreenChanged() {
|
||||
_anim->handleScreenChanged();
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::clearFrame() {
|
||||
_anim->clearFrame();
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::drawFrame() {
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::updateScreen() {
|
||||
_anim->updateScreen();
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::drawTextObject() {
|
||||
if (_textObject.textMem && _textSurface) {
|
||||
_anim->drawTextObject(&_textObject.textSprite, _textSurface);
|
||||
}
|
||||
}
|
||||
|
||||
void MoviePlayerMPEG::undrawTextObject() {
|
||||
// As long as we only have subtitles for full-sized cutscenes, we don't
|
||||
// really need to implement this function.
|
||||
}
|
||||
|
||||
void AnimationState::drawTextObject(SpriteInfo *s, byte *src) {
|
||||
int moviePitch = _movieScale * _movieWidth;
|
||||
int textX = _movieScale * s->x;
|
||||
int textY = _movieScale * (_frameHeight - s->h - 12);
|
||||
|
||||
OverlayColor *dst = _overlay + textY * moviePitch + textX;
|
||||
|
||||
Graphics::PixelFormat format = _sys->getOverlayFormat();
|
||||
OverlayColor pen = format.RGBToColor(255, 255, 255);
|
||||
OverlayColor border = format.RGBToColor(0, 0, 0);
|
||||
|
||||
// TODO: Use the AdvMame scalers for the text? Pre-scale it?
|
||||
|
||||
for (int y = 0; y < s->h; y++) {
|
||||
OverlayColor *ptr = dst;
|
||||
|
||||
for (int x = 0; x < s->w; x++) {
|
||||
switch (src[x]) {
|
||||
case 1:
|
||||
*ptr++ = border;
|
||||
if (_movieScale > 1) {
|
||||
*ptr++ = border;
|
||||
if (_movieScale > 2)
|
||||
*ptr++ = border;
|
||||
}
|
||||
break;
|
||||
case 255:
|
||||
*ptr++ = pen;
|
||||
if (_movieScale > 1) {
|
||||
*ptr++ = pen;
|
||||
if (_movieScale > 2)
|
||||
*ptr++ = pen;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ptr += _movieScale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_movieScale > 1) {
|
||||
memcpy(dst + moviePitch, dst, _movieScale * s->w * sizeof(OverlayColor));
|
||||
if (_movieScale > 2)
|
||||
memcpy(dst + 2 * moviePitch, dst, _movieScale * s->w * sizeof(OverlayColor));
|
||||
}
|
||||
|
||||
dst += _movieScale * moviePitch;
|
||||
src += s->w;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void AnimationState::clearFrame() {
|
||||
#ifdef BACKEND_8BIT
|
||||
memset(_vm->_screen->getScreen(), 0, _movieWidth * _movieHeight);
|
||||
#else
|
||||
Graphics::PixelFormat format = _sys->getOverlayFormat();
|
||||
OverlayColor black = format.RGBToColor(0, 0, 0);
|
||||
|
||||
for (int i = 0; i < _movieScale * _movieWidth * _movieScale * _movieHeight; i++)
|
||||
_overlay[i] = black;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AnimationState::drawYUV(int width, int height, byte *const *dat) {
|
||||
_frameWidth = width;
|
||||
_frameHeight = height;
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
byte *buf = _vm->_screen->getScreen() + ((480 - height) / 2) * RENDERWIDE + (640 - width) / 2;
|
||||
|
||||
int x, y;
|
||||
|
||||
int ypos = 0;
|
||||
int cpos = 0;
|
||||
int linepos = 0;
|
||||
|
||||
for (y = 0; y < height; y += 2) {
|
||||
for (x = 0; x < width; x += 2) {
|
||||
int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * (BITDEPTH + 1)) + ((dat[1][cpos] + ROUNDADD) >> SHIFT)) * (BITDEPTH + 1);
|
||||
cpos++;
|
||||
|
||||
buf[linepos ] = _lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)];
|
||||
buf[RENDERWIDE + linepos++] = _lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)];
|
||||
buf[linepos ] = _lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)];
|
||||
buf[RENDERWIDE + linepos++] = _lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)];
|
||||
}
|
||||
linepos += (2 * RENDERWIDE - width);
|
||||
ypos += width;
|
||||
}
|
||||
#else
|
||||
plotYUV(width, height, dat);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Dummy player for subtitled speech only
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -802,10 +606,10 @@ bool MoviePlayerDummy::decodeFrame() {
|
||||
|
||||
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";
|
||||
|
||||
#if defined(USE_MPEG2) || defined(USE_ZLIB)
|
||||
#if defined(USE_ZLIB)
|
||||
byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos";
|
||||
#else
|
||||
byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with MPEG2 or ZLib support";
|
||||
byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with ZLib support";
|
||||
#endif
|
||||
|
||||
byte *msg;
|
||||
@ -885,6 +689,12 @@ void MoviePlayerDummy::undrawTextObject() {
|
||||
MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) {
|
||||
static char filename[20];
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s.smk", name);
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
return new MoviePlayerSMK(vm, name);
|
||||
}
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
snprintf(filename, sizeof(filename), "%s.dxa", name);
|
||||
|
||||
@ -893,13 +703,12 @@ MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
snprintf(filename, sizeof(filename), "%s.mp2", name);
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
return new MoviePlayerMPEG(vm, name);
|
||||
GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK");
|
||||
dialog.runModal();
|
||||
}
|
||||
#endif
|
||||
|
||||
return new MoviePlayerDummy(vm, name);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
#define SWORD2_ANIMATION_H
|
||||
|
||||
#include "graphics/video/dxa_player.h"
|
||||
#include "graphics/video/mpeg_player.h"
|
||||
#include "graphics/video/smk_player.h"
|
||||
#include "sound/mixer.h"
|
||||
|
||||
#include "sword2/screen.h"
|
||||
@ -97,7 +97,6 @@ protected:
|
||||
bool _seamless;
|
||||
|
||||
int _framesSkipped;
|
||||
bool _forceFrame;
|
||||
|
||||
static const MovieInfo _movies[];
|
||||
|
||||
@ -126,7 +125,6 @@ public:
|
||||
MoviePlayer(Sword2Engine *vm, const char *name);
|
||||
virtual ~MoviePlayer();
|
||||
|
||||
void updatePalette(byte *pal, bool packed = true);
|
||||
virtual bool load();
|
||||
bool userInterrupt();
|
||||
void play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut);
|
||||
@ -148,57 +146,20 @@ public:
|
||||
bool load();
|
||||
};
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
class AnimationState : public ::Graphics::BaseAnimationState {
|
||||
private:
|
||||
Sword2Engine *_vm;
|
||||
MoviePlayer *_player;
|
||||
|
||||
public:
|
||||
AnimationState(Sword2Engine *vm, MoviePlayer *player);
|
||||
~AnimationState();
|
||||
|
||||
#ifndef BACKEND_8BIT
|
||||
void drawTextObject(SpriteInfo *s, byte *src);
|
||||
#endif
|
||||
|
||||
void clearFrame();
|
||||
|
||||
private:
|
||||
void drawYUV(int width, int height, byte *const *dat);
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
void setPalette(byte *pal);
|
||||
#endif
|
||||
};
|
||||
|
||||
class MoviePlayerMPEG : public MoviePlayer {
|
||||
class MoviePlayerSMK : public MoviePlayer, ::Graphics::SMKPlayer {
|
||||
protected:
|
||||
AnimationState *_anim;
|
||||
|
||||
virtual bool decodeFrame();
|
||||
|
||||
#ifndef BACKEND_8BIT
|
||||
void handleScreenChanged();
|
||||
void clearFrame();
|
||||
void drawFrame();
|
||||
void updateScreen();
|
||||
void drawTextObject();
|
||||
void undrawTextObject();
|
||||
#endif
|
||||
bool decodeFrame();
|
||||
|
||||
public:
|
||||
MoviePlayerMPEG(Sword2Engine *vm, const char *name);
|
||||
~MoviePlayerMPEG();
|
||||
MoviePlayerSMK(Sword2Engine *vm, const char *name);
|
||||
~MoviePlayerSMK();
|
||||
|
||||
bool load();
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer {
|
||||
protected:
|
||||
void setPalette(byte *pal);
|
||||
bool decodeFrame();
|
||||
|
||||
public:
|
||||
|
@ -252,9 +252,11 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) {
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("SWORD2"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("SMACKS"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("sword2"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("video"));
|
||||
Common::File::addDefaultDirectory(_gameDataDir.getChild("smacks"));
|
||||
|
||||
if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo"))
|
||||
_features = GF_DEMO;
|
||||
|
@ -141,6 +141,12 @@ public:
|
||||
*/
|
||||
virtual bool decodeNextFrame() = 0;
|
||||
|
||||
/**
|
||||
* Used to read the sound header from DXA files. It's not pretty,
|
||||
* but it's slightly better than exposing _fileStream
|
||||
*/
|
||||
uint32 readSoundHeader() { return _fileStream->readUint32BE(); }
|
||||
|
||||
protected:
|
||||
struct {
|
||||
uint32 width;
|
||||
|
Loading…
Reference in New Issue
Block a user