[Scummvm-git-logs] scummvm master -> 9bf07073fb064679302ddfe75c706bbdc1c02c87

madmoose thomas at fach-pedersen.net
Sun Aug 27 22:40:35 CEST 2017


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
9bf07073fb BLADERUNNER: Add Overlay videos


Commit: 9bf07073fb064679302ddfe75c706bbdc1c02c87
    https://github.com/scummvm/scummvm/commit/9bf07073fb064679302ddfe75c706bbdc1c02c87
Author: Thomas Fach-Pedersen (thomas at fach-pedersen.net)
Date: 2017-08-27T22:39:36+02:00

Commit Message:
BLADERUNNER: Add Overlay videos

Changed paths:
  A engines/bladerunner/overlays.cpp
  A engines/bladerunner/overlays.h
    engines/bladerunner/bladerunner.cpp
    engines/bladerunner/bladerunner.h
    engines/bladerunner/module.mk
    engines/bladerunner/script/scene/ct01.cpp
    engines/bladerunner/script/script.cpp
    engines/bladerunner/vqa_decoder.cpp
    engines/bladerunner/vqa_decoder.h
    engines/bladerunner/vqa_player.cpp
    engines/bladerunner/vqa_player.h


diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index d138360..121ad81 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 7118dcc..066937c 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 eeaff45..711ddd3 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 0000000..946cbe2
--- /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 0000000..edeb0d1
--- /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<OverlayVideo> _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 5a2c62c..21e6fc7 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 72f4e50..25d78e4 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 06cba12..275ec18 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 8ef2ddd..c76a8b3 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<CodebookInfo> _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 a340f79..51766d6 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 dde5201..1be47bd 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);





More information about the Scummvm-git-logs mailing list