aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorFilippos Karapetis2011-02-03 14:37:50 +0000
committerFilippos Karapetis2011-02-03 14:37:50 +0000
commit74caf6cd714cdb031db78f2fd44cff0378d3f08c (patch)
tree9bd03be7dfb5554bb232a75e3fb55956b753aab1 /engines
parent496ca9a669dc81f64fe6199ae12628044d37035f (diff)
downloadscummvm-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')
-rw-r--r--engines/sci/engine/kgraphics.cpp11
-rw-r--r--engines/sci/graphics/robot.cpp173
-rw-r--r--engines/sci/graphics/robot.h15
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