From 74a8b530f196233b287c9775e9c80774c4811058 Mon Sep 17 00:00:00 2001 From: Thomas Fach-Pedersen Date: Fri, 6 Feb 2015 15:31:43 +0100 Subject: BLADERUNNER: Add support for ambient sounds, game flags and variables, and use VQA z-buffer when rendering. --- engines/bladerunner/ambient_sounds.cpp | 216 +++++++++++++++++++ engines/bladerunner/ambient_sounds.h | 120 +++++++++++ engines/bladerunner/archive.cpp | 1 - engines/bladerunner/archive.h | 2 + engines/bladerunner/audio_player.cpp | 368 +++++++++++++++++++++++++++++++++ engines/bladerunner/audio_player.h | 74 +++++++ engines/bladerunner/bladerunner.cpp | 41 +++- engines/bladerunner/bladerunner.h | 16 +- engines/bladerunner/gameflags.cpp | 68 ++++++ engines/bladerunner/gameflags.h | 47 +++++ engines/bladerunner/gameinfo.cpp | 2 +- engines/bladerunner/gameinfo.h | 10 +- engines/bladerunner/module.mk | 3 + engines/bladerunner/scene.cpp | 8 +- engines/bladerunner/scene.h | 5 +- engines/bladerunner/script/rc01.cpp | 131 +++++++++--- engines/bladerunner/script/script.cpp | 89 ++++++++ engines/bladerunner/script/script.h | 36 ++++ engines/bladerunner/slice_renderer.cpp | 20 +- engines/bladerunner/slice_renderer.h | 4 +- engines/bladerunner/vqa_decoder.cpp | 66 +++--- engines/bladerunner/vqa_decoder.h | 5 + engines/bladerunner/vqa_player.cpp | 6 + engines/bladerunner/vqa_player.h | 2 + 24 files changed, 1259 insertions(+), 81 deletions(-) create mode 100644 engines/bladerunner/ambient_sounds.cpp create mode 100644 engines/bladerunner/ambient_sounds.h create mode 100644 engines/bladerunner/audio_player.cpp create mode 100644 engines/bladerunner/audio_player.h create mode 100644 engines/bladerunner/gameflags.cpp create mode 100644 engines/bladerunner/gameflags.h diff --git a/engines/bladerunner/ambient_sounds.cpp b/engines/bladerunner/ambient_sounds.cpp new file mode 100644 index 0000000000..77b819578f --- /dev/null +++ b/engines/bladerunner/ambient_sounds.cpp @@ -0,0 +1,216 @@ +/* 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/ambient_sounds.h" + +#include "bladerunner/audio_player.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/gameinfo.h" + +#include "common/debug.h" +#include "common/system.h" + +namespace BladeRunner { + +#define NON_LOOPING_SOUNDS 25 +#define LOOPING_SOUNDS 3 + +AmbientSounds::AmbientSounds(BladeRunnerEngine *vm) + : _vm(vm) +{ + _nonLoopingSounds = new NonLoopingSound[NON_LOOPING_SOUNDS]; + _loopingSounds = new LoopingSound[LOOPING_SOUNDS]; + _ambientVolume = 65; + + for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) { + NonLoopingSound &track = _nonLoopingSounds[i]; + track.isActive = false; + } + + for (int i = 0; i != LOOPING_SOUNDS; ++i) { + LoopingSound &track = _loopingSounds[i]; + track.isActive = false; + } +} + +AmbientSounds::~AmbientSounds() { + delete[] _nonLoopingSounds; + delete[] _loopingSounds; +} + +static inline void sort(int &a, int &b) { + if (a > b) { + int t = a; + a = b; + b = t; + } +} + +void AmbientSounds::addSound( + int id, + int timeRangeBegin, int timeRangeEnd, + int volumeRangeBegin, int volumeRangeEnd, + int unk1RangeBegin, int unk1RangeEnd, + int unk2RangeBegin, int unk2RangeEnd, + int priority, int unk3) +{ + const char *name = _vm->_gameInfo->getSfxTrack(id); + + sort(volumeRangeBegin, volumeRangeEnd); + sort(unk1RangeBegin, unk1RangeEnd); + sort(unk2RangeBegin, unk2RangeEnd); + + addSoundByName( + name, + timeRangeBegin, timeRangeEnd, + volumeRangeBegin, volumeRangeEnd, + unk1RangeBegin, unk1RangeEnd, + unk2RangeBegin, unk2RangeEnd, + priority, unk3 + ); +} + +void AmbientSounds::addLoopingSound(int sfx_id, int volume, int unk, int fadeInTime) { + const char *name = _vm->_gameInfo->getSfxTrack(sfx_id); + + int32 hash = mix_id(name); + + if (findLoopingTrackByHash(hash) >= 0) + return; + + int i = findAvailableLoopingTrack(); + if (i == -1) + return; + + int actualVolume = volume * _ambientVolume / 100; + + int balance = 0; + + _vm->_audioPlayer->playAud(name, actualVolume, balance, balance, 100, AudioPlayer::LOOP | AudioPlayer::OVERRIDE_VOLUME); +} + +void AmbientSounds::tick() { + uint32 now = g_system->getMillis(); + + for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) { + NonLoopingSound &track = _nonLoopingSounds[i]; + + if (!track.isActive || track.nextPlayTime > now) + continue; + + int pan1, pan2; + + pan1 = _vm->_rnd.getRandomNumberRng(track.pan1begin, track.pan1end); + if (track.pan2begin == -101) { + pan2 = pan1; + } else { + pan2 = _vm->_rnd.getRandomNumberRng(track.pan2begin, track.pan2end); + } + + track.volume = _vm->_rnd.getRandomNumberRng(track.volume1, track.volume2); + + track.audio_player_track = _vm->_audioPlayer->playAud( + track.name, + track.volume * _ambientVolume / 100, + pan1, pan2, + track.priority, + AudioPlayer::OVERRIDE_VOLUME + ); + + track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.time1, track.time2); + + } +} + +int AmbientSounds::findAvailableNonLoopingTrack() { + for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) { + if (!_nonLoopingSounds[i].isActive) + return i; + } + + return -1; +} + +int AmbientSounds::findNonLoopingTrackByHash(int32 hash) { + for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) { + NonLoopingSound &track = _nonLoopingSounds[i]; + + if (track.isActive && track.hash == hash) + return i; + } + + return -1; +} + +int AmbientSounds::findAvailableLoopingTrack() { + for (int i = 0; i != LOOPING_SOUNDS; ++i) { + if (!_loopingSounds[i].isActive) + return i; + } + + return -1; +} + +int AmbientSounds::findLoopingTrackByHash(int32 hash) { + for (int i = 0; i != LOOPING_SOUNDS; ++i) { + LoopingSound &track = _loopingSounds[i]; + + if (track.isActive && track.hash == hash) + return i; + } + + return -1; +} + +void AmbientSounds::addSoundByName( + const char *name, + int timeRangeBegin, int timeRangeEnd, + int volumeRangeBegin, int volumeRangeEnd, + int pan1begin, int pan1end, + int pan2begin, int pan2end, + int priority, int unk3) +{ + int i = findAvailableNonLoopingTrack(); + if (i < 0) + return; + + NonLoopingSound &track = _nonLoopingSounds[i]; + + uint32 now = g_system->getMillis(); + + track.isActive = true; + strcpy(track.name, name); + track.hash = mix_id(name); + track.time1 = 1000 * timeRangeBegin; + track.time2 = 1000 * timeRangeEnd; + track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.time1, track.time2); + track.volume1 = volumeRangeBegin; + track.volume2 = volumeRangeEnd; + track.volume = 0; + track.pan1begin = pan1begin; + track.pan1end = pan1end; + track.pan2begin = pan2begin; + track.pan2end = pan2end; + track.priority = priority; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ambient_sounds.h b/engines/bladerunner/ambient_sounds.h new file mode 100644 index 0000000000..e5428e9f80 --- /dev/null +++ b/engines/bladerunner/ambient_sounds.h @@ -0,0 +1,120 @@ +/* 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_AMBIENT_SOUNDS_H +#define BLADERUNNER_AMBIENT_SOUNDS_H + +#include "audio/audiostream.h" + +namespace BladeRunner { + +class BladeRunnerEngine; + +class AmbientSounds { + BladeRunnerEngine *_vm; + + struct NonLoopingSound { + bool isActive; + char name[13]; + int32 hash; + int32 audio_player_track; + int32 time1; + int32 time2; + uint32 nextPlayTime; + int32 volume1; + int32 volume2; + int32 volume; + int32 pan1begin; + int32 pan1end; + int32 pan2begin; + int32 pan2end; + int32 priority; + }; + + struct LoopingSound { + bool isActive; + char name[13]; + int32 hash; + int32 volume; + }; + + NonLoopingSound *_nonLoopingSounds; + LoopingSound *_loopingSounds; + int _ambientVolume; + +public: + AmbientSounds(BladeRunnerEngine *vm); + ~AmbientSounds(); + + void addSound( + int id, + int timeRangeBegin, int timeRangeEnd, + int volumeRangeBegin, int volumeRangeEnd, + int pan1begin, int pan1end, + int pan2begin, int pan2end, + int priority, int unk3 + ); + // removeSound + // addSpeechSound + // removeSpeechSound + // playSound + // playSpeech + // removeAllNonLoopingSounds + + // addLoopingSound + void addLoopingSound(int sfx_id, int volume, int unk, int fadeInTime); + // adjustLoopingSound + // removeLoopingSound + // removeAllLoopingSounds + + void tick(); + + // setVolume + // getVolume + +private: + int findAvailableNonLoopingTrack(); + int findNonLoopingTrackByHash(int32 hash); + + int findAvailableLoopingTrack(); + int findLoopingTrackByHash(int32 hash); + + // stopNonLoopingTrack + // stopLoopingTrack + + // saveToSaveGame + // initFromSaveGame + // addSoundByName + // playVolumeAdjustSound + + void addSoundByName( + const char *name, + int timeRangeBegin, int timeRangeEnd, + int volumeRangeBegin, int volumeRangeEnd, + int unk1RangeBegin, int unk1RangeEnd, + int unk2RangeBegin, int unk2RangeEnd, + int priority, int unk3); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/archive.cpp b/engines/bladerunner/archive.cpp index 4e355e8a9e..051fcd80c3 100644 --- a/engines/bladerunner/archive.cpp +++ b/engines/bladerunner/archive.cpp @@ -80,7 +80,6 @@ bool MIXArchive::isOpen() const { #define ROL(n) ((n << 1) | ((n >> 31) & 1)) -static int32 mix_id(const Common::String &name) { char buffer[12] = { 0 }; diff --git a/engines/bladerunner/archive.h b/engines/bladerunner/archive.h index 1225c71e18..03eda4ea7f 100644 --- a/engines/bladerunner/archive.h +++ b/engines/bladerunner/archive.h @@ -60,6 +60,8 @@ private: uint32 indexForId(int32 id) const; }; +int32 mix_id(const Common::String &name); + } // End of namespace BladeRunner #endif diff --git a/engines/bladerunner/audio_player.cpp b/engines/bladerunner/audio_player.cpp new file mode 100644 index 0000000000..293fc56fb7 --- /dev/null +++ b/engines/bladerunner/audio_player.cpp @@ -0,0 +1,368 @@ +/* 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 "audio_player.h" + +#include "bladerunner/archive.h" +#include "bladerunner/aud_decoder.h" + +#include "bladerunner/bladerunner.h" + +#include "audio/audiostream.h" +#include "audio/mixer.h" + +#include "common/array.h" +#include "common/debug.h" +#include "common/mutex.h" +#include "common/stream.h" + +namespace Common { + class MemoryReadStream; +} + +namespace BladeRunner { + +/* + * This is a poor imitation of Bladerunner's resource cache + */ +class AudioCache { + struct cacheItem { + int32 hash; + int refs; + uint lastAccess; + byte *data; + uint32 size; + }; + + Common::Mutex _mutex; + Common::Array _cacheItems; + + uint32 _totalSize; + uint32 _maxSize; + uint32 _accessCounter; +public: + AudioCache() : + _totalSize(0), + _maxSize(2457600), + _accessCounter(0) + {} + ~AudioCache(); + + bool canAllocate(uint32 size); + bool dropOldest(); + byte *findByHash(int32 hash); + void storeByHash(int32 hash, Common::SeekableReadStream *stream); + + void incRef(int32 hash); + void decRef(int32 hash); +}; + +AudioCache::~AudioCache() { + for (uint i = 0; i != _cacheItems.size(); ++i) { + free(_cacheItems[i].data); + } +} + +bool AudioCache::canAllocate(uint32 size) { + Common::StackLock lock(_mutex); + + return _maxSize - _totalSize >= size; +} + +bool AudioCache::dropOldest() { + Common::StackLock lock(_mutex); + + if (_cacheItems.size() == 0) + return false; + + uint oldest = 0; + for (uint i = 1; i != _cacheItems.size(); ++i) { + if (_cacheItems[i].refs == 0 && _cacheItems[i].lastAccess < _cacheItems[oldest].lastAccess) + oldest = i; + } + + free(_cacheItems[oldest].data); + _totalSize -= _cacheItems[oldest].size; + _cacheItems.remove_at(oldest); + return true; +} + +byte *AudioCache::findByHash(int32 hash) { + Common::StackLock lock(_mutex); + + for (uint i = 0; i != _cacheItems.size(); ++i) { + if (_cacheItems[i].hash == hash) { + _cacheItems[i].lastAccess = _accessCounter++; + return _cacheItems[i].data; + } + } + + return NULL; +} + +void AudioCache::storeByHash(int32 hash, Common::SeekableReadStream *stream) { + Common::StackLock lock(_mutex); + + uint32 size = stream->size(); + byte *data = (byte*)malloc(size); + stream->read(data, size); + + cacheItem item = { + hash, + 0, + _accessCounter++, + data, + size + }; + + _cacheItems.push_back(item); + _totalSize += size; +} + +void AudioCache::incRef(int32 hash) { + Common::StackLock lock(_mutex); + + for (uint i = 0; i != _cacheItems.size(); ++i) { + if (_cacheItems[i].hash == hash) { + _cacheItems[i].refs++; + return; + } + } + assert(0 && "AudioCache::incRef: hash not found"); +} + +void AudioCache::decRef(int32 hash) { + Common::StackLock lock(_mutex); + + for (uint i = 0; i != _cacheItems.size(); ++i) { + if (_cacheItems[i].hash == hash) { + assert(_cacheItems[i].refs > 0); + _cacheItems[i].refs--; + return; + } + } + assert(0 && "AudioCache::decRef: hash not found"); +} + +class AudStream : public Audio::RewindableAudioStream { + byte *_data; + byte *_p; + byte *_end; + AudioCache *_cache; + int32 _hash; + byte _compressionType; + uint16 _deafBlockRemain; + + ADPCMWestwoodDecoder _decoder; + +public: + AudStream(AudioCache *cache, int32 hash) + : _cache(cache), _hash(hash) + { + _data = _cache->findByHash(_hash); + _end = _data + READ_LE_UINT32(_data + 2) + 12; + _cache->incRef(_hash); + + assert(_end - _data >= 12); + + _compressionType = *(_data + 11); + + _deafBlockRemain = 0; + _p = _data + 12; + } + ~AudStream() { + _cache->decRef(_hash); + } + + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return false; } + int getRate() const { return READ_LE_UINT16(_data); }; + bool endOfData() const { return _p == _end; } + bool rewind(); +}; + +int AudStream::readBuffer(int16 *buffer, const int numSamples) { + int samplesRead = 0; + + assert(numSamples % 2 == 0); + + if (_compressionType == 99) { + while (samplesRead < numSamples) { + if (_deafBlockRemain == 0) { + if (_end - _p == 0) + break; + + assert(_end - _p >= 6); + + uint16 blockSize = READ_LE_UINT16(_p); + uint16 blockOutSize = READ_LE_UINT16(_p + 2); + uint32 sig = READ_LE_UINT32(_p + 4); + _p += 8; + + assert(sig == 0xdeaf); + assert(_end - _p >= blockSize); + assert(blockOutSize = 4 * blockSize); + + _deafBlockRemain = blockSize; + } + + assert(_end - _p >= _deafBlockRemain); + + int bytesConsumed = MIN(_deafBlockRemain, (numSamples - samplesRead) / 2); + + _decoder.decode(_p, bytesConsumed, buffer + samplesRead); + _p += bytesConsumed; + _deafBlockRemain -= bytesConsumed; + + samplesRead += 2 * bytesConsumed; + } + } else { + assert(0 && "readBuffer: Unimplemented"); + } + + return samplesRead; +} + +bool AudStream::rewind() { + _p = _data + 12; + _decoder.setParameters(0, 0); + return true; +} + +AudioPlayer::AudioPlayer(BladeRunnerEngine *vm) + : _vm(vm) +{ + _cache = new AudioCache(); + + for (int i = 0; i != 6; ++i) { + _tracks[i].hash = 0; + _tracks[i].priority = 0; + } +} + +AudioPlayer::~AudioPlayer() { + delete _cache; +} + +bool AudioPlayer::isTrackActive(Track *track) +{ + if (!track->isMaybeActive) + return false; + + return track->isMaybeActive = _vm->_mixer->isSoundHandleActive(track->soundHandle); +} + +void AudioPlayer::stopAll() +{ + for (int i = 0; i != TRACKS; ++i) { + _vm->_mixer->stopHandle(_tracks[i].soundHandle); + } +} + +void AudioPlayer::fadeAndStopTrack(Track *track, int time) +{ + (void)time; + + _vm->_mixer->stopHandle(track->soundHandle); +} + +int AudioPlayer::playAud(const Common::String &name, int volume, int panFrom, int panTo, int priority, byte flags) { + /* Find first available track or, alternatively, the lowest priority playing track */ + int trackId; + Track *track = NULL; + int lowestPriority = 100; + Track *lowestPriorityTrack = NULL; + + for (int i = 0; i != 6; ++i) { + track = &_tracks[i]; + if (!isTrackActive(track)) { + trackId = 1; + break; + } + + if (track->priority < lowestPriority) { + lowestPriority = track->priority; + lowestPriorityTrack = track; + } + } + + /* If there's no available track, stop the lowest priority track if it's lower than + * the new priority + */ + if (track == NULL && lowestPriority < priority) { + fadeAndStopTrack(lowestPriorityTrack, 1); + track = lowestPriorityTrack; + } + + /* If there's still no available track, give up */ + if (track == NULL) + return -1; + + /* Load audio resource and store in cache. Playback will happen directly from there. */ + int32 hash = mix_id(name); + if (!_cache->findByHash(hash)) { + Common::SeekableReadStream *r = _vm->getResourceStream(name); + if (!r) + return -1; + + int32 size = r->size(); + while (!_cache->canAllocate(size)) { + if (!_cache->dropOldest()) { + delete r; + return -1; + } + } + _cache->storeByHash(hash, r); + delete r; + } + + AudStream *audStream = new AudStream(_cache, hash); + + Audio::AudioStream *audioStream = audStream; + if (flags & LOOP) { + audioStream = new Audio::LoopingAudioStream(audStream, 0, DisposeAfterUse::YES); + } + + Audio::SoundHandle soundHandle; + + debug("PlayStream: %s", name.c_str()); + + int balance = panFrom; + + _vm->_mixer->playStream( + Audio::Mixer::kPlainSoundType, + &soundHandle, + audioStream, + -1, + volume * 255 / 100, + balance); + + track->isMaybeActive = true; + track->soundHandle = soundHandle; + track->priority = priority; + track->hash = hash; + track->volume = volume; + + return trackId; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/audio_player.h b/engines/bladerunner/audio_player.h new file mode 100644 index 0000000000..32c7dbb2d8 --- /dev/null +++ b/engines/bladerunner/audio_player.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_AUDIO_H +#define BLADERUNNER_AUDIO_H + +#include "audio/mixer.h" +#include "common/str.h" +#include "common/types.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class AudioCache; + +#define TRACKS 6 + +class AudioPlayer { + BladeRunnerEngine *_vm; + AudioCache *_cache; + + struct Track { + bool isMaybeActive; + Audio::SoundHandle soundHandle; + int priority; + int32 hash; + int volume; + + Track() + : isMaybeActive(false) + {} + }; + + Track _tracks[TRACKS]; + + bool isTrackActive(Track *track); + void fadeAndStopTrack(Track *track, int time); + +public: + AudioPlayer(BladeRunnerEngine *vm); + ~AudioPlayer(); + + enum { + LOOP = 1, + OVERRIDE_VOLUME = 2 + }; + + int playAud(const Common::String &name, int volume, int panFrom, int panTo, int priority, byte flags = 0); + + void stopAll(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 7da46f1f0e..c1c65742dd 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -1,3 +1,4 @@ + /* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names @@ -22,8 +23,11 @@ #include "bladerunner/bladerunner.h" +#include "bladerunner/ambient_sounds.h" +#include "bladerunner/audio_player.h" #include "bladerunner/chapters.h" #include "bladerunner/gameinfo.h" +#include "bladerunner/gameflags.h" #include "bladerunner/image.h" #include "bladerunner/outtake.h" #include "bladerunner/scene.h" @@ -43,12 +47,19 @@ namespace BladeRunner { -BladeRunnerEngine::BladeRunnerEngine(OSystem *syst) : Engine(syst) { +BladeRunnerEngine::BladeRunnerEngine(OSystem *syst) + : Engine(syst), + _rnd("bladerunner") +{ _windowIsActive = true; _gameIsRunning = true; + _ambientSounds = new AmbientSounds(this); + _audioPlayer = new AudioPlayer(this); _chapters = nullptr; _gameInfo = nullptr; + _gameFlags = new GameFlags(); + _gameVars = nullptr; _scene = new Scene(this); _script = new Script(this); _settings = new Settings(this); @@ -62,8 +73,12 @@ BladeRunnerEngine::~BladeRunnerEngine() { delete _settings; delete _script; delete _scene; + delete _gameVars; + delete _gameFlags; delete _gameInfo; delete _chapters; + delete _audioPlayer; + delete _ambientSounds; _surface1.free(); _surface2.free(); @@ -77,6 +92,8 @@ Common::Error BladeRunnerEngine::run() { Graphics::PixelFormat format = createRGB555(); initGraphics(640, 480, true, &format); + _system->showMouse(true); + if (!startup()) return Common::Error(Common::kUnknownError, "Failed to initialize resources"); @@ -111,6 +128,10 @@ bool BladeRunnerEngine::startup() { if (!r) return false; + _gameFlags->setFlagCount(_gameInfo->getFlagCount()); + + _gameVars = new int[_gameInfo->getGlobalVarCount()]; + _chapters = new Chapters(this); if (!_chapters) return false; @@ -139,6 +160,9 @@ bool BladeRunnerEngine::startup() { if (!r) return false; + _zBuffer1 = new uint16[640 * 480]; + _zBuffer2 = new uint16[640 * 480]; + initChapterAndScene(); return true; @@ -152,6 +176,8 @@ void BladeRunnerEngine::initChapterAndScene() { } void BladeRunnerEngine::shutdown() { + _mixer->stopAll(); + if (_chapters) { if (_chapters->hasOpenResources()) _chapters->closeResources(); @@ -212,15 +238,18 @@ void BladeRunnerEngine::gameTick() { // TODO: Call Script_Player_Walked_In if applicable // TODO: Gun range announcements // TODO: ZBUF repair dirty rects - // TODO: Tick Ambient Audio (in Replicant) + + _ambientSounds->tick(); bool backgroundChanged = false; - int frame = _scene->advanceFrame(_surface1); + int frame = _scene->advanceFrame(_surface1, _zBuffer1); if (frame >= 0) { _script->SceneFrameAdvanced(frame); backgroundChanged = true; } + (void)backgroundChanged; _surface2.copyFrom(_surface1); + memcpy(_zBuffer2, _zBuffer1, 640*480*2); // TODO: Render overlays (mostly in Replicant) // TODO: Tick Actor AI and Timers (timers in Replicant) @@ -230,13 +259,13 @@ void BladeRunnerEngine::gameTick() { // TODO: Tick and draw all actors in current set (drawing works in Replicant) // Hardcode McCoy in place to test the slice renderer - Vector3 pos(-151.98f, -0.30f, 318.15f); + Vector3 pos = _scene->_actorStartPosition; Vector3 draw_pos(pos.x, -pos.z, pos.y + 2); float facing = -1.570796f; _sliceRenderer->setView(_scene->_view); _sliceRenderer->setupFrame(19, 1, draw_pos, facing); - _sliceRenderer->drawFrame(_surface2); + _sliceRenderer->drawFrame(_surface2, _zBuffer2); // TODO: Draw items (drawing works in Replicant) // TODO: Draw item pickup (understood, drawing works in Replicant) @@ -264,7 +293,7 @@ void BladeRunnerEngine::outtakePlay(int id, bool noLocalization, int container) OuttakePlayer player(this); - player.play(name, noLocalization, -1); + player.play(name, noLocalization, container); } bool BladeRunnerEngine::openArchive(const Common::String &name) { diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index c3f7eac4d7..5ef23108f4 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -26,6 +26,7 @@ #include "bladerunner/archive.h" #include "common/array.h" +#include "common/random.h" #include "common/stream.h" #include "common/types.h" @@ -35,8 +36,11 @@ namespace BladeRunner { +class AmbientSounds; +class AudioPlayer; class Chapters; class GameInfo; +class GameFlags; class Scene; class Script; class Settings; @@ -48,18 +52,26 @@ public: bool _gameIsRunning; bool _windowIsActive; + AmbientSounds *_ambientSounds; + AudioPlayer *_audioPlayer; Chapters *_chapters; GameInfo *_gameInfo; + GameFlags *_gameFlags; Scene *_scene; Script *_script; Settings *_settings; SliceAnimations *_sliceAnimations; SliceRenderer *_sliceRenderer; + int *_gameVars; int in_script_counter; - Graphics::Surface _surface1; - Graphics::Surface _surface2; + Graphics::Surface _surface1; + Graphics::Surface _surface2; + uint16 *_zBuffer1; + uint16 *_zBuffer2; + + Common::RandomSource _rnd; private: static const int kArchiveCount = 10; diff --git a/engines/bladerunner/gameflags.cpp b/engines/bladerunner/gameflags.cpp new file mode 100644 index 0000000000..3704271e04 --- /dev/null +++ b/engines/bladerunner/gameflags.cpp @@ -0,0 +1,68 @@ +/* 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/gameflags.h" + +#include "common/debug.h" + +namespace BladeRunner { + +GameFlags::GameFlags() + : flags(NULL), flagCount(0) +{ +} + +GameFlags::~GameFlags() { + delete[] flags; +} + +void GameFlags::setFlagCount(int count) { + assert(count > 0); + + debug("flagCount: %d", count); + + flagCount = count; + flags = new uint32[count / 32 + 1]; + + for (int i = 0; i <= flagCount; ++i) + reset(i); +} + +void GameFlags::set(int flag) { + assert(flag >= 0 && flag <= flagCount); + + flags[flag / 32] |= (1 << (flag % 32)); +} + +void GameFlags::reset(int flag) { + assert(flag >= 0 && flag <= flagCount); + + flags[flag / 32] &= ~(1 << (flag % 32)); +} + +bool GameFlags::query(int flag) { + assert(flag >= 0 && flag <= flagCount); + + return !!(flags[flag / 32] & (1 << (flag % 32))); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/gameflags.h b/engines/bladerunner/gameflags.h new file mode 100644 index 0000000000..4df9e5aa80 --- /dev/null +++ b/engines/bladerunner/gameflags.h @@ -0,0 +1,47 @@ +/* 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_GAMEFLAGS_H +#define BLADERUNNER_GAMEFLAGS_H + +#include + +namespace BladeRunner { + +class GameFlags { + uint32 *flags; + int flagCount; + +public: + GameFlags(); + ~GameFlags(); + + void setFlagCount(int count); + + void set(int flag); + void reset(int flag); + bool query(int flag); +}; + +} // End of namespace BladeRunner + +#endif \ No newline at end of file diff --git a/engines/bladerunner/gameinfo.cpp b/engines/bladerunner/gameinfo.cpp index 712d5484c9..15058c8697 100644 --- a/engines/bladerunner/gameinfo.cpp +++ b/engines/bladerunner/gameinfo.cpp @@ -53,7 +53,7 @@ bool GameInfo::open(const Common::String &name) { uint32 unk; _actor_count = s->readUint32LE(); /* 00 */ - unk = s->readUint32LE(); /* 01 */ + _player_id = s->readUint32LE(); /* 01 */ _flag_count = s->readUint32LE(); /* 02 */ unk = s->readUint32LE(); /* 03 */ _global_var_count = s->readUint32LE(); /* 04 */ diff --git a/engines/bladerunner/gameinfo.h b/engines/bladerunner/gameinfo.h index 094d157949..8c8202b746 100644 --- a/engines/bladerunner/gameinfo.h +++ b/engines/bladerunner/gameinfo.h @@ -35,6 +35,7 @@ class GameInfo { BladeRunnerEngine *_vm; uint32 _actor_count; + uint32 _player_id; uint32 _flag_count; uint32 _global_var_count; uint32 _set_names_count; @@ -59,6 +60,7 @@ public: bool open(const Common::String &name); uint32 getActorCount() { return _actor_count; } + uint32 getPlayerId() { return _player_id; } uint32 getFlagCount() { return _flag_count; } uint32 getGlobalVarCount() { return _global_var_count; } uint32 getSetNamesCount() { return _set_names_count; } @@ -71,10 +73,10 @@ public: uint32 getCoverWaypointCount() { return _cover_waypoint_count; } uint32 getFleeWaypointCount() { return _flee_waypoint_count; } - char *getSetName(int i) { return _set_names[i]; } - char *getSfxTrack(int i) { return _sfx_tracks[i]; } - char *getMusicTrack(int i) { return _music_tracks[i]; } - char *getOuttake(int i) { return _outtakes[i]; } + const char *getSetName(int i) { return _set_names[i]; } + const char *getSfxTrack(int i) { return _sfx_tracks[i]; } + const char *getMusicTrack(int i) { return _music_tracks[i]; } + const char *getOuttake(int i) { return _outtakes[i]; } }; } // End of namespace BladeRunner diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index 37ba70bd51..080eda93f8 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -1,13 +1,16 @@ MODULE := engines/bladerunner MODULE_OBJS = \ + ambient_sounds.o \ archive.o \ aud_decoder.o \ + audio_player.o \ bladerunner.o \ chapters.o \ decompress_lcw.o \ decompress_lzo.o \ detection.o \ + gameflags.o \ gameinfo.o \ image.o \ matrix.o \ diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp index 2f357e2860..8a5870d64f 100644 --- a/engines/bladerunner/scene.cpp +++ b/engines/bladerunner/scene.cpp @@ -101,13 +101,19 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) { return true; } -int Scene::advanceFrame(Graphics::Surface &surface) { +int Scene::advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer) { int frame = _vqaPlayer.update(); if (frame >= 0) { surface.copyFrom(*_vqaPlayer.getSurface()); + memcpy(zBuffer, _vqaPlayer.getZBuffer(), 640*480*2); _view = _vqaPlayer.getView(); } return frame; } +void Scene::setActorStart(Vector3 position, int facing) { + _actorStartPosition = position; + _actorStartFacing = facing; +} + } // End of namespace BladeRunner diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h index d7904f2190..5856e0b0d3 100644 --- a/engines/bladerunner/scene.h +++ b/engines/bladerunner/scene.h @@ -41,6 +41,8 @@ public: int _nextSetId; int _nextSceneId; int _frame; + Vector3 _actorStartPosition; + int _actorStartFacing; bool _playerWalkedIn; View _view; @@ -58,7 +60,8 @@ public: } bool open(int setId, int sceneId, bool isLoadingGame); - int advanceFrame(Graphics::Surface &surface); + int advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer); + void setActorStart(Vector3 position, int facing); }; } // End of namespace BladeRunner diff --git a/engines/bladerunner/script/rc01.cpp b/engines/bladerunner/script/rc01.cpp index 560eb24742..2fa577856f 100644 --- a/engines/bladerunner/script/rc01.cpp +++ b/engines/bladerunner/script/rc01.cpp @@ -22,35 +22,99 @@ #include "bladerunner/script/script.h" +#include "bladerunner/ambient_sounds.h" +#include "bladerunner/audio_player.h" #include "bladerunner/bladerunner.h" namespace BladeRunner { void ScriptRC01::InitializeScene() { - _vm->outtakePlay(28, true); - _vm->outtakePlay(41, true); - _vm->outtakePlay( 0, false); - - _vm->ISez("Blade Runner"); - _vm->ISez(""); - _vm->ISez("From the dark recesses of David Leary's imagination comes a game unlike any"); - _vm->ISez("other. Blade Runner immerses you in the underbelly of future Los Angeles. Right"); - _vm->ISez("from the start, the story pulls you in with graphic descriptions of a"); - _vm->ISez("grandmother doing the shimmy in her underwear, child molestation, brutal"); - _vm->ISez("cold-blooded slaying of innocent animals, vomiting on desks, staring at a"); - _vm->ISez("woman's ass, the list goes on. And when the game starts, the real fun begins -"); - _vm->ISez("shoot down-on-their-luck homeless people and toss them into a dumpster. Watch"); - _vm->ISez("with sadistic glee as a dog gets blown into chunky, bloody, bits by an"); - _vm->ISez("explosive, and even murder a shy little girl who loves you. If you think David"); - _vm->ISez("Leary is sick, and you like sick, this is THE game for you."); - _vm->ISez(""); - _vm->ISez("JW: Don't forget the wasting of helpless mutated cripples in the underground."); - _vm->ISez("It's such a beautiful thing!"); - _vm->ISez(""); - _vm->ISez("DL: Go ahead. Just keep beating that snarling pit bull...ignore the foam"); - _vm->ISez("around his jaws. There's room on the top shelf of my fridge for at least one"); - _vm->ISez("more head... - Psychotic Dave"); - _vm->ISez(""); + if (!Game_Flag_Query(24)) { + Ambient_Sounds_Remove_All_Non_Looping_Sounds(1); + Ambient_Sounds_Remove_All_Looping_Sounds(1); + Outtake_Play(28, 1); // WSTLGO_E.VQA + Outtake_Play(41, 1); // BRLOGO_E.VQA + Outtake_Play( 0, 0); // INTRO_E.VQA + Outtake_Play(33, 1); // DSCENT_E.VQA + } + + Game_Flag_Set(9); // Force flag 9 so McCoy will be in view + if (Game_Flag_Query(9)) { + Setup_Scene_Information(-171.16, 5.55, 27.28, 616); + } else if (Game_Flag_Query(114)) { + Setup_Scene_Information(-471.98, -0.30, 258.15, 616); + } else { + Setup_Scene_Information( -10.98, -0.30, 318.15, 616); + } + + Scene_Exit_Add_2D_Exit(0, 314, 145, 340, 255, 0); + if (Game_Flag_Query(249)) + Scene_Exit_Add_2D_Exit(1, 482, 226, 639, 280, 2); + if (Global_Variable_Query(1) > 1 && Game_Flag_Query(710)) + Scene_Exit_Add_2D_Exit(2, 0, 0, 10, 479, 3); + if (!Game_Flag_Query(186)) + Scene_2D_Region_Add(0, 0, 294, 296, 479); + + Ambient_Sounds_Remove_All_Non_Looping_Sounds(0); + Ambient_Sounds_Add_Looping_Sound(54, 30, 0, 1); // CTRAIN1.AUD + + if (!Game_Flag_Query(186)) { + Ambient_Sounds_Add_Sound(181, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0470R.AUD + Ambient_Sounds_Add_Sound(182, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0480R.AUD + Ambient_Sounds_Add_Sound(183, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0500R.AUD + Ambient_Sounds_Add_Sound(184, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0540R.AUD + Ambient_Sounds_Add_Sound(185, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0560R.AUD + Ambient_Sounds_Add_Sound(186, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0870R.AUD + Ambient_Sounds_Add_Sound(188, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0900R.AUD + Ambient_Sounds_Add_Sound(189, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0940R.AUD + Ambient_Sounds_Add_Sound(190, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0960R.AUD + Ambient_Sounds_Add_Sound(191, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1070R.AUD + Ambient_Sounds_Add_Sound(192, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1080R.AUD + Ambient_Sounds_Add_Sound(193, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1100R.AUD + Ambient_Sounds_Add_Sound(194, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1140R.AUD + Ambient_Sounds_Add_Sound(195, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1160R.AUD + } + + Ambient_Sounds_Add_Looping_Sound(81, 60, 100, 1); // RCAMBR1.AUD + Ambient_Sounds_Add_Sound(82, 5, 30, 30, 50, -100, 100, -101, -101, 0, 0); // RCCARBY1.AUD + Ambient_Sounds_Add_Sound(83, 5, 30, 30, 55, -100, 100, -101, -101, 0, 0); // RCCARBY2.AUD + Ambient_Sounds_Add_Sound(84, 5, 30, 30, 50, -100, 100, -101, -101, 0, 0); // RCCARBY3.AUD + Ambient_Sounds_Add_Sound(67, 10, 50, 30, 50, -100, 100, -101, -101, 0, 0); // SPIN2A.AUD + Ambient_Sounds_Add_Sound(87, 20, 80, 20, 40, -100, 100, -101, -101, 0, 0); // SIREN2.AUD + + if (Game_Flag_Query(186)) { + if (!Game_Flag_Query(9) && !Game_Flag_Query(114)) + Scene_Loop_Start_Special(0, 5, 0); + if (Game_Flag_Query(249)) + Scene_Loop_Set_Default(6); + else + Scene_Loop_Set_Default(10); + } else { + if (!Game_Flag_Query(9) && !Game_Flag_Query(114)) + Scene_Loop_Start_Special(0, 0, 0); + Scene_Loop_Set_Default(1); + } + + I_Sez("Blade Runner"); + I_Sez(""); + I_Sez("From the dark recesses of David Leary's imagination comes a game unlike any"); + I_Sez("other. Blade Runner immerses you in the underbelly of future Los Angeles. Right"); + I_Sez("from the start, the story pulls you in with graphic descriptions of a"); + I_Sez("grandmother doing the shimmy in her underwear, child molestation, brutal"); + I_Sez("cold-blooded slaying of innocent animals, vomiting on desks, staring at a"); + I_Sez("woman's ass, the list goes on. And when the game starts, the real fun begins -"); + I_Sez("shoot down-on-their-luck homeless people and toss them into a dumpster. Watch"); + I_Sez("with sadistic glee as a dog gets blown into chunky, bloody, bits by an"); + I_Sez("explosive, and even murder a shy little girl who loves you. If you think David"); + I_Sez("Leary is sick, and you like sick, this is THE game for you."); + I_Sez(""); + I_Sez("JW: Don't forget the wasting of helpless mutated cripples in the underground."); + I_Sez("It's such a beautiful thing!"); + I_Sez(""); + I_Sez("DL: Go ahead. Just keep beating that snarling pit bull...ignore the foam"); + I_Sez("around his jaws. There's room on the top shelf of my fridge for at least one"); + I_Sez("more head... - Psychotic Dave"); + I_Sez(""); } void ScriptRC01::SceneLoaded() { @@ -58,7 +122,26 @@ void ScriptRC01::SceneLoaded() { } void ScriptRC01::SceneFrameAdvanced(int frame) { + if (frame == 1) + Sound_Play(118, 40, 0, 0, 50); // CARDOWN3.AUD + + if (frame == 61 || frame == 362) + Sound_Play(116, 100, 80, 80, 50); // SPINOPN4.AUD + + if (frame == 108 || frame == 409) + Sound_Play(119, 100, 80, 80, 50); // SPINCLS1.AUD + + if (frame == 183 || frame == 484) + Sound_Play(116, 100, 80, 80, 50); // SPINOPN4.AUD + + if (frame == 228 || frame == 523) + Sound_Play(119, 100, 80, 80, 50); // SPINCLS1.AUD + + if (frame == 243 || frame == 545) + Sound_Play(117, 40, 80, 80, 50); // CARUP3.AUD + if (frame == 315) + Sound_Play(118, 40, 80, 80, 50); // CARDOWN3.AUD } } // End of namespace BladeRunner diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp index 540d4313c7..9aca48fcf6 100644 --- a/engines/bladerunner/script/script.cpp +++ b/engines/bladerunner/script/script.cpp @@ -24,6 +24,13 @@ #include "bladerunner/bladerunner.h" +#include "bladerunner/ambient_sounds.h" +#include "bladerunner/audio_player.h" +#include "bladerunner/gameinfo.h" +#include "bladerunner/gameflags.h" +#include "bladerunner/scene.h" +#include "bladerunner/vector.h" + namespace BladeRunner { bool Script::open(const Common::String &name) { @@ -56,4 +63,86 @@ void Script::SceneFrameAdvanced(int frame) { _inScriptCounter--; } +void ScriptBase::Game_Flag_Set(int flag) { + _vm->_gameFlags->set(flag); +} + +void ScriptBase::Game_Flag_Reset(int flag) { + _vm->_gameFlags->reset(flag); +} + +bool ScriptBase::Game_Flag_Query(int flag) { + return _vm->_gameFlags->query(flag); +} + +int ScriptBase::Global_Variable_Set(int var, int value) { + return _vm->_gameVars[var] = value; +} + +int ScriptBase::Global_Variable_Reset(int var) { + return _vm->_gameVars[var] = 0; +} + +int ScriptBase::Global_Variable_Query(int var) { + return _vm->_gameVars[var]; +} + +int ScriptBase::Global_Variable_Increment(int var, int inc) { + return _vm->_gameVars[var] += inc; +} + +int ScriptBase::Global_Variable_Decrement(int var, int dec) { + return _vm->_gameVars[var] -= dec; +} + +void ScriptBase::Sound_Play(int id, int volume, int panFrom, int panTo, int priority) { + const char *name = _vm->_gameInfo->getSfxTrack(id); + _vm->_audioPlayer->playAud(name, volume, panFrom, panTo, priority); +} + +void ScriptBase::Scene_Loop_Set_Default(int a) { + debug("Scene_Loop_Set_Default(%d)", a); +} + +void ScriptBase::Scene_Loop_Start_Special(int a, int b, int c) { + debug("Scene_Loop_Start_Special(%d, %d, %d)", a, b, c); +} + +void ScriptBase::Outtake_Play(int id, int noLocalization, int container) { + _vm->outtakePlay(id, noLocalization, container); +} + +void ScriptBase::Ambient_Sounds_Add_Sound(int id, int time1, int time2, int volume1, int volume2, int pan1begin, int pan1end, int pan2begin, int pan2end, int priority, int unk) { + _vm->_ambientSounds->addSound(id, time1, time2, volume1, volume2, pan1begin, pan1end, pan2begin, pan2end, priority, unk); +} + +void ScriptBase::Ambient_Sounds_Remove_All_Non_Looping_Sounds(int time) { + // _vm->_ambientSounds->removeAllNonLoopingSounds(time); +} + +void ScriptBase::Ambient_Sounds_Add_Looping_Sound(int id, int volume, int pan, int fadeInTime) { + _vm->_ambientSounds->addLoopingSound(id, volume, pan, fadeInTime); +} + +void ScriptBase::Ambient_Sounds_Remove_All_Looping_Sounds(int time) { + // _vm->_ambientSounds->removeAllLoopingSounds(time); +} + +void ScriptBase::Setup_Scene_Information(float actorX, float actorY, float actorZ, int actorFacing) { + _vm->_scene->setActorStart(Vector3(actorX, actorY, actorZ), actorFacing); +} + +void ScriptBase::Scene_Exit_Add_2D_Exit(int a, int b, int c, int d, int e, int f) { + debug("Scene_Exit_Add_2D_Exit(%d, %d, %d, %d, %d, %d)", a, b, c, d, e, f); +} + +void ScriptBase::Scene_2D_Region_Add(int a, int b, int c, int d, int e) { + debug("Scene_2D_Region_Add(%d, %d, %d, %d, %d)", a, b, c, d, e); +} + +void ScriptBase::I_Sez(const char *str) { + _vm->ISez(str); +} + + } // End of namespace BladeRunner diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h index 83fd78dc39..e8bf1c029e 100644 --- a/engines/bladerunner/script/script.h +++ b/engines/bladerunner/script/script.h @@ -65,6 +65,42 @@ public: virtual void InitializeScene() = 0; virtual void SceneLoaded() = 0; virtual void SceneFrameAdvanced(int frame) = 0; + +protected: + + void Game_Flag_Set(int flag); + void Game_Flag_Reset(int flag); + bool Game_Flag_Query(int flag); + + int Global_Variable_Set(int, int); + int Global_Variable_Reset(int); + int Global_Variable_Query(int); + int Global_Variable_Increment(int, int); + int Global_Variable_Decrement(int, int); + + void Sound_Play(int id, int volume, int panFrom, int panTo, int priority); + + void Scene_Loop_Set_Default(int); + void Scene_Loop_Start_Special(int, int, int); + + void Outtake_Play(int id, int noLocalization = false, int container = -1); + void Ambient_Sounds_Add_Sound(int id, int time1, int time2, int volume1, int volume2, int pan1begin, int pan1end, int pan2begin, int pan2end, int priority, int unk); + // Ambient_Sounds_Remove_Sound + // Ambient_Sounds_Add_Speech_Sound + // Ambient_Sounds_Remove_Speech_Sound + // Ambient_Sounds_Play_Sound + // Ambient_Sounds_Play_Speech_Sound + void Ambient_Sounds_Remove_All_Non_Looping_Sounds(int time); + void Ambient_Sounds_Add_Looping_Sound(int id, int volume, int pan, int fadeInTime); + // Ambient_Sounds_Adjust_Looping_Sound + // Ambient_Sounds_Remove_Looping_Sound + void Ambient_Sounds_Remove_All_Looping_Sounds(int time); + void Setup_Scene_Information(float actorX, float actorY, float actorZ, int actorFacing); + + void Scene_Exit_Add_2D_Exit(int, int, int, int, int, int); + void Scene_2D_Region_Add(int, int, int, int, int); + + void I_Sez(const char *str); }; #define DECLARE_SCRIPT(name) \ diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp index e8e3ecf894..4e2300ec7f 100644 --- a/engines/bladerunner/slice_renderer.cpp +++ b/engines/bladerunner/slice_renderer.cpp @@ -322,7 +322,7 @@ void setupLookupTable(int t[256], int inc) { } } -void SliceRenderer::drawFrame(Graphics::Surface &surface) { +void SliceRenderer::drawFrame(Graphics::Surface &surface, uint16 *zbuffer) { assert(_sliceFramePtr); SliceLineIterator sliceLineIterator; @@ -340,7 +340,8 @@ void SliceRenderer::drawFrame(Graphics::Surface &surface) { int frameY = sliceLineIterator._field_18; - uint16 *frameLinePtr = (uint16*)surface.getPixels() + 640 * frameY; + uint16 *frameLinePtr = (uint16*)surface.getPixels() + 640 * frameY; + uint16 *zBufferLinePtr = zbuffer + 640 * frameY; while (sliceLineIterator._field_3C <= sliceLineIterator._field_1C) { _c3 = sliceLineIterator._field_00[0][2]; @@ -349,16 +350,17 @@ void SliceRenderer::drawFrame(Graphics::Surface &surface) { float sliceLine = sliceLineIterator.line(); if (frameY >= 0 && frameY < 480) - drawSlice((int)sliceLine, frameLinePtr); + drawSlice((int)sliceLine, frameLinePtr, zBufferLinePtr); sliceLineIterator.advance(); frameY += 1; frameLinePtr += 640; + zBufferLinePtr += 640; } } -void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) { - if (slice < 0 || slice >= _frameSliceCount) +void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr, uint16 *zbufLinePtr) { + if (slice < 0 || (uint32)slice >= _frameSliceCount) return; SlicePalette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex); @@ -371,11 +373,6 @@ void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) { uint32 polyCount = READ_LE_UINT32(p); p += 4; - - int zbufLinePtr[640]; - for (int i = 0; i != 640; ++i) - zbufLinePtr[i] = 65535; - while (polyCount--) { uint32 vertexCount = READ_LE_UINT32(p); p += 4; @@ -396,9 +393,10 @@ void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) { if (vertexZ >= 0 && vertexZ < 65536) { for (int x = previousVertexX; x != vertexX; ++x) { + // debug("\t%04x < %04x", vertexZ, zbufLinePtr[x]); if (vertexZ < zbufLinePtr[x]) { frameLinePtr[x] = palette[p[2]]; - zbufLinePtr[x] = (int16)vertexZ; + zbufLinePtr[x] = (uint16)vertexZ; } } } diff --git a/engines/bladerunner/slice_renderer.h b/engines/bladerunner/slice_renderer.h index 2e0fe93d77..79ebdd8951 100644 --- a/engines/bladerunner/slice_renderer.h +++ b/engines/bladerunner/slice_renderer.h @@ -76,7 +76,7 @@ class SliceRenderer { int _c6; Matrix3x2 calculateFacingRotationMatrix(); - void drawSlice(int slice, uint16 *frameLinePtr); + void drawSlice(int slice, uint16 *frameLinePtr, uint16 *zbufLinePtr); public: SliceRenderer(BladeRunnerEngine *vm) @@ -88,7 +88,7 @@ public: void setupFrame(int animation, int frame, Vector3 position, float facing, float scale = 1.0f); void calculateBoundingRect(); - void drawFrame(Graphics::Surface &surface); + void drawFrame(Graphics::Surface &surface, uint16 *zbuffer); }; } // End of namespace BladeRunner diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp index f5b8c80037..5c08284f40 100644 --- a/engines/bladerunner/vqa_decoder.cpp +++ b/engines/bladerunner/vqa_decoder.cpp @@ -196,6 +196,10 @@ const Graphics::Surface *VQADecoder::decodeVideoFrame() { return _videoTrack->decodeVideoFrame(); } +const uint16 *VQADecoder::decodeZBuffer() { + return _videoTrack->decodeZBuffer(); +} + Audio::SeekableAudioStream *VQADecoder::decodeAudioFrame() { return _audioTrack->decodeAudioFrame(); } @@ -295,6 +299,7 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) debug("_header.unk4 %d", _header.unk4); debug("_header.maxCBFZSize %d", _header.maxCBFZSize); debug("_header.unk5 %d", _header.unk5); + debug("\n"); } assert(_header.version == 2); @@ -538,6 +543,7 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) { _maxVPTRSize = header->maxVPTRSize; _maxCBFZSize = header->maxCBFZSize; _maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize; + _zbuffer = nullptr; _codebookSize = 0; _codebook = nullptr; @@ -644,7 +650,7 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s return true; } -#if 0 +#if 1 static int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen) { @@ -654,7 +660,7 @@ int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen) uint16 *curzp = curZBUF; uint16 *inp = (uint16*)src; - while (dstRemain && (inp - (uint16*)src) < (ptrdiff_t)srcLen) + while (dstRemain && (inp - (uint16*)src) < (std::ptrdiff_t)srcLen) { uint32 count = FROM_LE_16(*inp++); @@ -692,9 +698,9 @@ int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen) bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 size) { - s->skip(roundup(size)); - return true; -#if 0 + // s->skip(roundup(size)); + // return true; +#if 1 if (size > _maxZBUFChunkSize) { debug("VQA ERROR: ZBUF chunk size: %08x > %08x", size, _maxZBUFChunkSize); s->skip(roundup(size)); @@ -709,43 +715,47 @@ bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 s uint32 remain = size - 16; - if (width != width || height != height) + if (_width != width || _height != height) { debug("%d, %d, %d, %d", width, height, complete, unk0); s->skip(roundup(remain)); return false; } + _zbufChunkComplete = complete; + _zbufChunkSize = remain; s->read(_zbufChunk, roundup(remain)); - - if (!_zbuf) - { - if (!complete) { - s->skip(roundup(remain)); - return false; - } - _zbuf = new uint16[width * height]; - } - - if (complete) { - size_t zbufOutSize; - decompress_lzo1x(_zbufChunk, remain, (uint8*)_zbuf, &zbufOutSize); - } else { - decodeZBUF_partial(_zbufChunk, _zbuf, remain); - } #endif return true; } -#if 0 -bool VQADecoder::VQAVideoTrack::getZBUF(uint16 *zbuf) +#if 1 +const uint16 *VQADecoder::VQAVideoTrack::decodeZBuffer() { - if (!_zbuf) - return false; + if (_maxZBUFChunkSize == 0) + return nullptr; + + if (!_zbuffer) + _zbuffer = new uint16[_width * _height]; + // { + // if (!complete) { + // return false; + // } + // } + + if (_zbufChunkComplete) { + size_t zbufOutSize; + decompress_lzo1x(_zbufChunk, _zbufChunkSize, (uint8*)_zbuffer, &zbufOutSize); + } else { + decodeZBUF_partial(_zbufChunk, _zbuffer, _zbufChunkSize); + } - memcpy(zbuf, _zbuf, 2 * _header.width * _header.height); - return true; + // if (!_zbuf) + // return false; + + // memcpy(zbuf, _zbuffer, 2 * _width * _height); + return _zbuffer; } #endif diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h index 132c18ace2..8b4293dc7b 100644 --- a/engines/bladerunner/vqa_decoder.h +++ b/engines/bladerunner/vqa_decoder.h @@ -50,6 +50,7 @@ public: void readNextPacket(); const Graphics::Surface *decodeVideoFrame(); + const uint16 *decodeZBuffer(); Audio::SeekableAudioStream *decodeAudioFrame(); const View &getView() { return _videoTrack->getView(); } @@ -161,6 +162,7 @@ private: int getCurFrame() const; int getFrameCount() const; const Graphics::Surface *decodeVideoFrame(); + const uint16 *decodeZBuffer(); const View &getView() { return _view; } bool readVQFR(Common::SeekableReadStream *s, uint32 size); @@ -179,6 +181,7 @@ private: private: Graphics::Surface *_surface; + uint16 *_zbuffer; bool _hasNewFrame; uint16 _numFrames; @@ -195,6 +198,8 @@ private: uint32 _codebookSize; uint8 *_codebook; uint8 *_cbfz; + bool _zbufChunkComplete; + uint32 _zbufChunkSize; uint8 *_zbufChunk; uint32 _vpointerSize; diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp index 2b79ac7eec..8146c1abf9 100644 --- a/engines/bladerunner/vqa_player.cpp +++ b/engines/bladerunner/vqa_player.cpp @@ -64,6 +64,7 @@ int VQAPlayer::update() { if (_hasAudio) queueAudioFrame(_decoder.decodeAudioFrame()); _surface = _decoder.decodeVideoFrame(); + _zBuffer = _decoder.decodeZBuffer(); _view = _decoder.getView(); } @@ -87,6 +88,7 @@ int VQAPlayer::update() { _curFrame = _decodedFrame; if (_curFrame >= 0) { _surface = _decoder.decodeVideoFrame(); + _zBuffer = _decoder.decodeZBuffer(); _view = _decoder.getView(); } @@ -109,6 +111,10 @@ const Graphics::Surface *VQAPlayer::getSurface() const { return _surface; } +const uint16 *VQAPlayer::getZBuffer() const { + return _zBuffer; +} + void VQAPlayer::setLoopSpecial(int loop, bool wait) { _loopSpecial = loop; if (!wait) diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h index 4d87b59dee..80ebf19d2f 100644 --- a/engines/bladerunner/vqa_player.h +++ b/engines/bladerunner/vqa_player.h @@ -39,6 +39,7 @@ class VQAPlayer { Common::SeekableReadStream *_s; VQADecoder _decoder; const Graphics::Surface *_surface; + const uint16 *_zBuffer; Audio::QueuingAudioStream *_audioStream; int _curFrame; @@ -80,6 +81,7 @@ public: int update(); const Graphics::Surface *getSurface() const; + const uint16 *getZBuffer() const; const View &getView() const { return _view; } void setLoopSpecial(int loop, bool wait); -- cgit v1.2.3