BLADERUNNER: zbuffer is now updated between scene changes

updated vqa player udpate code
fixed some warnings
audio preloading still needs some work
This commit is contained in:
Peter Kohaut 2017-03-29 18:47:38 +02:00
parent d4ff2ddf10
commit 5f36e65855
8 changed files with 133 additions and 144 deletions

View File

@ -1163,9 +1163,9 @@ bool Actor::walkFindU2(Vector3 *newDestination, float targetWidth, int destinati
bool Actor::walkToU(const Vector3 &destination, float distance) {
Vector3 out;
bool isRunning;
bool flagIsRunning;
if (_walkInfo->findU1(_id, destination, distance, &out)) {
loopWalk(out, 0, false, false, _position, 0.0f, 24.0f, false, &isRunning, false);
loopWalk(out, 0, false, false, _position, 0.0f, 24.0f, false, &flagIsRunning, false);
return true;
}
return false;

View File

@ -605,23 +605,8 @@ void BladeRunnerEngine::gameTick() {
}
(void)backgroundChanged;
_surface2.copyFrom(_surface1);
#if 0
{
for (int y = 0; y != 480; ++y) {
for (int x = 0; x != 640; ++x) {
if (_scene->_regions->getRegionAtXY(x, y) >= 0) {
uint16 *p = (uint16*)_surface2.getBasePtr(x, y);
*p = 0x7C00;
}
if (_scene->_exits->getRegionAtXY(x, y) >= 0) {
uint16 *p = (uint16*)_surface2.getBasePtr(x, y);
*p = 0x7C08;
}
}
}
}
#endif
// TODO: remove zbuffer draw
//_surface2.copyRectToSurface(_zbuffer->getData(), 1280, 0, 0, 640, 480);
// TODO: Render overlays

View File

@ -27,7 +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(24); // force skip intro
#endif
if (!Game_Flag_Query(24)) {

View File

@ -208,7 +208,7 @@ void VQADecoder::decodeLights(Lights *lights) {
_videoTrack->decodeLights(lights);
}
void VQADecoder::readNextPacket() {
void VQADecoder::readPacket(int skipFlags) {
IFFChunkHeader chd;
if (remain(_s) < 8) {
@ -223,21 +223,20 @@ void VQADecoder::readNextPacket() {
}
bool rc = false;
switch (chd.id) {
// Video track
case kAESC: rc = _videoTrack->readAESC(_s, chd.size); break;
case kLITE: rc = _videoTrack->readLITE(_s, chd.size); break;
case kVIEW: rc = _videoTrack->readVIEW(_s, chd.size); break;
case kVQFL: rc = _videoTrack->readVQFL(_s, chd.size); break;
case kVQFR: rc = _videoTrack->readVQFR(_s, chd.size); break;
case kZBUF: rc = _videoTrack->readZBUF(_s, chd.size); break;
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;
// Sound track
case kSN2J: rc = _audioTrack->readSN2J(_s, chd.size); break;
case kSND2: rc = _audioTrack->readSND2(_s, chd.size); break;
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;
default:
_s->skip(roundup(chd.size));
rc = false;
_s->skip(roundup(chd.size));
}
if (!rc) {
@ -247,14 +246,14 @@ void VQADecoder::readNextPacket() {
} while (chd.id != kVQFR);
}
void VQADecoder::readPacket(int frame) {
void VQADecoder::readFrame(int frame, int skipFlags) {
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);
readNextPacket();
readPacket(skipFlags);
}
bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) {

View File

@ -49,8 +49,7 @@ public:
bool loadStream(Common::SeekableReadStream *s);
void readNextPacket();
void readPacket(int frame);
void readFrame(int frame, int skipFlags);
const Graphics::Surface *decodeVideoFrame();
void decodeZBuffer(ZBuffer *zbuffer);
@ -141,6 +140,8 @@ private:
VQAVideoTrack *_videoTrack;
VQAAudioTrack *_audioTrack;
void readPacket(int skipFlags);
bool readVQHD(Common::SeekableReadStream *s, uint32 size);
bool readMSCI(Common::SeekableReadStream *s, uint32 size);
bool readMFCI(Common::SeekableReadStream *s, uint32 size);

View File

@ -47,10 +47,17 @@ bool VQAPlayer::open(const Common::String &name) {
_audioStream = Audio::makeQueuingAudioStream(_decoder.frequency(), false);
}
_repeatsCount = 0;
_loop = -1;
_frameBegin = -1;
_frameEnd = _decoder.numFrames() - 1;
_frameEndQueued = -1;
_repeatsCountQueued = -1;
if (_loopInitial >= 0) {
setLoop(_loopInitial, _repeatsCountInitial, 2, nullptr, nullptr);
setLoop(_loopInitial, _repeatsCountInitial, kLoopSetModeImmediate, nullptr, nullptr);
} else {
setBeginAndEndFrame(0, _decoder.numFrames() - 1, 0, 0, nullptr, nullptr);
setBeginAndEndFrame(0, _frameEnd, 0, kLoopSetModeJustStart, nullptr, nullptr);
}
return true;
@ -65,46 +72,76 @@ void VQAPlayer::close() {
int VQAPlayer::update() {
uint32 now = 60 * _vm->_system->getMillis();
if (_frameCurrent == -1) {
_frameCurrent = 0;
if (_frameCurrent >= 0) {
_decoder.readPacket(_frameCurrent);
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
_surface = _decoder.decodeVideoFrame();
}
_frameDecoded = calcNextFrame(_frameCurrent);
if (_frameDecoded >= 0) {
_decoder.readPacket(_frameDecoded);
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
}
if (_hasAudio) {
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream);
_audioStarted = true;
}
_nextFrameTime = now + 60000 / 15;
return _frameCurrent;
if (_frameNext < 0) {
_frameNext = _frameBegin;
}
if (now >= _nextFrameTime) {
_frameCurrent = _frameDecoded;
if (_frameCurrent >= 0) {
_surface = _decoder.decodeVideoFrame();
if ((_repeatsCount > 0 || _repeatsCount == -1) && (_frameNext > _frameEnd)) {
int loopEndQueued = _frameEndQueued;
if (_frameEndQueued != -1) {
_frameEnd = _frameEndQueued;
_frameEndQueued = -1;
}
if (_frameNext != _frameBegin) {
_frameNext = _frameBegin;
}
_frameDecoded = calcNextFrame(_frameCurrent);
if (_frameDecoded >= 0) {
_decoder.readPacket(_frameDecoded);
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
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);
}
}
_surface = nullptr;
return -1;
}
if (_frameNext > _frameEnd) {
return -3;
}
// TODO: preload audio
// int audioPreloadFrames = 1;
if (now >= _frameNextTime) {
int frame = _frameNext;
// _decoder.readFrame(_frameNext, 0x2);
_decoder.readFrame(_frameNext, 0);
_surface = _decoder.decodeVideoFrame();
if (_hasAudio) {
queueAudioFrame(_decoder.decodeAudioFrame());
if (!_audioStarted) {
// for (int i = 0; i < audioPreloadFrames; i++) {
// if (_frameNext + i < _frameEnd) {
// _decoder.readFrame(_frameNext + i, 0x1);
// queueAudioFrame(_decoder.decodeAudioFrame());
// }
// }
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream);
_audioStarted = true;
}
// if (_frameNext + audioPreloadFrames < _frameEnd) {
// _decoder.readFrame(_frameNext + audioPreloadFrames, 0x1);
// queueAudioFrame(_decoder.decodeAudioFrame());
// }
}
if (_frameNextTime == 0) {
_frameNextTime = now + 60000 / 15;
} else {
_frameNextTime += 60000 / 15;
}
_nextFrameTime += 60000 / 15;
return _frameCurrent;
_frameNext++;
return frame;
}
_surface = nullptr;
@ -127,8 +164,8 @@ void VQAPlayer::updateLights(Lights *lights) {
_decoder.decodeLights(lights);
}
bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopMode, void (*callback)(void *, int, int), void *callbackData) {
// debug("VQAPlayer::setBeginAndEndFrameFromLoop(%i, %i, %i, %x, %p), streamLoaded = %i", loop, repeatsCount, loopMode, (uint)callback, callbackData, _s != nullptr);
bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopSetMode, void (*callback)(void *, int, int), void *callbackData) {
debug("VQAPlayer::setBeginAndEndFrameFromLoop(%i, %i, %i), streamLoaded = %i", loop, repeatsCount, loopSetMode, _s != nullptr);
if (_s == nullptr) {
_loopInitial = loop;
_repeatsCountInitial = repeatsCount;
@ -139,41 +176,37 @@ bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopMode, void (*callbac
if (!_decoder.getLoopBeginAndEndFrame(loop, &begin, &end)) {
return false;
}
if (setBeginAndEndFrame(begin, end, repeatsCount, loopMode, callback, callbackData)) {
if (setBeginAndEndFrame(begin, end, repeatsCount, loopSetMode, 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, %x, %p), streamLoaded = %i", begin, end, repeatsCount, loopMode, (uint)callback, callbackData, _s != nullptr);
bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopSetMode, void (*callback)(void *, int, int), void *callbackData) {
debug("VQAPlayer::setBeginAndEndFrame(%i, %i, %i, %i), streamLoaded = %i", begin, end, repeatsCount, loopSetMode, _s != nullptr);
if (repeatsCount < 0) {
repeatsCount = -1;
}
if (_repeatsCount == 0 && loopMode == 1) {
loopMode = 2;
if (_repeatsCount == 0 && loopSetMode == kLoopSetModeEnqueue) {
loopSetMode = kLoopSetModeImmediate;
}
//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) {
if (loopSetMode == kLoopSetModeJustStart) {
_repeatsCount = repeatsCount;
} else if (loopSetMode == kLoopSetModeEnqueue) {
_repeatsCountQueued = repeatsCount;
_frameEndQueued = end;
} else if (loopMode == 2) {
} else if (loopSetMode == kLoopSetModeImmediate) {
_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;
seekToFrame(begin);
}
_callbackLoopEnded = callback;
@ -182,6 +215,12 @@ bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int lo
return true;
}
bool VQAPlayer::seekToFrame(int frame) {
_frameNext = frame;
_frameNextTime = 60 * _vm->_system->getMillis();
return true;
}
int VQAPlayer::getLoopBeginFrame(int loop) {
int begin, end;
if (!_decoder.getLoopBeginAndEndFrame(loop, &begin, &end)) {
@ -198,47 +237,6 @@ int VQAPlayer::getLoopEndFrame(int loop) {
return end;
}
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 ((_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);
}
}
}
//TODO: original game is using end of loop instead of count of frames
if (frameNext == _decoder.numFrames()) {
return -3;
}
return frameNext;
}
void VQAPlayer::queueAudioFrame(Audio::AudioStream *audioStream) {
int n = _audioStream->numQueuedStreams();
if (n == 0)

View File

@ -32,6 +32,12 @@
namespace BladeRunner {
enum LoopSetModes {
kLoopSetModeJustStart = 0,
kLoopSetModeEnqueue = 1,
kLoopSetModeImmediate = 2
};
class BladeRunnerEngine;
class View;
class Lights;
@ -47,8 +53,7 @@ class VQAPlayer {
const uint16 *_zBuffer;
Audio::QueuingAudioStream *_audioStream;
int _frameCurrent;
int _frameDecoded;
int _frameNext;
int _frameBegin;
int _frameEnd;
int _loop;
@ -60,7 +65,7 @@ class VQAPlayer {
int _loopInitial;
int _repeatsCountInitial;
uint32 _nextFrameTime;
uint32 _frameNextTime;
bool _hasAudio;
bool _audioStarted;
Audio::SoundHandle _soundHandle;
@ -74,9 +79,9 @@ public:
: _vm(vm),
_s(nullptr),
_surface(nullptr),
_zBuffer(nullptr),
_audioStream(nullptr),
_frameCurrent(-1),
_frameDecoded(-1),
_frameNext(-1),
_frameBegin(-1),
_frameEnd(-1),
_loop(-1),
@ -85,11 +90,11 @@ public:
_frameEndQueued(-1),
_loopInitial(-1),
_repeatsCountInitial(-1),
_nextFrameTime(0),
_frameNextTime(0),
_hasAudio(false),
_audioStarted(false),
_callbackLoopEnded(nullptr) {
}
_callbackLoopEnded(nullptr),
_callbackData(nullptr) { }
~VQAPlayer() {
close();
@ -104,14 +109,15 @@ public:
void updateView(View *view);
void updateLights(Lights *lights);
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);
bool setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopSetMode, void(*callback)(void *, int, int), void *callbackData);
bool setLoop(int loop, int repeatsCount, int loopSetMode, void(*callback)(void*, int, int), void* callbackData);
bool seekToFrame(int frame);
int getLoopBeginFrame(int loop);
int getLoopEndFrame(int loop);
private:
int calcNextFrame(int frame);
void queueAudioFrame(Audio::AudioStream *audioStream);
};

View File

@ -93,9 +93,9 @@ static int decodePartialZBuffer(const uint8 *src, uint16 *curZBUF, uint32 srcLen
uint32 dstRemain = dstSize;
uint16 *curzp = curZBUF;
uint16 *inp = (uint16*)src;
const uint16 *inp = (const uint16*)src;
while (dstRemain && (inp - (uint16*)src) < (std::ptrdiff_t)srcLen) {
while (dstRemain && (inp - (const uint16*)src) < (std::ptrdiff_t)srcLen) {
uint32 count = FROM_LE_16(*inp++);
if (count & 0x8000) {
@ -129,12 +129,12 @@ bool ZBuffer::decodeData(const uint8 *data, int size) {
return false;
}
uint32 width, height, complete, unk0;
uint32 width, height, complete;// , unk0;
width = READ_LE_UINT32(data + 0);
height = READ_LE_UINT32(data + 4);
complete = READ_LE_UINT32(data + 8);
unk0 = READ_LE_UINT32(data + 12);
/*unk0 =*/ READ_LE_UINT32(data + 12);
if (width != (uint32)_width || height != (uint32)_height) {
warning("zbuffer size mismatch (%d, %d) != (%d, %d)", _width, _height, width, height);