diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 62457cae6..03ec412d1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (window); // Create sound system - mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); + mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound)); if (!mSkipMenu) { diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 663f88852..9b5fb1b3d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -34,8 +34,9 @@ namespace MWSound { - SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) + , mFallback(fallbackMap) , mOutput(new DEFAULT_OUTPUT(*this)) , mMasterVolume(1.0f) , mSFXVolume(1.0f) @@ -61,6 +62,13 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); + mNearWaterRadius = mFallback.getFallbackInt("Water_NearWaterRadius"); + mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints"); + mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance"); + mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance"); + mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID"); + mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID"); + mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); mBufferCacheMax *= 1024*1024; @@ -796,6 +804,96 @@ namespace MWSound } } + void SoundManager::updateWaterSound(float /*duration*/) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::ConstPtr player = world->getPlayerPtr(); + osg::Vec3f pos = player.getRefData().getPosition().asVec3(); + + float volume = 0.0f; + const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID; + + if (!mListenerUnderwater) + { + if (player.getCell()->getCell()->hasWater()) + { + float dist = std::abs(player.getCell()->getWaterLevel() - pos.z()); + + if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance) + { + volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance; + + if (mNearWaterPoints > 1) + { + int underwaterPoints = 0; + + float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1); + + for (int x = 0; x < mNearWaterPoints; x++) + { + for (int y = 0; y < mNearWaterPoints; y++) + { + float height = world->getTerrainHeightAt( + osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f)); + + if (height < 0) + underwaterPoints++; + } + } + + volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints); + } + } + else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance) + { + volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance; + } + } + } + else + volume = 1.0f; + + volume = std::min(volume, 1.0f); + + if (mNearWaterSound) + { + if (volume == 0.0f) + { + mOutput->finishSound(mNearWaterSound); + mNearWaterSound.reset(); + } + else + { + bool soundIdChanged = false; + + Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); + + for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + { + for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter) + { + if (pairiter->first == mNearWaterSound) + { + if (pairiter->second != sfx) + soundIdChanged = true; + break; + } + } + } + + if (soundIdChanged) + { + mOutput->finishSound(mNearWaterSound); + mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } + else if (sfx) + mNearWaterSound->setVolume(volume * sfx->mVolume); + } + } + else if (volume > 0.0f) + mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } + void SoundManager::updateSounds(float duration) { static float timePassed = 0.0; @@ -941,6 +1039,7 @@ namespace MWSound { updateSounds(duration); updateRegionSound(duration); + updateWaterSound(duration); } } @@ -1105,6 +1204,7 @@ namespace MWSound mOutput->finishStream(*trkiter); mActiveTracks.clear(); mUnderwaterSound.reset(); + mNearWaterSound.reset(); stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d499dce7d..abf5edb97 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -11,6 +11,8 @@ #include +#include + #include "../mwbase/soundmanager.hpp" namespace VFS @@ -44,6 +46,8 @@ namespace MWSound { const VFS::Manager* mVFS; + Fallback::Map mFallback; + std::auto_ptr mOutput; // Caches available music tracks by @@ -56,6 +60,13 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; + int mNearWaterRadius; + int mNearWaterPoints; + float mNearWaterIndoorTolerance; + float mNearWaterOutdoorTolerance; + std::string mNearWaterIndoorID; + std::string mNearWaterOutdoorID; + typedef std::auto_ptr > SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain @@ -94,6 +105,7 @@ namespace MWSound int mPausedSoundTypes; MWBase::SoundPtr mUnderwaterSound; + MWBase::SoundPtr mNearWaterSound; Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); @@ -108,6 +120,7 @@ namespace MWSound void streamMusicFull(const std::string& filename); void updateSounds(float duration); void updateRegionSound(float duration); + void updateWaterSound(float duration); float volumeFromType(PlayType type) const; @@ -119,7 +132,7 @@ namespace MWSound friend class OpenAL_Output; public: - SoundManager(const VFS::Manager* vfs, bool useSound); + SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound); virtual ~SoundManager(); virtual void processChangedSettings(const Settings::CategorySettingVector& settings);