diff options
| author | Filippos Karapetis | 2011-02-08 19:50:45 +0000 | 
|---|---|---|
| committer | Filippos Karapetis | 2011-02-08 19:50:45 +0000 | 
| commit | 72a9706950675cc3fd04e39d0f842193d66a5f9e (patch) | |
| tree | 39ad5b83dfc81c0836f1dc3473f73f4cd19990db | |
| parent | 656afd6daa2b468fdf2731f082d1fd5897e43110 (diff) | |
| download | scummvm-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.cpp | 25 | ||||
| -rw-r--r-- | engines/sci/video/robot_decoder.cpp | 64 | ||||
| -rw-r--r-- | engines/sci/video/robot_decoder.h | 8 | 
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; | 
