aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippos Karapetis2011-02-08 19:50:45 +0000
committerFilippos Karapetis2011-02-08 19:50:45 +0000
commit72a9706950675cc3fd04e39d0f842193d66a5f9e (patch)
tree39ad5b83dfc81c0836f1dc3473f73f4cd19990db
parent656afd6daa2b468fdf2731f082d1fd5897e43110 (diff)
downloadscummvm-rg350-72a9706950675cc3fd04e39d0f842193d66a5f9e.tar.gz
scummvm-rg350-72a9706950675cc3fd04e39d0f842193d66a5f9e.tar.bz2
scummvm-rg350-72a9706950675cc3fd04e39d0f842193d66a5f9e.zip
SCI: Some work on robot videos
- The size of the videos is now calculated when they are loaded (this helps remove some nasty hacks and constant memory reallocations and simplifies the code) - Some work on frame placement (e.g. in robot 1305, Phantasmagoria) svn-id: r55830
-rw-r--r--engines/sci/engine/kvideo.cpp25
-rw-r--r--engines/sci/video/robot_decoder.cpp64
-rw-r--r--engines/sci/video/robot_decoder.h8
3 files changed, 68 insertions, 29 deletions
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 1ed3a713b0..e905764d03 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -51,15 +51,12 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
uint16 screenWidth = g_system->getWidth();
uint16 screenHeight = g_system->getHeight();
bool isVMD = videoState.fileName.hasSuffix(".vmd");
- 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];
- }
+
+ 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;
@@ -76,13 +73,8 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
y = (screenHeight - height) / 2;
}
} else {
- if (!isRobot) {
x = (screenWidth - width) / 2;
y = (screenHeight - height) / 2;
- } else {
- x = 0;
- y = 0;
- }
}
bool skipVideo = false;
@@ -99,10 +91,7 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
g_sci->_gfxScreen->scale2x((byte *)frame->pixels, scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel);
g_system->copyRectToScreen(scaleBuffer, 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);
+ g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, width, height);
}
if (videoDecoder->hasDirtyPalette())
diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp
index d243816ff7..8dd60cd9a6 100644
--- a/engines/sci/video/robot_decoder.cpp
+++ b/engines/sci/video/robot_decoder.cpp
@@ -76,6 +76,8 @@ enum robotPalTypes {
RobotDecoder::RobotDecoder(Audio::Mixer *mixer, bool isBigEndian) {
_surface = 0;
+ _width = 0;
+ _height = 0;
_fileStream = 0;
_audioStream = 0;
_dirtyPalette = false;
@@ -123,6 +125,9 @@ bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) {
readPaletteChunk(_header.paletteDataSize);
readFrameSizesChunk();
+ calculateVideoDimensions();
+ _surface->create(_width, _height, 1);
+
return true;
}
@@ -218,31 +223,56 @@ void RobotDecoder::readFrameSizesChunk() {
_fileStream->seek((curPos & ~0x7ff) + 2048);
}
+void RobotDecoder::calculateVideoDimensions() {
+ // This is an O(n) operation, as each frame has a different size.
+ // We need to know the actual frame size to have a constant video size.
+ uint32 pos = _fileStream->pos();
+
+ for (uint32 curFrame = 0; curFrame < _header.frameCount; curFrame++) {
+ _fileStream->skip(4);
+ uint16 frameWidth = _fileStream->readUint16();
+ uint16 frameHeight = _fileStream->readUint16();
+ if (frameWidth > _width)
+ _width = frameWidth;
+ if (frameHeight > _height)
+ _height = frameHeight;
+ _fileStream->skip(_frameTotalSize[curFrame] - 8);
+ }
+
+ _fileStream->seek(pos);
+}
+
const Graphics::Surface *RobotDecoder::decodeNextFrame() {
// Read frame image header (24 bytes)
_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
+ _fileStream->skip(4); // unknown, almost always 0
+ uint16 frameX = _fileStream->readUint16();
+ uint16 frameY = _fileStream->readUint16();
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;
+ // FIXME: A frame's height + position can go off limits... why? With the
+ // following, we cut the contents to fit the frame
+ uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, _height - frameY);
+ // FIXME: Same goes for the frame's width + position. In this case, we
+ // modify the position to fit the contents on screen.
+ if (frameWidth + frameX > _width)
+ frameX = _width - frameWidth;
+ assert (frameWidth + frameX <= _width && scaledHeight + frameY <= _height);
DecompressorLZS lzs;
+ byte *decompressedFrame = new byte[decompressedSize];
+ byte *outPtr = decompressedFrame;
if (_header.version == 4) {
// v4 has just the one fragment, it seems, and ignores the fragment count
Common::SeekableSubReadStream fragmentStream(_fileStream, _fileStream->pos(), _fileStream->pos() + compressedSize);
- lzs.unpack(&fragmentStream, (byte *)_surface->pixels, compressedSize, decompressedSize);
+ lzs.unpack(&fragmentStream, outPtr, compressedSize, decompressedSize);
} else {
- byte *outPtr = (byte *)_surface->pixels;
-
for (uint16 i = 0; i < frameFragments; ++i) {
uint32 compressedFragmentSize = _fileStream->readUint32();
uint32 decompressedFragmentSize = _fileStream->readUint32();
@@ -261,6 +291,24 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() {
}
}
+ // Copy over the decompressed frame
+ byte *inFrame = decompressedFrame;
+ byte *outFrame = (byte *)_surface->pixels;
+
+ // Black out the surface
+ memset(outFrame, 0, _width * _height);
+
+ // Move to the correct y coordinate
+ outFrame += _width * frameY;
+
+ for (uint16 y = 0; y < scaledHeight; y++) {
+ memcpy(outFrame + frameX, inFrame, frameWidth);
+ inFrame += frameWidth;
+ outFrame += _width;
+ }
+
+ delete[] decompressedFrame;
+
// +1 because we start with frame number -1
uint32 audioChunkSize = _frameTotalSize[_curFrame + 1] - (24 + compressedSize);
diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h
index eb0a150c9d..b8ca0ee857 100644
--- a/engines/sci/video/robot_decoder.h
+++ b/engines/sci/video/robot_decoder.h
@@ -62,9 +62,8 @@ public:
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; }
+ uint16 getWidth() const { return _width; }
+ uint16 getHeight() const { return _height; }
uint32 getFrameCount() const { return _header.frameCount; }
const Graphics::Surface *decodeNextFrame();
Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
@@ -80,6 +79,7 @@ private:
void readHeaderChunk();
void readPaletteChunk(uint16 chunkSize);
void readFrameSizesChunk();
+ void calculateVideoDimensions();
void freeData();
@@ -89,6 +89,8 @@ private:
Common::SeekableSubReadStreamEndian *_fileStream;
+ uint16 _width;
+ uint16 _height;
uint32 *_frameTotalSize;
byte _palette[256 * 3];
bool _dirtyPalette;