aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2012-01-07 00:20:27 -0500
committerWillem Jan Palenstijn2012-02-23 22:48:18 +0100
commit8812f885bc95f0e4af05c333780eb77a8c2eaa19 (patch)
treed9f434b6254b3bb943256328f6242dcdaec23717
parentdf21e72fe22132a802856bccc5f4bba27e4d3c17 (diff)
downloadscummvm-rg350-8812f885bc95f0e4af05c333780eb77a8c2eaa19.tar.gz
scummvm-rg350-8812f885bc95f0e4af05c333780eb77a8c2eaa19.tar.bz2
scummvm-rg350-8812f885bc95f0e4af05c333780eb77a8c2eaa19.zip
SWORD2: Add support for PSX stream playback
-rw-r--r--engines/sword2/animation.cpp140
-rw-r--r--engines/sword2/animation.h17
-rw-r--r--engines/sword2/function.cpp4
-rw-r--r--engines/sword2/sword2.cpp1
4 files changed, 121 insertions, 41 deletions
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 80b4809722..e77ae98163 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -40,6 +40,11 @@
#include "gui/message.h"
+#include "video/smk_decoder.h"
+#include "video/psx_decoder.h"
+
+#include "engines/util.h"
+
namespace Sword2 {
///////////////////////////////////////////////////////////////////////////////
@@ -66,6 +71,10 @@ MoviePlayer::~MoviePlayer() {
* @param id the id of the file
*/
bool MoviePlayer::load(const char *name) {
+ // This happens when quitting during the "eye" cutscene.
+ if (_vm->shouldQuit())
+ return false;
+
if (_decoderType == kVideoDecoderDXA)
_bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name);
else
@@ -81,16 +90,26 @@ bool MoviePlayer::load(const char *name) {
case kVideoDecoderSMK:
filename = Common::String::format("%s.smk", name);
break;
+ case kVideoDecoderPSX:
+ filename = Common::String::format("%s.str", name);
+
+ // Need to switch to true color
+ initGraphics(640, 480, true, 0);
+
+ // Need to load here in case it fails in which case we'd need
+ // to go back to paletted mode
+ if (_decoder->loadFile(filename)) {
+ return true;
+ } else {
+ initGraphics(640, 480, true);
+ return false;
+ }
}
return _decoder->loadFile(filename.c_str());
}
void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) {
- // This happens when quitting during the "eye" cutscene.
- if (_vm->shouldQuit())
- return;
-
_leadOutFrame = _decoder->getFrameCount();
if (_leadOutFrame > 60)
_leadOutFrame -= 60;
@@ -120,6 +139,11 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI
while (_snd->isSoundHandleActive(*_bgSoundHandle))
_system->delayMillis(100);
+
+ if (_decoderType == kVideoDecoderPSX) {
+ // Need to jump back to paletted color
+ initGraphics(640, 480, true);
+ }
}
void MoviePlayer::openTextObject(uint32 index) {
@@ -165,7 +189,7 @@ void MoviePlayer::openTextObject(uint32 index) {
}
}
-void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
+void MoviePlayer::closeTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch) {
if (index < _numMovieTexts) {
MovieText *text = &_movieTexts[index];
@@ -180,23 +204,23 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
int frameWidth = _decoder->getWidth();
int frameHeight = _decoder->getHeight();
+
+ if (_decoderType == kVideoDecoderPSX)
+ frameHeight *= 2;
+
int frameX = (_system->getWidth() - frameWidth) / 2;
int frameY = (_system->getHeight() - frameHeight) / 2;
- byte black = findBlackPalIndex();
-
- byte *dst = screen + _textY * pitch;
+ uint32 black = getBlackColor();
for (int y = 0; y < text->_textSprite.h; y++) {
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
- memset(dst + _textX, black, text->_textSprite.w);
+ screen->hLine(_textX, _textY + y, _textX + text->_textSprite.w, black);
} else {
if (frameX > _textX)
- memset(dst + _textX, black, frameX - _textX);
+ screen->hLine(_textX, _textY + y, frameX, black);
if (frameX + frameWidth < _textX + text->_textSprite.w)
- memset(dst + frameX + frameWidth, black, _textX + text->_textSprite.w - (frameX + frameWidth));
+ screen->hLine(frameX + frameWidth, _textY + y, text->_textSprite.w, black);
}
-
- dst += pitch;
}
}
@@ -206,11 +230,24 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
}
}
-void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
+#define PUT_PIXEL(c) \
+ switch (screen->format.bytesPerPixel) { \
+ case 1: \
+ *dst = (c); \
+ break; \
+ case 2: \
+ WRITE_UINT16(dst, (c)); \
+ break; \
+ case 4: \
+ WRITE_UINT32(dst, (c)); \
+ break; \
+ }
+
+void MoviePlayer::drawTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch) {
MovieText *text = &_movieTexts[index];
- byte white = findWhitePalIndex();
- byte black = findBlackPalIndex();
+ uint32 white = getWhiteColor();
+ uint32 black = getBlackColor();
if (text->_textMem && _textSurface) {
byte *src = text->_textSprite.data;
@@ -226,17 +263,20 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
src = psxSpriteBuffer;
}
- byte *dst = screen + _textY * pitch + _textX;
-
for (int y = 0; y < height; y++) {
+ byte *dst = (byte *)screen->getBasePtr(_textX, _textY + y);
+
for (int x = 0; x < width; x++) {
- if (src[x] == 1)
- dst[x] = black;
- else if (src[x] == 255)
- dst[x] = white;
+ if (src[x] == 1) {
+ PUT_PIXEL(black);
+ } else if (src[x] == 255) {
+ PUT_PIXEL(white);
+ }
+
+ dst += screen->format.bytesPerPixel;
}
+
src += width;
- dst += pitch;
}
// Free buffer used to resize psx sprite
@@ -245,7 +285,9 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
}
}
-void MoviePlayer::performPostProcessing(byte *screen, uint16 pitch) {
+#undef PUT_PIXEL
+
+void MoviePlayer::performPostProcessing(Graphics::Surface *screen, uint16 pitch) {
MovieText *text;
int frame = _decoder->getCurFrame();
@@ -286,8 +328,12 @@ bool MoviePlayer::playVideo() {
while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
if (_decoder->needsUpdate()) {
const Graphics::Surface *frame = _decoder->decodeNextFrame();
- if (frame)
- _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ if (frame) {
+ if (_decoderType == kVideoDecoderPSX)
+ drawFramePSX(frame);
+ else
+ _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ }
if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
@@ -319,7 +365,7 @@ bool MoviePlayer::playVideo() {
}
Graphics::Surface *screen = _vm->_system->lockScreen();
- performPostProcessing((byte *)screen->pixels, screen->pitch);
+ performPostProcessing(screen, screen->pitch);
_vm->_system->unlockScreen();
_vm->_system->updateScreen();
}
@@ -335,12 +381,29 @@ bool MoviePlayer::playVideo() {
return !_vm->shouldQuit();
}
-byte MoviePlayer::findBlackPalIndex() {
- return _black;
+uint32 MoviePlayer::getBlackColor() {
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black;
}
-byte MoviePlayer::findWhitePalIndex() {
- return _white;
+uint32 MoviePlayer::getWhiteColor() {
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF) : _white;
+}
+
+void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
+ // The PSX videos have half resolution
+
+ Graphics::Surface scaledFrame;
+ scaledFrame.create(frame->w, frame->h * 2, frame->format);
+
+ for (int y = 0; y < scaledFrame.h; y++)
+ memcpy(scaledFrame.getBasePtr(0, y), frame->getBasePtr(0, y / 2), scaledFrame.w * scaledFrame.format.bytesPerPixel);
+
+ uint16 x = (g_system->getWidth() - scaledFrame.w) / 2;
+ uint16 y = (g_system->getHeight() - scaledFrame.h) / 2;
+
+ _vm->_system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h);
+
+ scaledFrame.free();
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
@@ -358,10 +421,23 @@ uint32 DXADecoderWithSound::getElapsedTime() const {
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system) {
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount) {
Common::String filename;
Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle;
+ filename = Common::String::format("%s.str", name);
+
+ if (Common::File::exists(filename)) {
+#ifdef USE_RGB_COLOR
+ Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x, frameCount);
+ return new MoviePlayer(vm, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX);
+#else
+ GUI::MessageDialog dialog(_("PSX cutscenes found but ScummVM has been built without RGB color support"), _("OK"));
+ dialog.runModal();
+ return NULL;
+#endif
+ }
+
filename = Common::String::format("%s.smk", name);
if (Common::File::exists(filename)) {
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 1f5fced03b..3ef8dac754 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -26,7 +26,6 @@
#define SWORD2_ANIMATION_H
#include "video/dxa_decoder.h"
-#include "video/smk_decoder.h"
#include "video/video_decoder.h"
#include "audio/mixer.h"
@@ -36,7 +35,8 @@ namespace Sword2 {
enum DecoderType {
kVideoDecoderDXA = 0,
- kVideoDecoderSMK = 1
+ kVideoDecoderSMK = 1,
+ kVideoDecoderPSX = 2
};
struct MovieText {
@@ -93,18 +93,19 @@ protected:
uint32 _leadOut;
int _leadOutFrame;
- void performPostProcessing(byte *screen, uint16 pitch);
+ void performPostProcessing(Graphics::Surface *screen, uint16 pitch);
bool playVideo();
+ void drawFramePSX(const Graphics::Surface *frame);
void openTextObject(uint32 index);
- void closeTextObject(uint32 index, byte *screen, uint16 pitch);
- void drawTextObject(uint32 index, byte *screen, uint16 pitch);
+ void closeTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch);
+ void drawTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch);
- byte findBlackPalIndex();
- byte findWhitePalIndex();
+ uint32 getBlackColor();
+ uint32 getWhiteColor();
};
-MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system);
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount);
} // End of namespace Sword2
diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp
index 60ee6176a4..836b252d6c 100644
--- a/engines/sword2/function.cpp
+++ b/engines/sword2/function.cpp
@@ -2137,7 +2137,9 @@ int32 Logic::fnPlaySequence(int32 *params) {
// pause sfx during sequence
_vm->_sound->pauseFx();
- _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system);
+ uint32 frameCount = Sword2Engine::isPsx() ? params[1] : 0;
+
+ _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system, frameCount);
if (_moviePlayer && _moviePlayer->load(filename)) {
_moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut);
diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp
index 3b7965259c..bdfc388c5f 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -255,6 +255,7 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst), _rnd("sword2") {
SearchMan.addSubDirectoryMatching(gameDataDir, "sword2");
SearchMan.addSubDirectoryMatching(gameDataDir, "video");
SearchMan.addSubDirectoryMatching(gameDataDir, "smacks");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "streams"); // PSX video
if (!scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo") || !scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2psxdemo"))
_features = GF_DEMO;