Add OpenMW commits up to 11 Jul 2020

# Conflicts:
#   .travis.yml
#   apps/openmw/mwmechanics/actors.cpp
pull/593/head
David Cernat 5 years ago
commit 39e429c9eb

@ -7,19 +7,24 @@ Debian:
- linux
image: debian:bullseye
cache:
key: apt-cache
key: cache.002
paths:
- apt-cache/
- ccache/
before_script:
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
- apt-get update -yq
- apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake build-essential libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-iostreams-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt5opengl5-dev libopenal-dev libopenscenegraph-dev libunshield-dev libtinyxml-dev libmygui-dev libbullet-dev
- apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake build-essential libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-iostreams-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt5opengl5-dev libopenal-dev libopenscenegraph-dev libunshield-dev libtinyxml-dev libmygui-dev libbullet-dev ccache
stage: build
script:
- export CCACHE_BASEDIR="`pwd`"
- export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
- ccache -z -M 250M
- cores_to_use=$((`nproc`-2)); if (( $cores_to_use < 1 )); then cores_to_use=1; fi
- mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../
- mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- make -j$cores_to_use
- DESTDIR=artifacts make install
- ccache -s
artifacts:
paths:
- build/artifacts/

@ -71,11 +71,11 @@ before_script:
- ./CI/before_script.${TRAVIS_OS_NAME}.sh
script:
- cd ./build
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j3; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then ../CI/check_package.osx.sh; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ${ANALYZE} make -j3; fi
# - if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
# - if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then ../CI/check_package.osx.sh; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
- cd "${TRAVIS_BUILD_DIR}"
- ccache -s
#deploy:

@ -17,6 +17,7 @@
Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound
Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
Bug #5370: Opening an unlocked but trapped door uses the key
Bug #5384: openmw-cs: deleting an instance requires reload of scene window to show in editor
Bug #5397: NPC greeting does not reset if you leave + reenter area
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
Bug #5403: Enchantment effect doesn't show on an enemy during death animation
@ -43,6 +44,7 @@
Feature #5362: Show the soul gems' trapped soul in count dialog
Feature #5445: Handle NiLines
Feature #5457: Realistic diagonal movement
Feature #5486: Fixes trainers to choose their training skills based on their base skill points
Task #5480: Drop Qt4 support
0.46.0

@ -1,8 +1,5 @@
#!/bin/sh -e
brew update
brew outdated pkgconfig || brew upgrade pkgconfig
brew install qt
brew install ccache
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-ef2462c.zip -o ~/openmw-deps.zip

@ -606,7 +606,7 @@ printf "Bullet 2.89 (${BULLET_DBL_DISPLAY})... "
eval 7z x -y "${DEPS}/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" $STRIP
mv "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}" Bullet
fi
export BULLET_ROOT="$(real_pwd)/Bullet"
add_cmake_opts -DBULLET_ROOT="$(real_pwd)/Bullet"
echo Done.
}
cd $DEPS

@ -13,10 +13,17 @@ cmake \
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
-D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
-D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
-D CMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++" \
-D CMAKE_C_FLAGS_RELEASE="-g -O0" \
-D CMAKE_CXX_FLAGS_RELEASE="-g -O0" \
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.9" \
-D CMAKE_OSX_SYSROOT="macosx10.14" \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_BUILD_TYPE=RELEASE \
-D OPENMW_OSX_DEPLOYMENT=TRUE \
-D BUILD_ESMTOOL=FALSE \
-D BUILD_OPENMW=TRUE \
-D BUILD_OPENCS=FALSE \
-D BUILD_ESMTOOL=TRUE \
-D BUILD_BSATOOL=TRUE \
-D BUILD_ESSIMPORTER=TRUE \
-D BUILD_NIFTEST=TRUE \
-G"Unix Makefiles" \
..

@ -326,7 +326,7 @@ include_directories("."
${Boost_INCLUDE_DIR}
${MyGUI_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${Bullet_INCLUDE_DIRS}
${BULLET_INCLUDE_DIRS}
)
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})

@ -90,6 +90,7 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
}
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
loadSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
// Input Settings
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
@ -155,6 +156,7 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
saveSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
// Input Settings
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");

@ -94,7 +94,7 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value
// views that the whole row has changed.
emit dataChanged(this->index(index.row(), 0),
this->index(index.row(), columnCount(index.parent())));
this->index(index.row(), columnCount(index.parent()) - 1));
} else
{

@ -26,6 +26,8 @@
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/actorutil.hpp"
#include <components/settings/settings.hpp>
#include "tooltips.hpp"
namespace
@ -52,6 +54,7 @@ namespace MWGui
TrainingWindow::TrainingWindow()
: WindowBase("openmw_trainingwindow.layout")
, mTimeAdvancer(0.05f)
, mTrainingSkillBasedOnBaseSkill(Settings::Manager::getBool("trainers training skills based on base skill", "Game"))
{
getWidget(mTrainingOptions, "TrainingOptions");
getWidget(mCancelButton, "CancelButton");
@ -88,9 +91,10 @@ namespace MWGui
// NPC can train you in his best 3 skills
std::vector< std::pair<int, float> > skills;
MWMechanics::NpcStats const& actorStats(actor.getClass().getNpcStats(actor));
for (int i=0; i<ESM::Skill::Length; ++i)
{
float value = actor.getClass().getSkill(actor, i);
float value = getSkillForTraining(actorStats, i);
skills.push_back(std::make_pair(i, value));
}
@ -152,7 +156,7 @@ namespace MWGui
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
return;
if (mPtr.getClass().getSkill(mPtr, skillId) <= pcStats.getSkill (skillId).getBase ())
if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skillId) <= pcStats.getSkill(skillId).getBase())
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sServiceTrainingWords}");
return;
@ -232,6 +236,13 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
}
float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const
{
if (mTrainingSkillBasedOnBaseSkill)
return stats.getSkill(skillId).getBase();
return stats.getSkill(skillId).getModified();
}
void TrainingWindow::onFrame(float dt)
{
checkReferenceAvailable();

@ -6,6 +6,11 @@
#include "timeadvancer.hpp"
#include "waitdialog.hpp"
namespace MWMechanics
{
class NpcStats;
}
namespace MWGui
{
@ -35,12 +40,17 @@ namespace MWGui
void onTrainingProgressChanged(int cur, int total);
void onTrainingFinished();
// Retrieve the base skill value if the setting 'training skills based on base skill' is set;
// otherwise returns the modified skill
float getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const;
MyGUI::Widget* mTrainingOptions;
MyGUI::Button* mCancelButton;
MyGUI::TextBox* mPlayerGold;
WaitDialogProgressBar mProgressBar;
TimeAdvancer mTimeAdvancer;
bool mTrainingSkillBasedOnBaseSkill; //corresponds to the setting 'training skills based on base skill'
};
}

@ -2160,6 +2160,7 @@ namespace MWMechanics
}
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
{
bool isPlayer = iter->first == getPlayer();
notifyDied(iter->first);
// Reset magic effects and recalculate derived effects
@ -2167,16 +2168,8 @@ namespace MWMechanics
stats.modifyMagicEffects(MWMechanics::MagicEffects());
stats.getActiveSpells().clear();
/*
Start of tes3mp change (major)
Don't clear spells for dying players and actors because it doesn't really make
any sense
*/
//stats.getSpells().clear();
/*
End of tes3mp change (major)
*/
if (!isPlayer)
stats.getSpells().clear();
// Make sure spell effects are removed
purgeSpellEffects(stats.getActorId());
@ -2186,7 +2179,7 @@ namespace MWMechanics
if (iter->first.getClass().isNpc())
calculateNpcStatModifiers(iter->first, 0);
if( iter->first == getPlayer())
if (isPlayer)
{
//player's death animation is over

@ -2072,6 +2072,7 @@ void CharacterController::update(float duration, bool animationOnly)
mTimeUntilWake -= duration;
bool isPlayer = mPtr == MWMechanics::getPlayer();
bool isFirstPersonPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
float scale = mPtr.getCellRef().getScale();
@ -2167,7 +2168,7 @@ void CharacterController::update(float duration, bool animationOnly)
float effectiveRotation = rot.z();
static const bool turnToMovementDirection = Settings::Manager::getBool("turn to movement direction", "Game");
if (turnToMovementDirection && !(isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson()))
if (turnToMovementDirection && !isFirstPersonPlayer)
{
float targetMovementAngle = vec.y() >= 0 ? std::atan2(-vec.x(), vec.y()) : std::atan2(vec.x(), -vec.y());
movementSettings.mIsStrafing = (stats.getDrawState() != MWMechanics::DrawState_Nothing || inwater)
@ -2396,8 +2397,7 @@ void CharacterController::update(float duration, bool animationOnly)
// It seems only bipedal actors use turning animations.
// Also do not use turning animations in the first-person view and when sneaking.
bool isFirstPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
if (!sneak && jumpstate == JumpState_None && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr))
if (!sneak && jumpstate == JumpState_None && !isFirstPersonPlayer && mPtr.getClass().isBipedal(mPtr))
{
if(effectiveRotation > rotationThreshold)
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
@ -2421,6 +2421,26 @@ void CharacterController::update(float duration, bool animationOnly)
sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal);
}
if (turnToMovementDirection)
{
float targetSwimmingPitch;
if (inwater && vec.y() != 0 && !isFirstPersonPlayer && !movementSettings.mIsStrafing)
targetSwimmingPitch = -mPtr.getRefData().getPosition().rot[0];
else
targetSwimmingPitch = 0;
float maxSwimPitchDelta = 3.0f * duration;
float swimmingPitch = mAnimation->getBodyPitchRadians();
swimmingPitch += osg::clampBetween(targetSwimmingPitch - swimmingPitch, -maxSwimPitchDelta, maxSwimPitchDelta);
mAnimation->setBodyPitchRadians(swimmingPitch);
}
if (inwater && isPlayer && !isFirstPersonPlayer)
{
static const float swimUpwardCoef = Settings::Manager::getFloat("swim upward coef", "Game");
static const float swimForwardCoef = sqrtf(1.0f - swimUpwardCoef * swimUpwardCoef);
vec.z() = std::abs(vec.y()) * swimUpwardCoef;
vec.y() *= swimForwardCoef;
}
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
if (isPlayer)
{

@ -623,6 +623,7 @@ namespace MWRender
, mHeadPitchRadians(0.f)
, mUpperBodyYawRadians(0.f)
, mLegsYawRadians(0.f)
, mBodyPitchRadians(0.f)
, mHasMagicEffects(false)
, mAlpha(1.f)
{
@ -1340,11 +1341,11 @@ namespace MWRender
float yawOffset = 0;
if (mRootController)
{
bool enable = std::abs(mLegsYawRadians) > epsilon;
bool enable = std::abs(mLegsYawRadians) > epsilon || std::abs(mBodyPitchRadians) > epsilon;
mRootController->setEnabled(enable);
if (enable)
{
mRootController->setRotate(osg::Quat(mLegsYawRadians, osg::Vec3f(0,0,1)));
mRootController->setRotate(osg::Quat(mLegsYawRadians, osg::Vec3f(0,0,1)) * osg::Quat(mBodyPitchRadians, osg::Vec3f(1,0,0)));
yawOffset = mLegsYawRadians;
}
}

@ -273,6 +273,7 @@ protected:
float mHeadPitchRadians;
float mUpperBodyYawRadians;
float mLegsYawRadians;
float mBodyPitchRadians;
RotateController* addRotateController(std::string bone);
@ -489,6 +490,8 @@ public:
virtual void setLegsYawRadians(float v) { mLegsYawRadians = v; }
virtual float getUpperBodyYawRadians() const { return mUpperBodyYawRadians; }
virtual float getLegsYawRadians() const { return mLegsYawRadians; }
virtual void setBodyPitchRadians(float v) { mBodyPitchRadians = v; }
virtual float getBodyPitchRadians() const { return mBodyPitchRadians; }
virtual void setAccurateAiming(bool enabled) {}
virtual bool canBeHarvested() const { return false; }

@ -3,6 +3,7 @@
#include <osg/Camera>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
@ -56,7 +57,7 @@ namespace MWRender
mFurthest(800.f),
mIsNearest(false),
mHeight(124.f),
mBaseCameraDistance(192.f),
mBaseCameraDistance(Settings::Manager::getFloat("third person camera distance", "Camera")),
mVanityToggleQueued(false),
mVanityToggleQueuedValue(false),
mViewModeToggleQueued(false),
@ -380,7 +381,7 @@ namespace MWRender
return mCameraDistance;
}
void Camera::setBaseCameraDistance(float dist, bool adjust)
void Camera::updateBaseCameraDistance(float dist, bool adjust)
{
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)
return;
@ -407,7 +408,10 @@ namespace MWRender
if (mVanity.enabled || mPreviewMode)
mPreviewCam.offset = dist;
else if (!mFirstPersonView)
{
mBaseCameraDistance = dist;
Settings::Manager::setFloat("third person camera distance", "Camera", dist);
}
setCameraDistance();
}

@ -119,7 +119,7 @@ namespace MWRender
/// Set base camera distance for current mode. Don't work on 1st person view.
/// \param adjust Indicates should distance be adjusted or set.
void setBaseCameraDistance(float dist, bool adjust = false);
void updateBaseCameraDistance(float dist, bool adjust = false);
/// Set camera distance for current mode. Don't work on 1st person view.
/// \param adjust Indicates should distance be adjusted or set.

@ -273,7 +273,7 @@ osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration)
{
osg::Vec3f ret = Animation::runAnimation(duration);
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0] + getBodyPitchRadians());
return ret;
}

@ -349,6 +349,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> par
mPartPriorities[i] = 0;
}
std::fill(mSounds.begin(), mSounds.end(), nullptr);
updateNpcBase();
}
@ -745,7 +747,7 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed)
mFirstPersonNeckController->setOffset(mFirstPersonOffset);
}
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0] + getBodyPitchRadians());
return ret;
}
@ -756,10 +758,10 @@ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type)
mPartslots[type] = -1;
mObjectParts[type].reset();
if (!mSoundIds[type].empty() && !mSoundsDisabled)
if (mSounds[type] != nullptr && !mSoundsDisabled)
{
MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mSoundIds[type]);
mSoundIds[type].clear();
MWBase::Environment::get().getSoundManager()->stopSound(mSounds[type]);
mSounds[type] = nullptr;
}
}
@ -838,10 +840,10 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
MWWorld::ConstContainerStoreIterator csi = inv.getSlot(group < 0 ? MWWorld::InventoryStore::Slot_Helmet : group);
if (csi != inv.end())
{
mSoundIds[type] = csi->getClass().getSound(*csi);
if (!mSoundIds[type].empty())
const auto soundId = csi->getClass().getSound(*csi);
if (!soundId.empty())
{
MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, mSoundIds[type],
mSounds[type] = MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, soundId,
1.0f, 1.0f, MWSound::Type::Sfx, MWSound::PlayMode::Loop
);
}

@ -8,12 +8,19 @@
#include "actoranimation.hpp"
#include "weaponanimation.hpp"
#include <array>
namespace ESM
{
struct NPC;
struct BodyPart;
}
namespace MWSound
{
class Sound;
}
namespace MWRender
{
@ -40,7 +47,7 @@ private:
// Bounded Parts
PartHolderPtr mObjectParts[ESM::PRT_Count];
std::string mSoundIds[ESM::PRT_Count];
std::array<MWSound::Sound*, ESM::PRT_Count> mSounds;
const ESM::NPC *mNpc;
std::string mHeadModel;

@ -670,16 +670,27 @@ namespace MWRender
{
if (mActiveGridOnly && !std::get<2>(id)) return false;
pos /= ESM::Land::REAL_SIZE;
clampToCell(pos);
osg::Vec2f center = std::get<0>(id);
float halfSize = std::get<1>(id)/2;
return pos.x() >= center.x()-halfSize && pos.y() >= center.y()-halfSize && pos.x() <= center.x()+halfSize && pos.y() <= center.y()+halfSize;
}
void clampToCell(osg::Vec3f& cellPos)
{
osg::Vec2i min (mCell.x(), mCell.y());
osg::Vec2i max (mCell.x()+1, mCell.y()+1);
if (cellPos.x() < min.x()) cellPos.x() = min.x();
if (cellPos.x() > max.x()) cellPos.x() = max.x();
if (cellPos.y() < min.y()) cellPos.y() = min.y();
if (cellPos.y() > max.y()) cellPos.y() = max.y();
}
osg::Vec3f mPosition;
osg::Vec2i mCell;
std::set<MWRender::ChunkId> mToClear;
bool mActiveGridOnly = false;
};
bool ObjectPaging::enableObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, bool enabled)
bool ObjectPaging::enableObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, const osg::Vec2i& cell, bool enabled)
{
if (!typeFilter(type, false))
return false;
@ -693,6 +704,7 @@ namespace MWRender
ClearCacheFunctor ccf;
ccf.mPosition = pos;
ccf.mCell = cell;
mCache->call(ccf);
if (ccf.mToClear.empty()) return false;
for (auto chunk : ccf.mToClear)
@ -700,7 +712,7 @@ namespace MWRender
return true;
}
bool ObjectPaging::blacklistObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos)
bool ObjectPaging::blacklistObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, const osg::Vec2i& cell)
{
if (!typeFilter(type, false))
return false;
@ -713,6 +725,7 @@ namespace MWRender
ClearCacheFunctor ccf;
ccf.mPosition = pos;
ccf.mCell = cell;
ccf.mActiveGridOnly = true;
mCache->call(ccf);
if (ccf.mToClear.empty()) return false;

@ -34,10 +34,10 @@ namespace MWRender
virtual unsigned int getNodeMask() override;
/// @return true if view needs rebuild
bool enableObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, bool enabled);
bool enableObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, const osg::Vec2i& cell, bool enabled);
/// @return true if view needs rebuild
bool blacklistObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos);
bool blacklistObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, const osg::Vec2i& cell);
void clear();

@ -1340,7 +1340,7 @@ namespace MWRender
if(mCamera->isNearest() && dist > 0.f)
mCamera->toggleViewMode();
else if (override)
mCamera->setBaseCameraDistance(-dist / 120.f * 10, adjust);
mCamera->updateBaseCameraDistance(-dist / 120.f * 10, adjust);
else
mCamera->setCameraDistance(-dist / 120.f * 10, adjust);
}
@ -1348,7 +1348,7 @@ namespace MWRender
{
mCamera->toggleViewMode();
if (override)
mCamera->setBaseCameraDistance(0.f, false);
mCamera->updateBaseCameraDistance(0.f, false);
else
mCamera->setCameraDistance(0.f, false);
}
@ -1397,7 +1397,7 @@ namespace MWRender
void RenderingManager::changeVanityModeScale(float factor)
{
if(mCamera->isVanityOrPreviewModeEnabled())
mCamera->setBaseCameraDistance(-factor/120.f*10, true);
mCamera->updateBaseCameraDistance(-factor/120.f*10, true);
}
void RenderingManager::overrideFieldOfView(float val)
@ -1517,7 +1517,7 @@ namespace MWRender
{
if (!ptr.isInCell() || !ptr.getCell()->isExterior() || !mObjectPaging)
return false;
if (mObjectPaging->enableObject(type, ptr.getCellRef().getRefNum(), ptr.getCellRef().getPosition().asVec3(), enabled))
if (mObjectPaging->enableObject(type, ptr.getCellRef().getRefNum(), ptr.getCellRef().getPosition().asVec3(), osg::Vec2i(ptr.getCell()->getCell()->getGridX(), ptr.getCell()->getCell()->getGridY()), enabled))
{
mTerrain->rebuildViews();
return true;
@ -1530,7 +1530,7 @@ namespace MWRender
return;
const ESM::RefNum & refnum = ptr.getCellRef().getRefNum();
if (!refnum.hasContentFile()) return;
if (mObjectPaging->blacklistObject(type, refnum, ptr.getCellRef().getPosition().asVec3()))
if (mObjectPaging->blacklistObject(type, refnum, ptr.getCellRef().getPosition().asVec3(), osg::Vec2i(ptr.getCell()->getCell()->getGridX(), ptr.getCell()->getCell()->getGridY())))
mTerrain->rebuildViews();
}
bool RenderingManager::pagingUnlockCache()

@ -200,6 +200,7 @@ void RippleSimulation::emitRipple(const osg::Vec3f &pos)
{
if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20)
{
osgParticle::ParticleSystem::ScopedWriteLock lock(*mParticleSystem->getReadWriteMutex());
osgParticle::Particle* p = mParticleSystem->createParticle(nullptr);
p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f));
p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI));

@ -58,9 +58,6 @@ namespace MWSound
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
, mSoundBuffers(new SoundBufferList::element_type())
, mBufferCacheSize(0)
, mSounds(new std::deque<Sound>())
, mStreams(new std::deque<Stream>())
, mMusic(nullptr)
, mListenerUnderwater(false)
, mListenerPos(0,0,0)
, mListenerDir(1,0,0)
@ -268,39 +265,17 @@ namespace MWSound
return nullptr;
}
Sound *SoundManager::getSoundRef()
SoundPtr SoundManager::getSoundRef()
{
Sound *ret;
if(!mUnusedSounds.empty())
{
ret = mUnusedSounds.back();
mUnusedSounds.pop_back();
}
else
{
mSounds->emplace_back();
ret = &mSounds->back();
}
return ret;
return mSounds.get();
}
Stream *SoundManager::getStreamRef()
{
Stream *ret;
if(!mUnusedStreams.empty())
StreamPtr SoundManager::getStreamRef()
{
ret = mUnusedStreams.back();
mUnusedStreams.pop_back();
}
else
{
mStreams->emplace_back();
ret = &mStreams->back();
}
return ret;
return mStreams.get();
}
Stream *SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal)
StreamPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
static const float fAudioMinDistanceMult = world->getStore().get<ESM::GameSetting>().find("fAudioMinDistanceMult")->mValue.getFloat();
@ -312,23 +287,20 @@ namespace MWSound
bool played;
float basevol = volumeFromType(Type::Voice);
Stream *sound = getStreamRef();
StreamPtr sound = getStreamRef();
if(playlocal)
{
sound->init(1.0f, basevol, 1.0f, PlayMode::NoEnv|Type::Voice|Play_2D);
played = mOutput->streamSound(decoder, sound, true);
played = mOutput->streamSound(decoder, sound.get(), true);
}
else
{
sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
PlayMode::Normal|Type::Voice|Play_3D);
played = mOutput->streamSound3D(decoder, sound, true);
played = mOutput->streamSound3D(decoder, sound.get(), true);
}
if(!played)
{
mUnusedStreams.push_back(sound);
return nullptr;
}
return sound;
}
@ -342,8 +314,7 @@ namespace MWSound
{
if(mMusic)
{
mOutput->finishStream(mMusic);
mUnusedStreams.push_back(mMusic);
mOutput->finishStream(mMusic.get());
mMusic = nullptr;
}
}
@ -363,7 +334,7 @@ namespace MWSound
mMusic = getStreamRef();
mMusic->init(1.0f, volumeFromType(Type::Music), 1.0f,
PlayMode::NoEnv|Type::Music|Play_2D);
mOutput->streamSound(decoder, mMusic);
mOutput->streamSound(decoder, mMusic.get());
}
void SoundManager::advanceMusic(const std::string& filename)
@ -413,7 +384,7 @@ namespace MWSound
bool SoundManager::isMusicPlaying()
{
return mMusic && mOutput->isStreamPlaying(mMusic);
return mMusic && mOutput->isStreamPlaying(mMusic.get());
}
void SoundManager::playPlaylist(const std::string &playlist)
@ -496,10 +467,10 @@ namespace MWSound
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
stopSay(ptr);
Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
StreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
if(!sound) return;
mSaySoundsQueue.emplace(ptr, sound);
mSaySoundsQueue.emplace(ptr, std::move(sound));
}
float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const
@ -507,7 +478,7 @@ namespace MWSound
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end())
{
Stream *sound = snditer->second;
Stream *sound = snditer->second.get();
return mOutput->getStreamLoudness(sound);
}
@ -527,10 +498,10 @@ namespace MWSound
return;
stopSay(MWWorld::ConstPtr());
Stream *sound = playVoice(decoder, osg::Vec3f(), true);
StreamPtr sound = playVoice(decoder, osg::Vec3f(), true);
if(!sound) return;
mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), sound));
mActiveSaySounds.emplace(MWWorld::ConstPtr(), std::move(sound));
}
bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const
@ -538,7 +509,7 @@ namespace MWSound
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end())
{
if(mOutput->isStreamPlaying(snditer->second))
if(mOutput->isStreamPlaying(snditer->second.get()))
return false;
return true;
}
@ -550,7 +521,7 @@ namespace MWSound
SaySoundMap::const_iterator snditer = mSaySoundsQueue.find(ptr);
if(snditer != mSaySoundsQueue.end())
{
if(mOutput->isStreamPlaying(snditer->second))
if(mOutput->isStreamPlaying(snditer->second.get()))
return true;
return false;
}
@ -558,7 +529,7 @@ namespace MWSound
snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end())
{
if(mOutput->isStreamPlaying(snditer->second))
if(mOutput->isStreamPlaying(snditer->second.get()))
return true;
return false;
}
@ -571,16 +542,14 @@ namespace MWSound
SaySoundMap::iterator snditer = mSaySoundsQueue.find(ptr);
if(snditer != mSaySoundsQueue.end())
{
mOutput->finishStream(snditer->second);
mUnusedStreams.push_back(snditer->second);
mOutput->finishStream(snditer->second.get());
mSaySoundsQueue.erase(snditer);
}
snditer = mActiveSaySounds.find(ptr);
if(snditer != mActiveSaySounds.end())
{
mOutput->finishStream(snditer->second);
mUnusedStreams.push_back(snditer->second);
mOutput->finishStream(snditer->second.get());
mActiveSaySounds.erase(snditer);
}
}
@ -591,27 +560,24 @@ namespace MWSound
if(!mOutput->isInitialized())
return nullptr;
Stream *track = getStreamRef();
StreamPtr track = getStreamRef();
track->init(1.0f, volumeFromType(type), 1.0f, PlayMode::NoEnv|type|Play_2D);
if(!mOutput->streamSound(decoder, track))
{
mUnusedStreams.push_back(track);
if(!mOutput->streamSound(decoder, track.get()))
return nullptr;
}
mActiveTracks.insert(
std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track), track
);
return track;
Stream* result = track.get();
const auto it = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track);
mActiveTracks.insert(it, std::move(track));
return result;
}
void SoundManager::stopTrack(Stream *stream)
{
mOutput->finishStream(stream);
TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream);
if(iter != mActiveTracks.end() && *iter == stream)
TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream,
[] (const StreamPtr& lhs, Stream* rhs) { return lhs.get() < rhs; });
if(iter != mActiveTracks.end() && iter->get() == stream)
mActiveTracks.erase(iter);
mUnusedStreams.push_back(stream);
}
double SoundManager::getTrackTimeDelay(Stream *stream)
@ -620,7 +586,7 @@ namespace MWSound
}
Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, Type type, PlayMode mode, float offset)
Sound* SoundManager::playSound(const std::string& soundId, float volume, float pitch, Type type, PlayMode mode, float offset)
{
if(!mOutput->isInitialized())
return nullptr;
@ -631,13 +597,10 @@ namespace MWSound
// Only one copy of given sound can be played at time, so stop previous copy
stopSound(sfx, MWWorld::ConstPtr());
Sound *sound = getSoundRef();
SoundPtr sound = getSoundRef();
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
if(!mOutput->playSound(sound, sfx->mHandle, offset))
{
mUnusedSounds.push_back(sound);
if(!mOutput->playSound(sound.get(), sfx->mHandle, offset))
return nullptr;
}
if(sfx->mUses++ == 0)
{
@ -645,8 +608,9 @@ namespace MWSound
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
return sound;
Sound* result = sound.get();
mActiveSounds[MWWorld::ConstPtr()].emplace_back(std::move(sound), sfx);
return result;
}
Sound *SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId,
@ -656,35 +620,32 @@ namespace MWSound
if(!mOutput->isInitialized())
return nullptr;
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
if ((mode & PlayMode::RemoveAtDistance) && (mListenerPos - objpos).length2() > 2000 * 2000)
return nullptr;
// Look up the sound in the ESM data
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr;
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
if((mode&PlayMode::RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000)
return nullptr;
// Only one copy of given sound can be played at time on ptr, so stop previous copy
stopSound(sfx, ptr);
bool played;
Sound *sound = getSoundRef();
SoundPtr sound = getSoundRef();
if(!(mode&PlayMode::NoPlayerLocal) && ptr == MWMechanics::getPlayer())
{
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
played = mOutput->playSound(sound, sfx->mHandle, offset);
played = mOutput->playSound(sound.get(), sfx->mHandle, offset);
}
else
{
sound->init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch,
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
played = mOutput->playSound3D(sound, sfx->mHandle, offset);
played = mOutput->playSound3D(sound.get(), sfx->mHandle, offset);
}
if(!played)
{
mUnusedSounds.push_back(sound);
return nullptr;
}
if(sfx->mUses++ == 0)
{
@ -692,8 +653,9 @@ namespace MWSound
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[ptr].push_back(std::make_pair(sound, sfx));
return sound;
Sound* result = sound.get();
mActiveSounds[ptr].emplace_back(std::move(sound), sfx);
return result;
}
Sound *SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId,
@ -707,14 +669,11 @@ namespace MWSound
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if(!sfx) return nullptr;
Sound *sound = getSoundRef();
SoundPtr sound = getSoundRef();
sound->init(initialPos, volume * sfx->mVolume, volumeFromType(type), pitch,
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
if(!mOutput->playSound3D(sound, sfx->mHandle, offset))
{
mUnusedSounds.push_back(sound);
if(!mOutput->playSound3D(sound.get(), sfx->mHandle, offset))
return nullptr;
}
if(sfx->mUses++ == 0)
{
@ -722,8 +681,9 @@ namespace MWSound
if(iter != mUnusedBuffers.end())
mUnusedBuffers.erase(iter);
}
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
return sound;
Sound* result = sound.get();
mActiveSounds[MWWorld::ConstPtr()].emplace_back(std::move(sound), sfx);
return result;
}
void SoundManager::stopSound(Sound *sound)
@ -740,7 +700,7 @@ namespace MWSound
for(SoundBufferRefPair &snd : snditer->second)
{
if(snd.second == sfx)
mOutput->finishSound(snd.first);
mOutput->finishSound(snd.first.get());
}
}
}
@ -762,14 +722,14 @@ namespace MWSound
if(snditer != mActiveSounds.end())
{
for(SoundBufferRefPair &snd : snditer->second)
mOutput->finishSound(snd.first);
mOutput->finishSound(snd.first.get());
}
SaySoundMap::iterator sayiter = mSaySoundsQueue.find(ptr);
if(sayiter != mSaySoundsQueue.end())
mOutput->finishStream(sayiter->second);
mOutput->finishStream(sayiter->second.get());
sayiter = mActiveSaySounds.find(ptr);
if(sayiter != mActiveSaySounds.end())
mOutput->finishStream(sayiter->second);
mOutput->finishStream(sayiter->second.get());
}
void SoundManager::stopSound(const MWWorld::CellStore *cell)
@ -779,20 +739,20 @@ namespace MWSound
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
{
for(SoundBufferRefPair &sndbuf : snd.second)
mOutput->finishSound(sndbuf.first);
mOutput->finishSound(sndbuf.first.get());
}
}
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
{
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
mOutput->finishStream(snd.second);
mOutput->finishStream(snd.second.get());
}
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
mOutput->finishStream(snd.second);
mOutput->finishStream(snd.second.get());
}
}
@ -802,7 +762,9 @@ namespace MWSound
SoundMap::iterator snditer = mActiveSounds.find(ptr);
if(snditer != mActiveSounds.end())
{
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
if (sfx == nullptr)
return;
for(SoundBufferRefPair &sndbuf : snditer->second)
{
if(sndbuf.second == sfx)
@ -819,7 +781,7 @@ namespace MWSound
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
return std::find_if(snditer->second.cbegin(), snditer->second.cend(),
[this,sfx](const SoundBufferRefPair &snd) -> bool
{ return snd.second == sfx && mOutput->isSoundPlaying(snd.first); }
{ return snd.second == sfx && mOutput->isSoundPlaying(snd.first.get()); }
) != snditer->second.cend();
}
return false;
@ -936,7 +898,7 @@ namespace MWSound
const auto pairiter = std::find_if(
snditer->second.begin(), snditer->second.end(),
[this](const SoundBufferRefPairList::value_type &item) -> bool
{ return mNearWaterSound == item.first; }
{ return mNearWaterSound == item.first.get(); }
);
if (pairiter != snditer->second.end() && pairiter->second != sfx)
soundIdChanged = true;
@ -962,7 +924,11 @@ namespace MWSound
SaySoundMap::iterator queuesayiter = mSaySoundsQueue.begin();
while (queuesayiter != mSaySoundsQueue.end())
{
mActiveSaySounds[queuesayiter->first] = queuesayiter->second;
const auto dst = mActiveSaySounds.find(queuesayiter->first);
if (dst == mActiveSaySounds.end())
mActiveSaySounds.emplace(queuesayiter->first, std::move(queuesayiter->second));
else
dst->second = std::move(queuesayiter->second);
mSaySoundsQueue.erase(queuesayiter++);
}
@ -1003,10 +969,9 @@ namespace MWSound
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
while(sndidx != snditer->second.end())
{
Sound *sound;
Sound_Buffer *sfx;
Sound *sound = sndidx->first.get();
Sound_Buffer *sfx = sndidx->second;
std::tie(sound, sfx) = *sndidx;
if(!ptr.isEmpty() && sound->getIs3D())
{
const ESM::Position &pos = ptr.getRefData().getPosition();
@ -1023,10 +988,9 @@ namespace MWSound
if(!mOutput->isSoundPlaying(sound))
{
mOutput->finishSound(sound);
mUnusedSounds.push_back(sound);
if(sound == mUnderwaterSound)
if (sound == mUnderwaterSound)
mUnderwaterSound = nullptr;
if(sound == mNearWaterSound)
if (sound == mNearWaterSound)
mNearWaterSound = nullptr;
if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx);
@ -1050,7 +1014,7 @@ namespace MWSound
while(sayiter != mActiveSaySounds.end())
{
MWWorld::ConstPtr ptr = sayiter->first;
Stream *sound = sayiter->second;
Stream *sound = sayiter->second.get();
if(!ptr.isEmpty() && sound->getIs3D())
{
MWBase::World *world = MWBase::Environment::get().getWorld();
@ -1067,7 +1031,6 @@ namespace MWSound
if(!mOutput->isStreamPlaying(sound))
{
mOutput->finishStream(sound);
mUnusedStreams.push_back(sound);
mActiveSaySounds.erase(sayiter++);
}
else
@ -1082,7 +1045,7 @@ namespace MWSound
TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter)
{
Stream *sound = *trkiter;
Stream *sound = trkiter->get();
if(!mOutput->isStreamPlaying(sound))
{
mOutput->finishStream(sound);
@ -1113,7 +1076,7 @@ namespace MWSound
{
mMusic->updateFade(duration);
mOutput->updateStream(mMusic);
mOutput->updateStream(mMusic.get());
if (mMusic->getRealVolume() <= 0.f)
{
@ -1150,32 +1113,32 @@ namespace MWSound
{
for(SoundBufferRefPair &sndbuf : snd.second)
{
Sound *sound = sndbuf.first;
Sound *sound = sndbuf.first.get();
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateSound(sound);
}
}
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{
Stream *sound = snd.second;
Stream *sound = snd.second.get();
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound);
}
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
{
Stream *sound = snd.second;
Stream *sound = snd.second.get();
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound);
}
for(Stream *sound : mActiveTracks)
for (const StreamPtr& sound : mActiveTracks)
{
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound);
mOutput->updateStream(sound.get());
}
if(mMusic)
{
mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType()));
mOutput->updateStream(mMusic);
mOutput->updateStream(mMusic.get());
}
mOutput->finishUpdate();
}
@ -1204,17 +1167,17 @@ namespace MWSound
SaySoundMap::iterator sayiter = mSaySoundsQueue.find(old);
if(sayiter != mSaySoundsQueue.end())
{
Stream *stream = sayiter->second;
StreamPtr stream = std::move(sayiter->second);
mSaySoundsQueue.erase(sayiter);
mSaySoundsQueue.emplace(updated, stream);
mSaySoundsQueue.emplace(updated, std::move(stream));
}
sayiter = mActiveSaySounds.find(old);
if(sayiter != mActiveSaySounds.end())
{
Stream *stream = sayiter->second;
StreamPtr stream = std::move(sayiter->second);
mActiveSaySounds.erase(sayiter);
mActiveSaySounds.emplace(updated, stream);
mActiveSaySounds.emplace(updated, std::move(stream));
}
}
@ -1291,8 +1254,7 @@ namespace MWSound
{
for(SoundBufferRefPair &sndbuf : snd.second)
{
mOutput->finishSound(sndbuf.first);
mUnusedSounds.push_back(sndbuf.first);
mOutput->finishSound(sndbuf.first.get());
Sound_Buffer *sfx = sndbuf.second;
if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx);
@ -1303,24 +1265,15 @@ namespace MWSound
mNearWaterSound = nullptr;
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
{
mOutput->finishStream(snd.second);
mUnusedStreams.push_back(snd.second);
}
mOutput->finishStream(snd.second.get());
mSaySoundsQueue.clear();
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{
mOutput->finishStream(snd.second);
mUnusedStreams.push_back(snd.second);
}
mOutput->finishStream(snd.second.get());
mActiveSaySounds.clear();
for(Stream *sound : mActiveTracks)
{
mOutput->finishStream(sound);
mUnusedStreams.push_back(sound);
}
for(StreamPtr& sound : mActiveTracks)
mOutput->finishStream(sound.get());
mActiveTracks.clear();
mPlaybackPaused = false;
std::fill(std::begin(mPausedSoundTypes), std::end(mPausedSoundTypes), 0);

@ -9,7 +9,7 @@
#include <unordered_map>
#include <components/settings/settings.hpp>
#include <components/misc/objectpool.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/soundmanager.hpp"
@ -48,6 +48,9 @@ namespace MWSound
Play_3D = 1<<31
};
using SoundPtr = Misc::ObjectPtr<Sound>;
using StreamPtr = Misc::ObjectPtr<Stream>;
class SoundManager : public MWBase::SoundManager
{
const VFS::Manager* mVFS;
@ -79,25 +82,23 @@ namespace MWSound
typedef std::deque<Sound_Buffer*> SoundList;
SoundList mUnusedBuffers;
std::unique_ptr<std::deque<Sound>> mSounds;
std::vector<Sound*> mUnusedSounds;
Misc::ObjectPool<Sound> mSounds;
std::unique_ptr<std::deque<Stream>> mStreams;
std::vector<Stream*> mUnusedStreams;
Misc::ObjectPool<Stream> mStreams;
typedef std::pair<MWBase::Sound*,Sound_Buffer*> SoundBufferRefPair;
typedef std::pair<SoundPtr, Sound_Buffer*> SoundBufferRefPair;
typedef std::vector<SoundBufferRefPair> SoundBufferRefPairList;
typedef std::map<MWWorld::ConstPtr,SoundBufferRefPairList> SoundMap;
SoundMap mActiveSounds;
typedef std::map<MWWorld::ConstPtr,Stream*> SaySoundMap;
typedef std::map<MWWorld::ConstPtr, StreamPtr> SaySoundMap;
SaySoundMap mSaySoundsQueue;
SaySoundMap mActiveSaySounds;
typedef std::vector<Stream*> TrackList;
typedef std::vector<StreamPtr> TrackList;
TrackList mActiveTracks;
Stream *mMusic;
StreamPtr mMusic;
std::string mCurrentPlaylist;
bool mListenerUnderwater;
@ -127,10 +128,10 @@ namespace MWSound
// returns a decoder to start streaming, or nullptr if the sound was not found
DecoderPtr loadVoice(const std::string &voicefile);
Sound *getSoundRef();
Stream *getStreamRef();
SoundPtr getSoundRef();
StreamPtr getStreamRef();
Stream *playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal);
StreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal);
void streamMusicFull(const std::string& filename);
void advanceMusic(const std::string& filename);

@ -1555,6 +1555,9 @@ namespace MWWorld
{
if(ptr.getRefData().getBaseNode() != 0)
{
mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr);
mWorldScene->removeFromPagedRefs(ptr);
mRendering->rotateObject(ptr, rotate);
mPhysics->updateRotation(ptr);

@ -1,73 +0,0 @@
# - Try to find the Bullet physics engine
#
# This module accepts the following env variables
# BULLET_ROOT - Can be set to bullet install path or Windows build path
#
# Once done this will define
# Bullet_FOUND - System has the all required components.
# Bullet_INCLUDE_DIRS - Include directory necessary for using the required components headers.
# Bullet_LIBRARIES - Link these to use the required bullet components.
# Bullet_VERSION - Version of libbullet
#
# For each of the components
# - LinearMath
# - BulletCollision
# - BulletSoftBody
# - BulletDynamics
#
# Copyright (c) 2009, Philip Lowman <philip at yhbt.com>
# Modified for OpenMW to parse BT_BULLET_VERSION.
#
# Redistribution AND use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
include(LibFindMacros)
# Macro: _internal_find_bullet_library
# Checks for the given component by invoking pkgconfig etc.
macro(_internal_find_bullet_library _lib)
libfind_pkg_detect(Bullet_${_lib} bullet
FIND_LIBRARY ${_lib}
HINTS $ENV{BULLET_ROOT}
PATH_SUFFIXES lib
)
libfind_process(Bullet_${_lib})
endmacro()
set(_known_components LinearMath BulletCollision BulletSoftBody BulletDynamics)
# Check if the required components were found and add their stuff to the Bullet_* vars.
foreach (_component ${Bullet_FIND_COMPONENTS})
list(FIND _known_components ${_component} _known_component)
if (_known_component EQUAL -1)
message(FATAL_ERROR "Unknown component '${_component}'")
endif()
set(Bullet_${_component}_Debug_FIND_QUIETLY TRUE) # don't spam messages with optional Debug component
_internal_find_bullet_library(${_component})
_internal_find_bullet_library(${_component}_Debug)
if (Bullet_${_component}_Debug_FOUND)
set(Bullet_LIBRARIES ${Bullet_LIBRARIES} optimized ${Bullet_${_component}_LIBRARIES} debug ${Bullet_${_component}_Debug_LIBRARIES})
else()
set(Bullet_LIBRARIES ${Bullet_LIBRARIES} ${Bullet_${_component}_LIBRARIES})
endif()
endforeach()
libfind_pkg_detect(Bullet bullet
FIND_PATH btBulletCollisionCommon.h
HINTS $ENV{BULLET_ROOT}
PATH_SUFFIXES include/bullet
)
set(Bullet_INCLUDE_DIRS ${Bullet_INCLUDE_DIR})
libfind_version_header(Bullet LinearMath/btScalar.h BT_BULLET_VERSION)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet
FOUND_VAR Bullet_FOUND
VERSION_VAR Bullet_VERSION
HANDLE_COMPONENTS
REQUIRED_VARS
Bullet_LIBRARIES
Bullet_INCLUDE_DIR
)

@ -1,91 +0,0 @@
#-------------------------------------------------------------------
# This file is part of the CMake build system for OGRE
# (Object-oriented Graphics Rendering Engine)
# For the latest info, see https://www.ogre3d.org/
#
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
# - Try to find FreeType
#
# This module accepts the following env variable
# FREETYPE_DIR - Can be set to custom install path
#
# Once done, this will define
#
# Freetype_FOUND - system has FreeType
# Freetype_INCLUDE_DIRS - the FreeType include directories
# Freetype_LIBRARIES - link these to use FreeType
# Freetype_VERSION - version of FreeType
#
# libfreetype internals:
#
# ======================================
# new versions (2.5.2)
#
# file structure:
# <prefix>/include/freetype2/ft2build.h
# <prefix>/include/freetype2/freetype.h
# used as:
# #include <ft2build.h>
# #include <freetype.h>
# requires:
# -I <prefix>/include/freetype2/
#
# ======================================
# old versions (2.4.8, 2.3.5)
#
# file structure:
# <prefix>/include/ft2build.h
# <prefix>/include/freetype2/freetype/freetype.h
# used as:
# #include <ft2build.h>
# #include <freetype/freetype.h>
# requires:
# -I <prefix>/include/ -I <prefix>/include/freetype2/
#
# ======================================
include(LibFindMacros)
set(_REGULAR_INSTALL_PATHS
/usr/X11R6
/usr/local/X11R6
/usr/local/X11
/usr/freeware
ENV GTKMM_BASEPATH
[HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]
)
libfind_pkg_detect(Freetype freetype2
FIND_PATH ft2build.h
HINTS $ENV{FREETYPE_DIR}
PATHS ${_REGULAR_INSTALL_PATHS}
PATH_SUFFIXES include freetype2
FIND_LIBRARY freetype freetype2311 freetype239 freetype238 freetype235 freetype219
HINTS $ENV{FREETYPE_DIR}
PATHS ${_REGULAR_INSTALL_PATHS}
PATH_SUFFIXES lib
)
find_path(Freetype_OLD_INCLUDE_DIR
# in new versions of freetype old_include_dir equals to include_dir
# see explanation above
NAMES freetype/freetype.h freetype.h
PATHS ${Freetype_INCLUDE_DIR}
PATH_SUFFIXES freetype2
NO_DEFAULT_PATH
)
libfind_version_n_header(Freetype
NAMES freetype/freetype.h freetype.h
PATHS Freetype_OLD_INCLUDE_DIR
DEFINES FREETYPE_MAJOR FREETYPE_MINOR FREETYPE_PATCH
)
set(Freetype_PROCESS_INCLUDES Freetype_OLD_INCLUDE_DIR)
libfind_process(Freetype)
if (Freetype_INCLUDE_DIRS)
list(REMOVE_DUPLICATES Freetype_INCLUDE_DIRS)
endif()

@ -289,7 +289,7 @@ if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
endif()
endif ()
include_directories(${Bullet_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR})
@ -308,7 +308,7 @@ target_link_libraries(components
${OSGGA_LIBRARIES}
${OSGSHADOW_LIBRARIES}
${OSGANIMATION_LIBRARIES}
${Bullet_LIBRARIES}
${BULLET_LIBRARIES}
${SDL2_LIBRARIES}
${OPENGL_gl_LIBRARY}
${MyGUI_LIBRARIES}

@ -0,0 +1,83 @@
#ifndef OPENMW_COMPONENTS_MISC_OBJECTPOOL_H
#define OPENMW_COMPONENTS_MISC_OBJECTPOOL_H
#include <deque>
#include <memory>
#include <vector>
namespace Misc
{
template <class T>
class ObjectPool;
template <class T>
class ObjectPtrDeleter
{
public:
ObjectPtrDeleter(std::nullptr_t)
: mPool(nullptr) {}
ObjectPtrDeleter(ObjectPool<T>& pool)
: mPool(&pool) {}
void operator()(T* object) const
{
mPool->recycle(object);
}
private:
ObjectPool<T>* mPool;
};
template <class T>
struct ObjectPtr final : std::unique_ptr<T, ObjectPtrDeleter<T>>
{
using std::unique_ptr<T, ObjectPtrDeleter<T>>::unique_ptr;
using std::unique_ptr<T, ObjectPtrDeleter<T>>::operator=;
ObjectPtr()
: ObjectPtr(nullptr) {}
ObjectPtr(std::nullptr_t)
: std::unique_ptr<T, ObjectPtrDeleter<T>>(nullptr, nullptr) {}
};
template <class T>
class ObjectPool
{
friend class ObjectPtrDeleter<T>;
public:
ObjectPool()
: mObjects(std::make_unique<std::deque<T>>()) {}
ObjectPtr<T> get()
{
T* object;
if (!mUnused.empty())
{
object = mUnused.back();
mUnused.pop_back();
}
else
{
mObjects->emplace_back();
object = &mObjects->back();
}
return ObjectPtr<T>(object, ObjectPtrDeleter<T>(*this));
}
private:
std::unique_ptr<std::deque<T>> mObjects;
std::vector<T*> mUnused;
void recycle(T* object)
{
mUnused.push_back(object);
}
};
}
#endif

@ -114,6 +114,17 @@ while small values can result in the hands not being visible.
This setting can only be configured by editing the settings configuration file.
third person camera distance
----------------------------
:Type: floating point
:Range: 30-800
:Default: 192.0
Distance from the camera to the character in third person mode.
This setting can be changed in game using "Zoom In" / "Zoom Out" controls.
view over shoulder
------------------

@ -330,3 +330,29 @@ If disabled then the whole character's body is pointed to the direction of view.
If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it also changes straight right and straight left movement.
This setting can only be configured by editing the settings configuration file.
swim upward coef
----------------
:Type: floating point
:Range: -1.0 to 1.0
:Default: 0.0
Makes player swim a bit upward (or downward in case of negative value) from the line of sight. Intended to make simpler swimming without diving. Recommened range of values is from 0.0 to 0.2.
This setting can only be configured by editing the settings configuration file.
trainers training skills based on base skill
--------------------------------------------
:Type: boolean
:Range: True/False
:Default: False
The trainers in Morrowind choose their proposed training skills based on their 3 best attributes.
If disabled then the 3 best skills of trainers and the training limits take into account fortified/drained trainer skill.
If enabled then the 3 best skills of trainers and the training limits are based on the trainer base skills.
This setting can be controlled in Advanced tab of the launcher.

@ -33,6 +33,9 @@ field of view = 60.0
# Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen.
first person field of view = 60.0
# Distance from the camera to the character in third person mode.
third person camera distance = 192
# If enabled then third person camera is positioned above character's shoulder and crosshair is visible.
view over shoulder = false
@ -310,6 +313,12 @@ uncapped damage fatigue = false
# Turn lower body to movement direction. 'true' makes diagonal movement more realistic.
turn to movement direction = false
# Makes player swim a bit upward (or downward in case of negative value) from the line of sight.
swim upward coef = 0.0
# Make the training skills proposed by a trainer based on its base attribute instead of its modified ones
trainers training skills based on base skill = false
[General]
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).

@ -236,6 +236,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="trainersTrainingSkillsBasedOnBaseSkillCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Trainers now only choose which skills to train using their base skill points, allowing mercantile improving effects to be used without making mercantile an offered skill.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Trainers choose their training skills based on their base skill points</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

Loading…
Cancel
Save