diff options
author | Filippos Karapetis | 2011-02-03 14:37:50 +0000 |
---|---|---|
committer | Filippos Karapetis | 2011-02-03 14:37:50 +0000 |
commit | 74caf6cd714cdb031db78f2fd44cff0378d3f08c (patch) | |
tree | 9bd03be7dfb5554bb232a75e3fb55956b753aab1 /engines/sci | |
parent | 496ca9a669dc81f64fe6199ae12628044d37035f (diff) | |
download | scummvm-rg350-74caf6cd714cdb031db78f2fd44cff0378d3f08c.tar.gz scummvm-rg350-74caf6cd714cdb031db78f2fd44cff0378d3f08c.tar.bz2 scummvm-rg350-74caf6cd714cdb031db78f2fd44cff0378d3f08c.zip |
SCI21: Some robot related changes
- Don't reallocate the frame buffer on each update if its dimensions haven't changed
- Don't attempt to display the currently unsupported v4 robot files (used in PQ:SWAT)
- Signed/unsigned fixes
- Disabled the unused getFrameRect() function
- Some cleanup and reordering
svn-id: r55752
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/engine/kgraphics.cpp | 11 | ||||
-rw-r--r-- | engines/sci/graphics/robot.cpp | 173 | ||||
-rw-r--r-- | engines/sci/graphics/robot.h | 15 |
3 files changed, 123 insertions, 76 deletions
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 0065c7ae74..86068abe03 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -1414,14 +1414,17 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { case 1: // LSL6 hires (startup) // TODO return NULL_REG; // an integer is expected - case 4: { // start - int id = argv[1].toUint16(); - warning("kRobot(start), id %d", id); + case 4: { // start - we don't really have a use for this one + //int id = argv[1].toUint16(); + //warning("kRobot(start), id %d", id); } break; + case 7: // unknown, called e.g. by Phantasmagoria + warning("kRobot(%d)", subop); + break; case 8: // sync robot->drawNextFrame(); - // Sync + // Signal the engine scripts that the video is done if (robot->getCurFrame() == robot->getFrameCount()) writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); break; diff --git a/engines/sci/graphics/robot.cpp b/engines/sci/graphics/robot.cpp index a058761cf8..ea25072f74 100644 --- a/engines/sci/graphics/robot.cpp +++ b/engines/sci/graphics/robot.cpp @@ -62,13 +62,17 @@ namespace Sci { #ifdef ENABLE_SCI32 GfxRobot::GfxRobot(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette) : _resMan(resMan), _screen(screen), _palette(palette), _resourceData(0), - _imageStart(0), _audioStart(0), _audioLen(0) { + _imageStart(0), _audioStart(0), _audioLen(0), _outputBuffer(0), _outputBufferSize(0) { _resourceId = -1; _x = _y = 0; } GfxRobot::~GfxRobot() { - freeData(); + delete[] _resourceData; + delete[] _imageStart; + delete[] _audioStart; + delete[] _audioLen; + delete[] _outputBuffer; } void GfxRobot::init(GuiResourceId resourceId, uint16 x, uint16 y) { @@ -94,6 +98,13 @@ void GfxRobot::init(GuiResourceId resourceId, uint16 x, uint16 y) { return; } + // There are several versions of robot files, ranging from 3 to 6. Version + // 5 is the version of the majority of the robot files. PQ:SWAT is the only + // game that uses robots of a different version (version 4), but there are + // no known examples of other robot versions. + _version = _resourceData[6]; + + // Currently, we only support robot version 5. Robot version _frameCount = READ_LE_UINT16(_resourceData + 14); // There is another value in the header, at offset 0x12, which @@ -114,6 +125,20 @@ void GfxRobot::init(GuiResourceId resourceId, uint16 x, uint16 y) { if (_hasSound && READ_LE_UINT16(_resourceData + 10) == 0) _palOffset += READ_LE_UINT32(_resourceData + 60) + 14; + switch (_version) { + case 4: + // TODO: Add support for this version (used in PQ:SWAT) + warning("TODO: add support for v4 robot videos"); + _curFrame = _frameCount; // jump to the last frame + return; + case 5: + // Supported, the most well-known and used version + break; + default: + // Unsupported, error out so that we find out where this is used + error("Unknown robot version: %d", _version); + } + getFrameOffsets(); assert(_imageStart[_frameCount] == fileSize); @@ -122,6 +147,40 @@ void GfxRobot::init(GuiResourceId resourceId, uint16 x, uint16 y) { debug("Robot %d, %d frames, sound: %s\n", resourceId, _frameCount, _hasSound ? "yes" : "no"); } +void GfxRobot::getFrameOffsets() { + int *audioEnd = new int[_frameCount]; + int *videoEnd = new int[_frameCount]; + + for (int i = 0; i < _frameCount; ++i) { + videoEnd[i] = READ_LE_UINT16(_resourceData + _palOffset + 1200 + i * 2); + audioEnd[i] = READ_LE_UINT16(_resourceData + _palOffset + 1200 + _frameCount * 2 + i * 2); + } + + uint32 frameDataOffset = _palOffset + 0x4b0 + 0x400 + 0x200 + _frameCount * 4; + + // Pad to nearest 2 kilobytes + if (frameDataOffset & 0x7ff) + frameDataOffset = (frameDataOffset & ~0x7ff) + 0x800; + + _imageStart = new uint32[_frameCount + 1]; + _audioStart = new uint32[_frameCount]; + _audioLen = new uint32[_frameCount]; + + _imageStart[0] = frameDataOffset; + + // Plus one so we can assert on this in the calling routine + // The last one should point to end-of-file, unless I'm misunderstanding something + for (int i = 1; i < _frameCount + 1; ++i) + _imageStart[i] = _imageStart[i - 1] + audioEnd[i - 1]; + for (int i = 0; i < _frameCount; ++i) + _audioStart[i] = _imageStart[i] + videoEnd[i]; + for (int i = 0; i < _frameCount; ++i) + _audioLen[i] = _imageStart[i + 1] - _audioStart[i]; + + delete[] audioEnd; + delete[] videoEnd; +} + void GfxRobot::setPalette() { byte *paletteData = _resourceData + _palOffset; uint16 paletteSize = READ_LE_UINT16(_resourceData + 16); @@ -157,101 +216,79 @@ void GfxRobot::setPalette() { } void GfxRobot::drawNextFrame() { - int width, height; + uint16 width, height; + + // Make sure that we haven't reached the end of the video already + if (_curFrame == _frameCount) + return; - byte *pixels = assembleVideoFrame(_curFrame); + assembleVideoFrame(_curFrame); getFrameDimensions(_curFrame, width, height); - g_system->copyRectToScreen(pixels, width, _x, _y, width, height * getFrameScale(_curFrame) / 100); + + g_system->copyRectToScreen(_outputBuffer, width, _x, _y, width, height * getFrameScale(_curFrame) / 100); g_system->updateScreen(); g_system->delayMillis(100); - delete[] pixels; _curFrame++; if (_curFrame == _frameCount) { // End of robot video, restore palette g_system->setPalette(_savedPal, 0, 256); - freeData(); _resourceId = -1; + delete[] _outputBuffer; + _outputBuffer = 0; } } -void GfxRobot::getFrameOffsets() { - int *audioEnd = new int[_frameCount]; - int *videoEnd = new int[_frameCount]; - - for (int i = 0; i < _frameCount; ++i) { - videoEnd[i] = READ_LE_UINT16(_resourceData + _palOffset + 1200 + i * 2); - audioEnd[i] = READ_LE_UINT16(_resourceData + _palOffset + 1200 + _frameCount * 2 + i * 2); - } - - int frameDataOffset = _palOffset + 0x4b0 + 0x400 + 0x200 + _frameCount * 4; - - // Pad to nearest 2 kilobytes - if (frameDataOffset & 0x7ff) - frameDataOffset = (frameDataOffset & ~0x7ff)+0x800; - - _imageStart = new uint32[_frameCount + 1]; - _audioStart = new uint32[_frameCount]; - _audioLen = new uint32[_frameCount]; - - _imageStart[0] = frameDataOffset; - - // Plus one so we can assert on this in the calling routine - // The last one should point to end-of-file, unless I'm misunderstanding something - for (int i = 1; i < _frameCount + 1; ++i) - _imageStart[i] = _imageStart[i - 1] + audioEnd[i - 1]; - for (int i = 0; i < _frameCount; ++i) - _audioStart[i] = _imageStart[i] + videoEnd[i]; - for (int i = 0; i < _frameCount; ++i) - _audioLen[i] = _imageStart[i + 1] - _audioStart[i]; - - delete[] audioEnd; - delete[] videoEnd; -} - -byte *GfxRobot::assembleVideoFrame(int frame) { +void GfxRobot::assembleVideoFrame(uint16 frame) { byte *videoData = _resourceData + _imageStart[frame]; - int frameWidth = READ_LE_UINT16(videoData + 4); - int frameHeight = READ_LE_UINT16(videoData + 6); - int frameFragments = READ_LE_UINT16(videoData + 18); + uint16 frameWidth = READ_LE_UINT16(videoData + 4); + uint16 frameHeight = READ_LE_UINT16(videoData + 6); + uint16 frameFragments = READ_LE_UINT16(videoData + 18); - int decompressedSize = 0; + uint32 decompressedSize = 0; DecompressorLZS lzs; videoData = _resourceData + _imageStart[frame] + 24; for (int i = 0; i < frameFragments; ++i) { - int fragmentCompressed = READ_LE_UINT32(videoData); - int fragmentUncompressed = READ_LE_UINT32(videoData + 4); + uint32 fragmentCompressed = READ_LE_UINT32(videoData); + uint32 fragmentUncompressed = READ_LE_UINT32(videoData + 4); decompressedSize += fragmentUncompressed; videoData += 10 + fragmentCompressed; } - assert(decompressedSize == (frameWidth * frameHeight) * getFrameScale(frame) / 100); + assert(decompressedSize == (uint32)(frameWidth * frameHeight) * getFrameScale(frame) / 100); + + // Reallocate the output buffer, if its size has changed + if (decompressedSize != _outputBufferSize) { + delete[] _outputBuffer; + _outputBuffer = new byte[decompressedSize]; + } - byte *output = new byte[decompressedSize]; - int assemblePtr = 0; + _outputBufferSize = decompressedSize; + + uint32 assemblePtr = 0; videoData = _resourceData + _imageStart[frame] + 24; for (int i = 0; i < frameFragments; ++i) { - int fragmentCompressed = READ_LE_UINT32(videoData); - int fragmentUncompressed = READ_LE_UINT32(videoData + 4); + uint32 fragmentCompressed = READ_LE_UINT32(videoData); + uint32 fragmentUncompressed = READ_LE_UINT32(videoData + 4); uint16 compressionType = READ_LE_UINT16(videoData + 8); switch (compressionType) { case 0: { Common::MemoryReadStream compressedFrame(videoData + 10, fragmentCompressed, DisposeAfterUse::NO); - lzs.unpack(&compressedFrame, output + assemblePtr, fragmentCompressed, fragmentUncompressed); + lzs.unpack(&compressedFrame, _outputBuffer + assemblePtr, fragmentCompressed, fragmentUncompressed); assemblePtr += fragmentUncompressed; break; } case 2: // Untested - memcpy(output + assemblePtr, videoData + 10, fragmentCompressed); + memcpy(_outputBuffer + assemblePtr, videoData + 10, fragmentCompressed); assemblePtr += fragmentUncompressed; break; } @@ -262,32 +299,32 @@ byte *GfxRobot::assembleVideoFrame(int frame) { assert(assemblePtr == decompressedSize); // FILE *f = fopen("/tmp/flap", "w"); - // fwrite(output, 1, decompressedSize, f); + // fwrite(_outputBuffer, 1, decompressedSize, f); // fclose(f); // exit(1); - - return output; } -void GfxRobot::getFrameDimensions(int frame, int &width, int &height) { +void GfxRobot::getFrameDimensions(uint16 frame, uint16 &width, uint16 &height) { byte *videoData = _resourceData + _imageStart[frame]; width = READ_LE_UINT16(videoData + 4); height = READ_LE_UINT16(videoData + 6); } -void GfxRobot::getFrameRect(int frame, Common::Rect &rect) { +#if 0 +Common::Rect GfxRobot::getFrameRect(uint16 frame) { byte *videoData = _resourceData + _imageStart[frame]; - int x = READ_LE_UINT16(videoData + 8); - int y = READ_LE_UINT16(videoData + 10); - int w = READ_LE_UINT16(videoData + 12); - int h = READ_LE_UINT16(videoData + 14); + uint16 x = READ_LE_UINT16(videoData + 8); + uint16 y = READ_LE_UINT16(videoData + 10); + uint16 w = READ_LE_UINT16(videoData + 12); + uint16 h = READ_LE_UINT16(videoData + 14); - rect = Common::Rect(x, y, x + w, y + h); + return Common::Rect(x, y, x + w, y + h); } +#endif -int GfxRobot::getFrameScale(int frame) { +byte GfxRobot::getFrameScale(uint16 frame) { byte *videoData = _resourceData + _imageStart[frame]; return videoData[3]; } @@ -300,13 +337,13 @@ void GfxRobot::playAudio() { } } -void GfxRobot::freeData() -{ +void GfxRobot::freeData() { delete[] _resourceData; _resourceData = 0; delete[] _imageStart; _imageStart = 0; delete[] _audioStart; _audioStart = 0; delete[] _audioLen; _audioLen = 0; } + #endif } // End of namespace Sci diff --git a/engines/sci/graphics/robot.h b/engines/sci/graphics/robot.h index e5e1fa991d..f1b9324b6a 100644 --- a/engines/sci/graphics/robot.h +++ b/engines/sci/graphics/robot.h @@ -46,10 +46,13 @@ public: private: void initData(GuiResourceId resourceId); void getFrameOffsets(); - byte *assembleVideoFrame(int frame); - void getFrameDimensions(int frame, int &width, int &height); - void getFrameRect(int frame, Common::Rect &rect); // Not sure what to use this for yet - int getFrameScale(int frame); // Scale factor (multiplied by 100). More like custom height, but why use a percentage for it? + void assembleVideoFrame(uint16 frame); + void getFrameDimensions(uint16 frame, uint16 &width, uint16 &height); +#if 0 + // Unused + Common::Rect getFrameRect(uint16 frame); +#endif + byte getFrameScale(uint16 frame); // Scale factor (multiplied by 100). More like custom height, but why use a percentage for it? void setPalette(); void freeData(); @@ -61,6 +64,7 @@ private: byte *_resourceData; byte _savedPal[256 * 4]; + byte _version; // robot version uint16 _x; uint16 _y; //uint16 _width; @@ -74,6 +78,9 @@ private: uint32 *_audioStart; uint32 *_audioLen; uint16 _curFrame; + + byte *_outputBuffer; + uint32 _outputBufferSize; }; #endif |