diff options
author | Filippos Karapetis | 2011-02-07 12:24:09 +0000 |
---|---|---|
committer | Filippos Karapetis | 2011-02-07 12:24:09 +0000 |
commit | 6f9ac84f77f140c8008ffec0e57fcf2ddd17a10e (patch) | |
tree | dbf6c0eae66fe09f7ab9e397ba41c60e2b01c970 /engines/sci | |
parent | d7fb5239e7ed9b95442b8a481cdd9e6c25a9acc5 (diff) | |
download | scummvm-rg350-6f9ac84f77f140c8008ffec0e57fcf2ddd17a10e.tar.gz scummvm-rg350-6f9ac84f77f140c8008ffec0e57fcf2ddd17a10e.tar.bz2 scummvm-rg350-6f9ac84f77f140c8008ffec0e57fcf2ddd17a10e.zip |
SCI: Converted the robot decoder into a regular video decoder, and decoupled it from the
SciEngine class
- Robot videos are now shown in frameOut(), like they should, and kRobot(sync) is only
used for syncing with the game scripts
- Hooked video playing into the "play_video" console command
svn-id: r55801
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/console.cpp | 40 | ||||
-rw-r--r-- | engines/sci/console.h | 3 | ||||
-rw-r--r-- | engines/sci/engine/kgraphics.cpp | 15 | ||||
-rw-r--r-- | engines/sci/engine/kvideo.cpp | 33 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 34 | ||||
-rw-r--r-- | engines/sci/graphics/paint32.cpp | 10 | ||||
-rw-r--r-- | engines/sci/graphics/paint32.h | 2 | ||||
-rw-r--r-- | engines/sci/module.mk | 2 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 8 | ||||
-rw-r--r-- | engines/sci/sci.h | 4 | ||||
-rw-r--r-- | engines/sci/video/robot_decoder.cpp (renamed from engines/sci/graphics/robot.cpp) | 264 | ||||
-rw-r--r-- | engines/sci/video/robot_decoder.h (renamed from engines/sci/graphics/robot.h) | 70 |
12 files changed, 240 insertions, 245 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 3bb6675ff7..562b770afa 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -53,6 +53,7 @@ #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 #include "video/coktel_decoder.h" +#include "sci/video/robot_decoder.h" #endif #include "common/file.h" @@ -119,9 +120,6 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), DCmd_Register("set_palette", WRAP_METHOD(Console, cmdSetPalette)); DCmd_Register("draw_pic", WRAP_METHOD(Console, cmdDrawPic)); DCmd_Register("draw_cel", WRAP_METHOD(Console, cmdDrawCel)); -#ifdef ENABLE_SCI32 - DCmd_Register("draw_robot", WRAP_METHOD(Console, cmdDrawRobot)); -#endif DCmd_Register("undither", WRAP_METHOD(Console, cmdUndither)); DCmd_Register("pic_visualize", WRAP_METHOD(Console, cmdPicVisualize)); DCmd_Register("play_video", WRAP_METHOD(Console, cmdPlayVideo)); @@ -243,16 +241,16 @@ void Console::postEnter() { #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { videoDecoder = new Video::VMDDecoder(g_system->getMixer()); -#endif + } else if (_videoFile.hasSuffix(".rbt")) { + videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { -#ifdef ENABLE_SCI32 duckMode = true; - videoDecoder = new Video::AviDecoder(g_system->getMixer()); -#else - warning("Duck videos require SCI32 support compiled in"); + videoDecoder = new Video::AviDecoder(g_system->getMixer()); #endif } else if (_videoFile.hasSuffix(".avi")) { videoDecoder = new Video::AviDecoder(g_system->getMixer()); + } else { + warning("Unrecognized video type"); } if (videoDecoder && videoDecoder->loadFile(_videoFile)) { @@ -1509,27 +1507,6 @@ bool Console::cmdDrawCel(int argc, const char **argv) { return true; } -#ifdef ENABLE_SCI32 -bool Console::cmdDrawRobot(int argc, const char **argv) { - if (argc < 2) { - DebugPrintf("Draws frames from a robot resource\n"); - DebugPrintf("Usage: %s <resourceId>\n", argv[0]); - DebugPrintf("where <resourceId> is the id of the robot resource to draw\n"); - return true; - } - - uint16 resourceId = atoi(argv[1]); - - if (_engine->_gfxPaint32) { - _engine->_gfxPaint32->debugDrawRobot(resourceId); - } else { - DebugPrintf("command not available in non-sci32 games"); - } - return true; -} - -#endif - bool Console::cmdUndither(int argc, const char **argv) { if (argc != 2) { DebugPrintf("Enable/disable undithering.\n"); @@ -1569,7 +1546,7 @@ bool Console::cmdPicVisualize(int argc, const char **argv) { bool Console::cmdPlayVideo(int argc, const char **argv) { if (argc < 2) { - DebugPrintf("Plays a SEQ, AVI, DUK or VMD video.\n"); + DebugPrintf("Plays a SEQ, AVI, VMD, RBT or DUK video.\n"); DebugPrintf("Usage: %s <video file name> <delay>\n", argv[0]); DebugPrintf("The video file name should include the extension\n"); DebugPrintf("Delay is only used in SEQ videos and is measured in ticks (default: 10)\n"); @@ -1579,7 +1556,8 @@ bool Console::cmdPlayVideo(int argc, const char **argv) { Common::String filename = argv[1]; filename.toLowercase(); - if (filename.hasSuffix(".seq") || filename.hasSuffix(".avi") || filename.hasSuffix(".vmd") || filename.hasSuffix(".duk")) { + if (filename.hasSuffix(".seq") || filename.hasSuffix(".avi") || filename.hasSuffix(".vmd") || + filename.hasSuffix(".rbt") || filename.hasSuffix(".duk")) { _videoFile = filename; _videoFrameDelay = (argc == 2) ? 10 : atoi(argv[2]); return Cmd_Exit(0, 0); diff --git a/engines/sci/console.h b/engines/sci/console.h index 670c89e672..b0a1de6ebd 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -91,9 +91,6 @@ private: bool cmdSetPalette(int argc, const char **argv); bool cmdDrawPic(int argc, const char **argv); bool cmdDrawCel(int argc, const char **argv); -#ifdef ENABLE_SCI32 - bool cmdDrawRobot(int argc, const char **argv); -#endif bool cmdUndither(int argc, const char **argv); bool cmdPicVisualize(int argc, const char **argv); bool cmdPlayVideo(int argc, const char **argv); diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 0c0e3bf720..8730724d68 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -48,12 +48,12 @@ #include "sci/graphics/paint16.h" #include "sci/graphics/picture.h" #include "sci/graphics/ports.h" -#include "sci/graphics/robot.h" #include "sci/graphics/screen.h" #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 #include "sci/graphics/frameout.h" +#include "sci/video/robot_decoder.h" #endif namespace Sci { @@ -1398,7 +1398,6 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 subop = argv[0].toUint16(); - GfxRobot *robot = g_sci->_gfxRobot; switch (subop) { case 0: { // init @@ -1408,7 +1407,8 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 x = argv[4].toUint16(); int16 y = argv[5].toUint16(); warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); - robot->init(id, x, y); + g_sci->_robotDecoder->load(id); + g_sci->_robotDecoder->setPos(x, y); } break; case 1: // LSL6 hires (startup) @@ -1423,10 +1423,13 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { warning("kRobot(%d)", subop); break; case 8: // sync - robot->processNextFrame(); - // Signal the engine scripts that the video is done - if (robot->getCurFrame() == robot->getFrameCount()) + if ((uint32)g_sci->_robotDecoder->getCurFrame() != g_sci->_robotDecoder->getFrameCount() - 1) { + writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); + } else { + g_sci->_robotDecoder->close(); + // Signal the engine scripts that the video is done writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); + } break; default: warning("kRobot(%d)", subop); diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index ef47f9b9c6..1ed3a713b0 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -51,12 +51,15 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { uint16 screenWidth = g_system->getWidth(); uint16 screenHeight = g_system->getHeight(); bool isVMD = videoState.fileName.hasSuffix(".vmd"); - - if (screenWidth == 640 && width <= 320 && height <= 240 && ((videoState.flags & kDoubled) || !isVMD)) { - width *= 2; - height *= 2; - pitch *= 2; - scaleBuffer = new byte[width * height * bytesPerPixel]; + bool isRobot = videoState.fileName.hasSuffix(".rbt"); + + if (!isRobot) { + if (screenWidth == 640 && width <= 320 && height <= 240 && ((videoState.flags & kDoubled) || !isVMD)) { + width *= 2; + height *= 2; + pitch *= 2; + scaleBuffer = new byte[width * height * bytesPerPixel]; + } } uint16 x, y; @@ -73,8 +76,13 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { y = (screenHeight - height) / 2; } } else { - x = (screenWidth - width) / 2; - y = (screenHeight - height) / 2; + if (!isRobot) { + x = (screenWidth - width) / 2; + y = (screenHeight - height) / 2; + } else { + x = 0; + y = 0; + } } bool skipVideo = false; @@ -84,13 +92,18 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); + if (frame) { if (scaleBuffer) { // TODO: Probably should do aspect ratio correction in e.g. GK1 Windows g_sci->_gfxScreen->scale2x((byte *)frame->pixels, scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel); g_system->copyRectToScreen(scaleBuffer, pitch, x, y, width, height); - } else - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, width, height); + } else { + if (!isRobot) + g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, width, height); + else // Frames in robot videos have different dimensions + g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + } if (videoDecoder->hasDirtyPalette()) videoDecoder->setSystemPalette(); diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 8af41ddf57..5b690f289a 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -40,8 +40,8 @@ #include "sci/graphics/paint32.h" #include "sci/graphics/palette.h" #include "sci/graphics/picture.h" -#include "sci/graphics/robot.h" #include "sci/graphics/frameout.h" +#include "sci/video/robot_decoder.h" namespace Sci { @@ -339,8 +339,38 @@ static int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font) { } void GfxFrameout::kernelFrameout() { - if (g_sci->_gfxRobot->isPlaying()) + if (g_sci->_robotDecoder->isVideoLoaded()) { + bool skipVideo = false; + RobotDecoder *videoDecoder = g_sci->_robotDecoder; + uint16 x = videoDecoder->getPos().x; + uint16 y = videoDecoder->getPos().y; + + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + + while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { + if (videoDecoder->needsUpdate()) { + const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); + if (frame) { + g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + + g_system->updateScreen(); + } + } + + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } + + g_system->delayMillis(10); + } return; + } _palette->palVaryUpdate(); diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp index 2fb4b832e5..aa3bf8dfb3 100644 --- a/engines/sci/graphics/paint32.cpp +++ b/engines/sci/graphics/paint32.cpp @@ -39,7 +39,6 @@ #include "sci/graphics/view.h" #include "sci/graphics/screen.h" #include "sci/graphics/palette.h" -#include "sci/graphics/robot.h" namespace Sci { @@ -81,13 +80,4 @@ void GfxPaint32::kernelGraphDrawLine(Common::Point startPoint, Common::Point end _screen->drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, color, priority, control); } -void GfxPaint32::debugDrawRobot(GuiResourceId robotId) { - GfxRobot *test = new GfxRobot(g_sci->getResMan(), _screen, _palette); - test->init(robotId, 0, 0); - while (test->getCurFrame() + 1 < test->getFrameCount()) { - test->processNextFrame(); - } - delete test; -} - } // End of namespace Sci diff --git a/engines/sci/graphics/paint32.h b/engines/sci/graphics/paint32.h index a048d7f307..3fa9d11d9b 100644 --- a/engines/sci/graphics/paint32.h +++ b/engines/sci/graphics/paint32.h @@ -48,8 +48,6 @@ public: void kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle); void kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control); - void debugDrawRobot(GuiResourceId robotId); - private: ResourceManager *_resMan; SegManager *_segMan; diff --git a/engines/sci/module.mk b/engines/sci/module.mk index ad133e8a82..005fe21cfa 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -79,7 +79,7 @@ ifdef ENABLE_SCI32 MODULE_OBJS += \ graphics/frameout.o \ graphics/paint32.o \ - graphics/robot.o + video/robot_decoder.o endif # This module can be built as a plugin diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 978762968e..ce2f2de85d 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -66,8 +66,8 @@ #include "sci/graphics/transitions.h" #ifdef ENABLE_SCI32 -#include "sci/graphics/robot.h" #include "sci/graphics/frameout.h" +#include "sci/video/robot_decoder.h" #endif namespace Sci { @@ -151,7 +151,7 @@ SciEngine::~SciEngine() { DebugMan.clearAllDebugChannels(); #ifdef ENABLE_SCI32 - delete _gfxRobot; + delete _robotDecoder; delete _gfxFrameout; #endif delete _gfxMenu; @@ -582,7 +582,7 @@ void SciEngine::initGraphics() { _gfxText16 = 0; _gfxTransitions = 0; #ifdef ENABLE_SCI32 - _gfxRobot = 0; + _robotDecoder = 0; _gfxFrameout = 0; _gfxPaint32 = 0; #endif @@ -611,7 +611,7 @@ void SciEngine::initGraphics() { _gfxCompare = new GfxCompare(_gamestate->_segMan, _kernel, _gfxCache, _gfxScreen, _gfxCoordAdjuster); _gfxPaint32 = new GfxPaint32(_resMan, _gamestate->_segMan, _kernel, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette); _gfxPaint = _gfxPaint32; - _gfxRobot = new GfxRobot(_resMan, _gfxScreen, _gfxPalette); + _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); } else { #endif diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 86e54fec03..9404425af6 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -77,7 +77,7 @@ class GfxTransitions; #ifdef ENABLE_SCI32 class SciGui32; -class GfxRobot; +class RobotDecoder; class GfxFrameout; #endif @@ -313,7 +313,7 @@ public: GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager #ifdef ENABLE_SCI32 - GfxRobot *_gfxRobot; + RobotDecoder *_robotDecoder; GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx #endif diff --git a/engines/sci/graphics/robot.cpp b/engines/sci/video/robot_decoder.cpp index 464e32fad1..f547407076 100644 --- a/engines/sci/graphics/robot.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -23,25 +23,20 @@ * */ -// fopen() and friends so we can dump frames and stuff to disk, for debugging -// #define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/screen.h" -#include "sci/graphics/robot.h" -#include "sci/graphics/palette.h" -#include "sci/sound/audio.h" +#include "common/debug.h" +#include "common/endian.h" +#include "common/archive.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/util.h" #include "graphics/surface.h" +#include "sound/decoders/raw.h" -#include "sound/audiostream.h" -#include "sound/mixer.h" - -#include "common/archive.h" -#include "common/system.h" -#include "common/stream.h" -#include "common/substream.h" +#include "sci/resource.h" +#include "sci/util.h" +#include "sci/sound/audio.h" +#include "sci/video/robot_decoder.h" namespace Sci { @@ -49,6 +44,7 @@ namespace Sci { // - Positioning // - Proper handling of frame scaling - scaled frames look squashed // (probably because both dimensions should be scaled) +// - Transparency support // - Timing - the arbitrary 100ms delay between each frame is not quite right // - Proper handling of sound chunks in some cases, so that the frame size // table can be ignored (it's only used to determine the correct sound chunk @@ -73,34 +69,40 @@ namespace Sci { #ifdef ENABLE_SCI32 -GfxRobot::GfxRobot(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette) - : _resMan(resMan), _screen(screen), _palette(palette), _outputBuffer(0), - _outputBufferSize(0), _audioStream(0), _frameTotalSize(0), _robotFile(0) { - _x = _y = 0; +RobotDecoder::RobotDecoder(Audio::Mixer *mixer, bool isBigEndian) { + _surface = 0; + _fileStream = 0; + _audioStream = 0; + _dirtyPalette = false; + _pos = Common::Point(0, 0); + _mixer = mixer; + _isBigEndian = isBigEndian; } -GfxRobot::~GfxRobot() { - freeData(); +RobotDecoder::~RobotDecoder() { + close(); } -void GfxRobot::init(GuiResourceId resourceId, uint16 x, uint16 y) { - _x = x; - _y = y; - _curFrame = 0; - - Common::String fileName = Common::String::format("%d.rbt", resourceId); +bool RobotDecoder::load(GuiResourceId id) { + Common::String fileName = Common::String::format("%d.rbt", id); Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); if (!stream) { warning("Unable to open robot file %s", fileName.c_str()); - return; + return false; } - _robotFile = new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), - g_sci->getPlatform() == Common::kPlatformMacintosh, DisposeAfterUse::YES); + return load(stream); +} - readHeaderChunk(); +bool RobotDecoder::load(Common::SeekableReadStream *stream) { + close(); + + _fileStream = new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), _isBigEndian, DisposeAfterUse::YES); + _surface = new Graphics::Surface(); + readHeaderChunk(); + // There are several versions of robot files, ranging from 3 to 6. // v3: no known examples // v4: PQ:SWAT demo @@ -109,106 +111,90 @@ void GfxRobot::init(GuiResourceId resourceId, uint16 x, uint16 y) { if (_header.version < 4 || _header.version > 6) error("Unknown robot version: %d", _header.version); - _frameTotalSize = new uint32[_header.frameCount]; - if (_header.hasSound) { _audioStream = Audio::makeQueuingAudioStream(11025, false); - g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_audioHandle, _audioStream); + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_audioHandle, _audioStream); } readPaletteChunk(); readFrameSizesChunk(); - - debug("Robot %d, %d frames, sound: %s\n", resourceId, _header.frameCount, _header.hasSound ? "yes" : "no"); + return true; } -void GfxRobot::readHeaderChunk() { +void RobotDecoder::readHeaderChunk() { // Header (60 bytes) - _robotFile->skip(6); - _header.version = _robotFile->readUint16(); - _header.audioChunkSize = _robotFile->readUint16(); - _header.audioSilenceSize = _robotFile->readUint16(); - _robotFile->skip(2); - _header.frameCount = _robotFile->readUint16(); - _header.paletteDataSize = _robotFile->readUint16(); - _header.unkChunkDataSize = _robotFile->readUint16(); - _robotFile->skip(5); - _header.hasSound = _robotFile->readByte(); - _robotFile->skip(34); + _fileStream->skip(6); + _header.version = _fileStream->readUint16(); + _header.audioChunkSize = _fileStream->readUint16(); + _header.audioSilenceSize = _fileStream->readUint16(); + _fileStream->skip(2); + _header.frameCount = _fileStream->readUint16(); + _header.paletteDataSize = _fileStream->readUint16(); + _header.unkChunkDataSize = _fileStream->readUint16(); + _fileStream->skip(5); + _header.hasSound = _fileStream->readByte(); + _fileStream->skip(34); // Some videos (e.g. robot 1305 in Phantasmagoria and // robot 184 in Lighthouse) have an unknown chunk before // the palette chunk (probably used for sound preloading). // Skip it here. if (_header.unkChunkDataSize) - _robotFile->skip(_header.unkChunkDataSize); + _fileStream->skip(_header.unkChunkDataSize); } -void GfxRobot::readPaletteChunk() { - byte *paletteChunk = new byte[_header.paletteDataSize]; - _robotFile->read(paletteChunk, _header.paletteDataSize); - - int startIndex = paletteChunk[25]; - int colorCount = READ_SCI11ENDIAN_UINT16(paletteChunk + 29); - - if (colorCount > 256) - error("Invalid color count: %d", colorCount); +void RobotDecoder::readPaletteChunk() { + byte *paletteData = new byte[_header.paletteDataSize]; + _fileStream->read(paletteData, _header.paletteDataSize); - Palette resourcePal; - _palette->createFromData(paletteChunk, _header.paletteDataSize, &resourcePal); - delete[] paletteChunk; + // SCI1.1 palette + uint16 palColorStart = READ_SCI11ENDIAN_UINT16(paletteData + 25); + uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); - byte robotPal[256 * 4]; + int palOffset = 37; + memset(_palette, 0, 256 * 3); - for (int i = 0; i < 256; ++i) { - _savedPal[i * 4 + 0] = _palette->_sysPalette.colors[i].r; - _savedPal[i * 4 + 1] = _palette->_sysPalette.colors[i].g; - _savedPal[i * 4 + 2] = _palette->_sysPalette.colors[i].b; - _savedPal[i * 4 + 3] = 0; - } - - memcpy(robotPal, _savedPal, sizeof(_savedPal)); - - for (int i = 0; i < colorCount; ++i) { - int index = i + startIndex; - robotPal[index * 4 + 0] = resourcePal.colors[index].r; - robotPal[index * 4 + 1] = resourcePal.colors[index].g; - robotPal[index * 4 + 2] = resourcePal.colors[index].b; - robotPal[index * 4 + 3] = 0; + for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + _palette[colorNo * 3 + 0] = paletteData[palOffset++]; + _palette[colorNo * 3 + 1] = paletteData[palOffset++]; + _palette[colorNo * 3 + 2] = paletteData[palOffset++]; } - g_system->setPalette(robotPal, 0, 256); + _dirtyPalette = true; + delete[] paletteData; } -void GfxRobot::readFrameSizesChunk() { +void RobotDecoder::readFrameSizesChunk() { // The robot video file contains 2 tables, with one entry for each frame: // - A table containing the size of the image in each video frame // - A table containing the total size of each video frame. // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, // they contain 32-bit integers. + _frameTotalSize = new uint32[_header.frameCount]; + // TODO: The table reading code can probably be removed once the // audio chunk size is figured out (check the TODO inside processNextFrame()) #if 0 // We don't need any of the two tables to play the video, so we ignore // both of them. uint16 wordSize = _header.version == 6 ? 4 : 2; - _robotFile->skip(_header.frameCount * wordSize * 2); + _fileStream->skip(_header.frameCount * wordSize * 2); #else switch (_header.version) { case 4: case 5: // sizes are 16-bit integers // Skip table with frame image sizes, as we don't need it - _robotFile->skip(_header.frameCount * 2); + _fileStream->skip(_header.frameCount * 2); for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _robotFile->readUint16(); + _frameTotalSize[i] = _fileStream->readUint16(); break; case 6: // sizes are 32-bit integers // Skip table with frame image sizes, as we don't need it - _robotFile->skip(_header.frameCount * 4); + _fileStream->skip(_header.frameCount * 4); for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _robotFile->readUint32(); + _frameTotalSize[i] = _fileStream->readUint32(); break; default: error("Can't yet handle index table for robot version %d", _header.version); @@ -216,58 +202,49 @@ void GfxRobot::readFrameSizesChunk() { #endif // 2 more unknown tables - _robotFile->skip(1024 + 512); + _fileStream->skip(1024 + 512); // Pad to nearest 2 kilobytes - uint32 curPos = _robotFile->pos(); + uint32 curPos = _fileStream->pos(); if (curPos & 0x7ff) - _robotFile->seek((curPos & ~0x7ff) + 2048); + _fileStream->seek((curPos & ~0x7ff) + 2048); } -void GfxRobot::processNextFrame() { - // Make sure that we haven't reached the end of the video already - if (_curFrame == _header.frameCount) - return; - +const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Read frame image header (24 bytes) - _robotFile->skip(3); - byte frameScale = _robotFile->readByte(); - uint16 frameWidth = _robotFile->readUint16(); - uint16 frameHeight = _robotFile->readUint16(); - _robotFile->skip(8); // x, y, width and height of the frame - uint16 compressedSize = _robotFile->readUint16(); - uint16 frameFragments = _robotFile->readUint16(); - _robotFile->skip(4); // unknown - - uint32 decompressedSize = frameWidth * (frameHeight * frameScale / 100); - - // Reallocate the output buffer, if its size has increased - if (decompressedSize > _outputBufferSize) { - delete[] _outputBuffer; - _outputBuffer = new byte[decompressedSize]; - } - - _outputBufferSize = decompressedSize; + _fileStream->skip(3); + byte frameScale = _fileStream->readByte(); + uint16 frameWidth = _fileStream->readUint16(); + uint16 frameHeight = _fileStream->readUint16(); + _fileStream->skip(8); // x, y, width and height of the frame + uint16 compressedSize = _fileStream->readUint16(); + uint16 frameFragments = _fileStream->readUint16(); + _fileStream->skip(4); // unknown + + uint32 decompressedSize = frameWidth * frameHeight * frameScale / 100; + _surface->free(); + _surface->create(frameWidth, frameHeight, 1); + _surface->w = frameWidth * frameScale / 100; DecompressorLZS lzs; if (_header.version == 4) { // v4 has just the one fragment, it seems, and ignores the fragment count - Common::SeekableSubReadStream fragmentStream(_robotFile, _robotFile->pos(), _robotFile->pos() + compressedSize); - lzs.unpack(&fragmentStream, _outputBuffer, compressedSize, decompressedSize); + Common::SeekableSubReadStream fragmentStream(_fileStream, _fileStream->pos(), _fileStream->pos() + compressedSize); + lzs.unpack(&fragmentStream, (byte *)_surface->pixels, compressedSize, decompressedSize); } else { - byte *outPtr = _outputBuffer; + byte *outPtr = (byte *)_surface->pixels; for (uint16 i = 0; i < frameFragments; ++i) { - uint32 compressedFragmentSize = _robotFile->readUint32(); - uint32 decompressedFragmentSize = _robotFile->readUint32(); - uint16 compressionType = _robotFile->readUint16(); + uint32 compressedFragmentSize = _fileStream->readUint32(); + uint32 decompressedFragmentSize = _fileStream->readUint32(); + uint16 compressionType = _fileStream->readUint16(); if (compressionType == 0) { - Common::SeekableSubReadStream fragmentStream(_robotFile, _robotFile->pos(), _robotFile->pos() + compressedFragmentSize); + Common::SeekableSubReadStream fragmentStream(_fileStream, _fileStream->pos(), _fileStream->pos() + compressedFragmentSize); lzs.unpack(&fragmentStream, outPtr, compressedFragmentSize, decompressedFragmentSize); } else if (compressionType == 2) { // untested - _robotFile->read(outPtr, compressedFragmentSize); + _fileStream->read(outPtr, compressedFragmentSize); } else { error("Unknown frame compression found: %d", compressionType); } @@ -276,52 +253,55 @@ void GfxRobot::processNextFrame() { } } - uint32 audioChunkSize = _frameTotalSize[_curFrame] - (24 + compressedSize); + // +1 because we start with frame number -1 + uint32 audioChunkSize = _frameTotalSize[_curFrame + 1] - (24 + compressedSize); // TODO: The audio chunk size below is usually correct, but there are some // exceptions (e.g. robot 4902 in Phantasmagoria, towards its end) #if 0 // Read frame audio header (14 bytes) - _robotFile->skip(2); // buffer position - _robotFile->skip(2); // unknown (usually 1) - _robotFile->skip(2); /*uint16 audioChunkSize = _robotFile->readUint16() + 8;*/ - _robotFile->skip(2); + _fileStream->skip(2); // buffer position + _fileStream->skip(2); // unknown (usually 1) + _fileStream->skip(2); /*uint16 audioChunkSize = _fileStream->readUint16() + 8;*/ + _fileStream->skip(2); #endif // Queue the next audio frame // FIXME: For some reason, there are audio hiccups/gaps if (_header.hasSound) { - _robotFile->skip(8); // header - _audioStream->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_robotFile, audioChunkSize - 8), + _fileStream->skip(8); // header + _audioStream->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize - 8), (audioChunkSize - 8) * 2, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); } else { - _robotFile->skip(audioChunkSize); + _fileStream->skip(audioChunkSize); } - // Show frame - g_system->copyRectToScreen(_outputBuffer, frameWidth, _x, _y, frameWidth, frameHeight * frameScale / 100); - g_system->updateScreen(); - g_system->delayMillis(100); // TODO: This isn't quite right + if (_curFrame == -1) + _startTime = g_system->getMillis(); _curFrame++; - if (_curFrame == _header.frameCount) { - // End of robot video, restore palette - g_system->setPalette(_savedPal, 0, 256); - freeData(); - } + return _surface; } -void GfxRobot::freeData() { +void RobotDecoder::close() { + if (!_fileStream) + return; + + delete _fileStream; + _fileStream = 0; + + _surface->free(); + delete _surface; + _surface = 0; + if (_header.hasSound) { - g_system->getMixer()->stopHandle(_audioHandle); + _mixer->stopHandle(_audioHandle); //delete _audioStream; _audioStream = 0; } - delete[] _frameTotalSize; _frameTotalSize = 0; - delete[] _outputBuffer; _outputBuffer = 0; - _outputBufferSize = 0; - delete _robotFile; _robotFile = 0; + + reset(); } #endif diff --git a/engines/sci/graphics/robot.h b/engines/sci/video/robot_decoder.h index ffb4d0e6e7..aa68c50f5a 100644 --- a/engines/sci/graphics/robot.h +++ b/engines/sci/video/robot_decoder.h @@ -23,16 +23,16 @@ * */ -#ifndef SCI_GRAPHICS_ROBOT_H -#define SCI_GRAPHICS_ROBOT_H +#ifndef SCI_VIDEO_ROBOT_DECODER_H +#define SCI_VIDEO_ROBOT_DECODER_H +#include "common/rational.h" +#include "common/rect.h" +#include "common/stream.h" +#include "common/substream.h" #include "sound/audiostream.h" #include "sound/mixer.h" -#include "sound/decoders/raw.h" - -namespace Common { - class SeekableSubReadStreamEndian; -} +#include "video/video_decoder.h" namespace Sci { @@ -52,17 +52,29 @@ struct RobotHeader { // 34 bytes, unknown }; -class GfxRobot { +class RobotDecoder : public Video::FixedRateVideoDecoder { public: - GfxRobot(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette); - ~GfxRobot(); - - void init(GuiResourceId resourceId, uint16 x, uint16 y); - void processNextFrame(); - uint16 getCurFrame() { return _curFrame; } - uint16 getFrameCount() { return _header.frameCount; } - bool isPlaying() { return _robotFile != 0; } - void playAudio(); + RobotDecoder(Audio::Mixer *mixer, bool isBigEndian); + virtual ~RobotDecoder(); + + bool load(Common::SeekableReadStream *stream); + bool load(GuiResourceId id); + void close(); + + bool isVideoLoaded() const { return _fileStream != 0; } + uint16 getWidth() const { assert(_surface); return _surface->w; } + uint16 getHeight() const { assert(_surface); return _surface->h; } + uint16 getPitch() const { assert(_surface); return _surface->pitch; } + uint32 getFrameCount() const { return _header.frameCount; } + const Graphics::Surface *decodeNextFrame(); + Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } + const byte *getPalette() { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + void setPos(uint16 x, uint16 y) { _pos = Common::Point(x, y); } + Common::Point getPos() const { return _pos; } + +protected: + Common::Rational getFrameRate() const { return Common::Rational(60, 10); } private: void readHeaderChunk(); @@ -71,25 +83,19 @@ private: void freeData(); - ResourceManager *_resMan; - GfxScreen *_screen; - GfxPalette *_palette; + RobotHeader _header; + Common::Point _pos; + bool _isBigEndian; - byte _savedPal[256 * 4]; + Common::SeekableSubReadStreamEndian *_fileStream; - Common::SeekableSubReadStreamEndian *_robotFile; + uint32 *_frameTotalSize; + byte _palette[256 * 3]; + bool _dirtyPalette; + Graphics::Surface *_surface; Audio::QueuingAudioStream *_audioStream; Audio::SoundHandle _audioHandle; - - RobotHeader _header; - - uint16 _x; - uint16 _y; - uint16 _curFrame; - uint32 *_frameTotalSize; - - byte *_outputBuffer; - uint32 _outputBufferSize; + Audio::Mixer *_mixer; }; #endif |