Skip to content
Permalink
Browse files

BLADERUNNER: Added correct video looping and loop switching

  • Loading branch information
peterkohaut committed Mar 26, 2017
1 parent 96b31ca commit f5ebf4d6803feaf1e1ae914db1dad8ff4e39b445
Showing with 129 additions and 50 deletions.
  1. +1 −4 engines/bladerunner/script/scene/rc01.cpp
  2. +101 −34 engines/bladerunner/vqa_player.cpp
  3. +27 −12 engines/bladerunner/vqa_player.h
@@ -27,10 +27,7 @@ namespace BladeRunner {
void SceneScriptRC01::InitializeScene() {
#if _DEBUG
//TODO: not part of game, remove
Game_Flag_Set(24); // force skip intro
// Game_Flag_Set(9); // Force flag 9 so McCoy will be in view

Footstep_Sound_Override_On(0);
// Game_Flag_Set(24); // force skip intro
#endif

if (!Game_Flag_Query(24)) {
@@ -32,18 +32,26 @@ namespace BladeRunner {

bool VQAPlayer::open(const Common::String &name) {
_s = _vm->getResourceStream(name);
if (!_s)
if (!_s) {
return false;
}

if(!_decoder.loadStream(_s)) {
if (!_decoder.loadStream(_s)) {
delete _s;
_s = nullptr;
return false;
}

_hasAudio = _decoder.hasAudio();
if (_hasAudio)
if (_hasAudio) {
_audioStream = Audio::makeQueuingAudioStream(_decoder.frequency(), false);
}

if (_loopInitial >= 0) {
setLoop(_loopInitial, _repeatsCountInitial, 2, nullptr, nullptr);
} else {
setBeginAndEndFrame(0, _decoder.numFrames() - 1, 0, 0, nullptr, nullptr);
}

return true;
}
@@ -57,19 +65,19 @@ void VQAPlayer::close() {
int VQAPlayer::update() {
uint32 now = 60 * _vm->_system->getMillis();

if (_curFrame == -1) {
_curFrame = 0;
if (_curFrame >= 0) {
_decoder.readPacket(_curFrame);
if (_frameCurrent == -1) {
_frameCurrent = 0;
if (_frameCurrent >= 0) {
_decoder.readPacket(_frameCurrent);
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
_surface = _decoder.decodeVideoFrame();
_zBuffer = _decoder.decodeZBuffer();
}

_decodedFrame = calcNextFrame(_curFrame);
if (_decodedFrame >= 0) {
_decoder.readPacket(_decodedFrame);
_frameDecoded = calcNextFrame(_frameCurrent);
if (_frameDecoded >= 0) {
_decoder.readPacket(_frameDecoded);
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
}
@@ -80,25 +88,25 @@ int VQAPlayer::update() {
}

_nextFrameTime = now + 60000 / 15;
return _curFrame;
return _frameCurrent;
}

if (now >= _nextFrameTime) {
_curFrame = _decodedFrame;
if (_curFrame >= 0) {
_frameCurrent = _frameDecoded;
if (_frameCurrent >= 0) {
_surface = _decoder.decodeVideoFrame();
_zBuffer = _decoder.decodeZBuffer();
}

_decodedFrame = calcNextFrame(_curFrame);
if (_decodedFrame >= 0) {
_decoder.readPacket(_decodedFrame);
_frameDecoded = calcNextFrame(_frameCurrent);
if (_frameDecoded >= 0) {
_decoder.readPacket(_frameDecoded);
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
}

_nextFrameTime += 60000 / 15;
return _curFrame;
return _frameCurrent;
}

_surface = nullptr;
@@ -121,21 +129,58 @@ void VQAPlayer::updateLights(Lights *lights) {
_decoder.decodeLights(lights);
}

bool VQAPlayer::setLoop(int loop, int unknown, int loopMode, void(*callback)(void*, int, int), void *callbackData) {
bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopMode, void (*callback)(void *, int, int), void *callbackData) {
debug("VQAPlayer::setBeginAndEndFrameFromLoop(%i, %i, %i, %p, %p), streamLoaded = %i", loop, repeatsCount, loopMode, (void*)callback, callbackData, _s != nullptr);
if (_s == nullptr) {
_loopInitial = loop;
_repeatsCountInitial = repeatsCount;
return true;
}

int begin, end;
if (!_decoder.getLoopBeginAndEndFrame(loop, &begin, &end)) {
return false;
}
if (setBeginAndEndFrame(begin, end, repeatsCount, loopMode, callback, callbackData)) {
_loop = loop;
return true;
}
return false;
}

bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopMode, void (*callback)(void *, int, int), void *callbackData) {
debug("VQAPlayer::setBeginAndEndFrame(%i, %i, %i, %i, %p, %p), streamLoaded = %i", begin, end, repeatsCount, loopMode, (void*)callback, callbackData, _s != nullptr);

if (repeatsCount < 0) {
repeatsCount = -1;
}

_curLoop = loop;
_loopBegin = begin;
_loopEnd = end;
if (_repeatsCount == 0 && loopMode == 1) {
loopMode = 2;
}

//TODO: there is code in original game which deals with changing loop at start of loop, is it nescesarry? loc_46EA04

_frameBegin = begin;

if (loopMode == 1) {
_repeatsCountQueued = repeatsCount;
_frameEndQueued = end;
} else if (loopMode == 2) {
_repeatsCount = repeatsCount;
_frameEnd = end;
_frameCurrent = begin;
//TODO: extract this to seek function
_decoder.readPacket(_frameCurrent);
_frameDecoded = _frameCurrent;
_nextFrameTime = 60 * _vm->_system->getMillis();
} else if (loopMode == 0) {
_repeatsCount = repeatsCount;
}

_callbackLoopEnded = callback;
_callbackData = callbackData;

// warning("\t\t\tActive Loop: %d - %d\n", begin, end);

return true;
}

@@ -155,23 +200,45 @@ int VQAPlayer::getLoopEndFrame(int loop) {
return end;
}

int VQAPlayer::calcNextFrame(int frame) const {
if (frame < 0)
int VQAPlayer::calcNextFrame(int frame) {
//TODO: needs a slight refactoring, because it is not only calculating the next frame
if (frame < 0) {
return -3;
}

int frameNext = frame + 1;

if (_curLoop != -1 && frame >= _loopEnd) {
frame = _loopBegin;
if (_callbackLoopEnded != nullptr) {
_callbackLoopEnded(_callbackData, 0, _curLoop);
if ((_repeatsCount > 0 || _repeatsCount == -1) && (frameNext > _frameEnd)) {
int loopEndQueued = _frameEndQueued;
if (_frameEndQueued != -1) {
_frameEnd = _frameEndQueued;
_frameEndQueued = -1;
}
if (frameNext != _frameBegin) {
frameNext = _frameBegin;
}

if (loopEndQueued == -1) {
if (_repeatsCount != -1) {
_repeatsCount--;
}
//callback for repeat, it is not used in the blade runner
} else {
_repeatsCount = _repeatsCountQueued;
_repeatsCountQueued = -1;

if (_callbackLoopEnded != nullptr) {
_callbackLoopEnded(_callbackData, 0, _loop);
}
}
} else {
frame++;
}

if (frame == _decoder.numFrames())
frame = -3;
//TODO: original game is using end of loop instead of count of frames
if (frameNext == _decoder.numFrames()) {
return -3;
}

return frame;
return frameNext;
}

void VQAPlayer::queueAudioFrame(Audio::AudioStream *audioStream) {
@@ -36,6 +36,8 @@ class BladeRunnerEngine;
class View;
class Lights;

//TODO: split this into two components as it is in original game: universal vqa player, blade runner player functionality

class VQAPlayer {
BladeRunnerEngine *_vm;
Common::SeekableReadStream *_s;
@@ -44,11 +46,18 @@ class VQAPlayer {
const uint16 *_zBuffer;
Audio::QueuingAudioStream *_audioStream;

int _curFrame;
int _decodedFrame;
int _curLoop;
int _loopBegin;
int _loopEnd;
int _frameCurrent;
int _frameDecoded;
int _frameBegin;
int _frameEnd;
int _loop;
int _repeatsCount;

int _repeatsCountQueued;
int _frameEndQueued;

int _loopInitial;
int _repeatsCountInitial;

uint32 _nextFrameTime;
bool _hasAudio;
@@ -65,11 +74,16 @@ class VQAPlayer {
_s(nullptr),
_surface(nullptr),
_audioStream(nullptr),
_curFrame(-1),
_decodedFrame(-1),
_curLoop(-1),
_loopBegin(-1),
_loopEnd(-1),
_frameCurrent(-1),
_frameDecoded(-1),
_frameBegin(-1),
_frameEnd(-1),
_loop(-1),
_repeatsCount(-1),
_repeatsCountQueued(-1),
_frameEndQueued(-1),
_loopInitial(-1),
_repeatsCountInitial(-1),
_nextFrameTime(0),
_hasAudio(false),
_audioStarted(false),
@@ -89,13 +103,14 @@ class VQAPlayer {
void updateView(View *view);
void updateLights(Lights *lights);

bool setLoop(int loop, int unknown, int loopMode, void(*callback)(void*, int, int), void* callbackData);
bool setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopMode, void(*callback)(void *, int, int), void *callbackData);
bool setLoop(int loop, int repeatsCount, int loopMode, void(*callback)(void*, int, int), void* callbackData);

int getLoopBeginFrame(int loop);
int getLoopEndFrame(int loop);

private:
int calcNextFrame(int frame) const;
int calcNextFrame(int frame);
void queueAudioFrame(Audio::AudioStream *audioStream);
};

0 comments on commit f5ebf4d

Please sign in to comment.
You can’t perform that action at this time.