mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 02:45:32 +00:00
Merge pull request #2946 from elsid/sound_update_water
Put logic to update water sound id and volume into a separate class
This commit is contained in:
commit
acf36344d4
5 changed files with 157 additions and 67 deletions
|
@ -57,7 +57,7 @@ add_openmw_dir (mwscript
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output
|
soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output
|
||||||
loudness movieaudiofactory alext efx efx-presets regionsoundselector
|
loudness movieaudiofactory alext efx efx-presets regionsoundselector watersoundupdater
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwworld
|
add_openmw_dir (mwworld
|
||||||
|
|
|
@ -30,6 +30,23 @@
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
WaterSoundUpdaterSettings makeWaterSoundUpdaterSettings()
|
||||||
|
{
|
||||||
|
WaterSoundUpdaterSettings settings;
|
||||||
|
|
||||||
|
settings.mNearWaterRadius = Fallback::Map::getInt("Water_NearWaterRadius");
|
||||||
|
settings.mNearWaterPoints = Fallback::Map::getInt("Water_NearWaterPoints");
|
||||||
|
settings.mNearWaterIndoorTolerance = Fallback::Map::getFloat("Water_NearWaterIndoorTolerance");
|
||||||
|
settings.mNearWaterOutdoorTolerance = Fallback::Map::getFloat("Water_NearWaterOutdoorTolerance");
|
||||||
|
settings.mNearWaterIndoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterIndoorID"));
|
||||||
|
settings.mNearWaterOutdoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterOutdoorID"));
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For combining PlayMode and Type flags
|
// For combining PlayMode and Type flags
|
||||||
inline int operator|(PlayMode a, Type b) { return static_cast<int>(a) | static_cast<int>(b); }
|
inline int operator|(PlayMode a, Type b) { return static_cast<int>(a) | static_cast<int>(b); }
|
||||||
|
|
||||||
|
@ -41,6 +58,7 @@ namespace MWSound
|
||||||
, mMusicVolume(1.0f)
|
, mMusicVolume(1.0f)
|
||||||
, mVoiceVolume(1.0f)
|
, mVoiceVolume(1.0f)
|
||||||
, mFootstepsVolume(1.0f)
|
, mFootstepsVolume(1.0f)
|
||||||
|
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
|
||||||
, mSoundBuffers(new SoundBufferList::element_type())
|
, mSoundBuffers(new SoundBufferList::element_type())
|
||||||
, mBufferCacheSize(0)
|
, mBufferCacheSize(0)
|
||||||
, mSounds(new std::deque<Sound>())
|
, mSounds(new std::deque<Sound>())
|
||||||
|
@ -65,13 +83,6 @@ namespace MWSound
|
||||||
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
||||||
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
||||||
|
|
||||||
mNearWaterRadius = Fallback::Map::getInt("Water_NearWaterRadius");
|
|
||||||
mNearWaterPoints = Fallback::Map::getInt("Water_NearWaterPoints");
|
|
||||||
mNearWaterIndoorTolerance = Fallback::Map::getFloat("Water_NearWaterIndoorTolerance");
|
|
||||||
mNearWaterOutdoorTolerance = Fallback::Map::getFloat("Water_NearWaterOutdoorTolerance");
|
|
||||||
mNearWaterIndoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterIndoorID"));
|
|
||||||
mNearWaterOutdoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterOutdoorID"));
|
|
||||||
|
|
||||||
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
||||||
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
||||||
mBufferCacheMax *= 1024*1024;
|
mBufferCacheMax *= 1024*1024;
|
||||||
|
@ -912,57 +923,12 @@ namespace MWSound
|
||||||
static const ESM::Cell *LastCell;
|
static const ESM::Cell *LastCell;
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||||
osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
|
||||||
const ESM::Cell *curcell = player.getCell()->getCell();
|
const ESM::Cell *curcell = player.getCell()->getCell();
|
||||||
|
const auto update = mWaterSoundUpdater.update(player, *world);
|
||||||
float volume = 0.0f;
|
|
||||||
const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID;
|
|
||||||
|
|
||||||
if (!mListenerUnderwater)
|
|
||||||
{
|
|
||||||
if (curcell->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 (mNearWaterSound)
|
||||||
{
|
{
|
||||||
if (volume == 0.0f)
|
if (update.mVolume == 0.0f)
|
||||||
{
|
{
|
||||||
mOutput->finishSound(mNearWaterSound);
|
mOutput->finishSound(mNearWaterSound);
|
||||||
mNearWaterSound = nullptr;
|
mNearWaterSound = nullptr;
|
||||||
|
@ -971,7 +937,7 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
bool soundIdChanged = false;
|
bool soundIdChanged = false;
|
||||||
|
|
||||||
Sound_Buffer *sfx = lookupSound(soundId);
|
Sound_Buffer *sfx = lookupSound(update.mId);
|
||||||
if(LastCell != curcell)
|
if(LastCell != curcell)
|
||||||
{
|
{
|
||||||
LastCell = curcell;
|
LastCell = curcell;
|
||||||
|
@ -991,16 +957,16 @@ namespace MWSound
|
||||||
if(soundIdChanged)
|
if(soundIdChanged)
|
||||||
{
|
{
|
||||||
mOutput->finishSound(mNearWaterSound);
|
mOutput->finishSound(mNearWaterSound);
|
||||||
mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop);
|
mNearWaterSound = playSound(update.mId, update.mVolume, 1.0f, Type::Sfx, PlayMode::Loop);
|
||||||
}
|
}
|
||||||
else if (sfx)
|
else if (sfx)
|
||||||
mNearWaterSound->setVolume(volume * sfx->mVolume);
|
mNearWaterSound->setVolume(update.mVolume * sfx->mVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (volume > 0.0f)
|
else if (update.mVolume > 0.0f)
|
||||||
{
|
{
|
||||||
LastCell = curcell;
|
LastCell = curcell;
|
||||||
mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop);
|
mNearWaterSound = playSound(update.mId, update.mVolume, 1.0f, Type::Sfx, PlayMode::Loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1165,7 +1131,7 @@ namespace MWSound
|
||||||
mMusic->updateFade(duration);
|
mMusic->updateFade(duration);
|
||||||
|
|
||||||
mOutput->updateStream(mMusic);
|
mOutput->updateStream(mMusic);
|
||||||
|
|
||||||
if (mMusic->getRealVolume() <= 0.f)
|
if (mMusic->getRealVolume() <= 0.f)
|
||||||
{
|
{
|
||||||
streamMusicFull(mNextMusic);
|
streamMusicFull(mNextMusic);
|
||||||
|
@ -1242,6 +1208,8 @@ namespace MWSound
|
||||||
mListenerUp = up;
|
mListenerUp = up;
|
||||||
|
|
||||||
mListenerUnderwater = underwater;
|
mListenerUnderwater = underwater;
|
||||||
|
|
||||||
|
mWaterSoundUpdater.setUnderwater(underwater);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::updatePtr(const MWWorld::ConstPtr &old, const MWWorld::ConstPtr &updated)
|
void SoundManager::updatePtr(const MWWorld::ConstPtr &old, const MWWorld::ConstPtr &updated)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "regionsoundselector.hpp"
|
#include "regionsoundselector.hpp"
|
||||||
|
#include "watersoundupdater.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
{
|
{
|
||||||
|
@ -61,12 +62,8 @@ namespace MWSound
|
||||||
float mVoiceVolume;
|
float mVoiceVolume;
|
||||||
float mFootstepsVolume;
|
float mFootstepsVolume;
|
||||||
|
|
||||||
int mNearWaterRadius;
|
WaterSoundUpdater mWaterSoundUpdater;
|
||||||
int mNearWaterPoints;
|
|
||||||
float mNearWaterIndoorTolerance;
|
|
||||||
float mNearWaterOutdoorTolerance;
|
|
||||||
std::string mNearWaterIndoorID;
|
|
||||||
std::string mNearWaterOutdoorID;
|
|
||||||
typedef std::unique_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
typedef std::unique_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
||||||
// List of sound buffers, grown as needed. New enties are added to the
|
// List of sound buffers, grown as needed. New enties are added to the
|
||||||
// back, allowing existing Sound_Buffer references/pointers to remain
|
// back, allowing existing Sound_Buffer references/pointers to remain
|
||||||
|
|
71
apps/openmw/mwsound/watersoundupdater.cpp
Normal file
71
apps/openmw/mwsound/watersoundupdater.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "watersoundupdater.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
WaterSoundUpdater::WaterSoundUpdater(const WaterSoundUpdaterSettings& settings)
|
||||||
|
: mSettings(settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WaterSoundUpdate WaterSoundUpdater::update(const MWWorld::ConstPtr& player, const MWBase::World& world) const
|
||||||
|
{
|
||||||
|
WaterSoundUpdate result;
|
||||||
|
|
||||||
|
result.mId = player.getCell()->isExterior() ? mSettings.mNearWaterOutdoorID : mSettings.mNearWaterIndoorID;
|
||||||
|
result.mVolume = std::min(1.0f, getVolume(player, world));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WaterSoundUpdater::getVolume(const MWWorld::ConstPtr& player, const MWBase::World& world) const
|
||||||
|
{
|
||||||
|
if (mListenerUnderwater)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
const MWWorld::CellStore& cell = *player.getCell();
|
||||||
|
|
||||||
|
if (!cell.getCell()->hasWater())
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
||||||
|
const float dist = std::abs(cell.getWaterLevel() - pos.z());
|
||||||
|
|
||||||
|
if (cell.isExterior() && dist < mSettings.mNearWaterOutdoorTolerance)
|
||||||
|
{
|
||||||
|
if (mSettings.mNearWaterPoints <= 1)
|
||||||
|
return (mSettings.mNearWaterOutdoorTolerance - dist) / mSettings.mNearWaterOutdoorTolerance;
|
||||||
|
|
||||||
|
const float step = mSettings.mNearWaterRadius * 2.0f / (mSettings.mNearWaterPoints - 1);
|
||||||
|
|
||||||
|
int underwaterPoints = 0;
|
||||||
|
|
||||||
|
for (int x = 0; x < mSettings.mNearWaterPoints; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < mSettings.mNearWaterPoints; y++)
|
||||||
|
{
|
||||||
|
const float terrainX = pos.x() - mSettings.mNearWaterRadius + x * step;
|
||||||
|
const float terrainY = pos.y() - mSettings.mNearWaterRadius + y * step;
|
||||||
|
const float height = world.getTerrainHeightAt(osg::Vec3f(terrainX, terrainY, 0.0f));
|
||||||
|
|
||||||
|
if (height < 0)
|
||||||
|
underwaterPoints++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return underwaterPoints * 2.0f / (mSettings.mNearWaterPoints * mSettings.mNearWaterPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cell.isExterior() && dist < mSettings.mNearWaterIndoorTolerance)
|
||||||
|
return (mSettings.mNearWaterIndoorTolerance - dist) / mSettings.mNearWaterIndoorTolerance;
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
54
apps/openmw/mwsound/watersoundupdater.hpp
Normal file
54
apps/openmw/mwsound/watersoundupdater.hpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef GAME_SOUND_WATERSOUNDUPDATER_H
|
||||||
|
#define GAME_SOUND_WATERSOUNDUPDATER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace MWBase
|
||||||
|
{
|
||||||
|
class World;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class ConstPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
struct WaterSoundUpdaterSettings
|
||||||
|
{
|
||||||
|
int mNearWaterRadius;
|
||||||
|
int mNearWaterPoints;
|
||||||
|
float mNearWaterIndoorTolerance;
|
||||||
|
float mNearWaterOutdoorTolerance;
|
||||||
|
std::string mNearWaterIndoorID;
|
||||||
|
std::string mNearWaterOutdoorID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WaterSoundUpdate
|
||||||
|
{
|
||||||
|
std::string mId;
|
||||||
|
float mVolume;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WaterSoundUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit WaterSoundUpdater(const WaterSoundUpdaterSettings& settings);
|
||||||
|
|
||||||
|
WaterSoundUpdate update(const MWWorld::ConstPtr& player, const MWBase::World& world) const;
|
||||||
|
|
||||||
|
void setUnderwater(bool value)
|
||||||
|
{
|
||||||
|
mListenerUnderwater = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const WaterSoundUpdaterSettings mSettings;
|
||||||
|
bool mListenerUnderwater = false;
|
||||||
|
|
||||||
|
float getVolume(const MWWorld::ConstPtr& player, const MWBase::World& world) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue