Merge pull request #292 from OpenMW/master

Add OpenMW commits up to 18 Sep 2017
pull/295/head
David Cernat 7 years ago committed by GitHub
commit 4d4eb1bb9f

@ -24,7 +24,7 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main)
main->addWidget (list); main->addWidget (list);
QFontMetrics metrics (QApplication::font()); QFontMetrics metrics (QApplication::font(list));
int maxWidth = 1; int maxWidth = 1;

@ -3,6 +3,7 @@
#include <MyGUI_ListBox.h> #include <MyGUI_ListBox.h>
#include <MyGUI_ImageBox.h> #include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h> #include <MyGUI_Gui.h>
#include <MyGUI_ScrollView.h>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -244,6 +245,11 @@ namespace MWGui
} }
} }
} }
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mSpellArea->setVisibleVScroll(false);
mSpellArea->setCanvasSize(MyGUI::IntSize(mSpellArea->getWidth(), std::max(mSpellArea->getHeight(), coord.top)));
mSpellArea->setVisibleVScroll(true);
mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0));
}
} }

@ -47,7 +47,7 @@ namespace MWGui
void updateSpells(); void updateSpells();
MyGUI::ListBox* mBirthList; MyGUI::ListBox* mBirthList;
MyGUI::Widget* mSpellArea; MyGUI::ScrollView* mSpellArea;
MyGUI::ImageBox* mBirthImage; MyGUI::ImageBox* mBirthImage;
std::vector<MyGUI::Widget*> mSpellItems; std::vector<MyGUI::Widget*> mSpellItems;

@ -750,7 +750,9 @@ namespace MWGui
lastId = item.getCellRef().getRefId(); lastId = item.getCellRef().getRefId();
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && isRightHandWeapon(item)) if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() &&
isRightHandWeapon(item) &&
item.getClass().canBeEquipped(item, player).first)
{ {
found = true; found = true;
break; break;

@ -1988,8 +1988,9 @@ namespace MWMechanics
{ {
std::string id = reader.getHString(); std::string id = reader.getHString();
int count; int count;
reader.getHNT (count, "COUN"); reader.getHNT(count, "COUN");
mDeathCount[id] = count; if (MWBase::Environment::get().getWorld()->getStore().find(id))
mDeathCount[id] = count;
} }
} }
} }

@ -1822,20 +1822,11 @@ void CharacterController::update(float duration)
if(sneak || inwater || flying) if(sneak || inwater || flying)
vec.z() = 0.0f; vec.z() = 0.0f;
if (inwater || flying)
cls.getCreatureStats(mPtr).land();
bool inJump = true; bool inJump = true;
if(!onground && !flying && !inwater) if(!onground && !flying && !inwater)
{ {
// In the air (either getting up —ascending part of jump— or falling). // In the air (either getting up —ascending part of jump— or falling).
if (world->isSlowFalling(mPtr))
{
// SlowFalling spell effect is active, do not keep previous fall height
cls.getCreatureStats(mPtr).land();
}
forcestateupdate = (mJumpState != JumpState_InAir); forcestateupdate = (mJumpState != JumpState_InAir);
jumpstate = JumpState_InAir; jumpstate = JumpState_InAir;
@ -1881,7 +1872,7 @@ void CharacterController::update(float duration)
} }
} }
} }
else if(mJumpState == JumpState_InAir) else if(mJumpState == JumpState_InAir && !inwater && !flying)
{ {
forcestateupdate = true; forcestateupdate = true;
jumpstate = JumpState_Landing; jumpstate = JumpState_Landing;
@ -1964,9 +1955,6 @@ void CharacterController::update(float duration)
movestate = mMovementState; movestate = mMovementState;
} }
if (onground)
cls.getCreatureStats(mPtr).land();
if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight) if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight)
clearAnimQueue(); clearAnimQueue();

@ -1404,14 +1404,16 @@ namespace MWPhysics
// Slow fall reduces fall speed by a factor of (effect magnitude / 200) // Slow fall reduces fall speed by a factor of (effect magnitude / 200)
float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f));
bool flying = world->isFlying(iter->first);
bool wasOnGround = physicActor->getOnGround();
osg::Vec3f position = physicActor->getPosition(); osg::Vec3f position = physicActor->getPosition();
float oldHeight = position.z(); float oldHeight = position.z();
bool positionChanged = false; bool positionChanged = false;
for (int i=0; i<numSteps; ++i) for (int i=0; i<numSteps; ++i)
{ {
position = MovementSolver::move(position, physicActor->getPtr(), physicActor, iter->second, physicsDt, position = MovementSolver::move(position, physicActor->getPtr(), physicActor, iter->second, physicsDt,
world->isFlying(iter->first), flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions);
waterlevel, slowFall, mCollisionWorld, mStandingCollisions);
if (position != physicActor->getPosition()) if (position != physicActor->getPosition())
positionChanged = true; positionChanged = true;
physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct
@ -1424,8 +1426,11 @@ namespace MWPhysics
float heightDiff = position.z() - oldHeight; float heightDiff = position.z() - oldHeight;
if (heightDiff < 0) MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); if ((wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1)
stats.land();
else if (heightDiff < 0)
stats.addToFallHeight(-heightDiff);
mMovementResults.push_back(std::make_pair(iter->first, interpolated)); mMovementResults.push_back(std::make_pair(iter->first, interpolated));
} }

@ -530,8 +530,10 @@ namespace MWRender
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
{ {
if(mPlayerAnimation.get()) if(mPlayerAnimation.get())
{
setupPlayer(ptr);
mPlayerAnimation->updatePtr(ptr); mPlayerAnimation->updatePtr(ptr);
}
mCamera->attachTo(ptr); mCamera->attachTo(ptr);
} }
@ -834,6 +836,7 @@ namespace MWRender
player.getRefData().setBaseNode(mPlayerNode); player.getRefData().setBaseNode(mPlayerNode);
mWater->removeEmitter(player);
mWater->addEmitter(player); mWater->addEmitter(player);
} }

@ -192,12 +192,11 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 },
}}; }};
auto fmt = std::find_if(fmtlist.cbegin(), fmtlist.cend(), for(auto &fmt : fmtlist)
[chans,type](const FormatEntry &fmt) -> bool {
{ return fmt.chans == chans && fmt.type == type; } if(fmt.chans == chans && fmt.type == type)
); return fmt.format;
if(fmt != fmtlist.cend()) }
return fmt->format;
if(alIsExtensionPresent("AL_EXT_MCFORMATS")) if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{ {
@ -209,18 +208,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 },
{ "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 },
}}; }};
ALenum format = AL_NONE;
std::find_if(mcfmtlist.cbegin(), mcfmtlist.cend(), for(auto &fmt : mcfmtlist)
[&format,chans,type](const FormatEntryExt &fmt) -> bool {
if(fmt.chans == chans && fmt.type == type)
{ {
if(fmt.chans == chans && fmt.type == type) ALenum format = alGetEnumValue(fmt.name);
format = alGetEnumValue(fmt.name); if(format != 0 && format != -1)
return format != 0 && format != -1; return format;
} }
); }
if(format != 0 && format != -1)
return format;
} }
if(alIsExtensionPresent("AL_EXT_FLOAT32")) if(alIsExtensionPresent("AL_EXT_FLOAT32"))
{ {
@ -228,18 +225,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 },
{ "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 },
}}; }};
ALenum format = AL_NONE;
std::find_if(fltfmtlist.cbegin(), fltfmtlist.cend(), for(auto &fmt : fltfmtlist)
[&format,chans,type](const FormatEntryExt &fmt) -> bool {
if(fmt.chans == chans && fmt.type == type)
{ {
if(fmt.chans == chans && fmt.type == type) ALenum format = alGetEnumValue(fmt.name);
format = alGetEnumValue(fmt.name); if(format != 0 && format != -1)
return format != 0 && format != -1; return format;
} }
); }
if(format != 0 && format != -1)
return format;
if(alIsExtensionPresent("AL_EXT_MCFORMATS")) if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{ {
@ -249,16 +244,15 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 },
}}; }};
std::find_if(fltmcfmtlist.cbegin(), fltmcfmtlist.cend(), for(auto &fmt : fltmcfmtlist)
[&format,chans,type](const FormatEntryExt &fmt) -> bool {
if(fmt.chans == chans && fmt.type == type)
{ {
if(fmt.chans == chans && fmt.type == type) ALenum format = alGetEnumValue(fmt.name);
format = alGetEnumValue(fmt.name); if(format != 0 && format != -1)
return format != 0 && format != -1; return format;
} }
); }
if(format != 0 && format != -1)
return format;
} }
} }
@ -547,11 +541,11 @@ ALint OpenAL_SoundStream::refillQueue()
std::vector<char> data(mBufferSize); std::vector<char> data(mBufferSize);
for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued) for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued)
{ {
size_t got = mDecoder->read(&data[0], data.size()); size_t got = mDecoder->read(data.data(), data.size());
if(got < data.size()) if(got < data.size())
{ {
mIsFinished = true; mIsFinished = true;
std::memset(&data[got], mSilence, data.size()-got); std::fill(data.begin()+got, data.end(), mSilence);
} }
if(got > 0) if(got > 0)
{ {
@ -559,7 +553,7 @@ ALint OpenAL_SoundStream::refillQueue()
mLoudnessAnalyzer->analyzeLoudness(data); mLoudnessAnalyzer->analyzeLoudness(data);
ALuint bufid = mBuffers[mCurrentBufIdx]; ALuint bufid = mBuffers[mCurrentBufIdx];
alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); alBufferData(bufid, mFormat, data.data(), data.size(), mSampleRate);
alSourceQueueBuffers(mSource, 1, &bufid); alSourceQueueBuffers(mSource, 1, &bufid);
mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size(); mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size();
} }
@ -594,25 +588,33 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
{ {
deinit(); deinit();
std::cout<< "Initializing OpenAL..." <<std::endl;
mDevice = alcOpenDevice(devname.c_str()); mDevice = alcOpenDevice(devname.c_str());
if(!mDevice) if(!mDevice && !devname.empty())
{ {
if(devname.empty()) std::cerr<< "Failed to open \""<<devname<<"\", trying default" <<std::endl;
std::cerr<< "Failed to open default audio device" <<std::endl; mDevice = alcOpenDevice(nullptr);
else
std::cerr<< "Failed to open \""<<devname<<"\"" <<std::endl;
return false;
} }
else if(!mDevice)
{ {
const ALCchar *name = NULL; std::cerr<< "Failed to open default audio device" <<std::endl;
if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT")) return false;
name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
if(alcGetError(mDevice) != AL_NO_ERROR || !name)
name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
std::cout << "Opened \""<<name<<"\"" << std::endl;
} }
const ALCchar *name = nullptr;
if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
if(alcGetError(mDevice) != AL_NO_ERROR || !name)
name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
std::cout<< "Opened \""<<name<<"\"" <<std::endl;
ALCint major=0, minor=0;
alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor);
std::cout<< " ALC Version: "<<major<<"."<<minor<<"\n"<<
" ALC Extensions: "<<alcGetString(mDevice, ALC_EXTENSIONS) <<std::endl;
ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX");
ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"); ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF");
@ -643,7 +645,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
} }
if(index < 0) if(index < 0)
std::cerr<< "Failed to find HRTF name \""<<hrtfname<<"\", using default" <<std::endl; std::cerr<< "Failed to find HRTF \""<<hrtfname<<"\", using default" <<std::endl;
else else
{ {
attrs.push_back(ALC_HRTF_ID_SOFT); attrs.push_back(ALC_HRTF_ID_SOFT);
@ -665,6 +667,11 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
return false; return false;
} }
std::cout<< " Vendor: "<<alGetString(AL_VENDOR)<<"\n"<<
" Renderer: "<<alGetString(AL_RENDERER)<<"\n"<<
" Version: "<<alGetString(AL_VERSION)<<"\n"<<
" Extensions: "<<alGetString(AL_EXTENSIONS)<<std::endl;
if(!ALC.SOFT_HRTF) if(!ALC.SOFT_HRTF)
std::cout<< "HRTF status unavailable" <<std::endl; std::cout<< "HRTF status unavailable" <<std::endl;
else else
@ -698,7 +705,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
{ {
ALuint src = 0; ALuint src = 0;
alGenSources(1, &src); alGenSources(1, &src);
if(getALError() != AL_NO_ERROR) if(alGetError() != AL_NO_ERROR)
break; break;
mFreeSources.push_back(src); mFreeSources.push_back(src);
} }
@ -824,8 +831,8 @@ void OpenAL_Output::deinit()
{ {
mStreamThread->removeAll(); mStreamThread->removeAll();
for(size_t i = 0;i < mFreeSources.size();i++) for(ALuint source : mFreeSources)
alDeleteSources(1, &mFreeSources[i]); alDeleteSources(1, &source);
mFreeSources.clear(); mFreeSources.clear();
if(mEffectSlot) if(mEffectSlot)
@ -934,7 +941,7 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode)
} }
Sound_Handle OpenAL_Output::loadSound(const std::string &fname) std::pair<Sound_Handle,size_t> OpenAL_Output::loadSound(const std::string &fname)
{ {
getALError(); getALError();
@ -959,27 +966,31 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname)
decoder->getInfo(&srate, &chans, &type); decoder->getInfo(&srate, &chans, &type);
format = getALFormat(chans, type); format = getALFormat(chans, type);
if(!format) return nullptr; if(!format) return std::make_pair(nullptr, 0);
decoder->readAll(data); decoder->readAll(data);
decoder->close(); decoder->close();
ALint size;
ALuint buf = 0; ALuint buf = 0;
alGenBuffers(1, &buf); alGenBuffers(1, &buf);
alBufferData(buf, format, &data[0], data.size(), srate); alBufferData(buf, format, data.data(), data.size(), srate);
alGetBufferi(buf, AL_SIZE, &size);
if(getALError() != AL_NO_ERROR) if(getALError() != AL_NO_ERROR)
{ {
if(buf && alIsBuffer(buf)) if(buf && alIsBuffer(buf))
alDeleteBuffers(1, &buf); alDeleteBuffers(1, &buf);
getALError(); getALError();
return nullptr; return std::make_pair(nullptr, 0);
} }
return MAKE_PTRID(buf); return std::make_pair(MAKE_PTRID(buf), size);
} }
void OpenAL_Output::unloadSound(Sound_Handle data) size_t OpenAL_Output::unloadSound(Sound_Handle data)
{ {
ALuint buffer = GET_PTRID(data); ALuint buffer = GET_PTRID(data);
if(!buffer) return 0;
// Make sure no sources are playing this buffer before unloading it. // Make sure no sources are playing this buffer before unloading it.
SoundVec::const_iterator iter = mActiveSounds.begin(); SoundVec::const_iterator iter = mActiveSounds.begin();
for(;iter != mActiveSounds.end();++iter) for(;iter != mActiveSounds.end();++iter)
@ -996,19 +1007,11 @@ void OpenAL_Output::unloadSound(Sound_Handle data)
alSourcei(source, AL_BUFFER, 0); alSourcei(source, AL_BUFFER, 0);
} }
} }
alDeleteBuffers(1, &buffer);
getALError();
}
size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const
{
ALuint buffer = GET_PTRID(data);
ALint size = 0; ALint size = 0;
alGetBufferi(buffer, AL_SIZE, &size); alGetBufferi(buffer, AL_SIZE, &size);
alDeleteBuffers(1, &buffer);
getALError(); getALError();
return size;
return (ALuint)size;
} }
@ -1368,23 +1371,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi
if(mWaterFilter) if(mWaterFilter)
{ {
ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL; ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL;
std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), for(Sound *sound : mActiveSounds)
[filter](const SoundVec::value_type &item) -> void {
{ if(sound->getUseEnv())
if(item->getUseEnv()) alSourcei(GET_PTRID(sound->mHandle), AL_DIRECT_FILTER, filter);
alSourcei(GET_PTRID(item->mHandle), AL_DIRECT_FILTER, filter); }
} for(Stream *sound : mActiveStreams)
); {
std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), if(sound->getUseEnv())
[filter](const StreamVec::value_type &item) -> void alSourcei(
{ reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle)->mSource,
if(item->getUseEnv()) AL_DIRECT_FILTER, filter
alSourcei( );
reinterpret_cast<OpenAL_SoundStream*>(item->mHandle)->mSource, }
AL_DIRECT_FILTER, filter
);
}
);
} }
// Update the environment effect // Update the environment effect
if(mEffectSlot) if(mEffectSlot)
@ -1403,23 +1402,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi
void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::pauseSounds(int types)
{ {
std::vector<ALuint> sources; std::vector<ALuint> sources;
std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), for(Sound *sound : mActiveSounds)
[types,&sources](const SoundVec::value_type &sound) -> void {
{ if((types&sound->getPlayType()))
if(sound && sound->mHandle && (types&sound->getPlayType())) sources.push_back(GET_PTRID(sound->mHandle));
sources.push_back(GET_PTRID(sound->mHandle)); }
} for(Stream *sound : mActiveStreams)
); {
std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), if((types&sound->getPlayType()))
[types,&sources](const StreamVec::value_type &stream) -> void
{ {
if(stream && stream->mHandle && (types&stream->getPlayType())) OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
{ sources.push_back(stream->mSource);
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>(stream->mHandle);
sources.push_back(strm->mSource);
}
} }
); }
if(!sources.empty()) if(!sources.empty())
{ {
alSourcePausev(sources.size(), sources.data()); alSourcePausev(sources.size(), sources.data());
@ -1430,23 +1425,19 @@ void OpenAL_Output::pauseSounds(int types)
void OpenAL_Output::resumeSounds(int types) void OpenAL_Output::resumeSounds(int types)
{ {
std::vector<ALuint> sources; std::vector<ALuint> sources;
std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), for(Sound *sound : mActiveSounds)
[types,&sources](const SoundVec::value_type &sound) -> void {
{ if((types&sound->getPlayType()))
if(sound && sound->mHandle && (types&sound->getPlayType())) sources.push_back(GET_PTRID(sound->mHandle));
sources.push_back(GET_PTRID(sound->mHandle)); }
} for(Stream *sound : mActiveStreams)
); {
std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), if((types&sound->getPlayType()))
[types,&sources](const StreamVec::value_type &stream) -> void
{ {
if(stream && stream->mHandle && (types&stream->getPlayType())) OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
{ sources.push_back(stream->mSource);
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>(stream->mHandle);
sources.push_back(strm->mSource);
}
} }
); }
if(!sources.empty()) if(!sources.empty())
{ {
alSourcePlayv(sources.size(), sources.data()); alSourcePlayv(sources.size(), sources.data());

@ -66,9 +66,8 @@ namespace MWSound
virtual std::vector<std::string> enumerateHrtf(); virtual std::vector<std::string> enumerateHrtf();
virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode); virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode);
virtual Sound_Handle loadSound(const std::string &fname); virtual std::pair<Sound_Handle,size_t> loadSound(const std::string &fname);
virtual void unloadSound(Sound_Handle data); virtual size_t unloadSound(Sound_Handle data);
virtual size_t getSoundDataSize(Sound_Handle data) const;
virtual bool playSound(Sound *sound, Sound_Handle data, float offset); virtual bool playSound(Sound *sound, Sound_Handle data, float offset);
virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset); virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset);

@ -36,9 +36,8 @@ namespace MWSound
virtual std::vector<std::string> enumerateHrtf() = 0; virtual std::vector<std::string> enumerateHrtf() = 0;
virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0; virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0;
virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual std::pair<Sound_Handle,size_t> loadSound(const std::string &fname) = 0;
virtual void unloadSound(Sound_Handle data) = 0; virtual size_t unloadSound(Sound_Handle data) = 0;
virtual size_t getSoundDataSize(Sound_Handle data) const = 0;
virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0; virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0;
virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0;

@ -26,11 +26,7 @@
#include "sound.hpp" #include "sound.hpp"
#include "openal_output.hpp" #include "openal_output.hpp"
#define SOUND_OUT "OpenAL"
#include "ffmpeg_decoder.hpp" #include "ffmpeg_decoder.hpp"
#ifndef SOUND_IN
#define SOUND_IN "FFmpeg"
#endif
namespace MWSound namespace MWSound
@ -84,45 +80,35 @@ namespace MWSound
mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax);
if(!useSound) if(!useSound)
{
std::cout<< "Sound disabled." <<std::endl;
return; return;
}
std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); std::string hrtfname = Settings::Manager::getString("hrtf", "Sound");
int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound");
HrtfMode hrtfmode = hrtfstate < 0 ? HrtfMode::Auto : HrtfMode hrtfmode = hrtfstate < 0 ? HrtfMode::Auto :
hrtfstate > 0 ? HrtfMode::Enable : HrtfMode::Disable; hrtfstate > 0 ? HrtfMode::Enable : HrtfMode::Disable;
std::cout << "Sound output: " << SOUND_OUT << std::endl;
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:\n";
std::for_each(names.cbegin(), names.cend(),
[](const std::string &name) -> void
{ std::cout <<" "<<name<<"\n"; }
);
std::cout.flush();
std::string devname = Settings::Manager::getString("device", "Sound"); std::string devname = Settings::Manager::getString("device", "Sound");
bool inited = mOutput->init(devname, hrtfname, hrtfmode); if(!mOutput->init(devname, hrtfname, hrtfmode))
if(!inited && !devname.empty())
{
std::cerr<< "Failed to initialize device \""<<devname<<"\", trying default" <<std::endl;
inited = mOutput->init(std::string(), hrtfname, hrtfmode);
}
if(!inited)
{ {
std::cerr<< "Failed to initialize default audio device, sound disabled" <<std::endl; std::cerr<< "Failed to initialize audio output, sound disabled" <<std::endl;
return; return;
} }
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:\n";
for(const std::string &name : names)
std::cout <<" "<<name<<"\n";
std::cout.flush();
names = mOutput->enumerateHrtf(); names = mOutput->enumerateHrtf();
if(!names.empty()) if(!names.empty())
{ {
std::cout<< "Enumerated HRTF names:\n"; std::cout<< "Enumerated HRTF names:\n";
std::for_each(names.cbegin(), names.cend(), for(const std::string &name : names)
[](const std::string &name) -> void std::cout <<" "<<name<<"\n";
{ std::cout<< " "<<name<<"\n"; }
);
std::cout.flush(); std::cout.flush();
} }
} }
@ -130,12 +116,11 @@ namespace MWSound
SoundManager::~SoundManager() SoundManager::~SoundManager()
{ {
clear(); clear();
SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); for(Sound_Buffer &sfx : *mSoundBuffers)
for(;sfxiter != mSoundBuffers->end();++sfxiter)
{ {
if(sfxiter->mHandle) if(sfx.mHandle)
mOutput->unloadSound(sfxiter->mHandle); mOutput->unloadSound(sfx.mHandle);
sfxiter->mHandle = 0; sfx.mHandle = 0;
} }
mUnusedBuffers.clear(); mUnusedBuffers.clear();
mOutput.reset(); mOutput.reset();
@ -200,9 +185,23 @@ namespace MWSound
// minRange, and maxRange), and ensure it's ready for use. // minRange, and maxRange), and ensure it's ready for use.
Sound_Buffer *SoundManager::loadSound(const std::string &soundId) Sound_Buffer *SoundManager::loadSound(const std::string &soundId)
{ {
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect((bool)(x), true)
#define UNLIKELY(x) __builtin_expect((bool)(x), false)
#else
#define LIKELY(x) (bool)(x)
#define UNLIKELY(x) (bool)(x)
#endif
if(UNLIKELY(mBufferNameMap.empty()))
{
MWBase::World *world = MWBase::Environment::get().getWorld();
for(const ESM::Sound &sound : world->getStore().get<ESM::Sound>())
insertSound(Misc::StringUtils::lowerCase(sound.mId), &sound);
}
Sound_Buffer *sfx; Sound_Buffer *sfx;
NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId);
if(snd != mBufferNameMap.end()) if(LIKELY(snd != mBufferNameMap.end()))
sfx = snd->second; sfx = snd->second;
else else
{ {
@ -211,13 +210,16 @@ namespace MWSound
if(!sound) return nullptr; if(!sound) return nullptr;
sfx = insertSound(soundId, sound); sfx = insertSound(soundId, sound);
} }
#undef LIKELY
#undef UNLIKELY
if(!sfx->mHandle) if(!sfx->mHandle)
{ {
sfx->mHandle = mOutput->loadSound(sfx->mResourceName); size_t size;
std::tie(sfx->mHandle, size) = mOutput->loadSound(sfx->mResourceName);
if(!sfx->mHandle) return nullptr; if(!sfx->mHandle) return nullptr;
mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); mBufferCacheSize += size;
if(mBufferCacheSize > mBufferCacheMax) if(mBufferCacheSize > mBufferCacheMax)
{ {
do { do {
@ -228,8 +230,8 @@ namespace MWSound
} }
Sound_Buffer *unused = mUnusedBuffers.back(); Sound_Buffer *unused = mUnusedBuffers.back();
mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); size = mOutput->unloadSound(unused->mHandle);
mOutput->unloadSound(unused->mHandle); mBufferCacheSize -= size;
unused->mHandle = 0; unused->mHandle = 0;
mUnusedBuffers.pop_back(); mUnusedBuffers.pop_back();
@ -678,11 +680,10 @@ namespace MWSound
if(snditer != mActiveSounds.end()) if(snditer != mActiveSounds.end())
{ {
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &snd : snditer->second)
for(;sndidx != snditer->second.end();++sndidx)
{ {
if(sndidx->second == sfx) if(snd.second == sfx)
mOutput->finishSound(sndidx->first); mOutput->finishSound(snd.first);
} }
} }
} }
@ -692,33 +693,28 @@ namespace MWSound
SoundMap::iterator snditer = mActiveSounds.find(ptr); SoundMap::iterator snditer = mActiveSounds.find(ptr);
if(snditer != mActiveSounds.end()) if(snditer != mActiveSounds.end())
{ {
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &snd : snditer->second)
for(;sndidx != snditer->second.end();++sndidx) mOutput->finishSound(snd.first);
mOutput->finishSound(sndidx->first);
} }
SaySoundMap::iterator sayiter = mActiveSaySounds.find(ptr);
if(sayiter != mActiveSaySounds.end())
mOutput->finishStream(sayiter->second);
} }
void SoundManager::stopSound(const MWWorld::CellStore *cell) void SoundManager::stopSound(const MWWorld::CellStore *cell)
{ {
SoundMap::iterator snditer = mActiveSounds.begin(); for(SoundMap::value_type &snd : mActiveSounds)
for(;snditer != mActiveSounds.end();++snditer)
{ {
if(snditer->first != MWWorld::ConstPtr() && if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
snditer->first != MWMechanics::getPlayer() &&
snditer->first.getCell() == cell)
{ {
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &sndbuf : snd.second)
for(;sndidx != snditer->second.end();++sndidx) mOutput->finishSound(sndbuf.first);
mOutput->finishSound(sndidx->first);
} }
} }
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(SaySoundMap::value_type &snd : mActiveSaySounds)
for(;sayiter != mActiveSaySounds.end();++sayiter)
{ {
if(sayiter->first != MWWorld::ConstPtr() && if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
sayiter->first != MWMechanics::getPlayer() && mOutput->finishStream(snd.second);
sayiter->first.getCell() == cell)
mOutput->finishStream(sayiter->second);
} }
} }
@ -728,11 +724,10 @@ namespace MWSound
if(snditer != mActiveSounds.end()) if(snditer != mActiveSounds.end())
{ {
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &sndbuf : snditer->second)
for(;sndidx != snditer->second.end();++sndidx)
{ {
if(sndidx->second == sfx) if(sndbuf.second == sfx)
mOutput->finishSound(sndidx->first); mOutput->finishSound(sndbuf.first);
} }
} }
} }
@ -744,11 +739,10 @@ namespace MWSound
if(snditer != mActiveSounds.end()) if(snditer != mActiveSounds.end())
{ {
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &sndbuf : snditer->second)
for(;sndidx != snditer->second.end();++sndidx)
{ {
if(sndidx->second == sfx) if(sndbuf.second == sfx)
sndidx->first->setFadeout(duration); sndbuf.first->setFadeout(duration);
} }
} }
} }
@ -759,12 +753,10 @@ namespace MWSound
if(snditer != mActiveSounds.end()) if(snditer != mActiveSounds.end())
{ {
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); return std::find_if(snditer->second.cbegin(), snditer->second.cend(),
for(;sndidx != snditer->second.end();++sndidx) [this,sfx](const SoundBufferRefPair &snd) -> bool
{ { return snd.second == sfx && mOutput->isSoundPlaying(snd.first); }
if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first)) ) != snditer->second.cend();
return true;
}
} }
return false; return false;
} }
@ -823,10 +815,8 @@ namespace MWSound
if(total == 0) if(total == 0)
{ {
std::for_each(regn->mSoundList.cbegin(), regn->mSoundList.cend(), for(const ESM::Region::SoundRef &sndref : regn->mSoundList)
[](const ESM::Region::SoundRef &sndref) -> void total += (int)sndref.mChance;
{ total += (int)sndref.mChance; }
);
if(total == 0) if(total == 0)
return; return;
} }
@ -834,20 +824,15 @@ namespace MWSound
int r = Misc::Rng::rollDice(total); int r = Misc::Rng::rollDice(total);
int pos = 0; int pos = 0;
std::find_if_not(regn->mSoundList.cbegin(), regn->mSoundList.cend(), for(const ESM::Region::SoundRef &sndref : regn->mSoundList)
[&pos, r, this](const ESM::Region::SoundRef &sndref) -> bool {
if(r - pos < sndref.mChance)
{ {
if(r - pos < sndref.mChance) playSound(sndref.mSound.toString(), 1.0f, 1.0f);
{ break;
playSound(sndref.mSound.toString(), 1.0f, 1.0f);
// Played this sound, stop iterating
return false;
}
pos += sndref.mChance;
// Not this sound, keep iterating
return true;
} }
); pos += sndref.mChance;
}
} }
void SoundManager::updateWaterSound(float /*duration*/) void SoundManager::updateWaterSound(float /*duration*/)
@ -1135,28 +1120,23 @@ namespace MWSound
if(!mOutput->isInitialized()) if(!mOutput->isInitialized())
return; return;
mOutput->startUpdate(); mOutput->startUpdate();
SoundMap::iterator snditer = mActiveSounds.begin(); for(SoundMap::value_type &snd : mActiveSounds)
for(;snditer != mActiveSounds.end();++snditer)
{ {
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &sndbuf : snd.second)
for(;sndidx != snditer->second.end();++sndidx)
{ {
Sound *sound = sndidx->first; Sound *sound = sndbuf.first;
sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateSound(sound); mOutput->updateSound(sound);
} }
} }
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(SaySoundMap::value_type &snd : mActiveSaySounds)
for(;sayiter != mActiveSaySounds.end();++sayiter)
{ {
Stream *sound = sayiter->second; Stream *sound = snd.second;
sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound); mOutput->updateStream(sound);
} }
TrackList::iterator trkiter = mActiveTracks.begin(); for(Stream *sound : mActiveTracks)
for(;trkiter != mActiveTracks.end();++trkiter)
{ {
Stream *sound = *trkiter;
sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound); mOutput->updateStream(sound);
} }
@ -1262,36 +1242,35 @@ namespace MWSound
void SoundManager::clear() void SoundManager::clear()
{ {
SoundMap::iterator snditer = mActiveSounds.begin(); stopMusic();
for(;snditer != mActiveSounds.end();++snditer)
for(SoundMap::value_type &snd : mActiveSounds)
{ {
SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(SoundBufferRefPair &sndbuf : snd.second)
for(;sndidx != snditer->second.end();++sndidx)
{ {
mOutput->finishSound(sndidx->first); mOutput->finishSound(sndbuf.first);
mUnusedSounds.push_back(sndidx->first); mUnusedSounds.push_back(sndbuf.first);
Sound_Buffer *sfx = sndidx->second; Sound_Buffer *sfx = sndbuf.second;
if(sfx->mUses-- == 1) if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx); mUnusedBuffers.push_front(sfx);
} }
} }
mActiveSounds.clear(); mActiveSounds.clear();
SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); mUnderwaterSound = nullptr;
for(;sayiter != mActiveSaySounds.end();++sayiter) mNearWaterSound = nullptr;
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{ {
mOutput->finishStream(sayiter->second); mOutput->finishStream(snd.second);
mUnusedStreams.push_back(sayiter->second); mUnusedStreams.push_back(snd.second);
} }
mActiveSaySounds.clear(); mActiveSaySounds.clear();
TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter) for(Stream *sound : mActiveTracks)
{ {
mOutput->finishStream(*trkiter); mOutput->finishStream(sound);
mUnusedStreams.push_back(*trkiter); mUnusedStreams.push_back(sound);
} }
mActiveTracks.clear(); mActiveTracks.clear();
mUnderwaterSound = nullptr;
mNearWaterSound = nullptr;
stopMusic();
} }
} }

@ -34,21 +34,19 @@ namespace Misc
if (i < m.size()) if (i < m.size())
{ {
int precision = 0; int precision = -1;
bool precisionSet = false;
if (m[i] == '.') if (m[i] == '.')
{ {
precision = 0;
while (++i < m.size() && m[i] >= '0' && m[i] <= '9') while (++i < m.size() && m[i] >= '0' && m[i] <= '9')
{ {
precision = precision * 10 + (m[i] - '0'); precision = precision * 10 + (m[i] - '0');
precisionSet = true;
} }
} }
if (i < m.size()) if (i < m.size())
{ {
width = (widthSet) ? width : -1; width = (widthSet) ? width : -1;
precision = (precisionSet) ? precision : -1;
if (m[i] == 'S' || m[i] == 's') if (m[i] == 'S' || m[i] == 's')
visitedPlaceholder(StringPlaceholder, pad, width, precision); visitedPlaceholder(StringPlaceholder, pad, width, precision);

@ -304,3 +304,42 @@ already checked. Load a game and make your way to Seyda Neen - or start a new ga
Check whether Arrille has one (or more) for sale, and whether Fargoth give you one Check whether Arrille has one (or more) for sale, and whether Fargoth give you one
when you return his healing ring. when you return his healing ring.
Placing in a chest
******************
For this example we will use the small chest intended for lockpick practice,
located in the Census and Excise Office in Seyda Neen.
First we need the ID of the chest - this can be obtained either by clicking on it in the console
in the game, or by applying a similar process in the CS -
World/Cells
Select "Seyda Neen, Census and Excise Office"
Right-click and select "View"
Use mouse wheel to zoom in/out, and mouse plus WASD keys to navigate
Click on the small chest
Either way, you should find the ID, which is "chest_small_02_lockprac".
Open the Objects table (World/Objects) and scroll down to find this item.
Alternatively use the Edit/Search facility, selecting ID rather than text,
enter "lockprac" (without the quotes) into the search box, press "Search",
which should return two rows, then select the "Container" one rather than the "Instance"
Right-click and "Edit Record".
Right-click the "Content" section and select "Add a row"
Set the Item ID of the new row to be your new ring - simplest way is probably to open the Objects
table if it's not already open, sort on the "Modified" column which should bring the ring,
with its status of "Added" to the top, then drag and drop to the chest row.
Increase the Count to 1.
Save the addon, then test to ensure it works - e.g. start a new game and lockpick the chest.

@ -11,7 +11,9 @@
</Widget> </Widget>
<!-- Spell list --> <!-- Spell list -->
<Widget type="Widget" skin="" position="8 160 519 178" align="Left Top" name="SpellArea"/> <Widget type="ScrollView" skin="MW_ScrollView" position="8 160 507 170" align="Left Top" name="SpellArea">
<Property key="CanvasAlign" value="Left"/>
</Widget>>
<!-- Dialog buttons --> <!-- Dialog buttons -->
<Widget type="HBox" position="0 338 511 24"> <Widget type="HBox" position="0 338 511 24">

Loading…
Cancel
Save