mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-10-06 15:26:32 +00:00
Add OpenMW commits up to 11 Jul 2020
# Conflicts: # .travis.yml # apps/openmw/mwmechanics/actors.cpp
This commit is contained in:
commit
39e429c9eb
35 changed files with 382 additions and 372 deletions
|
@ -7,19 +7,24 @@ Debian:
|
||||||
- linux
|
- linux
|
||||||
image: debian:bullseye
|
image: debian:bullseye
|
||||||
cache:
|
cache:
|
||||||
key: apt-cache
|
key: cache.002
|
||||||
paths:
|
paths:
|
||||||
- apt-cache/
|
- apt-cache/
|
||||||
|
- ccache/
|
||||||
before_script:
|
before_script:
|
||||||
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
||||||
- apt-get update -yq
|
- 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
|
stage: build
|
||||||
script:
|
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
|
- 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
|
- make -j$cores_to_use
|
||||||
- DESTDIR=artifacts make install
|
- DESTDIR=artifacts make install
|
||||||
|
- ccache -s
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- build/artifacts/
|
- build/artifacts/
|
||||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -71,11 +71,11 @@ before_script:
|
||||||
- ./CI/before_script.${TRAVIS_OS_NAME}.sh
|
- ./CI/before_script.${TRAVIS_OS_NAME}.sh
|
||||||
script:
|
script:
|
||||||
- cd ./build
|
- cd ./build
|
||||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j3; 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 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}" = "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 ./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 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
|
||||||
- cd "${TRAVIS_BUILD_DIR}"
|
- cd "${TRAVIS_BUILD_DIR}"
|
||||||
- ccache -s
|
- ccache -s
|
||||||
#deploy:
|
#deploy:
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound
|
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 #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
|
||||||
Bug #5370: Opening an unlocked but trapped door uses the key
|
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 #5397: NPC greeting does not reset if you leave + reenter area
|
||||||
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
||||||
Bug #5403: Enchantment effect doesn't show on an enemy during death animation
|
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 #5362: Show the soul gems' trapped soul in count dialog
|
||||||
Feature #5445: Handle NiLines
|
Feature #5445: Handle NiLines
|
||||||
Feature #5457: Realistic diagonal movement
|
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
|
Task #5480: Drop Qt4 support
|
||||||
|
|
||||||
0.46.0
|
0.46.0
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
|
|
||||||
brew update
|
|
||||||
brew outdated pkgconfig || brew upgrade pkgconfig
|
|
||||||
brew install qt
|
|
||||||
brew install ccache
|
brew install ccache
|
||||||
|
|
||||||
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-ef2462c.zip -o ~/openmw-deps.zip
|
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
|
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
|
mv "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}" Bullet
|
||||||
fi
|
fi
|
||||||
export BULLET_ROOT="$(real_pwd)/Bullet"
|
add_cmake_opts -DBULLET_ROOT="$(real_pwd)/Bullet"
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
|
|
|
@ -13,10 +13,17 @@ cmake \
|
||||||
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
||||||
-D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
|
-D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
|
||||||
-D CMAKE_CXX_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_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 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" \
|
-G"Unix Makefiles" \
|
||||||
..
|
..
|
||||||
|
|
|
@ -326,7 +326,7 @@ include_directories("."
|
||||||
${Boost_INCLUDE_DIR}
|
${Boost_INCLUDE_DIR}
|
||||||
${MyGUI_INCLUDE_DIRS}
|
${MyGUI_INCLUDE_DIRS}
|
||||||
${OPENAL_INCLUDE_DIR}
|
${OPENAL_INCLUDE_DIR}
|
||||||
${Bullet_INCLUDE_DIRS}
|
${BULLET_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
|
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
|
||||||
|
|
|
@ -90,6 +90,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
||||||
}
|
}
|
||||||
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
||||||
|
loadSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
||||||
|
|
||||||
// Input Settings
|
// Input Settings
|
||||||
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
||||||
|
@ -155,6 +156,7 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
||||||
saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
||||||
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
||||||
|
saveSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
||||||
|
|
||||||
// Input Settings
|
// Input Settings
|
||||||
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
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.
|
// views that the whole row has changed.
|
||||||
|
|
||||||
emit dataChanged(this->index(index.row(), 0),
|
emit dataChanged(this->index(index.row(), 0),
|
||||||
this->index(index.row(), columnCount(index.parent())));
|
this->index(index.row(), columnCount(index.parent()) - 1));
|
||||||
|
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -52,6 +54,7 @@ namespace MWGui
|
||||||
TrainingWindow::TrainingWindow()
|
TrainingWindow::TrainingWindow()
|
||||||
: WindowBase("openmw_trainingwindow.layout")
|
: WindowBase("openmw_trainingwindow.layout")
|
||||||
, mTimeAdvancer(0.05f)
|
, mTimeAdvancer(0.05f)
|
||||||
|
, mTrainingSkillBasedOnBaseSkill(Settings::Manager::getBool("trainers training skills based on base skill", "Game"))
|
||||||
{
|
{
|
||||||
getWidget(mTrainingOptions, "TrainingOptions");
|
getWidget(mTrainingOptions, "TrainingOptions");
|
||||||
getWidget(mCancelButton, "CancelButton");
|
getWidget(mCancelButton, "CancelButton");
|
||||||
|
@ -88,9 +91,10 @@ namespace MWGui
|
||||||
// NPC can train you in his best 3 skills
|
// NPC can train you in his best 3 skills
|
||||||
std::vector< std::pair<int, float> > 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)
|
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));
|
skills.push_back(std::make_pair(i, value));
|
||||||
}
|
}
|
||||||
|
@ -152,7 +156,7 @@ namespace MWGui
|
||||||
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
||||||
return;
|
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}");
|
MWBase::Environment::get().getWindowManager()->messageBox ("#{sServiceTrainingWords}");
|
||||||
return;
|
return;
|
||||||
|
@ -232,6 +236,13 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
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)
|
void TrainingWindow::onFrame(float dt)
|
||||||
{
|
{
|
||||||
checkReferenceAvailable();
|
checkReferenceAvailable();
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
#include "timeadvancer.hpp"
|
#include "timeadvancer.hpp"
|
||||||
#include "waitdialog.hpp"
|
#include "waitdialog.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
class NpcStats;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -35,12 +40,17 @@ namespace MWGui
|
||||||
void onTrainingProgressChanged(int cur, int total);
|
void onTrainingProgressChanged(int cur, int total);
|
||||||
void onTrainingFinished();
|
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::Widget* mTrainingOptions;
|
||||||
MyGUI::Button* mCancelButton;
|
MyGUI::Button* mCancelButton;
|
||||||
MyGUI::TextBox* mPlayerGold;
|
MyGUI::TextBox* mPlayerGold;
|
||||||
|
|
||||||
WaitDialogProgressBar mProgressBar;
|
WaitDialogProgressBar mProgressBar;
|
||||||
TimeAdvancer mTimeAdvancer;
|
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)
|
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
|
||||||
{
|
{
|
||||||
|
bool isPlayer = iter->first == getPlayer();
|
||||||
notifyDied(iter->first);
|
notifyDied(iter->first);
|
||||||
|
|
||||||
// Reset magic effects and recalculate derived effects
|
// Reset magic effects and recalculate derived effects
|
||||||
|
@ -2167,16 +2168,8 @@ namespace MWMechanics
|
||||||
stats.modifyMagicEffects(MWMechanics::MagicEffects());
|
stats.modifyMagicEffects(MWMechanics::MagicEffects());
|
||||||
stats.getActiveSpells().clear();
|
stats.getActiveSpells().clear();
|
||||||
|
|
||||||
/*
|
if (!isPlayer)
|
||||||
Start of tes3mp change (major)
|
stats.getSpells().clear();
|
||||||
|
|
||||||
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)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Make sure spell effects are removed
|
// Make sure spell effects are removed
|
||||||
purgeSpellEffects(stats.getActorId());
|
purgeSpellEffects(stats.getActorId());
|
||||||
|
@ -2186,7 +2179,7 @@ namespace MWMechanics
|
||||||
if (iter->first.getClass().isNpc())
|
if (iter->first.getClass().isNpc())
|
||||||
calculateNpcStatModifiers(iter->first, 0);
|
calculateNpcStatModifiers(iter->first, 0);
|
||||||
|
|
||||||
if( iter->first == getPlayer())
|
if (isPlayer)
|
||||||
{
|
{
|
||||||
//player's death animation is over
|
//player's death animation is over
|
||||||
|
|
||||||
|
|
|
@ -2072,6 +2072,7 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
mTimeUntilWake -= duration;
|
mTimeUntilWake -= duration;
|
||||||
|
|
||||||
bool isPlayer = mPtr == MWMechanics::getPlayer();
|
bool isPlayer = mPtr == MWMechanics::getPlayer();
|
||||||
|
bool isFirstPersonPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
|
||||||
bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
|
bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
|
||||||
|
|
||||||
float scale = mPtr.getCellRef().getScale();
|
float scale = mPtr.getCellRef().getScale();
|
||||||
|
@ -2167,7 +2168,7 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
|
|
||||||
float effectiveRotation = rot.z();
|
float effectiveRotation = rot.z();
|
||||||
static const bool turnToMovementDirection = Settings::Manager::getBool("turn to movement direction", "Game");
|
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());
|
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)
|
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.
|
// It seems only bipedal actors use turning animations.
|
||||||
// Also do not use turning animations in the first-person view and when sneaking.
|
// 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 && !isFirstPersonPlayer && mPtr.getClass().isBipedal(mPtr))
|
||||||
if (!sneak && jumpstate == JumpState_None && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr))
|
|
||||||
{
|
{
|
||||||
if(effectiveRotation > rotationThreshold)
|
if(effectiveRotation > rotationThreshold)
|
||||||
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
|
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);
|
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
|
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -623,6 +623,7 @@ namespace MWRender
|
||||||
, mHeadPitchRadians(0.f)
|
, mHeadPitchRadians(0.f)
|
||||||
, mUpperBodyYawRadians(0.f)
|
, mUpperBodyYawRadians(0.f)
|
||||||
, mLegsYawRadians(0.f)
|
, mLegsYawRadians(0.f)
|
||||||
|
, mBodyPitchRadians(0.f)
|
||||||
, mHasMagicEffects(false)
|
, mHasMagicEffects(false)
|
||||||
, mAlpha(1.f)
|
, mAlpha(1.f)
|
||||||
{
|
{
|
||||||
|
@ -1340,11 +1341,11 @@ namespace MWRender
|
||||||
float yawOffset = 0;
|
float yawOffset = 0;
|
||||||
if (mRootController)
|
if (mRootController)
|
||||||
{
|
{
|
||||||
bool enable = std::abs(mLegsYawRadians) > epsilon;
|
bool enable = std::abs(mLegsYawRadians) > epsilon || std::abs(mBodyPitchRadians) > epsilon;
|
||||||
mRootController->setEnabled(enable);
|
mRootController->setEnabled(enable);
|
||||||
if (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;
|
yawOffset = mLegsYawRadians;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,7 @@ protected:
|
||||||
float mHeadPitchRadians;
|
float mHeadPitchRadians;
|
||||||
float mUpperBodyYawRadians;
|
float mUpperBodyYawRadians;
|
||||||
float mLegsYawRadians;
|
float mLegsYawRadians;
|
||||||
|
float mBodyPitchRadians;
|
||||||
|
|
||||||
RotateController* addRotateController(std::string bone);
|
RotateController* addRotateController(std::string bone);
|
||||||
|
|
||||||
|
@ -489,6 +490,8 @@ public:
|
||||||
virtual void setLegsYawRadians(float v) { mLegsYawRadians = v; }
|
virtual void setLegsYawRadians(float v) { mLegsYawRadians = v; }
|
||||||
virtual float getUpperBodyYawRadians() const { return mUpperBodyYawRadians; }
|
virtual float getUpperBodyYawRadians() const { return mUpperBodyYawRadians; }
|
||||||
virtual float getLegsYawRadians() const { return mLegsYawRadians; }
|
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 void setAccurateAiming(bool enabled) {}
|
||||||
virtual bool canBeHarvested() const { return false; }
|
virtual bool canBeHarvested() const { return false; }
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -56,7 +57,7 @@ namespace MWRender
|
||||||
mFurthest(800.f),
|
mFurthest(800.f),
|
||||||
mIsNearest(false),
|
mIsNearest(false),
|
||||||
mHeight(124.f),
|
mHeight(124.f),
|
||||||
mBaseCameraDistance(192.f),
|
mBaseCameraDistance(Settings::Manager::getFloat("third person camera distance", "Camera")),
|
||||||
mVanityToggleQueued(false),
|
mVanityToggleQueued(false),
|
||||||
mVanityToggleQueuedValue(false),
|
mVanityToggleQueuedValue(false),
|
||||||
mViewModeToggleQueued(false),
|
mViewModeToggleQueued(false),
|
||||||
|
@ -380,7 +381,7 @@ namespace MWRender
|
||||||
return mCameraDistance;
|
return mCameraDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setBaseCameraDistance(float dist, bool adjust)
|
void Camera::updateBaseCameraDistance(float dist, bool adjust)
|
||||||
{
|
{
|
||||||
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)
|
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)
|
||||||
return;
|
return;
|
||||||
|
@ -407,7 +408,10 @@ namespace MWRender
|
||||||
if (mVanity.enabled || mPreviewMode)
|
if (mVanity.enabled || mPreviewMode)
|
||||||
mPreviewCam.offset = dist;
|
mPreviewCam.offset = dist;
|
||||||
else if (!mFirstPersonView)
|
else if (!mFirstPersonView)
|
||||||
|
{
|
||||||
mBaseCameraDistance = dist;
|
mBaseCameraDistance = dist;
|
||||||
|
Settings::Manager::setFloat("third person camera distance", "Camera", dist);
|
||||||
|
}
|
||||||
setCameraDistance();
|
setCameraDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ namespace MWRender
|
||||||
|
|
||||||
/// Set base camera distance for current mode. Don't work on 1st person view.
|
/// Set base camera distance for current mode. Don't work on 1st person view.
|
||||||
/// \param adjust Indicates should distance be adjusted or set.
|
/// \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.
|
/// Set camera distance for current mode. Don't work on 1st person view.
|
||||||
/// \param adjust Indicates should distance be adjusted or set.
|
/// \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);
|
osg::Vec3f ret = Animation::runAnimation(duration);
|
||||||
|
|
||||||
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
|
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0] + getBodyPitchRadians());
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,6 +349,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> par
|
||||||
mPartPriorities[i] = 0;
|
mPartPriorities[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::fill(mSounds.begin(), mSounds.end(), nullptr);
|
||||||
|
|
||||||
updateNpcBase();
|
updateNpcBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,7 +747,7 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed)
|
||||||
mFirstPersonNeckController->setOffset(mFirstPersonOffset);
|
mFirstPersonNeckController->setOffset(mFirstPersonOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
|
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0] + getBodyPitchRadians());
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -756,10 +758,10 @@ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type)
|
||||||
mPartslots[type] = -1;
|
mPartslots[type] = -1;
|
||||||
|
|
||||||
mObjectParts[type].reset();
|
mObjectParts[type].reset();
|
||||||
if (!mSoundIds[type].empty() && !mSoundsDisabled)
|
if (mSounds[type] != nullptr && !mSoundsDisabled)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mSoundIds[type]);
|
MWBase::Environment::get().getSoundManager()->stopSound(mSounds[type]);
|
||||||
mSoundIds[type].clear();
|
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);
|
MWWorld::ConstContainerStoreIterator csi = inv.getSlot(group < 0 ? MWWorld::InventoryStore::Slot_Helmet : group);
|
||||||
if (csi != inv.end())
|
if (csi != inv.end())
|
||||||
{
|
{
|
||||||
mSoundIds[type] = csi->getClass().getSound(*csi);
|
const auto soundId = csi->getClass().getSound(*csi);
|
||||||
if (!mSoundIds[type].empty())
|
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
|
1.0f, 1.0f, MWSound::Type::Sfx, MWSound::PlayMode::Loop
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,19 @@
|
||||||
#include "actoranimation.hpp"
|
#include "actoranimation.hpp"
|
||||||
#include "weaponanimation.hpp"
|
#include "weaponanimation.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct NPC;
|
struct NPC;
|
||||||
struct BodyPart;
|
struct BodyPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
class Sound;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -40,7 +47,7 @@ private:
|
||||||
|
|
||||||
// Bounded Parts
|
// Bounded Parts
|
||||||
PartHolderPtr mObjectParts[ESM::PRT_Count];
|
PartHolderPtr mObjectParts[ESM::PRT_Count];
|
||||||
std::string mSoundIds[ESM::PRT_Count];
|
std::array<MWSound::Sound*, ESM::PRT_Count> mSounds;
|
||||||
|
|
||||||
const ESM::NPC *mNpc;
|
const ESM::NPC *mNpc;
|
||||||
std::string mHeadModel;
|
std::string mHeadModel;
|
||||||
|
|
|
@ -670,16 +670,27 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
if (mActiveGridOnly && !std::get<2>(id)) return false;
|
if (mActiveGridOnly && !std::get<2>(id)) return false;
|
||||||
pos /= ESM::Land::REAL_SIZE;
|
pos /= ESM::Land::REAL_SIZE;
|
||||||
|
clampToCell(pos);
|
||||||
osg::Vec2f center = std::get<0>(id);
|
osg::Vec2f center = std::get<0>(id);
|
||||||
float halfSize = std::get<1>(id)/2;
|
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;
|
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::Vec3f mPosition;
|
||||||
|
osg::Vec2i mCell;
|
||||||
std::set<MWRender::ChunkId> mToClear;
|
std::set<MWRender::ChunkId> mToClear;
|
||||||
bool mActiveGridOnly = false;
|
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))
|
if (!typeFilter(type, false))
|
||||||
return false;
|
return false;
|
||||||
|
@ -693,6 +704,7 @@ namespace MWRender
|
||||||
|
|
||||||
ClearCacheFunctor ccf;
|
ClearCacheFunctor ccf;
|
||||||
ccf.mPosition = pos;
|
ccf.mPosition = pos;
|
||||||
|
ccf.mCell = cell;
|
||||||
mCache->call(ccf);
|
mCache->call(ccf);
|
||||||
if (ccf.mToClear.empty()) return false;
|
if (ccf.mToClear.empty()) return false;
|
||||||
for (auto chunk : ccf.mToClear)
|
for (auto chunk : ccf.mToClear)
|
||||||
|
@ -700,7 +712,7 @@ namespace MWRender
|
||||||
return true;
|
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))
|
if (!typeFilter(type, false))
|
||||||
return false;
|
return false;
|
||||||
|
@ -713,6 +725,7 @@ namespace MWRender
|
||||||
|
|
||||||
ClearCacheFunctor ccf;
|
ClearCacheFunctor ccf;
|
||||||
ccf.mPosition = pos;
|
ccf.mPosition = pos;
|
||||||
|
ccf.mCell = cell;
|
||||||
ccf.mActiveGridOnly = true;
|
ccf.mActiveGridOnly = true;
|
||||||
mCache->call(ccf);
|
mCache->call(ccf);
|
||||||
if (ccf.mToClear.empty()) return false;
|
if (ccf.mToClear.empty()) return false;
|
||||||
|
|
|
@ -34,10 +34,10 @@ namespace MWRender
|
||||||
virtual unsigned int getNodeMask() override;
|
virtual unsigned int getNodeMask() override;
|
||||||
|
|
||||||
/// @return true if view needs rebuild
|
/// @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
|
/// @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();
|
void clear();
|
||||||
|
|
||||||
|
|
|
@ -1340,7 +1340,7 @@ namespace MWRender
|
||||||
if(mCamera->isNearest() && dist > 0.f)
|
if(mCamera->isNearest() && dist > 0.f)
|
||||||
mCamera->toggleViewMode();
|
mCamera->toggleViewMode();
|
||||||
else if (override)
|
else if (override)
|
||||||
mCamera->setBaseCameraDistance(-dist / 120.f * 10, adjust);
|
mCamera->updateBaseCameraDistance(-dist / 120.f * 10, adjust);
|
||||||
else
|
else
|
||||||
mCamera->setCameraDistance(-dist / 120.f * 10, adjust);
|
mCamera->setCameraDistance(-dist / 120.f * 10, adjust);
|
||||||
}
|
}
|
||||||
|
@ -1348,7 +1348,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
mCamera->toggleViewMode();
|
mCamera->toggleViewMode();
|
||||||
if (override)
|
if (override)
|
||||||
mCamera->setBaseCameraDistance(0.f, false);
|
mCamera->updateBaseCameraDistance(0.f, false);
|
||||||
else
|
else
|
||||||
mCamera->setCameraDistance(0.f, false);
|
mCamera->setCameraDistance(0.f, false);
|
||||||
}
|
}
|
||||||
|
@ -1397,7 +1397,7 @@ namespace MWRender
|
||||||
void RenderingManager::changeVanityModeScale(float factor)
|
void RenderingManager::changeVanityModeScale(float factor)
|
||||||
{
|
{
|
||||||
if(mCamera->isVanityOrPreviewModeEnabled())
|
if(mCamera->isVanityOrPreviewModeEnabled())
|
||||||
mCamera->setBaseCameraDistance(-factor/120.f*10, true);
|
mCamera->updateBaseCameraDistance(-factor/120.f*10, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::overrideFieldOfView(float val)
|
void RenderingManager::overrideFieldOfView(float val)
|
||||||
|
@ -1517,7 +1517,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
if (!ptr.isInCell() || !ptr.getCell()->isExterior() || !mObjectPaging)
|
if (!ptr.isInCell() || !ptr.getCell()->isExterior() || !mObjectPaging)
|
||||||
return false;
|
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();
|
mTerrain->rebuildViews();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1530,7 +1530,7 @@ namespace MWRender
|
||||||
return;
|
return;
|
||||||
const ESM::RefNum & refnum = ptr.getCellRef().getRefNum();
|
const ESM::RefNum & refnum = ptr.getCellRef().getRefNum();
|
||||||
if (!refnum.hasContentFile()) return;
|
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();
|
mTerrain->rebuildViews();
|
||||||
}
|
}
|
||||||
bool RenderingManager::pagingUnlockCache()
|
bool RenderingManager::pagingUnlockCache()
|
||||||
|
|
|
@ -200,6 +200,7 @@ void RippleSimulation::emitRipple(const osg::Vec3f &pos)
|
||||||
{
|
{
|
||||||
if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20)
|
if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20)
|
||||||
{
|
{
|
||||||
|
osgParticle::ParticleSystem::ScopedWriteLock lock(*mParticleSystem->getReadWriteMutex());
|
||||||
osgParticle::Particle* p = mParticleSystem->createParticle(nullptr);
|
osgParticle::Particle* p = mParticleSystem->createParticle(nullptr);
|
||||||
p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f));
|
p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f));
|
||||||
p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI));
|
p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI));
|
||||||
|
|
|
@ -58,9 +58,6 @@ namespace MWSound
|
||||||
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
|
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
|
||||||
, mSoundBuffers(new SoundBufferList::element_type())
|
, mSoundBuffers(new SoundBufferList::element_type())
|
||||||
, mBufferCacheSize(0)
|
, mBufferCacheSize(0)
|
||||||
, mSounds(new std::deque<Sound>())
|
|
||||||
, mStreams(new std::deque<Stream>())
|
|
||||||
, mMusic(nullptr)
|
|
||||||
, mListenerUnderwater(false)
|
, mListenerUnderwater(false)
|
||||||
, mListenerPos(0,0,0)
|
, mListenerPos(0,0,0)
|
||||||
, mListenerDir(1,0,0)
|
, mListenerDir(1,0,0)
|
||||||
|
@ -268,39 +265,17 @@ namespace MWSound
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound *SoundManager::getSoundRef()
|
SoundPtr SoundManager::getSoundRef()
|
||||||
{
|
{
|
||||||
Sound *ret;
|
return mSounds.get();
|
||||||
if(!mUnusedSounds.empty())
|
|
||||||
{
|
|
||||||
ret = mUnusedSounds.back();
|
|
||||||
mUnusedSounds.pop_back();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSounds->emplace_back();
|
|
||||||
ret = &mSounds->back();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream *SoundManager::getStreamRef()
|
StreamPtr SoundManager::getStreamRef()
|
||||||
{
|
{
|
||||||
Stream *ret;
|
return mStreams.get();
|
||||||
if(!mUnusedStreams.empty())
|
|
||||||
{
|
|
||||||
ret = mUnusedStreams.back();
|
|
||||||
mUnusedStreams.pop_back();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mStreams->emplace_back();
|
|
||||||
ret = &mStreams->back();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
static const float fAudioMinDistanceMult = world->getStore().get<ESM::GameSetting>().find("fAudioMinDistanceMult")->mValue.getFloat();
|
static const float fAudioMinDistanceMult = world->getStore().get<ESM::GameSetting>().find("fAudioMinDistanceMult")->mValue.getFloat();
|
||||||
|
@ -312,23 +287,20 @@ namespace MWSound
|
||||||
|
|
||||||
bool played;
|
bool played;
|
||||||
float basevol = volumeFromType(Type::Voice);
|
float basevol = volumeFromType(Type::Voice);
|
||||||
Stream *sound = getStreamRef();
|
StreamPtr sound = getStreamRef();
|
||||||
if(playlocal)
|
if(playlocal)
|
||||||
{
|
{
|
||||||
sound->init(1.0f, basevol, 1.0f, PlayMode::NoEnv|Type::Voice|Play_2D);
|
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
|
else
|
||||||
{
|
{
|
||||||
sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
|
sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
|
||||||
PlayMode::Normal|Type::Voice|Play_3D);
|
PlayMode::Normal|Type::Voice|Play_3D);
|
||||||
played = mOutput->streamSound3D(decoder, sound, true);
|
played = mOutput->streamSound3D(decoder, sound.get(), true);
|
||||||
}
|
}
|
||||||
if(!played)
|
if(!played)
|
||||||
{
|
|
||||||
mUnusedStreams.push_back(sound);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,8 +314,7 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
if(mMusic)
|
if(mMusic)
|
||||||
{
|
{
|
||||||
mOutput->finishStream(mMusic);
|
mOutput->finishStream(mMusic.get());
|
||||||
mUnusedStreams.push_back(mMusic);
|
|
||||||
mMusic = nullptr;
|
mMusic = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,7 +334,7 @@ namespace MWSound
|
||||||
mMusic = getStreamRef();
|
mMusic = getStreamRef();
|
||||||
mMusic->init(1.0f, volumeFromType(Type::Music), 1.0f,
|
mMusic->init(1.0f, volumeFromType(Type::Music), 1.0f,
|
||||||
PlayMode::NoEnv|Type::Music|Play_2D);
|
PlayMode::NoEnv|Type::Music|Play_2D);
|
||||||
mOutput->streamSound(decoder, mMusic);
|
mOutput->streamSound(decoder, mMusic.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::advanceMusic(const std::string& filename)
|
void SoundManager::advanceMusic(const std::string& filename)
|
||||||
|
@ -413,7 +384,7 @@ namespace MWSound
|
||||||
|
|
||||||
bool SoundManager::isMusicPlaying()
|
bool SoundManager::isMusicPlaying()
|
||||||
{
|
{
|
||||||
return mMusic && mOutput->isStreamPlaying(mMusic);
|
return mMusic && mOutput->isStreamPlaying(mMusic.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::playPlaylist(const std::string &playlist)
|
void SoundManager::playPlaylist(const std::string &playlist)
|
||||||
|
@ -496,10 +467,10 @@ namespace MWSound
|
||||||
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
|
const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans();
|
||||||
|
|
||||||
stopSay(ptr);
|
stopSay(ptr);
|
||||||
Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
|
StreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer()));
|
||||||
if(!sound) return;
|
if(!sound) return;
|
||||||
|
|
||||||
mSaySoundsQueue.emplace(ptr, sound);
|
mSaySoundsQueue.emplace(ptr, std::move(sound));
|
||||||
}
|
}
|
||||||
|
|
||||||
float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const
|
float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const
|
||||||
|
@ -507,7 +478,7 @@ namespace MWSound
|
||||||
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
|
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
|
||||||
if(snditer != mActiveSaySounds.end())
|
if(snditer != mActiveSaySounds.end())
|
||||||
{
|
{
|
||||||
Stream *sound = snditer->second;
|
Stream *sound = snditer->second.get();
|
||||||
return mOutput->getStreamLoudness(sound);
|
return mOutput->getStreamLoudness(sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,10 +498,10 @@ namespace MWSound
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stopSay(MWWorld::ConstPtr());
|
stopSay(MWWorld::ConstPtr());
|
||||||
Stream *sound = playVoice(decoder, osg::Vec3f(), true);
|
StreamPtr sound = playVoice(decoder, osg::Vec3f(), true);
|
||||||
if(!sound) return;
|
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
|
bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const
|
||||||
|
@ -538,7 +509,7 @@ namespace MWSound
|
||||||
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
|
SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr);
|
||||||
if(snditer != mActiveSaySounds.end())
|
if(snditer != mActiveSaySounds.end())
|
||||||
{
|
{
|
||||||
if(mOutput->isStreamPlaying(snditer->second))
|
if(mOutput->isStreamPlaying(snditer->second.get()))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -550,7 +521,7 @@ namespace MWSound
|
||||||
SaySoundMap::const_iterator snditer = mSaySoundsQueue.find(ptr);
|
SaySoundMap::const_iterator snditer = mSaySoundsQueue.find(ptr);
|
||||||
if(snditer != mSaySoundsQueue.end())
|
if(snditer != mSaySoundsQueue.end())
|
||||||
{
|
{
|
||||||
if(mOutput->isStreamPlaying(snditer->second))
|
if(mOutput->isStreamPlaying(snditer->second.get()))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -558,7 +529,7 @@ namespace MWSound
|
||||||
snditer = mActiveSaySounds.find(ptr);
|
snditer = mActiveSaySounds.find(ptr);
|
||||||
if(snditer != mActiveSaySounds.end())
|
if(snditer != mActiveSaySounds.end())
|
||||||
{
|
{
|
||||||
if(mOutput->isStreamPlaying(snditer->second))
|
if(mOutput->isStreamPlaying(snditer->second.get()))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -571,16 +542,14 @@ namespace MWSound
|
||||||
SaySoundMap::iterator snditer = mSaySoundsQueue.find(ptr);
|
SaySoundMap::iterator snditer = mSaySoundsQueue.find(ptr);
|
||||||
if(snditer != mSaySoundsQueue.end())
|
if(snditer != mSaySoundsQueue.end())
|
||||||
{
|
{
|
||||||
mOutput->finishStream(snditer->second);
|
mOutput->finishStream(snditer->second.get());
|
||||||
mUnusedStreams.push_back(snditer->second);
|
|
||||||
mSaySoundsQueue.erase(snditer);
|
mSaySoundsQueue.erase(snditer);
|
||||||
}
|
}
|
||||||
|
|
||||||
snditer = mActiveSaySounds.find(ptr);
|
snditer = mActiveSaySounds.find(ptr);
|
||||||
if(snditer != mActiveSaySounds.end())
|
if(snditer != mActiveSaySounds.end())
|
||||||
{
|
{
|
||||||
mOutput->finishStream(snditer->second);
|
mOutput->finishStream(snditer->second.get());
|
||||||
mUnusedStreams.push_back(snditer->second);
|
|
||||||
mActiveSaySounds.erase(snditer);
|
mActiveSaySounds.erase(snditer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,27 +560,24 @@ namespace MWSound
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Stream *track = getStreamRef();
|
StreamPtr track = getStreamRef();
|
||||||
track->init(1.0f, volumeFromType(type), 1.0f, PlayMode::NoEnv|type|Play_2D);
|
track->init(1.0f, volumeFromType(type), 1.0f, PlayMode::NoEnv|type|Play_2D);
|
||||||
if(!mOutput->streamSound(decoder, track))
|
if(!mOutput->streamSound(decoder, track.get()))
|
||||||
{
|
|
||||||
mUnusedStreams.push_back(track);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
mActiveTracks.insert(
|
Stream* result = track.get();
|
||||||
std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track), track
|
const auto it = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track);
|
||||||
);
|
mActiveTracks.insert(it, std::move(track));
|
||||||
return track;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopTrack(Stream *stream)
|
void SoundManager::stopTrack(Stream *stream)
|
||||||
{
|
{
|
||||||
mOutput->finishStream(stream);
|
mOutput->finishStream(stream);
|
||||||
TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream);
|
TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream,
|
||||||
if(iter != mActiveTracks.end() && *iter == stream)
|
[] (const StreamPtr& lhs, Stream* rhs) { return lhs.get() < rhs; });
|
||||||
|
if(iter != mActiveTracks.end() && iter->get() == stream)
|
||||||
mActiveTracks.erase(iter);
|
mActiveTracks.erase(iter);
|
||||||
mUnusedStreams.push_back(stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double SoundManager::getTrackTimeDelay(Stream *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())
|
if(!mOutput->isInitialized())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -631,13 +597,10 @@ namespace MWSound
|
||||||
// Only one copy of given sound can be played at time, so stop previous copy
|
// Only one copy of given sound can be played at time, so stop previous copy
|
||||||
stopSound(sfx, MWWorld::ConstPtr());
|
stopSound(sfx, MWWorld::ConstPtr());
|
||||||
|
|
||||||
Sound *sound = getSoundRef();
|
SoundPtr sound = getSoundRef();
|
||||||
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
|
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
|
||||||
if(!mOutput->playSound(sound, sfx->mHandle, offset))
|
if(!mOutput->playSound(sound.get(), sfx->mHandle, offset))
|
||||||
{
|
|
||||||
mUnusedSounds.push_back(sound);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if(sfx->mUses++ == 0)
|
if(sfx->mUses++ == 0)
|
||||||
{
|
{
|
||||||
|
@ -645,8 +608,9 @@ namespace MWSound
|
||||||
if(iter != mUnusedBuffers.end())
|
if(iter != mUnusedBuffers.end())
|
||||||
mUnusedBuffers.erase(iter);
|
mUnusedBuffers.erase(iter);
|
||||||
}
|
}
|
||||||
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
|
Sound* result = sound.get();
|
||||||
return sound;
|
mActiveSounds[MWWorld::ConstPtr()].emplace_back(std::move(sound), sfx);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound *SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId,
|
Sound *SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId,
|
||||||
|
@ -656,35 +620,32 @@ namespace MWSound
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized())
|
||||||
return nullptr;
|
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
|
// Look up the sound in the ESM data
|
||||||
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
|
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
if(!sfx) return nullptr;
|
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
|
// Only one copy of given sound can be played at time on ptr, so stop previous copy
|
||||||
stopSound(sfx, ptr);
|
stopSound(sfx, ptr);
|
||||||
|
|
||||||
bool played;
|
bool played;
|
||||||
Sound *sound = getSoundRef();
|
SoundPtr sound = getSoundRef();
|
||||||
if(!(mode&PlayMode::NoPlayerLocal) && ptr == MWMechanics::getPlayer())
|
if(!(mode&PlayMode::NoPlayerLocal) && ptr == MWMechanics::getPlayer())
|
||||||
{
|
{
|
||||||
sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D);
|
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
|
else
|
||||||
{
|
{
|
||||||
sound->init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch,
|
sound->init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch,
|
||||||
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
|
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)
|
if(!played)
|
||||||
{
|
|
||||||
mUnusedSounds.push_back(sound);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if(sfx->mUses++ == 0)
|
if(sfx->mUses++ == 0)
|
||||||
{
|
{
|
||||||
|
@ -692,8 +653,9 @@ namespace MWSound
|
||||||
if(iter != mUnusedBuffers.end())
|
if(iter != mUnusedBuffers.end())
|
||||||
mUnusedBuffers.erase(iter);
|
mUnusedBuffers.erase(iter);
|
||||||
}
|
}
|
||||||
mActiveSounds[ptr].push_back(std::make_pair(sound, sfx));
|
Sound* result = sound.get();
|
||||||
return sound;
|
mActiveSounds[ptr].emplace_back(std::move(sound), sfx);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound *SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId,
|
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));
|
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
if(!sfx) return nullptr;
|
if(!sfx) return nullptr;
|
||||||
|
|
||||||
Sound *sound = getSoundRef();
|
SoundPtr sound = getSoundRef();
|
||||||
sound->init(initialPos, volume * sfx->mVolume, volumeFromType(type), pitch,
|
sound->init(initialPos, volume * sfx->mVolume, volumeFromType(type), pitch,
|
||||||
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
|
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
|
||||||
if(!mOutput->playSound3D(sound, sfx->mHandle, offset))
|
if(!mOutput->playSound3D(sound.get(), sfx->mHandle, offset))
|
||||||
{
|
|
||||||
mUnusedSounds.push_back(sound);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if(sfx->mUses++ == 0)
|
if(sfx->mUses++ == 0)
|
||||||
{
|
{
|
||||||
|
@ -722,8 +681,9 @@ namespace MWSound
|
||||||
if(iter != mUnusedBuffers.end())
|
if(iter != mUnusedBuffers.end())
|
||||||
mUnusedBuffers.erase(iter);
|
mUnusedBuffers.erase(iter);
|
||||||
}
|
}
|
||||||
mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx));
|
Sound* result = sound.get();
|
||||||
return sound;
|
mActiveSounds[MWWorld::ConstPtr()].emplace_back(std::move(sound), sfx);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopSound(Sound *sound)
|
void SoundManager::stopSound(Sound *sound)
|
||||||
|
@ -740,7 +700,7 @@ namespace MWSound
|
||||||
for(SoundBufferRefPair &snd : snditer->second)
|
for(SoundBufferRefPair &snd : snditer->second)
|
||||||
{
|
{
|
||||||
if(snd.second == sfx)
|
if(snd.second == sfx)
|
||||||
mOutput->finishSound(snd.first);
|
mOutput->finishSound(snd.first.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -762,14 +722,14 @@ namespace MWSound
|
||||||
if(snditer != mActiveSounds.end())
|
if(snditer != mActiveSounds.end())
|
||||||
{
|
{
|
||||||
for(SoundBufferRefPair &snd : snditer->second)
|
for(SoundBufferRefPair &snd : snditer->second)
|
||||||
mOutput->finishSound(snd.first);
|
mOutput->finishSound(snd.first.get());
|
||||||
}
|
}
|
||||||
SaySoundMap::iterator sayiter = mSaySoundsQueue.find(ptr);
|
SaySoundMap::iterator sayiter = mSaySoundsQueue.find(ptr);
|
||||||
if(sayiter != mSaySoundsQueue.end())
|
if(sayiter != mSaySoundsQueue.end())
|
||||||
mOutput->finishStream(sayiter->second);
|
mOutput->finishStream(sayiter->second.get());
|
||||||
sayiter = mActiveSaySounds.find(ptr);
|
sayiter = mActiveSaySounds.find(ptr);
|
||||||
if(sayiter != mActiveSaySounds.end())
|
if(sayiter != mActiveSaySounds.end())
|
||||||
mOutput->finishStream(sayiter->second);
|
mOutput->finishStream(sayiter->second.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopSound(const MWWorld::CellStore *cell)
|
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)
|
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
|
||||||
{
|
{
|
||||||
for(SoundBufferRefPair &sndbuf : snd.second)
|
for(SoundBufferRefPair &sndbuf : snd.second)
|
||||||
mOutput->finishSound(sndbuf.first);
|
mOutput->finishSound(sndbuf.first.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
|
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
|
||||||
{
|
{
|
||||||
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
|
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)
|
for(SaySoundMap::value_type &snd : mActiveSaySounds)
|
||||||
{
|
{
|
||||||
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
|
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);
|
SoundMap::iterator snditer = mActiveSounds.find(ptr);
|
||||||
if(snditer != mActiveSounds.end())
|
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)
|
for(SoundBufferRefPair &sndbuf : snditer->second)
|
||||||
{
|
{
|
||||||
if(sndbuf.second == sfx)
|
if(sndbuf.second == sfx)
|
||||||
|
@ -819,7 +781,7 @@ namespace MWSound
|
||||||
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
|
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
return std::find_if(snditer->second.cbegin(), snditer->second.cend(),
|
return std::find_if(snditer->second.cbegin(), snditer->second.cend(),
|
||||||
[this,sfx](const SoundBufferRefPair &snd) -> bool
|
[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();
|
) != snditer->second.cend();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -936,7 +898,7 @@ namespace MWSound
|
||||||
const auto pairiter = std::find_if(
|
const auto pairiter = std::find_if(
|
||||||
snditer->second.begin(), snditer->second.end(),
|
snditer->second.begin(), snditer->second.end(),
|
||||||
[this](const SoundBufferRefPairList::value_type &item) -> bool
|
[this](const SoundBufferRefPairList::value_type &item) -> bool
|
||||||
{ return mNearWaterSound == item.first; }
|
{ return mNearWaterSound == item.first.get(); }
|
||||||
);
|
);
|
||||||
if (pairiter != snditer->second.end() && pairiter->second != sfx)
|
if (pairiter != snditer->second.end() && pairiter->second != sfx)
|
||||||
soundIdChanged = true;
|
soundIdChanged = true;
|
||||||
|
@ -962,7 +924,11 @@ namespace MWSound
|
||||||
SaySoundMap::iterator queuesayiter = mSaySoundsQueue.begin();
|
SaySoundMap::iterator queuesayiter = mSaySoundsQueue.begin();
|
||||||
while (queuesayiter != mSaySoundsQueue.end())
|
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++);
|
mSaySoundsQueue.erase(queuesayiter++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,10 +969,9 @@ namespace MWSound
|
||||||
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
|
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
|
||||||
while(sndidx != snditer->second.end())
|
while(sndidx != snditer->second.end())
|
||||||
{
|
{
|
||||||
Sound *sound;
|
Sound *sound = sndidx->first.get();
|
||||||
Sound_Buffer *sfx;
|
Sound_Buffer *sfx = sndidx->second;
|
||||||
|
|
||||||
std::tie(sound, sfx) = *sndidx;
|
|
||||||
if(!ptr.isEmpty() && sound->getIs3D())
|
if(!ptr.isEmpty() && sound->getIs3D())
|
||||||
{
|
{
|
||||||
const ESM::Position &pos = ptr.getRefData().getPosition();
|
const ESM::Position &pos = ptr.getRefData().getPosition();
|
||||||
|
@ -1023,10 +988,9 @@ namespace MWSound
|
||||||
if(!mOutput->isSoundPlaying(sound))
|
if(!mOutput->isSoundPlaying(sound))
|
||||||
{
|
{
|
||||||
mOutput->finishSound(sound);
|
mOutput->finishSound(sound);
|
||||||
mUnusedSounds.push_back(sound);
|
if (sound == mUnderwaterSound)
|
||||||
if(sound == mUnderwaterSound)
|
|
||||||
mUnderwaterSound = nullptr;
|
mUnderwaterSound = nullptr;
|
||||||
if(sound == mNearWaterSound)
|
if (sound == mNearWaterSound)
|
||||||
mNearWaterSound = nullptr;
|
mNearWaterSound = nullptr;
|
||||||
if(sfx->mUses-- == 1)
|
if(sfx->mUses-- == 1)
|
||||||
mUnusedBuffers.push_front(sfx);
|
mUnusedBuffers.push_front(sfx);
|
||||||
|
@ -1050,7 +1014,7 @@ namespace MWSound
|
||||||
while(sayiter != mActiveSaySounds.end())
|
while(sayiter != mActiveSaySounds.end())
|
||||||
{
|
{
|
||||||
MWWorld::ConstPtr ptr = sayiter->first;
|
MWWorld::ConstPtr ptr = sayiter->first;
|
||||||
Stream *sound = sayiter->second;
|
Stream *sound = sayiter->second.get();
|
||||||
if(!ptr.isEmpty() && sound->getIs3D())
|
if(!ptr.isEmpty() && sound->getIs3D())
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
@ -1067,7 +1031,6 @@ namespace MWSound
|
||||||
if(!mOutput->isStreamPlaying(sound))
|
if(!mOutput->isStreamPlaying(sound))
|
||||||
{
|
{
|
||||||
mOutput->finishStream(sound);
|
mOutput->finishStream(sound);
|
||||||
mUnusedStreams.push_back(sound);
|
|
||||||
mActiveSaySounds.erase(sayiter++);
|
mActiveSaySounds.erase(sayiter++);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1082,7 +1045,7 @@ namespace MWSound
|
||||||
TrackList::iterator trkiter = mActiveTracks.begin();
|
TrackList::iterator trkiter = mActiveTracks.begin();
|
||||||
for(;trkiter != mActiveTracks.end();++trkiter)
|
for(;trkiter != mActiveTracks.end();++trkiter)
|
||||||
{
|
{
|
||||||
Stream *sound = *trkiter;
|
Stream *sound = trkiter->get();
|
||||||
if(!mOutput->isStreamPlaying(sound))
|
if(!mOutput->isStreamPlaying(sound))
|
||||||
{
|
{
|
||||||
mOutput->finishStream(sound);
|
mOutput->finishStream(sound);
|
||||||
|
@ -1113,7 +1076,7 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
mMusic->updateFade(duration);
|
mMusic->updateFade(duration);
|
||||||
|
|
||||||
mOutput->updateStream(mMusic);
|
mOutput->updateStream(mMusic.get());
|
||||||
|
|
||||||
if (mMusic->getRealVolume() <= 0.f)
|
if (mMusic->getRealVolume() <= 0.f)
|
||||||
{
|
{
|
||||||
|
@ -1150,32 +1113,32 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
for(SoundBufferRefPair &sndbuf : snd.second)
|
for(SoundBufferRefPair &sndbuf : snd.second)
|
||||||
{
|
{
|
||||||
Sound *sound = sndbuf.first;
|
Sound *sound = sndbuf.first.get();
|
||||||
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
||||||
mOutput->updateSound(sound);
|
mOutput->updateSound(sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(SaySoundMap::value_type &snd : mActiveSaySounds)
|
for(SaySoundMap::value_type &snd : mActiveSaySounds)
|
||||||
{
|
{
|
||||||
Stream *sound = snd.second;
|
Stream *sound = snd.second.get();
|
||||||
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
||||||
mOutput->updateStream(sound);
|
mOutput->updateStream(sound);
|
||||||
}
|
}
|
||||||
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
|
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
|
||||||
{
|
{
|
||||||
Stream *sound = snd.second;
|
Stream *sound = snd.second.get();
|
||||||
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
||||||
mOutput->updateStream(sound);
|
mOutput->updateStream(sound);
|
||||||
}
|
}
|
||||||
for(Stream *sound : mActiveTracks)
|
for (const StreamPtr& sound : mActiveTracks)
|
||||||
{
|
{
|
||||||
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
|
||||||
mOutput->updateStream(sound);
|
mOutput->updateStream(sound.get());
|
||||||
}
|
}
|
||||||
if(mMusic)
|
if(mMusic)
|
||||||
{
|
{
|
||||||
mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType()));
|
mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType()));
|
||||||
mOutput->updateStream(mMusic);
|
mOutput->updateStream(mMusic.get());
|
||||||
}
|
}
|
||||||
mOutput->finishUpdate();
|
mOutput->finishUpdate();
|
||||||
}
|
}
|
||||||
|
@ -1204,17 +1167,17 @@ namespace MWSound
|
||||||
SaySoundMap::iterator sayiter = mSaySoundsQueue.find(old);
|
SaySoundMap::iterator sayiter = mSaySoundsQueue.find(old);
|
||||||
if(sayiter != mSaySoundsQueue.end())
|
if(sayiter != mSaySoundsQueue.end())
|
||||||
{
|
{
|
||||||
Stream *stream = sayiter->second;
|
StreamPtr stream = std::move(sayiter->second);
|
||||||
mSaySoundsQueue.erase(sayiter);
|
mSaySoundsQueue.erase(sayiter);
|
||||||
mSaySoundsQueue.emplace(updated, stream);
|
mSaySoundsQueue.emplace(updated, std::move(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
sayiter = mActiveSaySounds.find(old);
|
sayiter = mActiveSaySounds.find(old);
|
||||||
if(sayiter != mActiveSaySounds.end())
|
if(sayiter != mActiveSaySounds.end())
|
||||||
{
|
{
|
||||||
Stream *stream = sayiter->second;
|
StreamPtr stream = std::move(sayiter->second);
|
||||||
mActiveSaySounds.erase(sayiter);
|
mActiveSaySounds.erase(sayiter);
|
||||||
mActiveSaySounds.emplace(updated, stream);
|
mActiveSaySounds.emplace(updated, std::move(stream));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1291,8 +1254,7 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
for(SoundBufferRefPair &sndbuf : snd.second)
|
for(SoundBufferRefPair &sndbuf : snd.second)
|
||||||
{
|
{
|
||||||
mOutput->finishSound(sndbuf.first);
|
mOutput->finishSound(sndbuf.first.get());
|
||||||
mUnusedSounds.push_back(sndbuf.first);
|
|
||||||
Sound_Buffer *sfx = sndbuf.second;
|
Sound_Buffer *sfx = sndbuf.second;
|
||||||
if(sfx->mUses-- == 1)
|
if(sfx->mUses-- == 1)
|
||||||
mUnusedBuffers.push_front(sfx);
|
mUnusedBuffers.push_front(sfx);
|
||||||
|
@ -1303,24 +1265,15 @@ namespace MWSound
|
||||||
mNearWaterSound = nullptr;
|
mNearWaterSound = nullptr;
|
||||||
|
|
||||||
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
|
for(SaySoundMap::value_type &snd : mSaySoundsQueue)
|
||||||
{
|
mOutput->finishStream(snd.second.get());
|
||||||
mOutput->finishStream(snd.second);
|
|
||||||
mUnusedStreams.push_back(snd.second);
|
|
||||||
}
|
|
||||||
mSaySoundsQueue.clear();
|
mSaySoundsQueue.clear();
|
||||||
|
|
||||||
for(SaySoundMap::value_type &snd : mActiveSaySounds)
|
for(SaySoundMap::value_type &snd : mActiveSaySounds)
|
||||||
{
|
mOutput->finishStream(snd.second.get());
|
||||||
mOutput->finishStream(snd.second);
|
|
||||||
mUnusedStreams.push_back(snd.second);
|
|
||||||
}
|
|
||||||
mActiveSaySounds.clear();
|
mActiveSaySounds.clear();
|
||||||
|
|
||||||
for(Stream *sound : mActiveTracks)
|
for(StreamPtr& sound : mActiveTracks)
|
||||||
{
|
mOutput->finishStream(sound.get());
|
||||||
mOutput->finishStream(sound);
|
|
||||||
mUnusedStreams.push_back(sound);
|
|
||||||
}
|
|
||||||
mActiveTracks.clear();
|
mActiveTracks.clear();
|
||||||
mPlaybackPaused = false;
|
mPlaybackPaused = false;
|
||||||
std::fill(std::begin(mPausedSoundTypes), std::end(mPausedSoundTypes), 0);
|
std::fill(std::begin(mPausedSoundTypes), std::end(mPausedSoundTypes), 0);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/misc/objectpool.hpp>
|
||||||
#include <components/fallback/fallback.hpp>
|
#include <components/fallback/fallback.hpp>
|
||||||
|
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
@ -48,6 +48,9 @@ namespace MWSound
|
||||||
Play_3D = 1<<31
|
Play_3D = 1<<31
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using SoundPtr = Misc::ObjectPtr<Sound>;
|
||||||
|
using StreamPtr = Misc::ObjectPtr<Stream>;
|
||||||
|
|
||||||
class SoundManager : public MWBase::SoundManager
|
class SoundManager : public MWBase::SoundManager
|
||||||
{
|
{
|
||||||
const VFS::Manager* mVFS;
|
const VFS::Manager* mVFS;
|
||||||
|
@ -79,25 +82,23 @@ namespace MWSound
|
||||||
typedef std::deque<Sound_Buffer*> SoundList;
|
typedef std::deque<Sound_Buffer*> SoundList;
|
||||||
SoundList mUnusedBuffers;
|
SoundList mUnusedBuffers;
|
||||||
|
|
||||||
std::unique_ptr<std::deque<Sound>> mSounds;
|
Misc::ObjectPool<Sound> mSounds;
|
||||||
std::vector<Sound*> mUnusedSounds;
|
|
||||||
|
|
||||||
std::unique_ptr<std::deque<Stream>> mStreams;
|
Misc::ObjectPool<Stream> mStreams;
|
||||||
std::vector<Stream*> mUnusedStreams;
|
|
||||||
|
|
||||||
typedef std::pair<MWBase::Sound*,Sound_Buffer*> SoundBufferRefPair;
|
typedef std::pair<SoundPtr, Sound_Buffer*> SoundBufferRefPair;
|
||||||
typedef std::vector<SoundBufferRefPair> SoundBufferRefPairList;
|
typedef std::vector<SoundBufferRefPair> SoundBufferRefPairList;
|
||||||
typedef std::map<MWWorld::ConstPtr,SoundBufferRefPairList> SoundMap;
|
typedef std::map<MWWorld::ConstPtr,SoundBufferRefPairList> SoundMap;
|
||||||
SoundMap mActiveSounds;
|
SoundMap mActiveSounds;
|
||||||
|
|
||||||
typedef std::map<MWWorld::ConstPtr,Stream*> SaySoundMap;
|
typedef std::map<MWWorld::ConstPtr, StreamPtr> SaySoundMap;
|
||||||
SaySoundMap mSaySoundsQueue;
|
SaySoundMap mSaySoundsQueue;
|
||||||
SaySoundMap mActiveSaySounds;
|
SaySoundMap mActiveSaySounds;
|
||||||
|
|
||||||
typedef std::vector<Stream*> TrackList;
|
typedef std::vector<StreamPtr> TrackList;
|
||||||
TrackList mActiveTracks;
|
TrackList mActiveTracks;
|
||||||
|
|
||||||
Stream *mMusic;
|
StreamPtr mMusic;
|
||||||
std::string mCurrentPlaylist;
|
std::string mCurrentPlaylist;
|
||||||
|
|
||||||
bool mListenerUnderwater;
|
bool mListenerUnderwater;
|
||||||
|
@ -127,10 +128,10 @@ namespace MWSound
|
||||||
// returns a decoder to start streaming, or nullptr if the sound was not found
|
// returns a decoder to start streaming, or nullptr if the sound was not found
|
||||||
DecoderPtr loadVoice(const std::string &voicefile);
|
DecoderPtr loadVoice(const std::string &voicefile);
|
||||||
|
|
||||||
Sound *getSoundRef();
|
SoundPtr getSoundRef();
|
||||||
Stream *getStreamRef();
|
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 streamMusicFull(const std::string& filename);
|
||||||
void advanceMusic(const std::string& filename);
|
void advanceMusic(const std::string& filename);
|
||||||
|
|
|
@ -1555,6 +1555,9 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if(ptr.getRefData().getBaseNode() != 0)
|
if(ptr.getRefData().getBaseNode() != 0)
|
||||||
{
|
{
|
||||||
|
mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr);
|
||||||
|
mWorldScene->removeFromPagedRefs(ptr);
|
||||||
|
|
||||||
mRendering->rotateObject(ptr, rotate);
|
mRendering->rotateObject(ptr, rotate);
|
||||||
mPhysics->updateRotation(ptr);
|
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()
|
||||||
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})
|
add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR})
|
||||||
|
|
||||||
|
@ -308,7 +308,7 @@ target_link_libraries(components
|
||||||
${OSGGA_LIBRARIES}
|
${OSGGA_LIBRARIES}
|
||||||
${OSGSHADOW_LIBRARIES}
|
${OSGSHADOW_LIBRARIES}
|
||||||
${OSGANIMATION_LIBRARIES}
|
${OSGANIMATION_LIBRARIES}
|
||||||
${Bullet_LIBRARIES}
|
${BULLET_LIBRARIES}
|
||||||
${SDL2_LIBRARIES}
|
${SDL2_LIBRARIES}
|
||||||
${OPENGL_gl_LIBRARY}
|
${OPENGL_gl_LIBRARY}
|
||||||
${MyGUI_LIBRARIES}
|
${MyGUI_LIBRARIES}
|
||||||
|
|
83
components/misc/objectpool.hpp
Normal file
83
components/misc/objectpool.hpp
Normal file
|
@ -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.
|
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
|
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.
|
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.
|
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.
|
# 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
|
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.
|
# If enabled then third person camera is positioned above character's shoulder and crosshair is visible.
|
||||||
view over shoulder = false
|
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 lower body to movement direction. 'true' makes diagonal movement more realistic.
|
||||||
turn to movement direction = false
|
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]
|
[General]
|
||||||
|
|
||||||
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).
|
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).
|
||||||
|
|
|
@ -236,6 +236,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="trainersTrainingSkillsBasedOnBaseSkillCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>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.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Trainers choose their training skills based on their base skill points</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
Loading…
Reference in a new issue