VOYEUR: Animation improvements to better handle Voyeur RL2 videos

This commit is contained in:
Paul Gilbert 2014-01-01 07:00:36 +11:00
parent 2d71a0594d
commit 577b7cefa0
3 changed files with 63 additions and 61 deletions

View File

@ -164,7 +164,7 @@ RL2Decoder::RL2VideoTrack::RL2VideoTrack(const RL2FileHeader &header, RL2AudioTr
_surface = new Graphics::Surface();
_surface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
_hasBackFrame = header._backSize != 0 && !header._isRLV3;
_hasBackFrame = header._backSize != 0;
_backSurface = NULL;
if (_hasBackFrame)
@ -218,10 +218,11 @@ Graphics::PixelFormat RL2Decoder::RL2VideoTrack::getPixelFormat() const {
const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() {
if (_curFrame == 0 && _hasBackFrame) {
// Read in the background frame
// Read in the initial background frame
_fileStream->seek(0x324);
rl2DecodeFrameWithoutBackground(0);
rl2DecodeFrameWithoutTransparency(0);
initBackSurface();
Common::copy((byte *)_surface->getPixels(), (byte *)_surface->getPixels() + (320 * 200),
(byte *)_backSurface->getPixels());
_dirtyRects.push_back(Common::Rect(0, 0, _surface->w, _surface->h));
@ -233,15 +234,12 @@ const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() {
// If there's any sound data, pass it to the audio track
_fileStream->seek(_header._frameSoundSizes[_curFrame], SEEK_CUR);
// Decode the graphic data
// Decode the graphic data using the appropriate method depending on whether the animation
// has a background or just raw frames without any background transparency
if (_hasBackFrame) {
if (_curFrame > 0)
Common::copy((byte *)_backSurface->getPixels(), (byte *)_backSurface->getPixels() + (320 * 200),
(byte *)_surface->getPixels());
rl2DecodeFrameWithBackground();
rl2DecodeFrameWithTransparency(_videoBase);
} else {
rl2DecodeFrameWithoutBackground();
rl2DecodeFrameWithoutTransparency(_videoBase);
}
_curFrame++;
@ -269,71 +267,71 @@ void RL2Decoder::RL2VideoTrack::copyFrame(uint8 *data) {
_dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight()));
}
void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithoutBackground(int screenOffset) {
void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithoutTransparency(int screenOffset) {
if (screenOffset == -1)
screenOffset = _videoBase;
const byte *srcP = !_backSurface ? NULL : (const byte *)_backSurface->getPixels();
byte *destP = (byte *)_surface->getPixels();
int frameSize = _surface->w * _surface->h - screenOffset;
// If a background was manually set, copy over the initial part remaining unchanged
if (srcP && screenOffset > 0) {
Common::copy(srcP, srcP + screenOffset, destP);
srcP += screenOffset;
}
destP += screenOffset;
byte *destP = (byte *)_surface->getPixels();
// Main frame decode loop
while (frameSize > 0) {
byte nextByte = _fileStream->readByte();
byte nextByte;
for (;;) {
nextByte = _fileStream->readByte();
if (nextByte < 0x80) {
// Simple byte to copy to output
assert(frameSize > 0);
*destP++ = nextByte;
--frameSize;
if (srcP)
++srcP;
} else if (nextByte == 0x80) {
int runLength = _fileStream->readByte();
if (runLength == 0)
return;
runLength = MIN(runLength, frameSize);
if (srcP) {
Common::copy(srcP, srcP + runLength, destP);
srcP += runLength;
} else {
Common::fill(destP, destP + runLength, 0);
}
destP += runLength;
frameSize -= runLength;
} else {
int runLength = _fileStream->readByte();
runLength = MIN(runLength, frameSize);
} else if (nextByte > 0x80) {
// Lower 7 bits a run length for the following byte
byte runLength = _fileStream->readByte();
assert(frameSize >= runLength);
Common::fill(destP, destP + runLength, nextByte & 0x7f);
destP += runLength;
frameSize -= runLength;
if (srcP)
srcP += runLength;
} else {
// Follow byte run length for zeroes. If zero, indicates end of image
byte runLength = _fileStream->readByte();
if (runLength == 0)
break;
assert(frameSize >= runLength);
Common::fill(destP, destP + runLength, 0);
destP += runLength;
frameSize -= runLength;
}
}
// If there's any remaining screen area, zero it out
byte *endP = (byte *)_surface->getPixels() + _surface->w * _surface->h;
if (destP != endP)
Common::fill(destP, endP, 0);
}
void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithBackground() {
int screenOffset = _videoBase;
int frameSize = _surface->w * _surface->h - _videoBase;
byte *src = (byte *)_backSurface->getPixels();
byte *dest = (byte *)_surface->getPixels();
void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithTransparency(int screenOffset) {
int frameSize = _surface->w * _surface->h;
byte *refP = (byte *)_backSurface->getPixels();
byte *destP = (byte *)_surface->getPixels();
while (frameSize > 0) {
// If there's a screen offset, copy unchanged initial pixels from reference surface
if (screenOffset > 0)
Common::copy(refP, refP + screenOffset, destP);
// Main decode loop
for (;;) {
byte nextByte = _fileStream->readByte();
if (nextByte == 0) {
dest[screenOffset] = src[screenOffset];
// Move one single byte from reference surface
assert(frameSize > 0);
destP[screenOffset] = refP[screenOffset];
++screenOffset;
--frameSize;
} else if (nextByte < 0x80) {
dest[screenOffset] = nextByte | 0x80;
// Raw byte to copy to output
assert(frameSize > 0);
destP[screenOffset] = nextByte;
++screenOffset;
--frameSize;
} else if (nextByte == 0x80) {
@ -341,19 +339,25 @@ void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithBackground() {
if (runLength == 0)
return;
assert(runLength <= frameSize);
Common::copy(src + screenOffset, src + screenOffset + runLength, dest);
assert(frameSize >= runLength);
Common::copy(refP + screenOffset, refP + screenOffset + runLength, destP + screenOffset);
screenOffset += runLength;
frameSize -= runLength;
} else {
// Run length of a single pixel value
byte runLength = _fileStream->readByte();
assert(runLength <= frameSize);
Common::fill(dest + screenOffset, dest + screenOffset + runLength, nextByte & 0x7f);
nextByte &= 0x7f;
assert(frameSize >= runLength);
Common::fill(destP + screenOffset, destP + screenOffset + runLength, nextByte);
screenOffset += runLength;
frameSize -= runLength;
}
}
// If there's a remaining section of the screen not covered, copy it from reference surface
if (screenOffset < (_surface->w * _surface->h))
Common::copy(refP + screenOffset, refP + (_surface->w * _surface->h), destP + screenOffset);
}
void RL2Decoder::RL2VideoTrack::setupBackSurface(Graphics::Surface *surface) {

View File

@ -130,8 +130,8 @@ private:
Common::List<Common::Rect> _dirtyRects;
void copyFrame(uint8 *data);
void rl2DecodeFrameWithBackground();
void rl2DecodeFrameWithoutBackground(int screenOffset = -1);
void rl2DecodeFrameWithTransparency(int screenOffset);
void rl2DecodeFrameWithoutTransparency(int screenOffset = -1);
void initBackSurface();
};

View File

@ -555,8 +555,6 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
decoder.loadVideo(videoId);
decoder.start();
decoder.getVideoTrack()->setupBackSurface(&_graphicsManager._screenSurface);
decoder.seek(Audio::Timestamp(_voy._vocSecondsOffset * 1000));
int endFrame = decoder.getCurFrame() + totalFrames;