From 9bf07073fb064679302ddfe75c706bbdc1c02c87 Mon Sep 17 00:00:00 2001 From: Thomas Fach-Pedersen Date: Sun, 27 Aug 2017 22:39:36 +0200 Subject: BLADERUNNER: Add Overlay videos --- engines/bladerunner/bladerunner.cpp | 10 +- engines/bladerunner/bladerunner.h | 2 + engines/bladerunner/module.mk | 1 + engines/bladerunner/overlays.cpp | 146 ++++++++++++++++++++++++++++++ engines/bladerunner/overlays.h | 74 +++++++++++++++ engines/bladerunner/script/scene/ct01.cpp | 1 - engines/bladerunner/script/script.cpp | 7 +- engines/bladerunner/vqa_decoder.cpp | 115 ++++++++++++++--------- engines/bladerunner/vqa_decoder.h | 41 ++++++--- engines/bladerunner/vqa_player.cpp | 75 +++++++-------- engines/bladerunner/vqa_player.h | 3 +- 11 files changed, 374 insertions(+), 101 deletions(-) create mode 100644 engines/bladerunner/overlays.cpp create mode 100644 engines/bladerunner/overlays.h diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index d138360fab..121ad8128e 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -44,6 +44,7 @@ #include "bladerunner/mouse.h" #include "bladerunner/outtake.h" #include "bladerunner/obstacles.h" +#include "bladerunner/overlays.h" #include "bladerunner/regions.h" #include "bladerunner/scene.h" #include "bladerunner/scene_objects.h" @@ -239,7 +240,8 @@ bool BladeRunnerEngine::startup(bool hasSavegames) { if (!openArchive("SPCHSFX.TLK")) return false; - // TODO: Video overlays + _overlays = new Overlays(this); + _overlays->init(); _zbuffer = new ZBuffer(); _zbuffer->init(640, 480); @@ -437,7 +439,8 @@ void BladeRunnerEngine::shutdown() { delete _ambientSounds; - // TODO: Delete overlays + delete _overlays; + _overlays = nullptr; delete _audioSpeech; @@ -646,10 +649,11 @@ void BladeRunnerEngine::gameTick() { } (void)backgroundChanged; blit(_surfaceInterface, _surfaceGame); + // TODO: remove zbuffer draw // _surfaceGame.copyRectToSurface(_zbuffer->getData(), 1280, 0, 0, 640, 480); - // TODO: Render overlays + _overlays->tick(); if (!inDialogueMenu) { actorsUpdate(); diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index 7118dcce83..066937ca38 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -69,6 +69,7 @@ class Items; class Lights; class Mouse; class Obstacles; +class Overlays; class Scene; class SceneObjects; class SceneScript; @@ -112,6 +113,7 @@ public: Font *_mainFont; Mouse *_mouse; Obstacles *_obstacles; + Overlays *_overlays; Scene *_scene; SceneObjects *_sceneObjects; SceneScript *_sceneScript; diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index eeaff45794..711ddd3346 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -39,6 +39,7 @@ MODULE_OBJS = \ movement_track.o \ obstacles.o \ outtake.o \ + overlays.o \ regions.o \ scene.o \ scene_objects.o \ diff --git a/engines/bladerunner/overlays.cpp b/engines/bladerunner/overlays.cpp new file mode 100644 index 0000000000..946cbe266d --- /dev/null +++ b/engines/bladerunner/overlays.cpp @@ -0,0 +1,146 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "bladerunner/overlays.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/archive.h" +#include "bladerunner/vqa_player.h" + +#include "graphics/surface.h" + +namespace BladeRunner { + +Overlays::Overlays(BladeRunnerEngine *vm) + : _vm(vm) +{ +} + +bool Overlays::init() { + reset(); + _videos.resize(kOverlayVideos); + + for (int i = 0; i < kOverlayVideos; ++i) { + _videos[i].vqaPlayer = nullptr; + resetSingle(i); + } + + return true; +} + +Overlays::~Overlays() { + for (int i = 0; i < kOverlayVideos; ++i) { + resetSingle(i); + } + _videos.clear(); + reset(); +} + +int Overlays::play(const Common::String &name, int loopId, int loopForever, int a5, int a6) { + int id = mix_id(name); + int index = findById(id); + if (index < 0) { + index = findEmpty(); + if (index < 0) { + return index; + } + _videos[index].id = id; + _videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceGame); + + // repeat forever + _videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr); + _videos[index].loaded = true; + } + + Common::String resourceName = Common::String::format("%s.VQA", name.c_str()); + _videos[index].vqaPlayer->open(resourceName); + _videos[index].vqaPlayer->setLoop( + loopId, + loopForever ? -1 : 0, + a5 ? kLoopSetModeImmediate : kLoopSetModeEnqueue, + nullptr, nullptr); + + return index; +} + +void Overlays::remove(const Common::String &name) { + int id = mix_id(name); + int index = findById(id); + if (index >= 0) { + resetSingle(index); + } +} + +void Overlays::tick() { + for (int i = 0; i < kOverlayVideos; ++i) { + if (_videos[i].loaded) { + int frame = _videos[i].vqaPlayer->update(true); + if (frame < 0) { + resetSingle(i); + } + } + } +} + +int Overlays::findById(int id) const { + for (int i = 0; i < kOverlayVideos; ++i) { + if (_videos[i].loaded && _videos[i].id == id) { + return i; + } + } + return -1; +} + +int Overlays::findEmpty() const { + for (int i = 0; i < kOverlayVideos; ++i) { + if (!_videos[i].loaded) { + return i; + } + } + return -1; +} + +void Overlays::resetSingle(int i) { + assert(i >= 0 && i < (int)_videos.size()); + if (_videos[i].vqaPlayer) { + delete _videos[i].vqaPlayer; + _videos[i].vqaPlayer = nullptr; + } + _videos[i].loaded = false; + _videos[i].id = 0; + _videos[i].field2 = -1; +} + +void Overlays::resetAll() { + for (int i = 0; i < kOverlayVideos; ++i) { + if (_videos[i].loaded) { + resetSingle(i); + } + } +} + +void Overlays::reset() { + _videos.clear(); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/overlays.h b/engines/bladerunner/overlays.h new file mode 100644 index 0000000000..edeb0d120c --- /dev/null +++ b/engines/bladerunner/overlays.h @@ -0,0 +1,74 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef BLADERUNNER_OVERLAYS_H +#define BLADERUNNER_OVERLAYS_H + +#include "common/array.h" +#include "common/str.h" + +namespace Graphics { + struct Surface; +}; + +namespace BladeRunner { + +class BladeRunnerEngine; +class VQAPlayer; + +struct OverlayVideo { + bool loaded; + VQAPlayer *vqaPlayer; + // char name[13]; + int32 id; + int field0; + int field1; + int field2; +}; + +class Overlays { + static const int kOverlayVideos = 5; + + BladeRunnerEngine *_vm; + Common::Array _videos; + +public: + Overlays(BladeRunnerEngine *vm); + bool init(); + ~Overlays(); + + int play(const Common::String &name, int a3, int a4, int a5, int a6); + void remove(const Common::String &name); + void tick(); + +private: + int findById(int32 id) const; + int findEmpty() const; + + void resetSingle(int i); + void resetAll(); + void reset(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/script/scene/ct01.cpp b/engines/bladerunner/script/scene/ct01.cpp index 5a2c62cfbb..21e6fc7600 100644 --- a/engines/bladerunner/script/scene/ct01.cpp +++ b/engines/bladerunner/script/scene/ct01.cpp @@ -366,7 +366,6 @@ void SceneScriptCT01::SceneFrameAdvanced(int frame) { } else { Ambient_Sounds_Play_Sound(66, Random_Query(33, 50), 0, 0, 0); } - } } } diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp index 72f4e50a53..25d78e4991 100644 --- a/engines/bladerunner/script/script.cpp +++ b/engines/bladerunner/script/script.cpp @@ -38,6 +38,7 @@ #include "bladerunner/items.h" #include "bladerunner/item_pickup.h" #include "bladerunner/movement_track.h" +#include "bladerunner/overlays.h" #include "bladerunner/regions.h" #include "bladerunner/set.h" #include "bladerunner/settings.h" @@ -818,13 +819,11 @@ bool ScriptBase::Music_Is_Playing() { } void ScriptBase::Overlay_Play(const char *overlay, int a2, int a3, int a4, int a5) { - //TODO - warning("Overlay_Play(%s, %d, %d, %d, %d)", overlay, a2, a3, a4, a5); + _vm->_overlays->play(overlay, a2, a3, a4, a5); } void ScriptBase::Overlay_Remove(const char *overlay) { - //TODO - warning("Overlay_Remove(%s)", overlay); + _vm->_overlays->remove(overlay); } void ScriptBase::Scene_Loop_Set_Default(int loopId) { diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp index 06cba12592..275ec18a4d 100644 --- a/engines/bladerunner/vqa_decoder.cpp +++ b/engines/bladerunner/vqa_decoder.cpp @@ -128,6 +128,9 @@ VQADecoder::VQADecoder(Graphics::Surface *surface) : } VQADecoder::~VQADecoder() { + for (uint i = 0; i < _codebooks.size(); ++i) { + delete[] _codebooks[i].data; + } delete _audioTrack; delete _videoTrack; delete[] _frameInfo; @@ -191,8 +194,9 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) { return true; } -void VQADecoder::decodeVideoFrame() { - _videoTrack->decodeVideoFrame(); +void VQADecoder::decodeVideoFrame(int frame, bool forceDraw) { + _decodingFrame = frame; + _videoTrack->decodeVideoFrame(forceDraw); } void VQADecoder::decodeZBuffer(ZBuffer *zbuffer) { @@ -215,7 +219,7 @@ void VQADecoder::decodeLights(Lights *lights) { _videoTrack->decodeLights(lights); } -void VQADecoder::readPacket(int skipFlags) { +void VQADecoder::readPacket(uint readFlags) { IFFChunkHeader chd; if (remain(_s) < 8) { @@ -232,15 +236,15 @@ void VQADecoder::readPacket(int skipFlags) { bool rc = false; // Video track switch (chd.id) { - case kAESC: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readAESC(_s, chd.size); break; - case kLITE: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readLITE(_s, chd.size); break; - case kVIEW: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVIEW(_s, chd.size); break; - case kVQFL: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFL(_s, chd.size); break; - case kVQFR: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFR(_s, chd.size); break; - case kZBUF: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readZBUF(_s, chd.size); break; + case kAESC: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readAESC(_s, chd.size); break; + case kLITE: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readLITE(_s, chd.size); break; + case kVIEW: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVIEW(_s, chd.size); break; + case kVQFL: rc = ((readFlags & kVQAReadVideo ) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFL(_s, chd.size, readFlags); break; + case kVQFR: rc = ((readFlags & kVQAReadVideo ) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFR(_s, chd.size, readFlags); break; + case kZBUF: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readZBUF(_s, chd.size); break; // Sound track - case kSN2J: rc = skipFlags & 2 ? _s->skip(roundup(chd.size)) : _audioTrack->readSN2J(_s, chd.size); break; - case kSND2: rc = skipFlags & 2 ? _s->skip(roundup(chd.size)) : _audioTrack->readSND2(_s, chd.size); break; + case kSN2J: rc = ((readFlags & kVQAReadAudio) == 0) ? _s->skip(roundup(chd.size)) : _audioTrack->readSN2J(_s, chd.size); break; + case kSND2: rc = ((readFlags & kVQAReadAudio) == 0) ? _s->skip(roundup(chd.size)) : _audioTrack->readSND2(_s, chd.size); break; default: rc = false; _s->skip(roundup(chd.size)); @@ -253,14 +257,16 @@ void VQADecoder::readPacket(int skipFlags) { } while (chd.id != kVQFR); } -void VQADecoder::readFrame(int frame, int skipFlags) { +void VQADecoder::readFrame(int frame, uint readFlags) { if (frame < 0 || frame >= numFrames()) { error("frame %d out of bounds, frame count is %d", frame, numFrames()); } uint32 frameOffset = 2 * (_frameInfo[frame] & 0x0FFFFFFF); _s->seek(frameOffset); - readPacket(skipFlags); + + _readingFrame = frame; + readPacket(readFlags); } bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) { @@ -289,10 +295,6 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) { _header.maxCBFZSize = s->readUint32LE(); _header.unk5 = s->readUint32LE(); - if (_header.offsetX || _header.offsetY) { - debug("_header.offsetX, _header.offsetY: %d %d", _header.offsetX, _header.offsetY); - } - // if (_header.unk3 || _header.unk4 != 4 || _header.unk5 || _header.flags != 0x0014) if (false) { debug("_header.version %d", _header.version); @@ -330,7 +332,7 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) { return true; } -bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size) { +bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size, uint readFlags) { IFFChunkHeader chd; while (size >= 8) { @@ -340,8 +342,8 @@ bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 s bool rc = false; switch (chd.id) { - case kCBFZ: rc = readCBFZ(s, chd.size); break; - case kVPTR: rc = readVPTR(s, chd.size); break; + case kCBFZ: rc = ((readFlags & kVQAReadCodebook ) == 0) ? s->skip(roundup(chd.size)) : readCBFZ(s, chd.size); break; + case kVPTR: rc = ((readFlags & kVQAReadVectorPointerTable) == 0) ? s->skip(roundup(chd.size)) : readVPTR(s, chd.size); break; default: s->skip(roundup(chd.size)); } @@ -426,6 +428,22 @@ bool VQADecoder::readLINF(Common::SeekableReadStream *s, uint32 size) { return true; } +VQADecoder::CodebookInfo &VQADecoder::codebookInfoForFrame(int frame) { + assert(frame < numFrames()); + assert(!_codebooks.empty()); + + CodebookInfo *ci = nullptr; + uint count = _codebooks.size(); + for (uint i = 0; i != count; ++i) { + if (frame >= _codebooks[count - i - 1].frame) { + return _codebooks[count - i - 1]; + } + } + + assert(ci && "No codebook found"); + return _codebooks[0]; +} + bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size) { IFFChunkHeader chd; @@ -433,17 +451,23 @@ bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size) { if (chd.id != kCINH || chd.size != 8u) return false; - _clipInfo.clipCount = s->readUint16LE(); + uint16 codebookCount = s->readUint16LE(); + _codebooks.resize(codebookCount); + s->skip(6); readIFFChunkHeader(_s, &chd); - if (chd.id != kCIND || chd.size != 6u * _clipInfo.clipCount) + if (chd.id != kCIND || chd.size != 6u * codebookCount) return false; - for (int i = 0; i != _clipInfo.clipCount; ++i) { - uint16 a = s->readUint16LE(); - uint32 b = s->readUint32LE(); - debug("VQADecoder::readCINF() i: %d a: 0x%04x b: 0x%08x", i, a, b); + for (int i = 0; i != codebookCount; ++i) { + _codebooks[i].frame = s->readUint16LE(); + _codebooks[i].size = s->readUint32LE(); + _codebooks[i].data = nullptr; + + // debug("Codebook %2d: %4d %8d", i, _codebooks[i].frame, _codebooks[i].size); + + assert(_codebooks[i].frame < numFrames()); } return true; @@ -543,11 +567,11 @@ bool VQADecoder::readMFCI(Common::SeekableReadStream *s, uint32 size) { } VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface) { - VQADecoder::Header *header = &vqaDecoder->_header; - + _vqaDecoder = vqaDecoder; _surface = surface; _hasNewFrame = false; + VQADecoder::Header *header = &vqaDecoder->_header; _numFrames = header->numFrames; _width = header->width; _height = header->height; @@ -562,7 +586,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surfa _maxCBFZSize = header->maxCBFZSize; _maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize; - _codebookSize = 0; _codebook = nullptr; _cbfz = nullptr; _zbufChunk = nullptr; @@ -580,7 +603,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surfa } VQADecoder::VQAVideoTrack::~VQAVideoTrack() { - delete[] _codebook; delete[] _cbfz; delete[] _zbufChunk; delete[] _vpointer; @@ -598,10 +620,6 @@ uint16 VQADecoder::VQAVideoTrack::getHeight() const { return _height; } -int VQADecoder::VQAVideoTrack::getCurFrame() const { - return _curFrame; -} - int VQADecoder::VQAVideoTrack::getFrameCount() const { return _numFrames; } @@ -610,15 +628,14 @@ Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const { return _frameRate; } -void VQADecoder::VQAVideoTrack::decodeVideoFrame() { - if (_hasNewFrame) { +void VQADecoder::VQAVideoTrack::decodeVideoFrame(bool forceDraw) { + if (_hasNewFrame || forceDraw) { decodeFrame((uint16*)_surface->getPixels()); - _curFrame++; _hasNewFrame = false; } } -bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size) { +bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size, uint readFlags) { IFFChunkHeader chd; while (size >= 8) { @@ -648,17 +665,22 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s return false; } - if (!_codebook) { - _codebookSize = 2 * _maxBlocks * _blockW * _blockH; - _codebook = new uint8[_codebookSize]; + CodebookInfo &codebookInfo = _vqaDecoder->codebookInfoForFrame(_vqaDecoder->_readingFrame); + if (codebookInfo.data) { + s->skip(roundup(size)); + return true; } + + uint32 codebookSize = 2 * _maxBlocks * _blockW * _blockH; + codebookInfo.data = new uint8[codebookSize]; + if (!_cbfz) { _cbfz = new uint8[roundup(_maxCBFZSize)]; } s->read(_cbfz, roundup(size)); - decompress_lcw(_cbfz, size, _codebook, _codebookSize); + decompress_lcw(_cbfz, size, codebookInfo.data, codebookSize); return true; } @@ -790,7 +812,7 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBl int blocks_per_line = frame_width / block_width; do { - uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX / 2; + uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX; uint32 frame_y = dstBlock / blocks_per_line * block_height + _offsetY; uint32 dst_offset = frame_x + frame_y * frame_stride; @@ -817,6 +839,13 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBl } bool VQADecoder::VQAVideoTrack::decodeFrame(uint16 *frame) { + VQADecoder::CodebookInfo &codebookInfo = _vqaDecoder->codebookInfoForFrame(_vqaDecoder->_decodingFrame); + + if (!codebookInfo.data) { + _vqaDecoder->readFrame(codebookInfo.frame, kVQAReadCodebook); + } + + _codebook = codebookInfo.data; if (!_codebook || !_vpointer) return false; diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h index 8ef2ddd9c4..c76a8b336a 100644 --- a/engines/bladerunner/vqa_decoder.h +++ b/engines/bladerunner/vqa_decoder.h @@ -43,6 +43,15 @@ class Lights; class View; class ZBuffer; +enum VQADecoderSkipFlags { + kVQAReadCodebook = 1, + kVQAReadVectorPointerTable = 2, + kVQAReadCustom = 4, + kVQAReadVideo = kVQAReadCodebook|kVQAReadVectorPointerTable|kVQAReadCustom, + kVQAReadAudio = 8, + kVQAReadAll = kVQAReadVideo|kVQAReadAudio +}; + class VQADecoder { public: VQADecoder(Graphics::Surface *surface); @@ -50,9 +59,9 @@ public: bool loadStream(Common::SeekableReadStream *s); - void readFrame(int frame, int skipFlags); + void readFrame(int frame, uint readFlags = kVQAReadAll); - void decodeVideoFrame(); + void decodeVideoFrame(int frame, bool forceDraw = false); void decodeZBuffer(ZBuffer *zbuffer); Audio::SeekableAudioStream *decodeAudioFrame(); void decodeView(View *view); @@ -120,8 +129,10 @@ private: } }; - struct ClipInfo { - uint16 clipCount; + struct CodebookInfo { + uint16 frame; + uint32 size; + uint8 *data; }; class VQAVideoTrack; @@ -131,8 +142,11 @@ private: Graphics::Surface *_surface; Header _header; + int _readingFrame; + int _decodingFrame; LoopInfo _loopInfo; - ClipInfo _clipInfo; + + Common::Array _codebooks; uint32 *_frameInfo; @@ -143,7 +157,7 @@ private: VQAVideoTrack *_videoTrack; VQAAudioTrack *_audioTrack; - void readPacket(int skipFlags); + void readPacket(uint readFlags); bool readVQHD(Common::SeekableReadStream *s, uint32 size); bool readMSCI(Common::SeekableReadStream *s, uint32 size); @@ -154,6 +168,8 @@ private: bool readLNIN(Common::SeekableReadStream *s, uint32 size); bool readCLIP(Common::SeekableReadStream *s, uint32 size); + VQADecoder::CodebookInfo &VQADecoder::codebookInfoForFrame(int frame); + class VQAVideoTrack { public: VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface); @@ -162,18 +178,17 @@ private: uint16 getWidth() const; uint16 getHeight() const; - int getCurFrame() const; int getFrameCount() const; - void decodeVideoFrame(); + void decodeVideoFrame(bool forceDraw); void decodeZBuffer(ZBuffer *zbuffer); void decodeView(View *view); void decodeAESC(AESC *aesc); void decodeLights(Lights *lights); - bool readVQFR(Common::SeekableReadStream *s, uint32 size); + bool readVQFR(Common::SeekableReadStream *s, uint32 size, uint readFlags); bool readVPTR(Common::SeekableReadStream *s, uint32 size); - bool readVQFL(Common::SeekableReadStream *s, uint32 size); + bool readVQFL(Common::SeekableReadStream *s, uint32 size, uint readFlags); bool readCBFZ(Common::SeekableReadStream *s, uint32 size); bool readZBUF(Common::SeekableReadStream *s, uint32 size); bool readVIEW(Common::SeekableReadStream *s, uint32 size); @@ -186,6 +201,7 @@ private: bool useAudioSync() const { return false; } private: + VQADecoder *_vqaDecoder; Graphics::Surface *_surface; bool _hasNewFrame; @@ -200,7 +216,6 @@ private: uint32 _maxCBFZSize; uint32 _maxZBUFChunkSize; - uint32 _codebookSize; uint8 *_codebook; uint8 *_cbfz; bool _zbufChunkComplete; @@ -215,9 +230,9 @@ private: uint8 *_viewData; uint32 _viewDataSize; uint8 *_lightsData; - uint32 _lightsDataSize; + uint32 _lightsDataSize; uint8 *_aescData; - uint32 _aescDataSize; + uint32 _aescDataSize; void VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha = false); bool decodeFrame(uint16 *frame); diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp index a340f798d1..51766d6e28 100644 --- a/engines/bladerunner/vqa_player.cpp +++ b/engines/bladerunner/vqa_player.cpp @@ -49,6 +49,7 @@ bool VQAPlayer::open(const Common::String &name) { _repeatsCount = 0; _loop = -1; + _frame = -1; _frameBegin = -1; _frameEnd = _decoder.numFrames() - 1; _frameEndQueued = -1; @@ -70,8 +71,9 @@ void VQAPlayer::close() { _s = nullptr; } -int VQAPlayer::update() { +int VQAPlayer::update(bool forceDraw) { uint32 now = 60 * _vm->_system->getMillis(); + int result = -1; if (_frameNext < 0) { _frameNext = _frameBegin; @@ -101,47 +103,48 @@ int VQAPlayer::update() { } } - return -1; - } - - if (_frameNext > _frameEnd) { - return -3; - } - - if (now < _frameNextTime) { - return -1; - } - - int frame = _frameNext; - _decoder.readFrame(_frameNext, 0x2); - _decoder.decodeVideoFrame(); - - int audioPreloadFrames = 14; - - if (_hasAudio) { - if (!_audioStarted) { - for (int i = 0; i < audioPreloadFrames; i++) { - if (_frameNext + i < _frameEnd) { - _decoder.readFrame(_frameNext + i, 0x1); - queueAudioFrame(_decoder.decodeAudioFrame()); + result = -1; + } else if (_frameNext > _frameEnd) { + result = -3; + } else if (now < _frameNextTime) { + result = -1; + } else { + _frame = _frameNext; + _decoder.readFrame(_frameNext, kVQAReadVideo); + _decoder.decodeVideoFrame(_frameNext); + + int audioPreloadFrames = 14; + + if (_hasAudio) { + if (!_audioStarted) { + for (int i = 0; i < audioPreloadFrames; i++) { + if (_frameNext + i < _frameEnd) { + _decoder.readFrame(_frameNext + i, kVQAReadAudio); + queueAudioFrame(_decoder.decodeAudioFrame()); + } } + _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream); + _audioStarted = true; } - _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream); - _audioStarted = true; + if (_frameNext + audioPreloadFrames < _frameEnd) { + _decoder.readFrame(_frameNext + audioPreloadFrames, kVQAReadAudio); + queueAudioFrame(_decoder.decodeAudioFrame()); + } + } + if (_frameNextTime == 0) { + _frameNextTime = now + 60000 / 15; } - if (_frameNext + audioPreloadFrames < _frameEnd) { - _decoder.readFrame(_frameNext + audioPreloadFrames, 0x1); - queueAudioFrame(_decoder.decodeAudioFrame()); + else { + _frameNextTime += 60000 / 15; } + _frameNext++; + result = _frame; } - if (_frameNextTime == 0) { - _frameNextTime = now + 60000 / 15; - } else { - _frameNextTime += 60000 / 15; + if (result < 0 && forceDraw && _frame != -1) { + _decoder.decodeVideoFrame(_frame, true); + result = _frame; } - - _frameNext++; - return frame; + return result; } void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) { diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h index dde5201932..1be47bd87e 100644 --- a/engines/bladerunner/vqa_player.h +++ b/engines/bladerunner/vqa_player.h @@ -52,6 +52,7 @@ class VQAPlayer { const uint16 *_zBuffer; Audio::QueuingAudioStream *_audioStream; + int _frame; int _frameNext; int _frameBegin; int _frameEnd; @@ -102,7 +103,7 @@ public: bool open(const Common::String &name); void close(); - int update(); + int update(bool forceDraw = false); void updateZBuffer(ZBuffer *zbuffer); void updateView(View *view); void updateAESC(AESC *aesc); -- cgit v1.2.3