mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-21 12:23:51 +00:00
Merge remote-tracking branch 'remotes/origin/master' into openxr_vr
This commit is contained in:
commit
c9e761eb88
114 changed files with 2260 additions and 1288 deletions
191
.gitlab-ci.yml
191
.gitlab-ci.yml
|
@ -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/
|
||||||
|
@ -41,26 +46,184 @@ MacOS:
|
||||||
paths:
|
paths:
|
||||||
- build/OpenMW-*.dmg
|
- build/OpenMW-*.dmg
|
||||||
|
|
||||||
Windows:
|
variables: &engine-targets
|
||||||
|
targets: "openmw,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
||||||
|
|
||||||
|
variables: &cs-targets
|
||||||
|
targets: "openmw-cs,bsatool,esmtool,niftest"
|
||||||
|
|
||||||
|
.Windows_Ninja_Base:
|
||||||
tags:
|
tags:
|
||||||
- windows
|
- windows
|
||||||
|
before_script:
|
||||||
|
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||||
|
- choco install git --force --params "/GitAndUnixToolsOnPath" -y
|
||||||
|
- choco install 7zip -y
|
||||||
|
- choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y
|
||||||
|
- choco install vswhere -y
|
||||||
|
- choco install ninja -y
|
||||||
|
- choco install python -y
|
||||||
|
- refreshenv
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
script:
|
script:
|
||||||
- Set-Variable -Name "time" -Value (date -Format "%H:%m")
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
- echo ${time}
|
- echo ${time}
|
||||||
- echo "started by ${GITLAB_USER_NAME}"
|
- echo "started by ${GITLAB_USER_NAME}"
|
||||||
# TODO: to anyone wanting to do further work here, we need to figure out how to get the below working
|
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N
|
||||||
# TODO: on gitlab's new shared windows runners. They currently don't have bash or anything else installed
|
- cd MSVC2019_64_Ninja
|
||||||
# TODO: it is currently just a bare windows 10 with powershell.
|
- .\ActivateMSVC.ps1
|
||||||
# - env # turn on for debugging
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
# - sh %CI_PROJECT_DIR%/CI/before_script.msvc.sh -c Release -p x64 -v 2017 -V
|
- cd $config
|
||||||
# - SET msBuildLocation="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe"
|
- |
|
||||||
# - call %msBuildLocation% MSVC2017_64\OpenMW.sln /t:Build /p:Configuration=Release /m:%NUMBER_OF_PROCESSORS%
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
# - 7z a OpenMW_MSVC2017_64_%CI_BUILD_REF_NAME%_%CI_BUILD_ID%.zip %CI_PROJECT_DIR%\MSVC2017_64\Release\
|
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb'
|
||||||
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
|
}
|
||||||
|
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
|
||||||
cache:
|
cache:
|
||||||
|
key: ninja-v2
|
||||||
paths:
|
paths:
|
||||||
- deps
|
- deps
|
||||||
|
- MSVC2019_64_Ninja/deps/Qt
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: always
|
||||||
paths:
|
paths:
|
||||||
- "*.zip"
|
- "*.zip"
|
||||||
|
- "*.log"
|
||||||
|
- MSVC2019_64_Ninja/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*/*/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*/*/*/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*/*/*/*/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*/*/*/*/*/*.log
|
||||||
|
- MSVC2019_64_Ninja/*/*/*/*/*/*/*/*.log
|
||||||
|
|
||||||
|
Windows_Ninja_Engine_Release:
|
||||||
|
extends:
|
||||||
|
- .Windows_Ninja_Base
|
||||||
|
variables:
|
||||||
|
<<: *engine-targets
|
||||||
|
config: "Release"
|
||||||
|
|
||||||
|
Windows_Ninja_Engine_Debug:
|
||||||
|
extends:
|
||||||
|
- .Windows_Ninja_Base
|
||||||
|
variables:
|
||||||
|
<<: *engine-targets
|
||||||
|
config: "Debug"
|
||||||
|
|
||||||
|
Windows_Ninja_Engine_RelWithDebInfo:
|
||||||
|
extends:
|
||||||
|
- .Windows_Ninja_Base
|
||||||
|
variables:
|
||||||
|
<<: *engine-targets
|
||||||
|
config: "RelWithDebInfo"
|
||||||
|
|
||||||
|
Windows_Ninja_CS_Release:
|
||||||
|
extends:
|
||||||
|
- .Windows_Ninja_Base
|
||||||
|
variables:
|
||||||
|
<<: *cs-targets
|
||||||
|
config: "Release"
|
||||||
|
|
||||||
|
Windows_Ninja_CS_Debug:
|
||||||
|
extends:
|
||||||
|
- .Windows_Ninja_Base
|
||||||
|
variables:
|
||||||
|
<<: *cs-targets
|
||||||
|
config: "Debug"
|
||||||
|
|
||||||
|
Windows_Ninja_CS_RelWithDebInfo:
|
||||||
|
extends:
|
||||||
|
- .Windows_Ninja_Base
|
||||||
|
variables:
|
||||||
|
<<: *cs-targets
|
||||||
|
config: "RelWithDebInfo"
|
||||||
|
|
||||||
|
.Windows_MSBuild_Base:
|
||||||
|
tags:
|
||||||
|
- windows
|
||||||
|
before_script:
|
||||||
|
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||||
|
- choco install git --force --params "/GitAndUnixToolsOnPath" -y
|
||||||
|
- choco install 7zip -y
|
||||||
|
- choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y
|
||||||
|
- choco install vswhere -y
|
||||||
|
- choco install python -y
|
||||||
|
- refreshenv
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
|
- echo ${time}
|
||||||
|
- echo "started by ${GITLAB_USER_NAME}"
|
||||||
|
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V
|
||||||
|
- cd MSVC2019_64
|
||||||
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
|
- cd $config
|
||||||
|
- |
|
||||||
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
|
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb'
|
||||||
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
|
}
|
||||||
|
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
|
||||||
|
cache:
|
||||||
|
key: msbuild-v2
|
||||||
|
paths:
|
||||||
|
- deps
|
||||||
|
- MSVC2019_64/deps/Qt
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- "*.zip"
|
||||||
|
- "*.log"
|
||||||
|
- MSVC2019_64/*.log
|
||||||
|
- MSVC2019_64/*/*.log
|
||||||
|
- MSVC2019_64/*/*/*.log
|
||||||
|
- MSVC2019_64/*/*/*/*.log
|
||||||
|
- MSVC2019_64/*/*/*/*/*.log
|
||||||
|
- MSVC2019_64/*/*/*/*/*/*.log
|
||||||
|
- MSVC2019_64/*/*/*/*/*/*/*.log
|
||||||
|
- MSVC2019_64/*/*/*/*/*/*/*/*.log
|
||||||
|
|
||||||
|
Windows_MSBuild_Engine_Release:
|
||||||
|
extends:
|
||||||
|
- .Windows_MSBuild_Base
|
||||||
|
variables:
|
||||||
|
<<: *engine-targets
|
||||||
|
config: "Release"
|
||||||
|
|
||||||
|
Windows_MSBuild_Engine_Debug:
|
||||||
|
extends:
|
||||||
|
- .Windows_MSBuild_Base
|
||||||
|
variables:
|
||||||
|
<<: *engine-targets
|
||||||
|
config: "Debug"
|
||||||
|
|
||||||
|
Windows_MSBuild_Engine_RelWithDebInfo:
|
||||||
|
extends:
|
||||||
|
- .Windows_MSBuild_Base
|
||||||
|
variables:
|
||||||
|
<<: *engine-targets
|
||||||
|
config: "RelWithDebInfo"
|
||||||
|
|
||||||
|
Windows_MSBuild_CS_Release:
|
||||||
|
extends:
|
||||||
|
- .Windows_MSBuild_Base
|
||||||
|
variables:
|
||||||
|
<<: *cs-targets
|
||||||
|
config: "Release"
|
||||||
|
|
||||||
|
Windows_MSBuild_CS_Debug:
|
||||||
|
extends:
|
||||||
|
- .Windows_MSBuild_Base
|
||||||
|
variables:
|
||||||
|
<<: *cs-targets
|
||||||
|
config: "Debug"
|
||||||
|
|
||||||
|
Windows_MSBuild_CS_RelWithDebInfo:
|
||||||
|
extends:
|
||||||
|
- .Windows_MSBuild_Base
|
||||||
|
variables:
|
||||||
|
<<: *cs-targets
|
||||||
|
config: "RelWithDebInfo"
|
|
@ -37,9 +37,9 @@ addons:
|
||||||
build_command: "make VERBOSE=1 -j3"
|
build_command: "make VERBOSE=1 -j3"
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: OpenMW (all) on macOS Xcode 10.2
|
- name: OpenMW (all) on MacOS 10.15 with Xcode 12
|
||||||
os: osx
|
os: osx
|
||||||
osx_image: xcode10.2
|
osx_image: xcode12
|
||||||
if: branch != coverity_scan
|
if: branch != coverity_scan
|
||||||
- name: OpenMW (all) on Ubuntu Focal with GCC
|
- name: OpenMW (all) on Ubuntu Focal with GCC
|
||||||
os: linux
|
os: linux
|
||||||
|
@ -71,8 +71,8 @@ before_script:
|
||||||
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}"
|
||||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -8,6 +8,7 @@
|
||||||
Bug #3714: Savegame fails to load due to conflict between SpellState and MagicEffects
|
Bug #3714: Savegame fails to load due to conflict between SpellState and MagicEffects
|
||||||
Bug #4021: Attributes and skills are not stored as floats
|
Bug #4021: Attributes and skills are not stored as floats
|
||||||
Bug #4623: Corprus implementation is incorrect
|
Bug #4623: Corprus implementation is incorrect
|
||||||
|
Bug #4764: Data race in osg ParticleSystem
|
||||||
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||||
Bug #5108: Savegame bloating due to inefficient fog textures format
|
Bug #5108: Savegame bloating due to inefficient fog textures format
|
||||||
Bug #5165: Active spells should use real time intead of timestamps
|
Bug #5165: Active spells should use real time intead of timestamps
|
||||||
|
@ -17,6 +18,8 @@
|
||||||
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 #5387: Move/MoveWorld don't update the object's cell properly
|
||||||
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
|
||||||
|
@ -29,17 +32,24 @@
|
||||||
Bug #5441: Enemies can't push a player character when in critical strike stance
|
Bug #5441: Enemies can't push a player character when in critical strike stance
|
||||||
Bug #5451: Magic projectiles don't disappear with the caster
|
Bug #5451: Magic projectiles don't disappear with the caster
|
||||||
Bug #5452: Autowalk is being included in savegames
|
Bug #5452: Autowalk is being included in savegames
|
||||||
|
Bug #5472: Mistify mod causes CTD in 0.46 on Mac
|
||||||
Bug #5479: NPCs who should be walking around town are standing around without walking
|
Bug #5479: NPCs who should be walking around town are standing around without walking
|
||||||
Bug #5484: Zero value items shouldn't be able to be bought or sold for 1 gold
|
Bug #5484: Zero value items shouldn't be able to be bought or sold for 1 gold
|
||||||
Bug #5485: Intimidate doesn't increase disposition on marginal wins
|
Bug #5485: Intimidate doesn't increase disposition on marginal wins
|
||||||
Bug #5490: Hits to carried left slot aren't redistributed if there's no shield equipped
|
Bug #5490: Hits to carried left slot aren't redistributed if there's no shield equipped
|
||||||
Bug #5499: Faction advance is available when requirements not met
|
Bug #5499: Faction advance is available when requirements not met
|
||||||
|
Bug #5502: Dead zone for analogue stick movement is too small
|
||||||
|
Bug #5507: Sound volume is not clamped on ingame settings update
|
||||||
|
Bug #5531: Actors flee using current rotation by axis x
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #2386: Distant Statics in the form of Object Paging
|
Feature #2386: Distant Statics in the form of Object Paging
|
||||||
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
|
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
|
||||||
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
|
||||||
|
Feature #5524: Resume failed script execution after reload
|
||||||
|
Feature #5525: Search fields tweaks (utf-8)
|
||||||
Task #5480: Drop Qt4 support
|
Task #5480: Drop Qt4 support
|
||||||
|
|
||||||
0.46.0
|
0.46.0
|
||||||
|
|
|
@ -39,6 +39,10 @@ originalIFS="$IFS"
|
||||||
IFS=$'\n\r'
|
IFS=$'\n\r'
|
||||||
for pair in $(cmd //c "set"); do
|
for pair in $(cmd //c "set"); do
|
||||||
IFS='=' read -r -a separatedPair <<< "${pair}"
|
IFS='=' read -r -a separatedPair <<< "${pair}"
|
||||||
|
if [ ${#separatedPair[@]} -ne 2 ]; then
|
||||||
|
echo "Parsed '$pair' as ${#separatedPair[@]} parts, expected 2."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
originalCmdEnv["${separatedPair[0]}"]="${separatedPair[1]}"
|
originalCmdEnv["${separatedPair[0]}"]="${separatedPair[1]}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -49,6 +53,10 @@ declare -A cmdEnvChanges
|
||||||
for pair in $cmdEnv; do
|
for pair in $cmdEnv; do
|
||||||
if [ -n "$pair" ]; then
|
if [ -n "$pair" ]; then
|
||||||
IFS='=' read -r -a separatedPair <<< "${pair}"
|
IFS='=' read -r -a separatedPair <<< "${pair}"
|
||||||
|
if [ ${#separatedPair[@]} -ne 2 ]; then
|
||||||
|
echo "Parsed '$pair' as ${#separatedPair[@]} parts, expected 2."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
key="${separatedPair[0]}"
|
key="${separatedPair[0]}"
|
||||||
value="${separatedPair[1]}"
|
value="${separatedPair[1]}"
|
||||||
if ! [ ${originalCmdEnv[$key]+_} ] || [ "${originalCmdEnv[$key]}" != "$value" ]; then
|
if ! [ ${originalCmdEnv[$key]+_} ] || [ "${originalCmdEnv[$key]}" != "$value" ]; then
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -621,7 +621,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" \
|
||||||
..
|
..
|
||||||
|
|
|
@ -312,7 +312,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}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(BUILD_VR_OPENXR)
|
if(BUILD_VR_OPENXR)
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -216,7 +216,6 @@ endif(APPLE)
|
||||||
|
|
||||||
target_link_libraries(openmw-cs
|
target_link_libraries(openmw-cs
|
||||||
${OSG_LIBRARIES}
|
${OSG_LIBRARIES}
|
||||||
${OPENTHREADS_LIBRARIES}
|
|
||||||
${OSGTEXT_LIBRARIES}
|
${OSGTEXT_LIBRARIES}
|
||||||
${OSGUTIL_LIBRARIES}
|
${OSGUTIL_LIBRARIES}
|
||||||
${OSGVIEWER_LIBRARIES}
|
${OSGVIEWER_LIBRARIES}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include "scenewidget.hpp"
|
#include "scenewidget.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
@ -184,7 +187,7 @@ void CompositeViewer::update()
|
||||||
double minFrameTime = _runMaxFrameRate > 0.0 ? 1.0 / _runMaxFrameRate : 0.0;
|
double minFrameTime = _runMaxFrameRate > 0.0 ? 1.0 / _runMaxFrameRate : 0.0;
|
||||||
if (dt < minFrameTime)
|
if (dt < minFrameTime)
|
||||||
{
|
{
|
||||||
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-dt));
|
std::this_thread::sleep_for(std::chrono::duration<double>(minFrameTime - dt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
||||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
||||||
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
|
||||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging
|
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ add_openmw_dir (mwgui
|
||||||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
||||||
draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours
|
draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwdialogue
|
add_openmw_dir (mwdialogue
|
||||||
|
@ -57,7 +57,7 @@ add_openmw_dir (mwscript
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output
|
soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output
|
||||||
loudness movieaudiofactory alext efx efx-presets
|
loudness movieaudiofactory alext efx efx-presets regionsoundselector watersoundupdater volumesettings
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwworld
|
add_openmw_dir (mwworld
|
||||||
|
@ -103,7 +103,6 @@ add_openmw_dir (mwbase
|
||||||
|
|
||||||
set(OPENMW_LINK_TARGETS
|
set(OPENMW_LINK_TARGETS
|
||||||
${OSG_LIBRARIES}
|
${OSG_LIBRARIES}
|
||||||
${OPENTHREADS_LIBRARIES}
|
|
||||||
${OSGPARTICLE_LIBRARIES}
|
${OSGPARTICLE_LIBRARIES}
|
||||||
${OSGUTIL_LIBRARIES}
|
${OSGUTIL_LIBRARIES}
|
||||||
${OSGDB_LIBRARIES}
|
${OSGDB_LIBRARIES}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
@ -73,6 +75,140 @@ namespace
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
Log(Debug::Error) << "SDL error: " << SDL_GetError();
|
Log(Debug::Error) << "SDL error: " << SDL_GetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UserStats
|
||||||
|
{
|
||||||
|
const std::string mLabel;
|
||||||
|
const std::string mBegin;
|
||||||
|
const std::string mEnd;
|
||||||
|
const std::string mTaken;
|
||||||
|
|
||||||
|
UserStats(const std::string& label, const std::string& prefix)
|
||||||
|
: mLabel(label),
|
||||||
|
mBegin(prefix + "_time_begin"),
|
||||||
|
mEnd(prefix + "_time_end"),
|
||||||
|
mTaken(prefix + "_time_taken")
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class UserStatsType : std::size_t
|
||||||
|
{
|
||||||
|
Input,
|
||||||
|
Sound,
|
||||||
|
State,
|
||||||
|
Script,
|
||||||
|
Mechanics,
|
||||||
|
Physics,
|
||||||
|
World,
|
||||||
|
Gui,
|
||||||
|
|
||||||
|
Number,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <UserStatsType type>
|
||||||
|
struct UserStatsValue
|
||||||
|
{
|
||||||
|
static const UserStats sValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::Input>::sValue {"Input", "input"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::Sound>::sValue {"Sound", "sound"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::State>::sValue {"State", "state"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::Script>::sValue {"Script", "script"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::Mechanics>::sValue {"Mech", "mechanics"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::Physics>::sValue {"Phys", "physics"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::World>::sValue {"World", "world"};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const UserStats UserStatsValue<UserStatsType::Gui>::sValue {"Gui", "gui"};
|
||||||
|
|
||||||
|
template <UserStatsType type>
|
||||||
|
struct ForEachUserStatsValue
|
||||||
|
{
|
||||||
|
template <class F>
|
||||||
|
static void apply(F&& f)
|
||||||
|
{
|
||||||
|
f(UserStatsValue<type>::sValue);
|
||||||
|
using Next = ForEachUserStatsValue<static_cast<UserStatsType>(static_cast<std::size_t>(type) + 1)>;
|
||||||
|
Next::apply(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ForEachUserStatsValue<UserStatsType::Number>
|
||||||
|
{
|
||||||
|
template <class F>
|
||||||
|
static void apply(F&&) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void forEachUserStatsValue(F&& f)
|
||||||
|
{
|
||||||
|
ForEachUserStatsValue<static_cast<UserStatsType>(0)>::apply(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <UserStatsType sType>
|
||||||
|
class ScopedProfile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedProfile(osg::Timer_t frameStart, unsigned int frameNumber, const osg::Timer& timer, osg::Stats& stats)
|
||||||
|
: mScopeStart(timer.tick()),
|
||||||
|
mFrameStart(frameStart),
|
||||||
|
mFrameNumber(frameNumber),
|
||||||
|
mTimer(timer),
|
||||||
|
mStats(stats)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedProfile(const ScopedProfile&) = delete;
|
||||||
|
ScopedProfile& operator=(const ScopedProfile&) = delete;
|
||||||
|
|
||||||
|
~ScopedProfile()
|
||||||
|
{
|
||||||
|
const osg::Timer_t end = mTimer.tick();
|
||||||
|
const UserStats& stats = UserStatsValue<sType>::sValue;
|
||||||
|
|
||||||
|
mStats.setAttribute(mFrameNumber, stats.mBegin, mTimer.delta_s(mFrameStart, mScopeStart));
|
||||||
|
mStats.setAttribute(mFrameNumber, stats.mTaken, mTimer.delta_s(mScopeStart, end));
|
||||||
|
mStats.setAttribute(mFrameNumber, stats.mEnd, mTimer.delta_s(mFrameStart, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const osg::Timer_t mScopeStart;
|
||||||
|
const osg::Timer_t mFrameStart;
|
||||||
|
const unsigned int mFrameNumber;
|
||||||
|
const osg::Timer& mTimer;
|
||||||
|
osg::Stats& mStats;
|
||||||
|
};
|
||||||
|
|
||||||
|
void initStatsHandler(Resource::Profiler& profiler)
|
||||||
|
{
|
||||||
|
const osg::Vec4f textColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
const osg::Vec4f barColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
const float multiplier = 1000;
|
||||||
|
const bool average = true;
|
||||||
|
const bool averageInInverseSpace = false;
|
||||||
|
const float maxValue = 10000;
|
||||||
|
|
||||||
|
forEachUserStatsValue([&] (const UserStats& v)
|
||||||
|
{
|
||||||
|
profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier,
|
||||||
|
average, averageInInverseSpace, v.mBegin, v.mEnd, maxValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMW::Engine::executeLocalScripts()
|
void OMW::Engine::executeLocalScripts()
|
||||||
|
@ -93,16 +229,25 @@ bool OMW::Engine::frame(float frametime)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mStartTick = mViewer->getStartTick();
|
const osg::Timer_t frameStart = mViewer->getStartTick();
|
||||||
|
const unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
||||||
|
const osg::Timer* const timer = osg::Timer::instance();
|
||||||
|
osg::Stats* const stats = mViewer->getViewerStats();
|
||||||
|
|
||||||
mEnvironment.setFrameDuration(frametime);
|
mEnvironment.setFrameDuration(frametime);
|
||||||
|
|
||||||
// update input
|
// update input
|
||||||
|
{
|
||||||
|
ScopedProfile<UserStatsType::Input> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
mEnvironment.getInputManager()->update(frametime, false);
|
mEnvironment.getInputManager()->update(frametime, false);
|
||||||
|
}
|
||||||
|
|
||||||
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
|
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
|
||||||
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
|
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
|
||||||
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
|
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
|
||||||
|
{
|
||||||
|
ScopedProfile<UserStatsType::Sound> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
|
|
||||||
if (!mEnvironment.getWindowManager()->isWindowVisible())
|
if (!mEnvironment.getWindowManager()->isWindowVisible())
|
||||||
{
|
{
|
||||||
mEnvironment.getSoundManager()->pausePlayback();
|
mEnvironment.getSoundManager()->pausePlayback();
|
||||||
|
@ -114,18 +259,23 @@ bool OMW::Engine::frame(float frametime)
|
||||||
// sound
|
// sound
|
||||||
if (mUseSound)
|
if (mUseSound)
|
||||||
mEnvironment.getSoundManager()->update(frametime);
|
mEnvironment.getSoundManager()->update(frametime);
|
||||||
|
}
|
||||||
|
|
||||||
// Main menu opened? Then scripts are also paused.
|
// Main menu opened? Then scripts are also paused.
|
||||||
bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu);
|
bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu);
|
||||||
|
|
||||||
// update game state
|
// update game state
|
||||||
|
{
|
||||||
|
ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
mEnvironment.getStateManager()->update (frametime);
|
mEnvironment.getStateManager()->update (frametime);
|
||||||
|
}
|
||||||
|
|
||||||
bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
|
bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
|
||||||
|
|
||||||
osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick();
|
{
|
||||||
if (mEnvironment.getStateManager()->getState()!=
|
ScopedProfile<UserStatsType::Script> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
MWBase::StateManager::State_NoGame)
|
|
||||||
|
if (mEnvironment.getStateManager()->getState() != MWBase::StateManager::State_NoGame)
|
||||||
{
|
{
|
||||||
if (!paused)
|
if (!paused)
|
||||||
{
|
{
|
||||||
|
@ -148,64 +298,50 @@ bool OMW::Engine::frame(float frametime)
|
||||||
mEnvironment.getWorld()->rechargeItems(frametime, true);
|
mEnvironment.getWorld()->rechargeItems(frametime, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
osg::Timer_t afterScriptTick = osg::Timer::instance()->tick();
|
|
||||||
|
|
||||||
// update actors
|
|
||||||
osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick();
|
|
||||||
if (mEnvironment.getStateManager()->getState()!=
|
|
||||||
MWBase::StateManager::State_NoGame)
|
|
||||||
{
|
|
||||||
mEnvironment.getMechanicsManager()->update(frametime,
|
|
||||||
guiActive);
|
|
||||||
}
|
}
|
||||||
osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick();
|
|
||||||
|
|
||||||
if (mEnvironment.getStateManager()->getState()==
|
// update mechanics
|
||||||
MWBase::StateManager::State_Running)
|
{
|
||||||
|
ScopedProfile<UserStatsType::Mechanics> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
|
|
||||||
|
if (mEnvironment.getStateManager()->getState() != MWBase::StateManager::State_NoGame)
|
||||||
|
{
|
||||||
|
mEnvironment.getMechanicsManager()->update(frametime, guiActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEnvironment.getStateManager()->getState() == MWBase::StateManager::State_Running)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
|
||||||
if(!guiActive && player.getClass().getCreatureStats(player).isDead())
|
if(!guiActive && player.getClass().getCreatureStats(player).isDead())
|
||||||
mEnvironment.getStateManager()->endGame();
|
mEnvironment.getStateManager()->endGame();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update physics
|
// update physics
|
||||||
osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();
|
{
|
||||||
if (mEnvironment.getStateManager()->getState()!=
|
ScopedProfile<UserStatsType::Physics> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
MWBase::StateManager::State_NoGame)
|
|
||||||
|
if (mEnvironment.getStateManager()->getState() != MWBase::StateManager::State_NoGame)
|
||||||
{
|
{
|
||||||
mEnvironment.getWorld()->updatePhysics(frametime, guiActive);
|
mEnvironment.getWorld()->updatePhysics(frametime, guiActive);
|
||||||
}
|
}
|
||||||
osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick();
|
}
|
||||||
|
|
||||||
// update world
|
// update world
|
||||||
osg::Timer_t beforeWorldTick = osg::Timer::instance()->tick();
|
{
|
||||||
if (mEnvironment.getStateManager()->getState()!=
|
ScopedProfile<UserStatsType::World> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
MWBase::StateManager::State_NoGame)
|
|
||||||
|
if (mEnvironment.getStateManager()->getState() != MWBase::StateManager::State_NoGame)
|
||||||
{
|
{
|
||||||
mEnvironment.getWorld()->update(frametime, guiActive);
|
mEnvironment.getWorld()->update(frametime, guiActive);
|
||||||
}
|
}
|
||||||
osg::Timer_t afterWorldTick = osg::Timer::instance()->tick();
|
}
|
||||||
|
|
||||||
// update GUI
|
// update GUI
|
||||||
|
{
|
||||||
|
ScopedProfile<UserStatsType::Gui> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
mEnvironment.getWindowManager()->update(frametime);
|
mEnvironment.getWindowManager()->update(frametime);
|
||||||
|
}
|
||||||
unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
|
||||||
osg::Stats* stats = mViewer->getViewerStats();
|
|
||||||
stats->setAttribute(frameNumber, "script_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeScriptTick));
|
|
||||||
stats->setAttribute(frameNumber, "script_time_taken", osg::Timer::instance()->delta_s(beforeScriptTick, afterScriptTick));
|
|
||||||
stats->setAttribute(frameNumber, "script_time_end", osg::Timer::instance()->delta_s(mStartTick, afterScriptTick));
|
|
||||||
|
|
||||||
stats->setAttribute(frameNumber, "mechanics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeMechanicsTick));
|
|
||||||
stats->setAttribute(frameNumber, "mechanics_time_taken", osg::Timer::instance()->delta_s(beforeMechanicsTick, afterMechanicsTick));
|
|
||||||
stats->setAttribute(frameNumber, "mechanics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterMechanicsTick));
|
|
||||||
|
|
||||||
stats->setAttribute(frameNumber, "physics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforePhysicsTick));
|
|
||||||
stats->setAttribute(frameNumber, "physics_time_taken", osg::Timer::instance()->delta_s(beforePhysicsTick, afterPhysicsTick));
|
|
||||||
stats->setAttribute(frameNumber, "physics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterPhysicsTick));
|
|
||||||
|
|
||||||
stats->setAttribute(frameNumber, "world_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeWorldTick));
|
|
||||||
stats->setAttribute(frameNumber, "world_time_taken", osg::Timer::instance()->delta_s(beforeWorldTick, afterWorldTick));
|
|
||||||
stats->setAttribute(frameNumber, "world_time_end", osg::Timer::instance()->delta_s(mStartTick, afterWorldTick));
|
|
||||||
|
|
||||||
if (stats->collectStats("resource"))
|
if (stats->collectStats("resource"))
|
||||||
{
|
{
|
||||||
|
@ -218,7 +354,6 @@ bool OMW::Engine::frame(float frametime)
|
||||||
|
|
||||||
mEnvironment.reportStats(frameNumber, *stats);
|
mEnvironment.reportStats(frameNumber, *stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -261,8 +396,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||||
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
|
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mStartTick = osg::Timer::instance()->tick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OMW::Engine::~Engine()
|
OMW::Engine::~Engine()
|
||||||
|
@ -724,14 +857,7 @@ void OMW::Engine::go()
|
||||||
// Setup profiler
|
// Setup profiler
|
||||||
osg::ref_ptr<Resource::Profiler> statshandler = new Resource::Profiler;
|
osg::ref_ptr<Resource::Profiler> statshandler = new Resource::Profiler;
|
||||||
|
|
||||||
statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
initStatsHandler(*statshandler);
|
||||||
"script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000);
|
|
||||||
statshandler->addUserStatsLine("Mech", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
|
||||||
"mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000);
|
|
||||||
statshandler->addUserStatsLine("Phys", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
|
||||||
"physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000);
|
|
||||||
statshandler->addUserStatsLine("World", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f),
|
|
||||||
"world_time_taken", 1000.0, true, false, "world_time_begin", "world_time_end", 10000);
|
|
||||||
|
|
||||||
mViewer->addEventHandler(statshandler);
|
mViewer->addEventHandler(statshandler);
|
||||||
|
|
||||||
|
@ -783,7 +909,7 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
if (!frame(dt))
|
if (!frame(dt))
|
||||||
{
|
{
|
||||||
OpenThreads::Thread::microSleep(5000);
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -803,7 +929,14 @@ void OMW::Engine::go()
|
||||||
if (stats)
|
if (stats)
|
||||||
{
|
{
|
||||||
const auto frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
const auto frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
||||||
mViewer->getViewerStats()->report(stats, frameNumber);
|
if (frameNumber >= 2)
|
||||||
|
{
|
||||||
|
mViewer->getViewerStats()->report(stats, frameNumber - 2);
|
||||||
|
osgViewer::Viewer::Cameras cameras;
|
||||||
|
mViewer->getCameras(cameras);
|
||||||
|
for (auto camera : cameras)
|
||||||
|
camera->getStats()->report(stats, frameNumber - 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mEnvironment.limitFrameRate(frameTimer.time_s());
|
mEnvironment.limitFrameRate(frameTimer.time_s());
|
||||||
|
|
|
@ -115,8 +115,6 @@ namespace OMW
|
||||||
bool mScriptBlacklistUse;
|
bool mScriptBlacklistUse;
|
||||||
bool mNewGame;
|
bool mNewGame;
|
||||||
|
|
||||||
osg::Timer_t mStartTick;
|
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
Engine (const Engine&);
|
Engine (const Engine&);
|
||||||
Engine& operator= (const Engine&);
|
Engine& operator= (const Engine&);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "environment.hpp"
|
#include "environment.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
#include <OpenThreads/Thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
#include "scriptmanager.hpp"
|
#include "scriptmanager.hpp"
|
||||||
|
@ -99,7 +99,7 @@ void MWBase::Environment::limitFrameRate(double dt) const
|
||||||
double minFrameTime = 1.0 / static_cast<double>(mFrameRateLimit);
|
double minFrameTime = 1.0 / static_cast<double>(mFrameRateLimit);
|
||||||
if (thisFrameTime < minFrameTime)
|
if (thisFrameTime < minFrameTime)
|
||||||
{
|
{
|
||||||
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime));
|
std::this_thread::sleep_for(std::chrono::duration<double>(minFrameTime - thisFrameTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,6 @@ namespace MWBase
|
||||||
virtual void drop (const MWWorld::CellStore *cellStore) = 0;
|
virtual void drop (const MWWorld::CellStore *cellStore) = 0;
|
||||||
///< Deregister all objects in the given cell.
|
///< Deregister all objects in the given cell.
|
||||||
|
|
||||||
virtual void watchActor (const MWWorld::Ptr& ptr) = 0;
|
|
||||||
///< On each update look for changes in a previously registered actor and update the
|
|
||||||
/// GUI accordingly.
|
|
||||||
|
|
||||||
virtual void update (float duration, bool paused) = 0;
|
virtual void update (float duration, bool paused) = 0;
|
||||||
///< Update objects
|
///< Update objects
|
||||||
///
|
///
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual ~ScriptManager() {}
|
virtual ~ScriptManager() {}
|
||||||
|
|
||||||
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
||||||
///< Run the script with the given name (compile first, if not compiled yet)
|
///< Run the script with the given name (compile first, if not compiled yet)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
#include "../mwsound/type.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -44,14 +45,7 @@ namespace MWSound
|
||||||
LoopNoEnv = Loop | NoEnv,
|
LoopNoEnv = Loop | NoEnv,
|
||||||
LoopRemoveAtDistance = Loop | RemoveAtDistance
|
LoopRemoveAtDistance = Loop | RemoveAtDistance
|
||||||
};
|
};
|
||||||
enum class Type {
|
|
||||||
Sfx = 1<<4, /* Normal SFX sound */
|
|
||||||
Voice = 1<<5, /* Voice sound */
|
|
||||||
Foot = 1<<6, /* Footstep sound */
|
|
||||||
Music = 1<<7, /* Music track */
|
|
||||||
Movie = 1<<8, /* Movie audio track */
|
|
||||||
Mask = Sfx | Voice | Foot | Music | Movie
|
|
||||||
};
|
|
||||||
// Used for creating a type mask for SoundManager::pauseSounds and resumeSounds
|
// Used for creating a type mask for SoundManager::pauseSounds and resumeSounds
|
||||||
inline int operator~(Type a) { return ~static_cast<int>(a); }
|
inline int operator~(Type a) { return ~static_cast<int>(a); }
|
||||||
inline int operator&(Type a, Type b) { return static_cast<int>(a) & static_cast<int>(b); }
|
inline int operator&(Type a, Type b) { return static_cast<int>(a) & static_cast<int>(b); }
|
||||||
|
@ -163,9 +157,6 @@ namespace MWBase
|
||||||
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
|
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
|
||||||
///< Stop all sounds for the given cell.
|
///< Stop all sounds for the given cell.
|
||||||
|
|
||||||
virtual void stopSound(const std::string& soundId) = 0;
|
|
||||||
///< Stop a non-3d looping sound
|
|
||||||
|
|
||||||
virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration) = 0;
|
virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration) = 0;
|
||||||
///< Fade out given sound (that is already playing) of given object
|
///< Fade out given sound (that is already playing) of given object
|
||||||
///< @param reference Reference to object, whose sound is faded out
|
///< @param reference Reference to object, whose sound is faded out
|
||||||
|
|
|
@ -154,27 +154,11 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
|
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
|
||||||
|
|
||||||
/// Set value for the given ID.
|
|
||||||
virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0;
|
|
||||||
virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0;
|
|
||||||
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0;
|
|
||||||
virtual void setValue (const std::string& id, const std::string& value) = 0;
|
|
||||||
virtual void setValue (const std::string& id, int value) = 0;
|
|
||||||
|
|
||||||
/// Set time left for the player to start drowning (update the drowning bar)
|
/// Set time left for the player to start drowning (update the drowning bar)
|
||||||
/// @param time time left to start drowning
|
/// @param time time left to start drowning
|
||||||
/// @param maxTime how long we can be underwater (in total) until drowning starts
|
/// @param maxTime how long we can be underwater (in total) until drowning starts
|
||||||
virtual void setDrowningTimeLeft (float time, float maxTime) = 0;
|
virtual void setDrowningTimeLeft (float time, float maxTime) = 0;
|
||||||
|
|
||||||
virtual void setPlayerClass (const ESM::Class &class_) = 0;
|
|
||||||
///< set current class of player
|
|
||||||
|
|
||||||
virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0;
|
|
||||||
///< configure skill groups, each set contains the skill ID for that group.
|
|
||||||
|
|
||||||
virtual void updateSkillArea() = 0;
|
|
||||||
///< update display of skills, factions, birth sign, reputation and bounty
|
|
||||||
|
|
||||||
virtual void changeCell(const MWWorld::CellStore* cell) = 0;
|
virtual void changeCell(const MWWorld::CellStore* cell) = 0;
|
||||||
///< change the active cell
|
///< change the active cell
|
||||||
|
|
||||||
|
@ -254,6 +238,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void update (float duration) = 0;
|
virtual void update (float duration) = 0;
|
||||||
|
|
||||||
|
virtual void updateConsoleObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a GMST string from the store, if there is no setting with the given
|
* Fetches a GMST string from the store, if there is no setting with the given
|
||||||
* ID or it is not a string the default string is returned.
|
* ID or it is not a string the default string is returned.
|
||||||
|
@ -360,6 +346,9 @@ namespace MWBase
|
||||||
virtual void windowResized(int x, int y) = 0;
|
virtual void windowResized(int x, int y) = 0;
|
||||||
virtual void windowClosed() = 0;
|
virtual void windowClosed() = 0;
|
||||||
virtual bool isWindowVisible() = 0;
|
virtual bool isWindowVisible() = 0;
|
||||||
|
|
||||||
|
virtual void watchActor(const MWWorld::Ptr& ptr) = 0;
|
||||||
|
virtual MWWorld::Ptr getWatchedActor() const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -368,7 +368,6 @@ namespace MWGui
|
||||||
if (klass)
|
if (klass)
|
||||||
{
|
{
|
||||||
mPlayerClass = *klass;
|
mPlayerClass = *klass;
|
||||||
MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass);
|
|
||||||
}
|
}
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog);
|
MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog);
|
||||||
mPickClassDialog = 0;
|
mPickClassDialog = 0;
|
||||||
|
@ -422,7 +421,6 @@ namespace MWGui
|
||||||
if (mNameDialog)
|
if (mNameDialog)
|
||||||
{
|
{
|
||||||
mPlayerName = mNameDialog->getTextInput();
|
mPlayerName = mNameDialog->getTextInput();
|
||||||
MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName);
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName);
|
MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName);
|
||||||
MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog);
|
MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog);
|
||||||
mNameDialog = 0;
|
mNameDialog = 0;
|
||||||
|
@ -525,7 +523,6 @@ namespace MWGui
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass);
|
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass);
|
||||||
mPlayerClass = klass;
|
mPlayerClass = klass;
|
||||||
MWBase::Environment::get().getWindowManager()->setPlayerClass(klass);
|
|
||||||
|
|
||||||
// Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later
|
// Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later
|
||||||
mCreateClassDialog->setVisible(false);
|
mCreateClassDialog->setVisible(false);
|
||||||
|
@ -722,7 +719,6 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find(mGenerateClass);
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find(mGenerateClass);
|
||||||
|
|
||||||
mPlayerClass = *klass;
|
mPlayerClass = *klass;
|
||||||
MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass);
|
|
||||||
|
|
||||||
updatePlayerHealth();
|
updatePlayerHealth();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#ifndef CHARACTER_CREATION_HPP
|
#ifndef CHARACTER_CREATION_HPP
|
||||||
#define CHARACTER_CREATION_HPP
|
#define CHARACTER_CREATION_HPP
|
||||||
|
|
||||||
#include <components/esm/loadskil.hpp>
|
|
||||||
#include <components/esm/loadclas.hpp>
|
#include <components/esm/loadclas.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "statswatcher.hpp"
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
@ -35,21 +34,21 @@ namespace MWGui
|
||||||
class ReviewDialog;
|
class ReviewDialog;
|
||||||
class MessageBoxManager;
|
class MessageBoxManager;
|
||||||
|
|
||||||
class CharacterCreation
|
class CharacterCreation : public StatsListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::vector<int> SkillList;
|
typedef std::vector<int> SkillList;
|
||||||
|
|
||||||
CharacterCreation(osg::Group* parent, Resource::ResourceSystem* resourceSystem);
|
CharacterCreation(osg::Group* parent, Resource::ResourceSystem* resourceSystem);
|
||||||
~CharacterCreation();
|
virtual ~CharacterCreation();
|
||||||
|
|
||||||
//Show a dialog
|
//Show a dialog
|
||||||
void spawnDialog(const char id);
|
void spawnDialog(const char id);
|
||||||
|
|
||||||
void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
|
void setValue (const std::string& id, const MWMechanics::AttributeValue& value) override;
|
||||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
|
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) override;
|
||||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) override;
|
||||||
void configureSkills (const SkillList& major, const SkillList& minor);
|
void configureSkills(const SkillList& major, const SkillList& minor) override;
|
||||||
|
|
||||||
void onFrame(float duration);
|
void onFrame(float duration);
|
||||||
|
|
||||||
|
|
|
@ -472,6 +472,12 @@ namespace MWGui
|
||||||
setCoord(10,10, width-10, height/2);
|
setCoord(10,10, width-10, height/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Console::updateSelectedObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr)
|
||||||
|
{
|
||||||
|
if (mPtr == currentPtr)
|
||||||
|
mPtr = newPtr;
|
||||||
|
}
|
||||||
|
|
||||||
void Console::setSelectedObject(const MWWorld::Ptr& object)
|
void Console::setSelectedObject(const MWWorld::Ptr& object)
|
||||||
{
|
{
|
||||||
if (!object.isEmpty())
|
if (!object.isEmpty())
|
||||||
|
|
|
@ -58,6 +58,8 @@ namespace MWGui
|
||||||
|
|
||||||
void executeFile (const std::string& path);
|
void executeFile (const std::string& path);
|
||||||
|
|
||||||
|
void updateSelectedObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
virtual void resetReference ();
|
virtual void resetReference ();
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
#define OPENMW_GAME_MWGUI_HUD_H
|
#define OPENMW_GAME_MWGUI_HUD_H
|
||||||
|
|
||||||
#include "mapwindow.hpp"
|
#include "mapwindow.hpp"
|
||||||
|
#include "statswatcher.hpp"
|
||||||
#include "../mwmechanics/stat.hpp"
|
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -17,12 +16,12 @@ namespace MWGui
|
||||||
class ItemWidget;
|
class ItemWidget;
|
||||||
class SpellWidget;
|
class SpellWidget;
|
||||||
|
|
||||||
class HUD : public WindowBase, public LocalMapBase
|
class HUD : public WindowBase, public LocalMapBase, public StatsListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender);
|
HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender);
|
||||||
virtual ~HUD();
|
virtual ~HUD();
|
||||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
|
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) override;
|
||||||
|
|
||||||
/// Set time left for the player to start drowning
|
/// Set time left for the player to start drowning
|
||||||
/// @param time time left to start drowning
|
/// @param time time left to start drowning
|
||||||
|
@ -48,7 +47,7 @@ namespace MWGui
|
||||||
void setCrosshairVisible(bool visible);
|
void setCrosshairVisible(bool visible);
|
||||||
void setCrosshairOwned(bool owned);
|
void setCrosshairOwned(bool owned);
|
||||||
|
|
||||||
void onFrame(float dt);
|
void onFrame(float dt) override;
|
||||||
|
|
||||||
void setCellName(const std::string& cellName);
|
void setCellName(const std::string& cellName);
|
||||||
|
|
||||||
|
@ -59,7 +58,7 @@ namespace MWGui
|
||||||
void setEnemy(const MWWorld::Ptr& enemy);
|
void setEnemy(const MWWorld::Ptr& enemy);
|
||||||
void resetEnemy();
|
void resetEnemy();
|
||||||
|
|
||||||
void clear();
|
void clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning;
|
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning;
|
||||||
|
@ -115,8 +114,8 @@ namespace MWGui
|
||||||
void onMapClicked(MyGUI::Widget* _sender);
|
void onMapClicked(MyGUI::Widget* _sender);
|
||||||
|
|
||||||
// LocalMapBase
|
// LocalMapBase
|
||||||
virtual void customMarkerCreated(MyGUI::Widget* marker);
|
virtual void customMarkerCreated(MyGUI::Widget* marker) override;
|
||||||
virtual void doorMarkerCreated(MyGUI::Widget* marker);
|
virtual void doorMarkerCreated(MyGUI::Widget* marker) override;
|
||||||
|
|
||||||
void updateEnemyHealthBar();
|
void updateEnemyHealthBar();
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,8 @@ namespace
|
||||||
return compareType(leftName, rightName);
|
return compareType(leftName, rightName);
|
||||||
|
|
||||||
// compare items by name
|
// compare items by name
|
||||||
leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase));
|
leftName = Misc::StringUtils::lowerCaseUtf8(left.mBase.getClass().getName(left.mBase));
|
||||||
rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase));
|
rightName = Misc::StringUtils::lowerCaseUtf8(right.mBase.getClass().getName(right.mBase));
|
||||||
|
|
||||||
result = leftName.compare(rightName);
|
result = leftName.compare(rightName);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
|
@ -213,7 +213,7 @@ namespace MWGui
|
||||||
|
|
||||||
if (!mNameFilter.empty())
|
if (!mNameFilter.empty())
|
||||||
{
|
{
|
||||||
const auto itemName = Misc::StringUtils::lowerCase(base.getClass().getName(base));
|
const auto itemName = Misc::StringUtils::lowerCaseUtf8(base.getClass().getName(base));
|
||||||
return itemName.find(mNameFilter) != std::string::npos;
|
return itemName.find(mNameFilter) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ namespace MWGui
|
||||||
|
|
||||||
for (const auto& effect : effects)
|
for (const auto& effect : effects)
|
||||||
{
|
{
|
||||||
const auto ciEffect = Misc::StringUtils::lowerCase(effect);
|
const auto ciEffect = Misc::StringUtils::lowerCaseUtf8(effect);
|
||||||
|
|
||||||
if (ciEffect.find(mEffectFilter) != std::string::npos)
|
if (ciEffect.find(mEffectFilter) != std::string::npos)
|
||||||
return true;
|
return true;
|
||||||
|
@ -285,7 +285,7 @@ namespace MWGui
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string compare = Misc::StringUtils::lowerCase(item.mBase.getClass().getName(item.mBase));
|
std::string compare = Misc::StringUtils::lowerCaseUtf8(item.mBase.getClass().getName(item.mBase));
|
||||||
if(compare.find(mNameFilter) == std::string::npos)
|
if(compare.find(mNameFilter) == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -318,12 +318,12 @@ namespace MWGui
|
||||||
|
|
||||||
void SortFilterItemModel::setNameFilter (const std::string& filter)
|
void SortFilterItemModel::setNameFilter (const std::string& filter)
|
||||||
{
|
{
|
||||||
mNameFilter = Misc::StringUtils::lowerCase(filter);
|
mNameFilter = Misc::StringUtils::lowerCaseUtf8(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SortFilterItemModel::setEffectFilter (const std::string& filter)
|
void SortFilterItemModel::setEffectFilter (const std::string& filter)
|
||||||
{
|
{
|
||||||
mEffectFilter = Misc::StringUtils::lowerCase(filter);
|
mEffectFilter = Misc::StringUtils::lowerCaseUtf8(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SortFilterItemModel::update()
|
void SortFilterItemModel::update()
|
||||||
|
|
188
apps/openmw/mwgui/statswatcher.cpp
Normal file
188
apps/openmw/mwgui/statswatcher.cpp
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#include "statswatcher.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
#include "../mwmechanics/spellutil.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
// mWatchedTimeToStartDrowning = -1 for correct drowning state check,
|
||||||
|
// if stats.getTimeToStartDrowning() == 0 already on game start
|
||||||
|
StatsWatcher::StatsWatcher()
|
||||||
|
: mWatchedLevel(-1), mWatchedTimeToStartDrowning(-1), mWatchedStatsEmpty(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::watchActor(const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
mWatched = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::update()
|
||||||
|
{
|
||||||
|
if (mWatched.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
||||||
|
const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched);
|
||||||
|
for (int i = 0;i < ESM::Attribute::Length;++i)
|
||||||
|
{
|
||||||
|
if (stats.getAttribute(i) != mWatchedAttributes[i] || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
std::stringstream attrname;
|
||||||
|
attrname << "AttribVal"<<(i+1);
|
||||||
|
|
||||||
|
mWatchedAttributes[i] = stats.getAttribute(i);
|
||||||
|
setValue(attrname.str(), stats.getAttribute(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.getHealth() != mWatchedHealth || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
static const std::string hbar("HBar");
|
||||||
|
mWatchedHealth = stats.getHealth();
|
||||||
|
setValue(hbar, stats.getHealth());
|
||||||
|
}
|
||||||
|
if (stats.getMagicka() != mWatchedMagicka || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
static const std::string mbar("MBar");
|
||||||
|
mWatchedMagicka = stats.getMagicka();
|
||||||
|
setValue(mbar, stats.getMagicka());
|
||||||
|
}
|
||||||
|
if (stats.getFatigue() != mWatchedFatigue || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
static const std::string fbar("FBar");
|
||||||
|
mWatchedFatigue = stats.getFatigue();
|
||||||
|
setValue(fbar, stats.getFatigue());
|
||||||
|
}
|
||||||
|
|
||||||
|
float timeToDrown = stats.getTimeToStartDrowning();
|
||||||
|
|
||||||
|
if (timeToDrown != mWatchedTimeToStartDrowning)
|
||||||
|
{
|
||||||
|
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
|
.find("fHoldBreathTime")->mValue.getFloat();
|
||||||
|
|
||||||
|
mWatchedTimeToStartDrowning = timeToDrown;
|
||||||
|
|
||||||
|
if(timeToDrown >= fHoldBreathTime || timeToDrown == -1.0) // -1.0 is a special value during initialization
|
||||||
|
winMgr->setDrowningBarVisibility(false);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
winMgr->setDrowningBarVisibility(true);
|
||||||
|
winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning(), fHoldBreathTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Loop over ESM::Skill::SkillEnum
|
||||||
|
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||||
|
{
|
||||||
|
if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
mWatchedSkills[i] = stats.getSkill(i);
|
||||||
|
setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.getLevel() != mWatchedLevel || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
mWatchedLevel = stats.getLevel();
|
||||||
|
setValue("level", mWatchedLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mWatched.getClass().isNpc())
|
||||||
|
{
|
||||||
|
const ESM::NPC *watchedRecord = mWatched.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
|
if (watchedRecord->mName != mWatchedName || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
mWatchedName = watchedRecord->mName;
|
||||||
|
setValue("name", watchedRecord->mName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watchedRecord->mRace != mWatchedRace || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
mWatchedRace = watchedRecord->mRace;
|
||||||
|
const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::Race>().find(watchedRecord->mRace);
|
||||||
|
setValue("race", race->mName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watchedRecord->mClass != mWatchedClass || mWatchedStatsEmpty)
|
||||||
|
{
|
||||||
|
mWatchedClass = watchedRecord->mClass;
|
||||||
|
const ESM::Class *cls = MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::Class>().find(watchedRecord->mClass);
|
||||||
|
setValue("class", cls->mName);
|
||||||
|
|
||||||
|
MWBase::WindowManager::SkillList majorSkills (5);
|
||||||
|
MWBase::WindowManager::SkillList minorSkills (5);
|
||||||
|
|
||||||
|
for (int i=0; i<5; ++i)
|
||||||
|
{
|
||||||
|
minorSkills[i] = cls->mData.mSkills[i][0];
|
||||||
|
majorSkills[i] = cls->mData.mSkills[i][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
configureSkills(majorSkills, minorSkills);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mWatchedStatsEmpty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::addListener(StatsListener* listener)
|
||||||
|
{
|
||||||
|
mListeners.insert(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::removeListener(StatsListener* listener)
|
||||||
|
{
|
||||||
|
mListeners.erase(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::setValue(const std::string& id, const MWMechanics::AttributeValue& value)
|
||||||
|
{
|
||||||
|
for (StatsListener* listener : mListeners)
|
||||||
|
listener->setValue(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::setValue(ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
||||||
|
{
|
||||||
|
/// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we
|
||||||
|
/// allow custom skills.
|
||||||
|
for (StatsListener* listener : mListeners)
|
||||||
|
listener->setValue(parSkill, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
|
||||||
|
{
|
||||||
|
for (StatsListener* listener : mListeners)
|
||||||
|
listener->setValue(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::setValue(const std::string& id, const std::string& value)
|
||||||
|
{
|
||||||
|
for (StatsListener* listener : mListeners)
|
||||||
|
listener->setValue(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::setValue(const std::string& id, int value)
|
||||||
|
{
|
||||||
|
for (StatsListener* listener : mListeners)
|
||||||
|
listener->setValue(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatsWatcher::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
||||||
|
{
|
||||||
|
for (StatsListener* listener : mListeners)
|
||||||
|
listener->configureSkills(major, minor);
|
||||||
|
}
|
||||||
|
}
|
69
apps/openmw/mwgui/statswatcher.hpp
Normal file
69
apps/openmw/mwgui/statswatcher.hpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef MWGUI_STATSWATCHER_H
|
||||||
|
#define MWGUI_STATSWATCHER_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <components/esm/attr.hpp>
|
||||||
|
#include <components/esm/loadskil.hpp>
|
||||||
|
|
||||||
|
#include "../mwmechanics/stat.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
class StatsListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Set value for the given ID.
|
||||||
|
virtual void setValue(const std::string& id, const MWMechanics::AttributeValue& value) {}
|
||||||
|
virtual void setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value) {}
|
||||||
|
virtual void setValue(const std::string& id, const std::string& value) {}
|
||||||
|
virtual void setValue(const std::string& id, int value) {}
|
||||||
|
virtual void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) {}
|
||||||
|
virtual void configureSkills(const std::vector<int>& major, const std::vector<int>& minor) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class StatsWatcher
|
||||||
|
{
|
||||||
|
MWWorld::Ptr mWatched;
|
||||||
|
|
||||||
|
MWMechanics::AttributeValue mWatchedAttributes[ESM::Attribute::Length];
|
||||||
|
MWMechanics::SkillValue mWatchedSkills[ESM::Skill::Length];
|
||||||
|
|
||||||
|
MWMechanics::DynamicStat<float> mWatchedHealth;
|
||||||
|
MWMechanics::DynamicStat<float> mWatchedMagicka;
|
||||||
|
MWMechanics::DynamicStat<float> mWatchedFatigue;
|
||||||
|
|
||||||
|
std::string mWatchedName;
|
||||||
|
std::string mWatchedRace;
|
||||||
|
std::string mWatchedClass;
|
||||||
|
|
||||||
|
int mWatchedLevel;
|
||||||
|
|
||||||
|
float mWatchedTimeToStartDrowning;
|
||||||
|
|
||||||
|
bool mWatchedStatsEmpty;
|
||||||
|
|
||||||
|
std::set<StatsListener*> mListeners;
|
||||||
|
|
||||||
|
void setValue(const std::string& id, const MWMechanics::AttributeValue& value);
|
||||||
|
void setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value);
|
||||||
|
void setValue(const std::string& id, const std::string& value);
|
||||||
|
void setValue(const std::string& id, int value);
|
||||||
|
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
||||||
|
void configureSkills(const std::vector<int>& major, const std::vector<int>& minor);
|
||||||
|
|
||||||
|
public:
|
||||||
|
StatsWatcher();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void addListener(StatsListener* listener);
|
||||||
|
void removeListener(StatsListener* listener);
|
||||||
|
|
||||||
|
void watchActor(const MWWorld::Ptr& ptr);
|
||||||
|
MWWorld::Ptr getWatchedActor() const { return mWatched; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,16 +1,14 @@
|
||||||
#ifndef MWGUI_STATS_WINDOW_H
|
#ifndef MWGUI_STATS_WINDOW_H
|
||||||
#define MWGUI_STATS_WINDOW_H
|
#define MWGUI_STATS_WINDOW_H
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "statswatcher.hpp"
|
||||||
#include "windowpinnablebase.hpp"
|
#include "windowpinnablebase.hpp"
|
||||||
|
|
||||||
#include <components/esm/loadskil.hpp>
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
class WindowManager;
|
||||||
|
|
||||||
class StatsWindow : public WindowPinnableBase, public NoDrop
|
class StatsWindow : public WindowPinnableBase, public NoDrop, public StatsListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::map<std::string, int> FactionList;
|
typedef std::map<std::string, int> FactionList;
|
||||||
|
@ -20,24 +18,24 @@ namespace MWGui
|
||||||
StatsWindow(DragAndDrop* drag);
|
StatsWindow(DragAndDrop* drag);
|
||||||
|
|
||||||
/// automatically updates all the data in the stats window, but only if it has changed.
|
/// automatically updates all the data in the stats window, but only if it has changed.
|
||||||
void onFrame(float dt);
|
void onFrame(float dt) override;
|
||||||
|
|
||||||
void setBar(const std::string& name, const std::string& tname, int val, int max);
|
void setBar(const std::string& name, const std::string& tname, int val, int max);
|
||||||
void setPlayerName(const std::string& playerName);
|
void setPlayerName(const std::string& playerName);
|
||||||
|
|
||||||
/// Set value for the given ID.
|
/// Set value for the given ID.
|
||||||
void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
|
void setValue (const std::string& id, const MWMechanics::AttributeValue& value) override;
|
||||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
|
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) override;
|
||||||
void setValue (const std::string& id, const std::string& value);
|
void setValue (const std::string& id, const std::string& value) override;
|
||||||
void setValue (const std::string& id, int value);
|
void setValue (const std::string& id, int value) override;
|
||||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) override;
|
||||||
|
void configureSkills(const SkillList& major, const SkillList& minor) override;
|
||||||
|
|
||||||
void configureSkills (const SkillList& major, const SkillList& minor);
|
|
||||||
void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; }
|
void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; }
|
||||||
void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; }
|
void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; }
|
||||||
void updateSkillArea();
|
void updateSkillArea();
|
||||||
|
|
||||||
virtual void onOpen() { onWindowResize(mMainWidget->castType<MyGUI::Window>()); }
|
virtual void onOpen() override { onWindowResize(mMainWidget->castType<MyGUI::Window>()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
|
@ -72,8 +70,8 @@ namespace MWGui
|
||||||
const int mMinFullWidth;
|
const int mMinFullWidth;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onPinToggled();
|
virtual void onPinToggled() override;
|
||||||
virtual void onTitleDoubleClicked();
|
virtual void onTitleDoubleClicked() override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,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
|
||||||
|
@ -40,6 +42,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");
|
||||||
|
@ -76,9 +79,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));
|
||||||
}
|
}
|
||||||
|
@ -140,7 +144,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;
|
||||||
|
@ -195,6 +199,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'
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "windowmanagerimp.hpp"
|
#include "windowmanagerimp.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <osgViewer/Viewer>
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
|
@ -286,6 +288,8 @@ namespace MWGui
|
||||||
mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer);
|
mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer);
|
||||||
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
|
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
|
||||||
Settings::Manager::getFloat("contrast", "Video"));
|
Settings::Manager::getFloat("contrast", "Video"));
|
||||||
|
|
||||||
|
mStatsWatcher.reset(new StatsWatcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::loadUserFonts()
|
void WindowManager::loadUserFonts()
|
||||||
|
@ -480,6 +484,10 @@ namespace MWGui
|
||||||
|
|
||||||
// Set up visibility
|
// Set up visibility
|
||||||
updateVisible();
|
updateVisible();
|
||||||
|
|
||||||
|
mStatsWatcher->addListener(mHud);
|
||||||
|
mStatsWatcher->addListener(mStatsWindow);
|
||||||
|
mStatsWatcher->addListener(mCharGen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WindowManager::getFontHeight() const
|
int WindowManager::getFontHeight() const
|
||||||
|
@ -492,8 +500,11 @@ namespace MWGui
|
||||||
if (newgame)
|
if (newgame)
|
||||||
{
|
{
|
||||||
disallowAll();
|
disallowAll();
|
||||||
|
|
||||||
|
mStatsWatcher->removeListener(mCharGen);
|
||||||
delete mCharGen;
|
delete mCharGen;
|
||||||
mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem);
|
mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem);
|
||||||
|
mStatsWatcher->addListener(mCharGen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
allow(GW_ALL);
|
allow(GW_ALL);
|
||||||
|
@ -503,6 +514,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
mStatsWatcher.reset();
|
||||||
|
|
||||||
mKeyboardNavigation.reset();
|
mKeyboardNavigation.reset();
|
||||||
|
|
||||||
MyGUI::LanguageManager::getInstance().eventRequestTag.clear();
|
MyGUI::LanguageManager::getInstance().eventRequestTag.clear();
|
||||||
|
@ -575,6 +588,11 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::updateConsoleObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr)
|
||||||
|
{
|
||||||
|
mConsole->updateSelectedObjectPtr(currentPtr, newPtr);
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::updateVisible()
|
void WindowManager::updateVisible()
|
||||||
{
|
{
|
||||||
bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper);
|
bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper);
|
||||||
|
@ -663,58 +681,11 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
|
|
||||||
{
|
|
||||||
mStatsWindow->setValue (id, value);
|
|
||||||
mCharGen->setValue(id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::setValue (int parSkill, const MWMechanics::SkillValue& value)
|
|
||||||
{
|
|
||||||
/// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we
|
|
||||||
/// allow custom skills.
|
|
||||||
mStatsWindow->setValue(static_cast<ESM::Skill::SkillEnum> (parSkill), value);
|
|
||||||
mCharGen->setValue(static_cast<ESM::Skill::SkillEnum> (parSkill), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value)
|
|
||||||
{
|
|
||||||
mStatsWindow->setValue (id, value);
|
|
||||||
mHud->setValue (id, value);
|
|
||||||
mCharGen->setValue(id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::setValue (const std::string& id, const std::string& value)
|
|
||||||
{
|
|
||||||
mStatsWindow->setValue (id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::setValue (const std::string& id, int value)
|
|
||||||
{
|
|
||||||
mStatsWindow->setValue (id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::setDrowningTimeLeft (float time, float maxTime)
|
void WindowManager::setDrowningTimeLeft (float time, float maxTime)
|
||||||
{
|
{
|
||||||
mHud->setDrowningTimeLeft(time, maxTime);
|
mHud->setDrowningTimeLeft(time, maxTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::setPlayerClass (const ESM::Class &class_)
|
|
||||||
{
|
|
||||||
mStatsWindow->setValue("class", class_.mName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::configureSkills (const SkillList& major, const SkillList& minor)
|
|
||||||
{
|
|
||||||
mStatsWindow->configureSkills (major, minor);
|
|
||||||
mCharGen->configureSkills(major, minor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::updateSkillArea()
|
|
||||||
{
|
|
||||||
mStatsWindow->updateSkillArea();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManager::removeDialog(Layout*dialog)
|
void WindowManager::removeDialog(Layout*dialog)
|
||||||
{
|
{
|
||||||
if (!dialog)
|
if (!dialog)
|
||||||
|
@ -767,7 +738,7 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
if (!mWindowVisible)
|
if (!mWindowVisible)
|
||||||
OpenThreads::Thread::microSleep(5000);
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mViewer->eventTraversal();
|
mViewer->eventTraversal();
|
||||||
|
@ -922,6 +893,8 @@ namespace MWGui
|
||||||
|
|
||||||
updateActivatedQuickKey();
|
updateActivatedQuickKey();
|
||||||
|
|
||||||
|
mStatsWatcher->update();
|
||||||
|
|
||||||
cleanupGarbage();
|
cleanupGarbage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1820,7 +1793,7 @@ namespace MWGui
|
||||||
if (!mWindowVisible)
|
if (!mWindowVisible)
|
||||||
{
|
{
|
||||||
mVideoWidget->pause();
|
mVideoWidget->pause();
|
||||||
OpenThreads::Thread::microSleep(5000);
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2246,4 +2219,14 @@ namespace MWGui
|
||||||
for (unsigned int i=0; i<mWindows.size(); ++i)
|
for (unsigned int i=0; i<mWindows.size(); ++i)
|
||||||
mWindows[i]->setVisible(visible);
|
mWindows[i]->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::watchActor(const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
mStatsWatcher->watchActor(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr WindowManager::getWatchedActor() const
|
||||||
|
{
|
||||||
|
return mStatsWatcher->getWatchedActor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,12 @@
|
||||||
|
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
|
||||||
|
|
||||||
#include <components/sdlutil/events.hpp>
|
#include <components/sdlutil/events.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "mapwindow.hpp"
|
#include "mapwindow.hpp"
|
||||||
|
#include "statswatcher.hpp"
|
||||||
#include "textcolours.hpp"
|
#include "textcolours.hpp"
|
||||||
|
|
||||||
#include <MyGUI_KeyCode.h>
|
#include <MyGUI_KeyCode.h>
|
||||||
|
@ -197,22 +196,11 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object);
|
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object);
|
||||||
|
|
||||||
///< Set value for the given ID.
|
|
||||||
virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
|
|
||||||
virtual void setValue (int parSkill, const MWMechanics::SkillValue& value);
|
|
||||||
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
|
|
||||||
virtual void setValue (const std::string& id, const std::string& value);
|
|
||||||
virtual void setValue (const std::string& id, int value);
|
|
||||||
|
|
||||||
/// Set time left for the player to start drowning (update the drowning bar)
|
/// Set time left for the player to start drowning (update the drowning bar)
|
||||||
/// @param time time left to start drowning
|
/// @param time time left to start drowning
|
||||||
/// @param maxTime how long we can be underwater (in total) until drowning starts
|
/// @param maxTime how long we can be underwater (in total) until drowning starts
|
||||||
virtual void setDrowningTimeLeft (float time, float maxTime);
|
virtual void setDrowningTimeLeft (float time, float maxTime);
|
||||||
|
|
||||||
virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player
|
|
||||||
virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group.
|
|
||||||
virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty
|
|
||||||
|
|
||||||
virtual void changeCell(const MWWorld::CellStore* cell); ///< change the active cell
|
virtual void changeCell(const MWWorld::CellStore* cell); ///< change the active cell
|
||||||
|
|
||||||
virtual void setFocusObject(const MWWorld::Ptr& focus);
|
virtual void setFocusObject(const MWWorld::Ptr& focus);
|
||||||
|
@ -256,6 +244,8 @@ namespace MWGui
|
||||||
virtual void unsetSelectedSpell();
|
virtual void unsetSelectedSpell();
|
||||||
virtual void unsetSelectedWeapon();
|
virtual void unsetSelectedWeapon();
|
||||||
|
|
||||||
|
virtual void updateConsoleObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr);
|
||||||
|
|
||||||
virtual void showCrosshair(bool show);
|
virtual void showCrosshair(bool show);
|
||||||
virtual bool getSubtitlesEnabled();
|
virtual bool getSubtitlesEnabled();
|
||||||
|
|
||||||
|
@ -300,6 +290,9 @@ namespace MWGui
|
||||||
virtual void windowClosed();
|
virtual void windowClosed();
|
||||||
virtual bool isWindowVisible();
|
virtual bool isWindowVisible();
|
||||||
|
|
||||||
|
virtual void watchActor(const MWWorld::Ptr& ptr);
|
||||||
|
virtual MWWorld::Ptr getWatchedActor() const;
|
||||||
|
|
||||||
virtual void executeInConsole (const std::string& path);
|
virtual void executeInConsole (const std::string& path);
|
||||||
|
|
||||||
virtual void enableRest() { mRestAllowed = true; }
|
virtual void enableRest() { mRestAllowed = true; }
|
||||||
|
@ -403,6 +396,7 @@ namespace MWGui
|
||||||
osgViewer::Viewer* mViewer;
|
osgViewer::Viewer* mViewer;
|
||||||
|
|
||||||
std::unique_ptr<Gui::FontLoader> mFontLoader;
|
std::unique_ptr<Gui::FontLoader> mFontLoader;
|
||||||
|
std::unique_ptr<StatsWatcher> mStatsWatcher;
|
||||||
|
|
||||||
bool mConsoleOnlyScripts;
|
bool mConsoleOnlyScripts;
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,11 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BindingsManager::setJoystickDeadZone(float deadZone)
|
||||||
|
{
|
||||||
|
mInputBinder->setJoystickDeadZone(deadZone);
|
||||||
|
}
|
||||||
|
|
||||||
float BindingsManager::getActionValue (int id) const
|
float BindingsManager::getActionValue (int id) const
|
||||||
{
|
{
|
||||||
return mInputBinder->getChannel(id)->getValue();
|
return mInputBinder->getChannel(id)->getValue();
|
||||||
|
|
|
@ -41,6 +41,8 @@ namespace MWInput
|
||||||
|
|
||||||
void setPlayerControlsEnabled(bool enabled);
|
void setPlayerControlsEnabled(bool enabled);
|
||||||
|
|
||||||
|
void setJoystickDeadZone(float deadZone);
|
||||||
|
|
||||||
bool isLeftOrRightButton(int action, bool joystick) const;
|
bool isLeftOrRightButton(int action, bool joystick) const;
|
||||||
|
|
||||||
bool actionIsActive(int id) const;
|
bool actionIsActive(int id) const;
|
||||||
|
|
|
@ -72,6 +72,10 @@ namespace MWInput
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
if (uiScale != 0.f)
|
if (uiScale != 0.f)
|
||||||
mInvUiScalingFactor = 1.f / uiScale;
|
mInvUiScalingFactor = 1.f / uiScale;
|
||||||
|
|
||||||
|
float deadZoneRadius = Settings::Manager::getFloat("joystick dead zone", "Input");
|
||||||
|
deadZoneRadius = std::min(std::max(deadZoneRadius, 0.0f), 0.5f);
|
||||||
|
mBindingsManager->setJoystickDeadZone(deadZoneRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
void ControllerManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
@ -100,10 +104,9 @@ namespace MWInput
|
||||||
// game mode does not move the position of the GUI cursor
|
// game mode does not move the position of the GUI cursor
|
||||||
float xMove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
float xMove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
||||||
float yMove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
float yMove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
||||||
if (xMove != 0 || yMove != 0 || zAxis != 0)
|
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
||||||
|
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
||||||
{
|
{
|
||||||
int mouseWheelMove = static_cast<int>(-zAxis * dt * 1500.0f);
|
|
||||||
|
|
||||||
mMouseManager->injectMouseMove(xMove, yMove, mouseWheelMove);
|
mMouseManager->injectMouseMove(xMove, yMove, mouseWheelMove);
|
||||||
mMouseManager->warpMouse();
|
mMouseManager->warpMouse();
|
||||||
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
|
|
@ -229,10 +229,10 @@ namespace MWInput
|
||||||
|
|
||||||
bool MouseManager::injectMouseButtonRelease(Uint8 button)
|
bool MouseManager::injectMouseButtonRelease(Uint8 button)
|
||||||
{
|
{
|
||||||
return MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(button));
|
return MyGUI::InputManager::getInstance().injectMouseRelease(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(button));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseManager::injectMouseMove(int xMove, int yMove, int mouseWheelMove)
|
void MouseManager::injectMouseMove(float xMove, float yMove, float mouseWheelMove)
|
||||||
{
|
{
|
||||||
mGuiCursorX += xMove;
|
mGuiCursorX += xMove;
|
||||||
mGuiCursorY += yMove;
|
mGuiCursorY += yMove;
|
||||||
|
@ -242,7 +242,7 @@ namespace MWInput
|
||||||
mGuiCursorX = std::max(0.f, std::min(mGuiCursorX, float(viewSize.width - 1)));
|
mGuiCursorX = std::max(0.f, std::min(mGuiCursorX, float(viewSize.width - 1)));
|
||||||
mGuiCursorY = std::max(0.f, std::min(mGuiCursorY, float(viewSize.height - 1)));
|
mGuiCursorY = std::max(0.f, std::min(mGuiCursorY, float(viewSize.height - 1)));
|
||||||
|
|
||||||
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), static_cast<int>(mMouseWheel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseManager::warpMouse()
|
void MouseManager::warpMouse()
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace MWInput
|
||||||
|
|
||||||
bool injectMouseButtonPress(Uint8 button);
|
bool injectMouseButtonPress(Uint8 button);
|
||||||
bool injectMouseButtonRelease(Uint8 button);
|
bool injectMouseButtonRelease(Uint8 button);
|
||||||
void injectMouseMove(int xMove, int yMove, int mouseWheelMove);
|
void injectMouseMove(float xMove, float yMove, float mouseWheelMove);
|
||||||
void warpMouse();
|
void warpMouse();
|
||||||
|
|
||||||
void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; }
|
void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; }
|
||||||
|
|
|
@ -1966,13 +1966,17 @@ 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
|
||||||
// One case where we need this is to make sure bound items are removed upon death
|
// One case where we need this is to make sure bound items are removed upon death
|
||||||
stats.modifyMagicEffects(MWMechanics::MagicEffects());
|
stats.modifyMagicEffects(MWMechanics::MagicEffects());
|
||||||
stats.getActiveSpells().clear();
|
stats.getActiveSpells().clear();
|
||||||
|
|
||||||
|
if (!isPlayer)
|
||||||
stats.getSpells().clear();
|
stats.getSpells().clear();
|
||||||
|
|
||||||
// Make sure spell effects are removed
|
// Make sure spell effects are removed
|
||||||
purgeSpellEffects(stats.getActorId());
|
purgeSpellEffects(stats.getActorId());
|
||||||
|
|
||||||
|
@ -1981,7 +1985,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
|
||||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||||
|
|
|
@ -344,6 +344,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
storage.mFleeBlindRunTimer += duration;
|
storage.mFleeBlindRunTimer += duration;
|
||||||
|
|
||||||
|
storage.mMovement.mRotation[0] = -actor.getRefData().getPosition().rot[0];
|
||||||
storage.mMovement.mRotation[2] = osg::PI + getZAngleToDir(target.getRefData().getPosition().asVec3()-actor.getRefData().getPosition().asVec3());
|
storage.mMovement.mRotation[2] = osg::PI + getZAngleToDir(target.getRefData().getPosition().asVec3()-actor.getRefData().getPosition().asVec3());
|
||||||
storage.mMovement.mPosition[1] = 1;
|
storage.mMovement.mPosition[1] = 1;
|
||||||
updateActorsMovement(actor, duration, storage);
|
updateActorsMovement(actor, duration, storage);
|
||||||
|
|
|
@ -1925,6 +1925,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();
|
||||||
|
@ -1988,7 +1989,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)
|
||||||
|
@ -2217,8 +2218,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;
|
||||||
|
@ -2242,6 +2242,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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -236,10 +236,8 @@ namespace MWMechanics
|
||||||
invStore.autoEquip(ptr);
|
invStore.autoEquip(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mWatchedTimeToStartDrowning = -1 for correct drowning state check,
|
|
||||||
// if stats.getTimeToStartDrowning() == 0 already on game start
|
|
||||||
MechanicsManager::MechanicsManager()
|
MechanicsManager::MechanicsManager()
|
||||||
: mWatchedLevel(-1), mWatchedTimeToStartDrowning(-1), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
|
: mUpdatePlayer (true), mClassSelected (false),
|
||||||
mRaceSelected (false), mAI(true)
|
mRaceSelected (false), mAI(true)
|
||||||
{
|
{
|
||||||
//buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
//buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
||||||
|
@ -261,16 +259,16 @@ namespace MWMechanics
|
||||||
|
|
||||||
void MechanicsManager::remove(const MWWorld::Ptr& ptr)
|
void MechanicsManager::remove(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
if(ptr == mWatched)
|
if(ptr == MWBase::Environment::get().getWindowManager()->getWatchedActor())
|
||||||
mWatched = MWWorld::Ptr();
|
MWBase::Environment::get().getWindowManager()->watchActor(MWWorld::Ptr());
|
||||||
mActors.removeActor(ptr);
|
mActors.removeActor(ptr);
|
||||||
mObjects.removeObject(ptr);
|
mObjects.removeObject(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
if(old == mWatched)
|
if(old == MWBase::Environment::get().getWindowManager()->getWatchedActor())
|
||||||
mWatched = ptr;
|
MWBase::Environment::get().getWindowManager()->watchActor(ptr);
|
||||||
|
|
||||||
if(ptr.getClass().isActor())
|
if(ptr.getClass().isActor())
|
||||||
mActors.updateActor(old, ptr);
|
mActors.updateActor(old, ptr);
|
||||||
|
@ -278,19 +276,12 @@ namespace MWMechanics
|
||||||
mObjects.updateObject(old, ptr);
|
mObjects.updateObject(old, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MechanicsManager::drop(const MWWorld::CellStore *cellStore)
|
void MechanicsManager::drop(const MWWorld::CellStore *cellStore)
|
||||||
{
|
{
|
||||||
mActors.dropActors(cellStore, mWatched);
|
mActors.dropActors(cellStore, getPlayer());
|
||||||
mObjects.dropObjects(cellStore);
|
mObjects.dropObjects(cellStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MechanicsManager::watchActor(const MWWorld::Ptr& ptr)
|
|
||||||
{
|
|
||||||
mWatched = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MechanicsManager::restoreStatsAfterCorprus(const MWWorld::Ptr& actor, const std::string& sourceId)
|
void MechanicsManager::restoreStatsAfterCorprus(const MWWorld::Ptr& actor, const std::string& sourceId)
|
||||||
{
|
{
|
||||||
auto& stats = actor.getClass().getCreatureStats (actor);
|
auto& stats = actor.getClass().getCreatureStats (actor);
|
||||||
|
@ -311,79 +302,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
void MechanicsManager::update(float duration, bool paused)
|
void MechanicsManager::update(float duration, bool paused)
|
||||||
{
|
{
|
||||||
if(!mWatched.isEmpty())
|
// Note: we should do it here since game mechanics and world updates use these values
|
||||||
{
|
MWWorld::Ptr ptr = getPlayer();
|
||||||
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
||||||
const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched);
|
|
||||||
for(int i = 0;i < ESM::Attribute::Length;++i)
|
|
||||||
{
|
|
||||||
if(stats.getAttribute(i) != mWatchedAttributes[i] || mWatchedStatsEmpty)
|
|
||||||
{
|
|
||||||
std::stringstream attrname;
|
|
||||||
attrname << "AttribVal"<<(i+1);
|
|
||||||
|
|
||||||
mWatchedAttributes[i] = stats.getAttribute(i);
|
|
||||||
winMgr->setValue(attrname.str(), stats.getAttribute(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stats.getHealth() != mWatchedHealth || mWatchedStatsEmpty)
|
|
||||||
{
|
|
||||||
static const std::string hbar("HBar");
|
|
||||||
mWatchedHealth = stats.getHealth();
|
|
||||||
winMgr->setValue(hbar, stats.getHealth());
|
|
||||||
}
|
|
||||||
if(stats.getMagicka() != mWatchedMagicka || mWatchedStatsEmpty)
|
|
||||||
{
|
|
||||||
static const std::string mbar("MBar");
|
|
||||||
mWatchedMagicka = stats.getMagicka();
|
|
||||||
winMgr->setValue(mbar, stats.getMagicka());
|
|
||||||
}
|
|
||||||
if(stats.getFatigue() != mWatchedFatigue || mWatchedStatsEmpty)
|
|
||||||
{
|
|
||||||
static const std::string fbar("FBar");
|
|
||||||
mWatchedFatigue = stats.getFatigue();
|
|
||||||
winMgr->setValue(fbar, stats.getFatigue());
|
|
||||||
}
|
|
||||||
|
|
||||||
float timeToDrown = stats.getTimeToStartDrowning();
|
|
||||||
|
|
||||||
if(timeToDrown != mWatchedTimeToStartDrowning)
|
|
||||||
{
|
|
||||||
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
|
||||||
.find("fHoldBreathTime")->mValue.getFloat();
|
|
||||||
|
|
||||||
mWatchedTimeToStartDrowning = timeToDrown;
|
|
||||||
|
|
||||||
if(timeToDrown >= fHoldBreathTime || timeToDrown == -1.0) // -1.0 is a special value during initialization
|
|
||||||
winMgr->setDrowningBarVisibility(false);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
winMgr->setDrowningBarVisibility(true);
|
|
||||||
winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning(), fHoldBreathTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Loop over ESM::Skill::SkillEnum
|
|
||||||
for(int i = 0; i < ESM::Skill::Length; ++i)
|
|
||||||
{
|
|
||||||
if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
|
||||||
{
|
|
||||||
mWatchedSkills[i] = stats.getSkill(i);
|
|
||||||
winMgr->setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stats.getLevel() != mWatchedLevel)
|
|
||||||
{
|
|
||||||
mWatchedLevel = stats.getLevel();
|
|
||||||
winMgr->setValue("level", mWatchedLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
mWatchedStatsEmpty = false;
|
|
||||||
|
|
||||||
// Update the equipped weapon icon
|
// Update the equipped weapon icon
|
||||||
MWWorld::InventoryStore& inv = mWatched.getClass().getInventoryStore(mWatched);
|
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
if (weapon == inv.end())
|
if (weapon == inv.end())
|
||||||
winMgr->unsetSelectedWeapon();
|
winMgr->unsetSelectedWeapon();
|
||||||
|
@ -398,49 +322,17 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
const std::string& spell = winMgr->getSelectedSpell();
|
const std::string& spell = winMgr->getSelectedSpell();
|
||||||
if (!spell.empty())
|
if (!spell.empty())
|
||||||
winMgr->setSelectedSpell(spell, int(getSpellSuccessChance(spell, mWatched)));
|
winMgr->setSelectedSpell(spell, int(MWMechanics::getSpellSuccessChance(spell, ptr)));
|
||||||
else
|
else
|
||||||
winMgr->unsetSelectedSpell();
|
winMgr->unsetSelectedSpell();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUpdatePlayer)
|
if (mUpdatePlayer)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
||||||
|
|
||||||
// basic player profile; should not change anymore after the creation phase is finished.
|
|
||||||
MWBase::WindowManager *winMgr =
|
|
||||||
MWBase::Environment::get().getWindowManager();
|
|
||||||
|
|
||||||
const ESM::NPC *player =
|
|
||||||
world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
|
||||||
|
|
||||||
const ESM::Race *race =
|
|
||||||
world->getStore().get<ESM::Race>().find(player->mRace);
|
|
||||||
const ESM::Class *cls =
|
|
||||||
world->getStore().get<ESM::Class>().find(player->mClass);
|
|
||||||
|
|
||||||
winMgr->setValue ("name", player->mName);
|
|
||||||
winMgr->setValue ("race", race->mName);
|
|
||||||
winMgr->setValue ("class", cls->mName);
|
|
||||||
|
|
||||||
mUpdatePlayer = false;
|
mUpdatePlayer = false;
|
||||||
|
|
||||||
MWBase::WindowManager::SkillList majorSkills (5);
|
|
||||||
MWBase::WindowManager::SkillList minorSkills (5);
|
|
||||||
|
|
||||||
for (int i=0; i<5; ++i)
|
|
||||||
{
|
|
||||||
minorSkills[i] = cls->mData.mSkills[i][0];
|
|
||||||
majorSkills[i] = cls->mData.mSkills[i][1];
|
|
||||||
}
|
|
||||||
|
|
||||||
winMgr->configureSkills (majorSkills, minorSkills);
|
|
||||||
|
|
||||||
// HACK? The player has been changed, so a new Animation object may
|
// HACK? The player has been changed, so a new Animation object may
|
||||||
// have been made for them. Make sure they're properly updated.
|
// have been made for them. Make sure they're properly updated.
|
||||||
MWWorld::Ptr ptr = getPlayer();
|
|
||||||
mActors.removeActor(ptr);
|
mActors.removeActor(ptr);
|
||||||
mActors.addActor(ptr, true);
|
mActors.addActor(ptr, true);
|
||||||
}
|
}
|
||||||
|
@ -517,7 +409,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
int MechanicsManager::getHoursToRest() const
|
int MechanicsManager::getHoursToRest() const
|
||||||
{
|
{
|
||||||
return mActors.getHoursToRest(mWatched);
|
return mActors.getHoursToRest(getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::setPlayerName (const std::string& name)
|
void MechanicsManager::setPlayerName (const std::string& name)
|
||||||
|
|
|
@ -21,20 +21,6 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
class MechanicsManager : public MWBase::MechanicsManager
|
class MechanicsManager : public MWBase::MechanicsManager
|
||||||
{
|
{
|
||||||
MWWorld::Ptr mWatched;
|
|
||||||
|
|
||||||
AttributeValue mWatchedAttributes[8];
|
|
||||||
SkillValue mWatchedSkills[27];
|
|
||||||
|
|
||||||
DynamicStat<float> mWatchedHealth;
|
|
||||||
DynamicStat<float> mWatchedMagicka;
|
|
||||||
DynamicStat<float> mWatchedFatigue;
|
|
||||||
|
|
||||||
int mWatchedLevel;
|
|
||||||
|
|
||||||
float mWatchedTimeToStartDrowning;
|
|
||||||
|
|
||||||
bool mWatchedStatsEmpty;
|
|
||||||
bool mUpdatePlayer;
|
bool mUpdatePlayer;
|
||||||
bool mClassSelected;
|
bool mClassSelected;
|
||||||
bool mRaceSelected;
|
bool mRaceSelected;
|
||||||
|
@ -68,10 +54,6 @@ namespace MWMechanics
|
||||||
virtual void drop(const MWWorld::CellStore *cellStore) override;
|
virtual void drop(const MWWorld::CellStore *cellStore) override;
|
||||||
///< Deregister all objects in the given cell.
|
///< Deregister all objects in the given cell.
|
||||||
|
|
||||||
virtual void watchActor(const MWWorld::Ptr& ptr) override;
|
|
||||||
///< On each update look for changes in a previously registered actor and update the
|
|
||||||
/// GUI accordingly.
|
|
||||||
|
|
||||||
virtual void update (float duration, bool paused) override;
|
virtual void update (float duration, bool paused) override;
|
||||||
///< Update objects
|
///< Update objects
|
||||||
///
|
///
|
||||||
|
|
|
@ -624,6 +624,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)
|
||||||
{
|
{
|
||||||
|
@ -1394,11 +1395,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1539,6 +1540,8 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
if (mLightListCallback)
|
if (mLightListCallback)
|
||||||
mObjectRoot->removeCullCallback(mLightListCallback);
|
mObjectRoot->removeCullCallback(mLightListCallback);
|
||||||
|
if (mTransparencyUpdater)
|
||||||
|
mObjectRoot->removeCullCallback(mTransparencyUpdater);
|
||||||
previousStateset = mObjectRoot->getStateSet();
|
previousStateset = mObjectRoot->getStateSet();
|
||||||
mObjectRoot->getParent(0)->removeChild(mObjectRoot);
|
mObjectRoot->getParent(0)->removeChild(mObjectRoot);
|
||||||
}
|
}
|
||||||
|
@ -1630,6 +1633,8 @@ namespace MWRender
|
||||||
if (!mLightListCallback)
|
if (!mLightListCallback)
|
||||||
mLightListCallback = new SceneUtil::LightListCallback;
|
mLightListCallback = new SceneUtil::LightListCallback;
|
||||||
mObjectRoot->addCullCallback(mLightListCallback);
|
mObjectRoot->addCullCallback(mLightListCallback);
|
||||||
|
if (mTransparencyUpdater)
|
||||||
|
mObjectRoot->addCullCallback(mTransparencyUpdater);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Group* Animation::getObjectRoot()
|
osg::Group* Animation::getObjectRoot()
|
||||||
|
|
|
@ -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 <components/sceneutil/visitor.hpp>
|
#include <components/sceneutil/visitor.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -63,14 +64,21 @@ 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),
|
||||||
mCameraDistance(0.f),
|
mCameraDistance(0.f),
|
||||||
mThirdPersonMode(ThirdPersonViewMode::Standard),
|
mMaxNextCameraDistance(800.f),
|
||||||
mOverShoulderOffset(osg::Vec2f(30.0f, -10.0f)),
|
mFocalPointCurrentOffset(osg::Vec2d()),
|
||||||
mSmoothTransitionToCombatMode(0.f)
|
mFocalPointTargetOffset(osg::Vec2d()),
|
||||||
|
mFocalPointTransitionSpeedCoef(1.f),
|
||||||
|
mSkipFocalPointTransition(true),
|
||||||
|
mPreviousTransitionInfluence(0.f),
|
||||||
|
mSmoothedSpeed(0.f),
|
||||||
|
mZoomOutWhenMoveCoef(Settings::Manager::getFloat("zoom out when move coef", "Camera")),
|
||||||
|
mDynamicCameraDistanceEnabled(false),
|
||||||
|
mShowCrosshairInThirdPersonMode(false)
|
||||||
{
|
{
|
||||||
mVanity.enabled = false;
|
mVanity.enabled = false;
|
||||||
mVanity.allowed = true;
|
mVanity.allowed = true;
|
||||||
|
@ -139,14 +147,11 @@ namespace MWRender
|
||||||
osg::Vec3d Camera::getFocalPointOffset() const
|
osg::Vec3d Camera::getFocalPointOffset() const
|
||||||
{
|
{
|
||||||
osg::Vec3d offset(0, 0, 10.f);
|
osg::Vec3d offset(0, 0, 10.f);
|
||||||
if (mThirdPersonMode == ThirdPersonViewMode::OverShoulder && !mPreviewMode && !mVanity.enabled)
|
if (!mPreviewMode && !mVanity.enabled)
|
||||||
{
|
{
|
||||||
float horizontalOffset = mOverShoulderOffset.x() * (1.f - mSmoothTransitionToCombatMode);
|
offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw());
|
||||||
float verticalOffset = mSmoothTransitionToCombatMode * 15.f + (1.f - mSmoothTransitionToCombatMode) * mOverShoulderOffset.y();
|
offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
|
||||||
|
offset.z() += mFocalPointCurrentOffset.y();
|
||||||
offset.x() += horizontalOffset * cos(getYaw());
|
|
||||||
offset.y() += horizontalOffset * sin(getYaw());
|
|
||||||
offset.z() += verticalOffset;
|
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
@ -238,35 +243,69 @@ namespace MWRender
|
||||||
// only show the crosshair in game mode
|
// only show the crosshair in game mode
|
||||||
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
|
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
|
||||||
wm->showCrosshair(!wm->isGuiMode() && !mVanity.enabled && !mPreviewMode
|
wm->showCrosshair(!wm->isGuiMode() && !mVanity.enabled && !mPreviewMode
|
||||||
&& (mFirstPersonView || mThirdPersonMode != ThirdPersonViewMode::Standard));
|
&& (mFirstPersonView || mShowCrosshairInThirdPersonMode));
|
||||||
|
|
||||||
if(mVanity.enabled)
|
if(mVanity.enabled)
|
||||||
{
|
{
|
||||||
rotateCamera(0.f, 0.f, osg::DegreesToRadians(3.f * duration), true);
|
rotateCamera(0.f, 0.f, osg::DegreesToRadians(3.f * duration), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSmoothTransitionToCombatMode(duration);
|
updateFocalPointOffset(duration);
|
||||||
|
|
||||||
|
float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr);
|
||||||
|
speed /= (1.f + speed / 500.f);
|
||||||
|
float maxDelta = 300.f * duration;
|
||||||
|
mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta);
|
||||||
|
|
||||||
|
mMaxNextCameraDistance = mCameraDistance + duration * (100.f + mBaseCameraDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setOverShoulderOffset(float horizontal, float vertical)
|
void Camera::setFocalPointTargetOffset(osg::Vec2d v)
|
||||||
{
|
{
|
||||||
mOverShoulderOffset = osg::Vec2f(horizontal, vertical);
|
mFocalPointTargetOffset = v;
|
||||||
|
mPreviousTransitionSpeed = mFocalPointTransitionSpeed;
|
||||||
|
mPreviousTransitionInfluence = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::updateSmoothTransitionToCombatMode(float duration)
|
void Camera::updateFocalPointOffset(float duration)
|
||||||
{
|
{
|
||||||
bool combatMode = true;
|
if (duration <= 0)
|
||||||
if (mTrackingPtr.getClass().isActor())
|
return;
|
||||||
combatMode = mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing;
|
|
||||||
float speed = ((combatMode ? 1.f : 0.f) - mSmoothTransitionToCombatMode) * 5;
|
|
||||||
if (speed != 0)
|
|
||||||
speed += speed > 0 ? 1 : -1;
|
|
||||||
|
|
||||||
mSmoothTransitionToCombatMode += speed * duration;
|
if (mSkipFocalPointTransition)
|
||||||
if (mSmoothTransitionToCombatMode > 1)
|
{
|
||||||
mSmoothTransitionToCombatMode = 1;
|
mSkipFocalPointTransition = false;
|
||||||
if (mSmoothTransitionToCombatMode < 0)
|
mPreviousExtraOffset = osg::Vec2d();
|
||||||
mSmoothTransitionToCombatMode = 0;
|
mPreviousTransitionInfluence = 0.f;
|
||||||
|
mFocalPointCurrentOffset = mFocalPointTargetOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec2d oldOffset = mFocalPointCurrentOffset;
|
||||||
|
|
||||||
|
if (mPreviousTransitionInfluence > 0)
|
||||||
|
{
|
||||||
|
mFocalPointCurrentOffset -= mPreviousExtraOffset;
|
||||||
|
mPreviousExtraOffset = mPreviousExtraOffset / mPreviousTransitionInfluence + mPreviousTransitionSpeed * duration;
|
||||||
|
mPreviousTransitionInfluence =
|
||||||
|
std::max(0.f, mPreviousTransitionInfluence - duration * mFocalPointTransitionSpeedCoef);
|
||||||
|
mPreviousExtraOffset *= mPreviousTransitionInfluence;
|
||||||
|
mFocalPointCurrentOffset += mPreviousExtraOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec2d delta = mFocalPointTargetOffset - mFocalPointCurrentOffset;
|
||||||
|
if (delta.length2() > 0)
|
||||||
|
{
|
||||||
|
float coef = duration * (1.0 + 5.0 / delta.length()) *
|
||||||
|
mFocalPointTransitionSpeedCoef * (1.0f - mPreviousTransitionInfluence);
|
||||||
|
mFocalPointCurrentOffset += delta * std::min(coef, 1.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPreviousExtraOffset = osg::Vec2d();
|
||||||
|
mPreviousTransitionInfluence = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
mFocalPointTransitionSpeed = (mFocalPointCurrentOffset - oldOffset) / duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::toggleViewMode(bool force)
|
void Camera::toggleViewMode(bool force)
|
||||||
|
@ -447,7 +486,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;
|
||||||
|
@ -474,7 +513,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,7 +536,15 @@ namespace MWRender
|
||||||
|
|
||||||
float Camera::getCameraDistanceCorrection() const
|
float Camera::getCameraDistanceCorrection() const
|
||||||
{
|
{
|
||||||
return mThirdPersonMode != ThirdPersonViewMode::Standard ? std::max(-getPitch(), 0.f) * 50.f : 0;
|
if (!mDynamicCameraDistanceEnabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
float pitchCorrection = std::max(-getPitch(), 0.f) * 50.f;
|
||||||
|
|
||||||
|
float smoothedSpeedSqr = mSmoothedSpeed * mSmoothedSpeed;
|
||||||
|
float speedCorrection = smoothedSpeedSqr / (smoothedSpeedSqr + 300.f*300.f) * mZoomOutWhenMoveCoef;
|
||||||
|
|
||||||
|
return pitchCorrection + speedCorrection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setCameraDistance()
|
void Camera::setCameraDistance()
|
||||||
|
@ -502,7 +552,11 @@ namespace MWRender
|
||||||
if (mVanity.enabled || mPreviewMode)
|
if (mVanity.enabled || mPreviewMode)
|
||||||
mCameraDistance = mPreviewCam.offset;
|
mCameraDistance = mPreviewCam.offset;
|
||||||
else if (!mFirstPersonView)
|
else if (!mFirstPersonView)
|
||||||
|
{
|
||||||
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection();
|
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection();
|
||||||
|
if (mDynamicCameraDistanceEnabled)
|
||||||
|
mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance);
|
||||||
|
}
|
||||||
mFocalPointAdjustment = osg::Vec3d();
|
mFocalPointAdjustment = osg::Vec3d();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,6 @@ namespace MWRender
|
||||||
/// \brief Camera control
|
/// \brief Camera control
|
||||||
class Camera
|
class Camera
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
enum class ThirdPersonViewMode {Standard, OverShoulder};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CamData {
|
struct CamData {
|
||||||
float roll, pitch, yaw, offset;
|
float roll, pitch, yaw, offset;
|
||||||
|
@ -57,15 +54,26 @@ namespace MWRender
|
||||||
bool mViewModeToggleQueued;
|
bool mViewModeToggleQueued;
|
||||||
|
|
||||||
float mCameraDistance;
|
float mCameraDistance;
|
||||||
|
float mMaxNextCameraDistance;
|
||||||
|
|
||||||
ThirdPersonViewMode mThirdPersonMode;
|
|
||||||
osg::Vec2f mOverShoulderOffset;
|
|
||||||
osg::Vec3d mFocalPointAdjustment;
|
osg::Vec3d mFocalPointAdjustment;
|
||||||
|
osg::Vec2d mFocalPointCurrentOffset;
|
||||||
|
osg::Vec2d mFocalPointTargetOffset;
|
||||||
|
float mFocalPointTransitionSpeedCoef;
|
||||||
|
bool mSkipFocalPointTransition;
|
||||||
|
|
||||||
// Makes sense only if mThirdPersonMode is OverShoulder. Can be in range [0, 1].
|
// This fields are used to make focal point transition smooth if previous transition was not finished.
|
||||||
// Used for smooth transition from non-combat camera position (0) to combat camera position (1).
|
float mPreviousTransitionInfluence;
|
||||||
float mSmoothTransitionToCombatMode;
|
osg::Vec2d mFocalPointTransitionSpeed;
|
||||||
void updateSmoothTransitionToCombatMode(float duration);
|
osg::Vec2d mPreviousTransitionSpeed;
|
||||||
|
osg::Vec2d mPreviousExtraOffset;
|
||||||
|
|
||||||
|
float mSmoothedSpeed;
|
||||||
|
float mZoomOutWhenMoveCoef;
|
||||||
|
bool mDynamicCameraDistanceEnabled;
|
||||||
|
bool mShowCrosshairInThirdPersonMode;
|
||||||
|
|
||||||
|
void updateFocalPointOffset(float duration);
|
||||||
float getCameraDistanceCorrection() const;
|
float getCameraDistanceCorrection() const;
|
||||||
|
|
||||||
osg::ref_ptr<osg::NodeCallback> mUpdateCallback;
|
osg::ref_ptr<osg::NodeCallback> mUpdateCallback;
|
||||||
|
@ -76,8 +84,11 @@ namespace MWRender
|
||||||
|
|
||||||
MWWorld::Ptr getTrackingPtr() const;
|
MWWorld::Ptr getTrackingPtr() const;
|
||||||
|
|
||||||
void setThirdPersonViewMode(ThirdPersonViewMode mode) { mThirdPersonMode = mode; }
|
void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; }
|
||||||
void setOverShoulderOffset(float horizontal, float vertical);
|
void setFocalPointTargetOffset(osg::Vec2d v);
|
||||||
|
void skipFocalPointTransition() { mSkipFocalPointTransition = true; }
|
||||||
|
void enableDynamicCameraDistance(bool v) { mDynamicCameraDistanceEnabled = v; }
|
||||||
|
void enableCrosshairInThirdPersonMode(bool v) { mShowCrosshairInThirdPersonMode = v; }
|
||||||
|
|
||||||
/// Update the view matrix of \a cam
|
/// Update the view matrix of \a cam
|
||||||
void updateCamera(osg::Camera* cam);
|
void updateCamera(osg::Camera* cam);
|
||||||
|
@ -125,7 +136,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
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -45,7 +52,7 @@ protected:
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
|
@ -428,7 +428,7 @@ namespace MWRender
|
||||||
|
|
||||||
if (activeGrid)
|
if (activeGrid)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
for (auto ref : getRefTracker().mBlacklist)
|
for (auto ref : getRefTracker().mBlacklist)
|
||||||
refs.erase(ref);
|
refs.erase(ref);
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ namespace MWRender
|
||||||
float dSqr = (viewPoint - pos).length2();
|
float dSqr = (viewPoint - pos).length2();
|
||||||
if (!activeGrid)
|
if (!activeGrid)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mSizeCacheMutex);
|
std::lock_guard<std::mutex> lock(mSizeCacheMutex);
|
||||||
SizeCache::iterator found = mSizeCache.find(pair.first);
|
SizeCache::iterator found = mSizeCache.find(pair.first);
|
||||||
if (found != mSizeCache.end() && found->second < dSqr*minSize*minSize)
|
if (found != mSizeCache.end() && found->second < dSqr*minSize*minSize)
|
||||||
continue;
|
continue;
|
||||||
|
@ -501,7 +501,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
if (getRefTracker().mDisabled.count(pair.first))
|
if (getRefTracker().mDisabled.count(pair.first))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -509,7 +509,7 @@ namespace MWRender
|
||||||
float radius2 = cnode->getBound().radius2() * ref.mScale*ref.mScale;
|
float radius2 = cnode->getBound().radius2() * ref.mScale*ref.mScale;
|
||||||
if (radius2 < dSqr*minSize*minSize && !activeGrid)
|
if (radius2 < dSqr*minSize*minSize && !activeGrid)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mSizeCacheMutex);
|
std::lock_guard<std::mutex> lock(mSizeCacheMutex);
|
||||||
mSizeCache[pair.first] = radius2;
|
mSizeCache[pair.first] = radius2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -670,22 +670,33 @@ 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;
|
||||||
|
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
if (enabled && !getWritableRefTracker().mDisabled.erase(refnum)) return false;
|
if (enabled && !getWritableRefTracker().mDisabled.erase(refnum)) return false;
|
||||||
if (!enabled && !getWritableRefTracker().mDisabled.insert(refnum).second) return false;
|
if (!enabled && !getWritableRefTracker().mDisabled.insert(refnum).second) return false;
|
||||||
if (mRefTrackerLocked) return false;
|
if (mRefTrackerLocked) 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,19 +712,20 @@ 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;
|
||||||
|
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
if (!getWritableRefTracker().mBlacklist.insert(refnum).second) return false;
|
if (!getWritableRefTracker().mBlacklist.insert(refnum).second) return false;
|
||||||
if (mRefTrackerLocked) return false;
|
if (mRefTrackerLocked) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -724,7 +737,7 @@ namespace MWRender
|
||||||
|
|
||||||
void ObjectPaging::clear()
|
void ObjectPaging::clear()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
mRefTrackerNew.mDisabled.clear();
|
mRefTrackerNew.mDisabled.clear();
|
||||||
mRefTrackerNew.mBlacklist.clear();
|
mRefTrackerNew.mBlacklist.clear();
|
||||||
mRefTrackerLocked = true;
|
mRefTrackerLocked = true;
|
||||||
|
@ -734,7 +747,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
if (!mRefTrackerLocked) return false;
|
if (!mRefTrackerLocked) return false;
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
mRefTrackerLocked = false;
|
mRefTrackerLocked = false;
|
||||||
if (mRefTracker == mRefTrackerNew)
|
if (mRefTracker == mRefTrackerNew)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <components/resource/resourcemanager.hpp>
|
#include <components/resource/resourcemanager.hpp>
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
#include <OpenThreads/Mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace MWRender
|
||||||
float mMinSizeMergeFactor;
|
float mMinSizeMergeFactor;
|
||||||
float mMinSizeCostMultiplier;
|
float mMinSizeCostMultiplier;
|
||||||
|
|
||||||
OpenThreads::Mutex mRefTrackerMutex;
|
std::mutex mRefTrackerMutex;
|
||||||
struct RefTracker
|
struct RefTracker
|
||||||
{
|
{
|
||||||
std::set<ESM::RefNum> mDisabled;
|
std::set<ESM::RefNum> mDisabled;
|
||||||
|
@ -72,7 +72,7 @@ namespace MWRender
|
||||||
const RefTracker& getRefTracker() const { return mRefTracker; }
|
const RefTracker& getRefTracker() const { return mRefTracker; }
|
||||||
RefTracker& getWritableRefTracker() { return mRefTrackerLocked ? mRefTrackerNew : mRefTracker; }
|
RefTracker& getWritableRefTracker() { return mRefTrackerLocked ? mRefTrackerNew : mRefTracker; }
|
||||||
|
|
||||||
OpenThreads::Mutex mSizeCacheMutex;
|
std::mutex mSizeCacheMutex;
|
||||||
typedef std::map<ESM::RefNum, float> SizeCache;
|
typedef std::map<ESM::RefNum, float> SizeCache;
|
||||||
SizeCache mSizeCache;
|
SizeCache mSizeCache;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <osg/Light>
|
#include <osg/Light>
|
||||||
#include <osg/LightModel>
|
#include <osg/LightModel>
|
||||||
|
@ -64,6 +66,7 @@
|
||||||
#include "vismask.hpp"
|
#include "vismask.hpp"
|
||||||
#include "pathgrid.hpp"
|
#include "pathgrid.hpp"
|
||||||
#include "camera.hpp"
|
#include "camera.hpp"
|
||||||
|
#include "viewovershoulder.hpp"
|
||||||
#include "water.hpp"
|
#include "water.hpp"
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
@ -311,6 +314,8 @@ namespace MWRender
|
||||||
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
|
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
|
||||||
|
|
||||||
mCamera.reset(new Camera(mViewer->getCamera()));
|
mCamera.reset(new Camera(mViewer->getCamera()));
|
||||||
|
if (Settings::Manager::getBool("view over shoulder", "Camera"))
|
||||||
|
mViewOverShoulderController.reset(new ViewOverShoulderController(mCamera.get()));
|
||||||
|
|
||||||
mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
|
mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
|
||||||
|
|
||||||
|
@ -371,7 +376,6 @@ namespace MWRender
|
||||||
float firstPersonFov = Settings::Manager::getFloat("first person field of view", "Camera");
|
float firstPersonFov = Settings::Manager::getFloat("first person field of view", "Camera");
|
||||||
mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f);
|
mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f);
|
||||||
mStateUpdater->setFogEnd(mViewDistance);
|
mStateUpdater->setFogEnd(mViewDistance);
|
||||||
updateThirdPersonViewMode();
|
|
||||||
|
|
||||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
|
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
|
||||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance));
|
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance));
|
||||||
|
@ -387,19 +391,6 @@ namespace MWRender
|
||||||
mWorkQueue = nullptr;
|
mWorkQueue = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::updateThirdPersonViewMode()
|
|
||||||
{
|
|
||||||
if (Settings::Manager::getBool("view over shoulder", "Camera"))
|
|
||||||
mCamera->setThirdPersonViewMode(Camera::ThirdPersonViewMode::OverShoulder);
|
|
||||||
else
|
|
||||||
mCamera->setThirdPersonViewMode(Camera::ThirdPersonViewMode::Standard);
|
|
||||||
|
|
||||||
std::stringstream offset(Settings::Manager::getString("view over shoulder offset", "Camera"));
|
|
||||||
float horizontal = 30.f, vertical = -10.f;
|
|
||||||
offset >> horizontal >> vertical;
|
|
||||||
mCamera->setOverShoulderOffset(horizontal, vertical);
|
|
||||||
}
|
|
||||||
|
|
||||||
osgUtil::IncrementalCompileOperation* RenderingManager::getIncrementalCompileOperation()
|
osgUtil::IncrementalCompileOperation* RenderingManager::getIncrementalCompileOperation()
|
||||||
{
|
{
|
||||||
return mViewer->getIncrementalCompileOperation();
|
return mViewer->getIncrementalCompileOperation();
|
||||||
|
@ -635,6 +626,8 @@ namespace MWRender
|
||||||
updateNavMesh();
|
updateNavMesh();
|
||||||
updateRecastMesh();
|
updateRecastMesh();
|
||||||
|
|
||||||
|
if (mViewOverShoulderController)
|
||||||
|
mViewOverShoulderController->update();
|
||||||
mCamera->update(dt, paused);
|
mCamera->update(dt, paused);
|
||||||
|
|
||||||
osg::Vec3d focal, cameraPos;
|
osg::Vec3d focal, cameraPos;
|
||||||
|
@ -717,25 +710,24 @@ namespace MWRender
|
||||||
|
|
||||||
virtual void operator () (osg::RenderInfo& renderInfo) const
|
virtual void operator () (osg::RenderInfo& renderInfo) const
|
||||||
{
|
{
|
||||||
Log(Debug::Verbose) << "NotifyDrawCompletedCallback: " << renderInfo.getState()->getFrameStamp()->getFrameNumber() << " >= " << mFrame;
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
|
||||||
if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame)
|
if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame)
|
||||||
{
|
{
|
||||||
mDone = true;
|
mDone = true;
|
||||||
mCondition.signal();
|
mCondition.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitTillDone()
|
void waitTillDone()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
if (mDone)
|
if (mDone)
|
||||||
return;
|
return;
|
||||||
mCondition.wait(&mMutex);
|
mCondition.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable OpenThreads::Condition mCondition;
|
mutable std::condition_variable mCondition;
|
||||||
mutable OpenThreads::Mutex mMutex;
|
mutable std::mutex mMutex;
|
||||||
mutable bool mDone;
|
mutable bool mDone;
|
||||||
unsigned int mFrame;
|
unsigned int mFrame;
|
||||||
};
|
};
|
||||||
|
@ -1384,7 +1376,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);
|
||||||
}
|
}
|
||||||
|
@ -1392,7 +1384,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);
|
||||||
}
|
}
|
||||||
|
@ -1441,7 +1433,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)
|
||||||
|
@ -1561,7 +1553,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;
|
||||||
|
@ -1574,7 +1566,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()
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace MWRender
|
||||||
class NpcAnimation;
|
class NpcAnimation;
|
||||||
class Pathgrid;
|
class Pathgrid;
|
||||||
class Camera;
|
class Camera;
|
||||||
|
class ViewOverShoulderController;
|
||||||
class Water;
|
class Water;
|
||||||
class TerrainStorage;
|
class TerrainStorage;
|
||||||
class LandManager;
|
class LandManager;
|
||||||
|
@ -302,6 +303,7 @@ namespace MWRender
|
||||||
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
|
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
|
||||||
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode;
|
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode;
|
||||||
std::unique_ptr<Camera> mCamera;
|
std::unique_ptr<Camera> mCamera;
|
||||||
|
std::unique_ptr<ViewOverShoulderController> mViewOverShoulderController;
|
||||||
osg::Vec3f mCurrentCameraPos;
|
osg::Vec3f mCurrentCameraPos;
|
||||||
|
|
||||||
osg::ref_ptr<StateUpdater> mStateUpdater;
|
osg::ref_ptr<StateUpdater> mStateUpdater;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
96
apps/openmw/mwrender/viewovershoulder.cpp
Normal file
96
apps/openmw/mwrender/viewovershoulder.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#include "viewovershoulder.hpp"
|
||||||
|
|
||||||
|
#include <osg/Quat>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
#include "../mwworld/refdata.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/drawstate.hpp"
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
ViewOverShoulderController::ViewOverShoulderController(Camera* camera) :
|
||||||
|
mCamera(camera), mMode(Mode::RightShoulder),
|
||||||
|
mAutoSwitchShoulder(Settings::Manager::getBool("auto switch shoulder", "Camera")),
|
||||||
|
mOverShoulderHorizontalOffset(30.f), mOverShoulderVerticalOffset(-10.f)
|
||||||
|
{
|
||||||
|
std::stringstream offset(Settings::Manager::getString("view over shoulder offset", "Camera"));
|
||||||
|
offset >> mOverShoulderHorizontalOffset >> mOverShoulderVerticalOffset;
|
||||||
|
mDefaultShoulderIsRight = mOverShoulderHorizontalOffset >= 0;
|
||||||
|
mOverShoulderHorizontalOffset = std::abs(mOverShoulderHorizontalOffset);
|
||||||
|
|
||||||
|
mCamera->enableDynamicCameraDistance(true);
|
||||||
|
mCamera->enableCrosshairInThirdPersonMode(true);
|
||||||
|
mCamera->setFocalPointTargetOffset({mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewOverShoulderController::update()
|
||||||
|
{
|
||||||
|
if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isFirstPerson())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Mode oldMode = mMode;
|
||||||
|
auto ptr = mCamera->getTrackingPtr();
|
||||||
|
if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing)
|
||||||
|
mMode = Mode::Combat;
|
||||||
|
else if (MWBase::Environment::get().getWorld()->isSwimming(ptr))
|
||||||
|
mMode = Mode::Swimming;
|
||||||
|
else if (oldMode == Mode::Combat || oldMode == Mode::Swimming)
|
||||||
|
mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder;
|
||||||
|
if (mAutoSwitchShoulder && (mMode == Mode::LeftShoulder || mMode == Mode::RightShoulder))
|
||||||
|
trySwitchShoulder();
|
||||||
|
if (oldMode == mMode) return;
|
||||||
|
|
||||||
|
if (oldMode == Mode::Combat || mMode == Mode::Combat)
|
||||||
|
mCamera->setFocalPointTransitionSpeed(5.f);
|
||||||
|
else
|
||||||
|
mCamera->setFocalPointTransitionSpeed(1.f);
|
||||||
|
|
||||||
|
switch (mMode)
|
||||||
|
{
|
||||||
|
case Mode::RightShoulder:
|
||||||
|
mCamera->setFocalPointTargetOffset({mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
|
||||||
|
break;
|
||||||
|
case Mode::LeftShoulder:
|
||||||
|
mCamera->setFocalPointTargetOffset({-mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
|
||||||
|
break;
|
||||||
|
case Mode::Combat:
|
||||||
|
case Mode::Swimming:
|
||||||
|
default:
|
||||||
|
mCamera->setFocalPointTargetOffset({0, 15});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewOverShoulderController::trySwitchShoulder()
|
||||||
|
{
|
||||||
|
const float limitToSwitch = 120; // switch to other shoulder if wall is closer than this limit
|
||||||
|
const float limitToSwitchBack = 300; // switch back to default shoulder if there is no walls at this distance
|
||||||
|
|
||||||
|
auto orient = osg::Quat(mCamera->getYaw(), osg::Vec3d(0,0,1));
|
||||||
|
osg::Vec3d playerPos = mCamera->getFocalPoint() - mCamera->getFocalPointOffset();
|
||||||
|
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
osg::Vec3d sideOffset = orient * osg::Vec3d(world->getHalfExtents(mCamera->getTrackingPtr()).x() - 1, 0, 0);
|
||||||
|
float rayRight = world->getDistToNearestRayHit(
|
||||||
|
playerPos + sideOffset, orient * osg::Vec3d(1, 1, 0), limitToSwitchBack + 1);
|
||||||
|
float rayLeft = world->getDistToNearestRayHit(
|
||||||
|
playerPos - sideOffset, orient * osg::Vec3d(-1, 1, 0), limitToSwitchBack + 1);
|
||||||
|
float rayForward = world->getDistToNearestRayHit(
|
||||||
|
playerPos, orient * osg::Vec3d(0, 1, 0), limitToSwitchBack + 1);
|
||||||
|
|
||||||
|
if (rayLeft < limitToSwitch && rayRight > limitToSwitchBack)
|
||||||
|
mMode = Mode::RightShoulder;
|
||||||
|
else if (rayRight < limitToSwitch && rayLeft > limitToSwitchBack)
|
||||||
|
mMode = Mode::LeftShoulder;
|
||||||
|
else if (rayLeft > limitToSwitchBack && rayRight > limitToSwitchBack && rayForward > limitToSwitchBack)
|
||||||
|
mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
apps/openmw/mwrender/viewovershoulder.hpp
Normal file
30
apps/openmw/mwrender/viewovershoulder.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef VIEWOVERSHOULDER_H
|
||||||
|
#define VIEWOVERSHOULDER_H
|
||||||
|
|
||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
class ViewOverShoulderController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ViewOverShoulderController(Camera* camera);
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void trySwitchShoulder();
|
||||||
|
enum class Mode { RightShoulder, LeftShoulder, Combat, Swimming };
|
||||||
|
|
||||||
|
Camera* mCamera;
|
||||||
|
Mode mMode;
|
||||||
|
bool mAutoSwitchShoulder;
|
||||||
|
float mOverShoulderHorizontalOffset;
|
||||||
|
float mOverShoulderVerticalOffset;
|
||||||
|
bool mDefaultShoulderIsRight;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VIEWOVERSHOULDER_H
|
|
@ -80,7 +80,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
mParser.getCode(code);
|
mParser.getCode(code);
|
||||||
mScripts.insert (std::make_pair (name, std::make_pair (code, mParser.getLocals())));
|
mScripts.emplace(name, CompiledScript(code, mParser.getLocals()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
// failed -> ignore script from now on.
|
// failed -> ignore script from now on.
|
||||||
std::vector<Interpreter::Type_Code> empty;
|
std::vector<Interpreter::Type_Code> empty;
|
||||||
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
mScripts.emplace(name, CompiledScript(empty, Compiler::Locals()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute script
|
// execute script
|
||||||
if (!iter->second.first.empty())
|
if (!iter->second.mByteCode.empty() && iter->second.mActive)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!mOpcodesInstalled)
|
if (!mOpcodesInstalled)
|
||||||
|
@ -118,7 +118,7 @@ namespace MWScript
|
||||||
mOpcodesInstalled = true;
|
mOpcodesInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext);
|
mInterpreter.run (&iter->second.mByteCode[0], iter->second.mByteCode.size(), interpreterContext);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (const MissingImplicitRefError& e)
|
catch (const MissingImplicitRefError& e)
|
||||||
|
@ -129,11 +129,21 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
|
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
|
||||||
|
|
||||||
iter->second.first.clear(); // don't execute again.
|
iter->second.mActive = false; // don't execute again.
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptManager::clear()
|
||||||
|
{
|
||||||
|
for (auto& script : mScripts)
|
||||||
|
{
|
||||||
|
script.second.mActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGlobalScripts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<int, int> ScriptManager::compileAll()
|
std::pair<int, int> ScriptManager::compileAll()
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -163,7 +173,7 @@ namespace MWScript
|
||||||
ScriptCollection::iterator iter = mScripts.find (name2);
|
ScriptCollection::iterator iter = mScripts.find (name2);
|
||||||
|
|
||||||
if (iter!=mScripts.end())
|
if (iter!=mScripts.end())
|
||||||
return iter->second.second;
|
return iter->second.mLocals;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,7 +41,20 @@ namespace MWScript
|
||||||
Interpreter::Interpreter mInterpreter;
|
Interpreter::Interpreter mInterpreter;
|
||||||
bool mOpcodesInstalled;
|
bool mOpcodesInstalled;
|
||||||
|
|
||||||
typedef std::pair<std::vector<Interpreter::Type_Code>, Compiler::Locals> CompiledScript;
|
struct CompiledScript
|
||||||
|
{
|
||||||
|
std::vector<Interpreter::Type_Code> mByteCode;
|
||||||
|
Compiler::Locals mLocals;
|
||||||
|
bool mActive;
|
||||||
|
|
||||||
|
CompiledScript(const std::vector<Interpreter::Type_Code>& code, const Compiler::Locals& locals)
|
||||||
|
{
|
||||||
|
mByteCode = code;
|
||||||
|
mLocals = locals;
|
||||||
|
mActive = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::map<std::string, CompiledScript> ScriptCollection;
|
typedef std::map<std::string, CompiledScript> ScriptCollection;
|
||||||
|
|
||||||
ScriptCollection mScripts;
|
ScriptCollection mScripts;
|
||||||
|
@ -55,6 +68,8 @@ namespace MWScript
|
||||||
Compiler::Context& compilerContext, int warningsMode,
|
Compiler::Context& compilerContext, int warningsMode,
|
||||||
const std::vector<std::string>& scriptBlacklist);
|
const std::vector<std::string>& scriptBlacklist);
|
||||||
|
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext);
|
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext);
|
||||||
///< Run the script with the given name (compile first, if not compiled yet)
|
///< Run the script with the given name (compile first, if not compiled yet)
|
||||||
|
|
||||||
|
|
|
@ -725,7 +725,8 @@ namespace MWScript
|
||||||
// We should move actors, standing on moving object, too.
|
// We should move actors, standing on moving object, too.
|
||||||
// This approach can be used to create elevators.
|
// This approach can be used to create elevators.
|
||||||
moveStandingActors(ptr, diff);
|
moveStandingActors(ptr, diff);
|
||||||
MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x(), worldPos.y(), worldPos.z());
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
|
||||||
|
MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x(), worldPos.y(), worldPos.z()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -761,7 +762,8 @@ namespace MWScript
|
||||||
// We should move actors, standing on moving object, too.
|
// We should move actors, standing on moving object, too.
|
||||||
// This approach can be used to create elevators.
|
// This approach can be used to create elevators.
|
||||||
moveStandingActors(ptr, diff);
|
moveStandingActors(ptr, diff);
|
||||||
MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+diff.x(), objPos[1]+diff.y(), objPos[2]+diff.z());
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
|
||||||
|
MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+diff.x(), objPos[1]+diff.y(), objPos[2]+diff.z()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -11,11 +15,6 @@
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include <OpenThreads/Thread>
|
|
||||||
#include <OpenThreads/Condition>
|
|
||||||
#include <OpenThreads/Mutex>
|
|
||||||
#include <OpenThreads/ScopedLock>
|
|
||||||
|
|
||||||
#include "openal_output.hpp"
|
#include "openal_output.hpp"
|
||||||
#include "sound_decoder.hpp"
|
#include "sound_decoder.hpp"
|
||||||
#include "sound.hpp"
|
#include "sound.hpp"
|
||||||
|
@ -309,31 +308,33 @@ const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
|
||||||
//
|
//
|
||||||
// A background streaming thread (keeps active streams processed)
|
// A background streaming thread (keeps active streams processed)
|
||||||
//
|
//
|
||||||
struct OpenAL_Output::StreamThread : public OpenThreads::Thread {
|
struct OpenAL_Output::StreamThread
|
||||||
|
{
|
||||||
typedef std::vector<OpenAL_SoundStream*> StreamVec;
|
typedef std::vector<OpenAL_SoundStream*> StreamVec;
|
||||||
StreamVec mStreams;
|
StreamVec mStreams;
|
||||||
|
|
||||||
std::atomic<bool> mQuitNow;
|
std::atomic<bool> mQuitNow;
|
||||||
OpenThreads::Mutex mMutex;
|
std::mutex mMutex;
|
||||||
OpenThreads::Condition mCondVar;
|
std::condition_variable mCondVar;
|
||||||
|
std::thread mThread;
|
||||||
|
|
||||||
StreamThread()
|
StreamThread()
|
||||||
: mQuitNow(false)
|
: mQuitNow(false)
|
||||||
|
, mThread([this] { run(); })
|
||||||
{
|
{
|
||||||
start();
|
|
||||||
}
|
}
|
||||||
~StreamThread()
|
~StreamThread()
|
||||||
{
|
{
|
||||||
mQuitNow = true;
|
mQuitNow = true;
|
||||||
mMutex.lock(); mMutex.unlock();
|
mMutex.lock(); mMutex.unlock();
|
||||||
mCondVar.broadcast();
|
mCondVar.notify_all();
|
||||||
join();
|
mThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread entry point
|
// thread entry point
|
||||||
virtual void run()
|
void run()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
while(!mQuitNow)
|
while(!mQuitNow)
|
||||||
{
|
{
|
||||||
StreamVec::iterator iter = mStreams.begin();
|
StreamVec::iterator iter = mStreams.begin();
|
||||||
|
@ -345,30 +346,30 @@ struct OpenAL_Output::StreamThread : public OpenThreads::Thread {
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
mCondVar.wait(&mMutex, 50);
|
mCondVar.wait_for(lock, std::chrono::milliseconds(50));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(OpenAL_SoundStream *stream)
|
void add(OpenAL_SoundStream *stream)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end())
|
if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end())
|
||||||
{
|
{
|
||||||
mStreams.push_back(stream);
|
mStreams.push_back(stream);
|
||||||
mCondVar.broadcast();
|
mCondVar.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(OpenAL_SoundStream *stream)
|
void remove(OpenAL_SoundStream *stream)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
|
StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
|
||||||
if(iter != mStreams.end()) mStreams.erase(iter);
|
if(iter != mStreams.end()) mStreams.erase(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeAll()
|
void removeAll()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
mStreams.clear();
|
mStreams.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1341,7 +1342,7 @@ double OpenAL_Output::getStreamOffset(Stream *sound)
|
||||||
{
|
{
|
||||||
if(!sound->mHandle) return 0.0;
|
if(!sound->mHandle) return 0.0;
|
||||||
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
|
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mStreamThread->mMutex);
|
std::lock_guard<std::mutex> lock(mStreamThread->mMutex);
|
||||||
return stream->getStreamOffset();
|
return stream->getStreamOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1349,7 +1350,7 @@ float OpenAL_Output::getStreamLoudness(Stream *sound)
|
||||||
{
|
{
|
||||||
if(!sound->mHandle) return 0.0;
|
if(!sound->mHandle) return 0.0;
|
||||||
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
|
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mStreamThread->mMutex);
|
std::lock_guard<std::mutex> lock(mStreamThread->mMutex);
|
||||||
return stream->getCurrentLoudness();
|
return stream->getCurrentLoudness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1357,7 +1358,7 @@ bool OpenAL_Output::isStreamPlaying(Stream *sound)
|
||||||
{
|
{
|
||||||
if(!sound->mHandle) return false;
|
if(!sound->mHandle) return false;
|
||||||
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
|
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mStreamThread->mMutex);
|
std::lock_guard<std::mutex> lock(mStreamThread->mMutex);
|
||||||
return stream->isPlaying();
|
return stream->isPlaying();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
71
apps/openmw/mwsound/regionsoundselector.cpp
Normal file
71
apps/openmw/mwsound/regionsoundselector.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "regionsoundselector.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
int addChance(int result, const ESM::Region::SoundRef &v)
|
||||||
|
{
|
||||||
|
return result + v.mChance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<std::string> RegionSoundSelector::getNextRandom(float duration, const std::string& regionName,
|
||||||
|
const MWBase::World& world)
|
||||||
|
{
|
||||||
|
mTimePassed += duration;
|
||||||
|
|
||||||
|
if (mTimePassed < mTimeToNextEnvSound)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const float a = Misc::Rng::rollClosedProbability();
|
||||||
|
// NOTE: We should use the "Minimum Time Between Environmental Sounds" and
|
||||||
|
// "Maximum Time Between Environmental Sounds" fallback settings here.
|
||||||
|
mTimeToNextEnvSound = 5.0f * a + 15.0f * (1.0f - a);
|
||||||
|
mTimePassed = 0;
|
||||||
|
|
||||||
|
if (mLastRegionName != regionName)
|
||||||
|
{
|
||||||
|
mLastRegionName = regionName;
|
||||||
|
mSumChance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ESM::Region* const region = world.getStore().get<ESM::Region>().search(mLastRegionName);
|
||||||
|
|
||||||
|
if (region == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (mSumChance == 0)
|
||||||
|
{
|
||||||
|
mSumChance = std::accumulate(region->mSoundList.begin(), region->mSoundList.end(), 0, addChance);
|
||||||
|
if (mSumChance == 0)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const int r = Misc::Rng::rollDice(mSumChance);
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
const auto isSelected = [&] (const ESM::Region::SoundRef& sound)
|
||||||
|
{
|
||||||
|
if (r - pos < sound.mChance)
|
||||||
|
return true;
|
||||||
|
pos += sound.mChance;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto it = std::find_if(region->mSoundList.begin(), region->mSoundList.end(), isSelected);
|
||||||
|
|
||||||
|
if (it == region->mSoundList.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return it->mSound;
|
||||||
|
}
|
||||||
|
}
|
29
apps/openmw/mwsound/regionsoundselector.hpp
Normal file
29
apps/openmw/mwsound/regionsoundselector.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef GAME_SOUND_REGIONSOUNDSELECTOR_H
|
||||||
|
#define GAME_SOUND_REGIONSOUNDSELECTOR_H
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace MWBase
|
||||||
|
{
|
||||||
|
class World;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
class RegionSoundSelector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boost::optional<std::string> getNextRandom(float duration, const std::string& regionName,
|
||||||
|
const MWBase::World& world);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float mTimeToNextEnvSound = 0.0f;
|
||||||
|
int mSumChance = 0;
|
||||||
|
std::string mLastRegionName;
|
||||||
|
float mTimePassed = 0.0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -11,85 +11,65 @@ namespace MWSound
|
||||||
inline int operator&(int a, PlayMode b) { return a & static_cast<int>(b); }
|
inline int operator&(int a, PlayMode b) { return a & static_cast<int>(b); }
|
||||||
inline int operator&(PlayMode a, PlayMode b) { return static_cast<int>(a) & static_cast<int>(b); }
|
inline int operator&(PlayMode a, PlayMode b) { return static_cast<int>(a) & static_cast<int>(b); }
|
||||||
|
|
||||||
|
struct SoundParams
|
||||||
|
{
|
||||||
|
osg::Vec3f mPos;
|
||||||
|
float mVolume = 1;
|
||||||
|
float mBaseVolume = 1;
|
||||||
|
float mPitch = 1;
|
||||||
|
float mMinDistance = 1;
|
||||||
|
float mMaxDistance = 1000;
|
||||||
|
int mFlags = 0;
|
||||||
|
float mFadeOutTime = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class SoundBase {
|
class SoundBase {
|
||||||
SoundBase& operator=(const SoundBase&) = delete;
|
SoundBase& operator=(const SoundBase&) = delete;
|
||||||
SoundBase(const SoundBase&) = delete;
|
SoundBase(const SoundBase&) = delete;
|
||||||
SoundBase(SoundBase&&) = delete;
|
SoundBase(SoundBase&&) = delete;
|
||||||
|
|
||||||
osg::Vec3f mPos;
|
SoundParams mParams;
|
||||||
float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */
|
|
||||||
float mBaseVolume;
|
|
||||||
float mPitch;
|
|
||||||
float mMinDistance;
|
|
||||||
float mMaxDistance;
|
|
||||||
int mFlags;
|
|
||||||
|
|
||||||
float mFadeOutTime;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Sound_Instance mHandle;
|
Sound_Instance mHandle = nullptr;
|
||||||
|
|
||||||
friend class OpenAL_Output;
|
friend class OpenAL_Output;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setPosition(const osg::Vec3f &pos) { mPos = pos; }
|
void setPosition(const osg::Vec3f &pos) { mParams.mPos = pos; }
|
||||||
void setVolume(float volume) { mVolume = volume; }
|
void setVolume(float volume) { mParams.mVolume = volume; }
|
||||||
void setBaseVolume(float volume) { mBaseVolume = volume; }
|
void setBaseVolume(float volume) { mParams.mBaseVolume = volume; }
|
||||||
void setFadeout(float duration) { mFadeOutTime = duration; }
|
void setFadeout(float duration) { mParams.mFadeOutTime = duration; }
|
||||||
void updateFade(float duration)
|
void updateFade(float duration)
|
||||||
{
|
{
|
||||||
if(mFadeOutTime > 0.0f)
|
if (mParams.mFadeOutTime > 0.0f)
|
||||||
{
|
{
|
||||||
float soundDuration = std::min(duration, mFadeOutTime);
|
float soundDuration = std::min(duration, mParams.mFadeOutTime);
|
||||||
mVolume *= (mFadeOutTime-soundDuration) / mFadeOutTime;
|
mParams.mVolume *= (mParams.mFadeOutTime - soundDuration) / mParams.mFadeOutTime;
|
||||||
mFadeOutTime -= soundDuration;
|
mParams.mFadeOutTime -= soundDuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const osg::Vec3f &getPosition() const { return mPos; }
|
const osg::Vec3f &getPosition() const { return mParams.mPos; }
|
||||||
float getRealVolume() const { return mVolume * mBaseVolume; }
|
float getRealVolume() const { return mParams.mVolume * mParams.mBaseVolume; }
|
||||||
float getPitch() const { return mPitch; }
|
float getPitch() const { return mParams.mPitch; }
|
||||||
float getMinDistance() const { return mMinDistance; }
|
float getMinDistance() const { return mParams.mMinDistance; }
|
||||||
float getMaxDistance() const { return mMaxDistance; }
|
float getMaxDistance() const { return mParams.mMaxDistance; }
|
||||||
|
|
||||||
MWSound::Type getPlayType() const
|
MWSound::Type getPlayType() const
|
||||||
{ return static_cast<MWSound::Type>(mFlags&MWSound::Type::Mask); }
|
{ return static_cast<MWSound::Type>(mParams.mFlags & MWSound::Type::Mask); }
|
||||||
bool getUseEnv() const { return !(mFlags&MWSound::PlayMode::NoEnv); }
|
bool getUseEnv() const { return !(mParams.mFlags & MWSound::PlayMode::NoEnv); }
|
||||||
bool getIsLooping() const { return mFlags&MWSound::PlayMode::Loop; }
|
bool getIsLooping() const { return mParams.mFlags & MWSound::PlayMode::Loop; }
|
||||||
bool getDistanceCull() const { return mFlags&MWSound::PlayMode::RemoveAtDistance; }
|
bool getDistanceCull() const { return mParams.mFlags & MWSound::PlayMode::RemoveAtDistance; }
|
||||||
bool getIs3D() const { return mFlags&Play_3D; }
|
bool getIs3D() const { return mParams.mFlags & Play_3D; }
|
||||||
|
|
||||||
void init(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
|
void init(const SoundParams& params)
|
||||||
{
|
{
|
||||||
mPos = pos;
|
mParams = params;
|
||||||
mVolume = vol;
|
|
||||||
mBaseVolume = basevol;
|
|
||||||
mPitch = pitch;
|
|
||||||
mMinDistance = mindist;
|
|
||||||
mMaxDistance = maxdist;
|
|
||||||
mFlags = flags;
|
|
||||||
mFadeOutTime = 0.0f;
|
|
||||||
mHandle = nullptr;
|
mHandle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(float vol, float basevol, float pitch, int flags)
|
SoundBase() = default;
|
||||||
{
|
|
||||||
mPos = osg::Vec3f(0.0f, 0.0f, 0.0f);
|
|
||||||
mVolume = vol;
|
|
||||||
mBaseVolume = basevol;
|
|
||||||
mPitch = pitch;
|
|
||||||
mMinDistance = 1.0f;
|
|
||||||
mMaxDistance = 1000.0f;
|
|
||||||
mFlags = flags;
|
|
||||||
mFadeOutTime = 0.0f;
|
|
||||||
mHandle = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundBase()
|
|
||||||
: mPos(0.0f, 0.0f, 0.0f), mVolume(1.0f), mBaseVolume(1.0f), mPitch(1.0f)
|
|
||||||
, mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(0), mFadeOutTime(0.0f)
|
|
||||||
, mHandle(nullptr)
|
|
||||||
{ }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sound : public SoundBase {
|
class Sound : public SoundBase {
|
||||||
|
|
|
@ -30,22 +30,34 @@
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr float sMinUpdateInterval = 1.0f / 30.0f;
|
||||||
|
|
||||||
|
WaterSoundUpdaterSettings makeWaterSoundUpdaterSettings()
|
||||||
|
{
|
||||||
|
WaterSoundUpdaterSettings settings;
|
||||||
|
|
||||||
|
settings.mNearWaterRadius = Fallback::Map::getInt("Water_NearWaterRadius");
|
||||||
|
settings.mNearWaterPoints = Fallback::Map::getInt("Water_NearWaterPoints");
|
||||||
|
settings.mNearWaterIndoorTolerance = Fallback::Map::getFloat("Water_NearWaterIndoorTolerance");
|
||||||
|
settings.mNearWaterOutdoorTolerance = Fallback::Map::getFloat("Water_NearWaterOutdoorTolerance");
|
||||||
|
settings.mNearWaterIndoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterIndoorID"));
|
||||||
|
settings.mNearWaterOutdoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterOutdoorID"));
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For combining PlayMode and Type flags
|
// For combining PlayMode and Type flags
|
||||||
inline int operator|(PlayMode a, Type b) { return static_cast<int>(a) | static_cast<int>(b); }
|
inline int operator|(PlayMode a, Type b) { return static_cast<int>(a) | static_cast<int>(b); }
|
||||||
|
|
||||||
SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound)
|
SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound)
|
||||||
: mVFS(vfs)
|
: mVFS(vfs)
|
||||||
, mOutput(new DEFAULT_OUTPUT(*this))
|
, mOutput(new DEFAULT_OUTPUT(*this))
|
||||||
, mMasterVolume(1.0f)
|
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
|
||||||
, mSFXVolume(1.0f)
|
|
||||||
, mMusicVolume(1.0f)
|
|
||||||
, mVoiceVolume(1.0f)
|
|
||||||
, mFootstepsVolume(1.0f)
|
|
||||||
, 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)
|
||||||
|
@ -54,24 +66,6 @@ namespace MWSound
|
||||||
, mNearWaterSound(nullptr)
|
, mNearWaterSound(nullptr)
|
||||||
, mPlaybackPaused(false)
|
, mPlaybackPaused(false)
|
||||||
{
|
{
|
||||||
mMasterVolume = Settings::Manager::getFloat("master volume", "Sound");
|
|
||||||
mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f);
|
|
||||||
mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound");
|
|
||||||
mSFXVolume = std::min(std::max(mSFXVolume, 0.0f), 1.0f);
|
|
||||||
mMusicVolume = Settings::Manager::getFloat("music volume", "Sound");
|
|
||||||
mMusicVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f);
|
|
||||||
mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound");
|
|
||||||
mVoiceVolume = std::min(std::max(mVoiceVolume, 0.0f), 1.0f);
|
|
||||||
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
|
||||||
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
|
||||||
|
|
||||||
mNearWaterRadius = Fallback::Map::getInt("Water_NearWaterRadius");
|
|
||||||
mNearWaterPoints = Fallback::Map::getInt("Water_NearWaterPoints");
|
|
||||||
mNearWaterIndoorTolerance = Fallback::Map::getFloat("Water_NearWaterIndoorTolerance");
|
|
||||||
mNearWaterOutdoorTolerance = Fallback::Map::getFloat("Water_NearWaterOutdoorTolerance");
|
|
||||||
mNearWaterIndoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterIndoorID"));
|
|
||||||
mNearWaterOutdoorID = Misc::StringUtils::lowerCase(Fallback::Map::getString("Water_NearWaterOutdoorID"));
|
|
||||||
|
|
||||||
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
||||||
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
||||||
mBufferCacheMax *= 1024*1024;
|
mBufferCacheMax *= 1024*1024;
|
||||||
|
@ -271,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();
|
||||||
|
@ -315,57 +287,46 @@ 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([&] {
|
||||||
played = mOutput->streamSound(decoder, sound, true);
|
SoundParams params;
|
||||||
|
params.mBaseVolume = basevol;
|
||||||
|
params.mFlags = PlayMode::NoEnv | Type::Voice | Play_2D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
played = mOutput->streamSound(decoder, sound.get(), true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance,
|
sound->init([&] {
|
||||||
PlayMode::Normal|Type::Voice|Play_3D);
|
SoundParams params;
|
||||||
played = mOutput->streamSound3D(decoder, sound, true);
|
params.mPos = pos;
|
||||||
|
params.mBaseVolume = basevol;
|
||||||
|
params.mMinDistance = minDistance;
|
||||||
|
params.mMaxDistance = maxDistance;
|
||||||
|
params.mFlags = PlayMode::Normal | Type::Voice | Play_3D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
played = mOutput->streamSound3D(decoder, sound.get(), true);
|
||||||
}
|
}
|
||||||
if(!played)
|
if(!played)
|
||||||
{
|
|
||||||
mUnusedStreams.push_back(sound);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the combined volume settings for the given sound type
|
// Gets the combined volume settings for the given sound type
|
||||||
float SoundManager::volumeFromType(Type type) const
|
float SoundManager::volumeFromType(Type type) const
|
||||||
{
|
{
|
||||||
float volume = mMasterVolume;
|
return mVolumeSettings.getVolumeFromType(type);
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case Type::Sfx:
|
|
||||||
volume *= mSFXVolume;
|
|
||||||
break;
|
|
||||||
case Type::Voice:
|
|
||||||
volume *= mVoiceVolume;
|
|
||||||
break;
|
|
||||||
case Type::Foot:
|
|
||||||
volume *= mFootstepsVolume;
|
|
||||||
break;
|
|
||||||
case Type::Music:
|
|
||||||
volume *= mMusicVolume;
|
|
||||||
break;
|
|
||||||
case Type::Movie:
|
|
||||||
case Type::Mask:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return volume;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopMusic()
|
void SoundManager::stopMusic()
|
||||||
{
|
{
|
||||||
if(mMusic)
|
if(mMusic)
|
||||||
{
|
{
|
||||||
mOutput->finishStream(mMusic);
|
mOutput->finishStream(mMusic.get());
|
||||||
mUnusedStreams.push_back(mMusic);
|
|
||||||
mMusic = nullptr;
|
mMusic = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,9 +344,13 @@ namespace MWSound
|
||||||
decoder->open(filename);
|
decoder->open(filename);
|
||||||
|
|
||||||
mMusic = getStreamRef();
|
mMusic = getStreamRef();
|
||||||
mMusic->init(1.0f, volumeFromType(Type::Music), 1.0f,
|
mMusic->init([&] {
|
||||||
PlayMode::NoEnv|Type::Music|Play_2D);
|
SoundParams params;
|
||||||
mOutput->streamSound(decoder, mMusic);
|
params.mBaseVolume = volumeFromType(Type::Music);
|
||||||
|
params.mFlags = PlayMode::NoEnv | Type::Music | Play_2D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
mOutput->streamSound(decoder, mMusic.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::advanceMusic(const std::string& filename)
|
void SoundManager::advanceMusic(const std::string& filename)
|
||||||
|
@ -435,7 +400,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)
|
||||||
|
@ -518,10 +483,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
|
||||||
|
@ -529,7 +494,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,10 +514,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
|
||||||
|
@ -560,7 +525,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;
|
||||||
}
|
}
|
||||||
|
@ -572,7 +537,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;
|
||||||
}
|
}
|
||||||
|
@ -580,7 +545,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;
|
||||||
}
|
}
|
||||||
|
@ -593,16 +558,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,27 +576,29 @@ 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([&] {
|
||||||
if(!mOutput->streamSound(decoder, track))
|
SoundParams params;
|
||||||
{
|
params.mBaseVolume = volumeFromType(type);
|
||||||
mUnusedStreams.push_back(track);
|
params.mFlags = PlayMode::NoEnv | type | Play_2D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
if(!mOutput->streamSound(decoder, track.get()))
|
||||||
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)
|
||||||
|
@ -653,13 +618,17 @@ 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([&] {
|
||||||
if(!mOutput->playSound(sound, sfx->mHandle, offset))
|
SoundParams params;
|
||||||
{
|
params.mVolume = volume * sfx->mVolume;
|
||||||
mUnusedSounds.push_back(sound);
|
params.mBaseVolume = volumeFromType(type);
|
||||||
|
params.mPitch = pitch;
|
||||||
|
params.mFlags = mode | type | Play_2D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
if(!mOutput->playSound(sound.get(), sfx->mHandle, offset))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if(sfx->mUses++ == 0)
|
if(sfx->mUses++ == 0)
|
||||||
{
|
{
|
||||||
|
@ -667,8 +636,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,
|
||||||
|
@ -678,35 +648,48 @@ namespace MWSound
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized())
|
||||||
return nullptr;
|
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());
|
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
|
||||||
if ((mode & PlayMode::RemoveAtDistance) && (mListenerPos - objpos).length2() > 2000 * 2000)
|
if ((mode & PlayMode::RemoveAtDistance) && (mListenerPos - objpos).length2() > 2000 * 2000)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// Look up the sound in the ESM data
|
||||||
|
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
|
if(!sfx) 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([&] {
|
||||||
played = mOutput->playSound(sound, sfx->mHandle, offset);
|
SoundParams params;
|
||||||
|
params.mVolume = volume * sfx->mVolume;
|
||||||
|
params.mBaseVolume = volumeFromType(type);
|
||||||
|
params.mPitch = pitch;
|
||||||
|
params.mFlags = mode | type | Play_2D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
played = mOutput->playSound(sound.get(), sfx->mHandle, offset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sound->init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch,
|
sound->init([&] {
|
||||||
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
|
SoundParams params;
|
||||||
played = mOutput->playSound3D(sound, sfx->mHandle, offset);
|
params.mPos = objpos;
|
||||||
|
params.mVolume = volume * sfx->mVolume;
|
||||||
|
params.mBaseVolume = volumeFromType(type);
|
||||||
|
params.mPitch = pitch;
|
||||||
|
params.mMinDistance = sfx->mMinDist;
|
||||||
|
params.mMaxDistance = sfx->mMaxDist;
|
||||||
|
params.mFlags = mode | type | Play_3D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
|
@ -714,8 +697,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,
|
||||||
|
@ -729,14 +713,20 @@ 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([&] {
|
||||||
sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D);
|
SoundParams params;
|
||||||
if(!mOutput->playSound3D(sound, sfx->mHandle, offset))
|
params.mPos = initialPos;
|
||||||
{
|
params.mVolume = volume * sfx->mVolume;
|
||||||
mUnusedSounds.push_back(sound);
|
params.mBaseVolume = volumeFromType(type);
|
||||||
|
params.mPitch = pitch;
|
||||||
|
params.mMinDistance = sfx->mMinDist;
|
||||||
|
params.mMaxDistance = sfx->mMaxDist;
|
||||||
|
params.mFlags = mode | type | Play_3D;
|
||||||
|
return params;
|
||||||
|
} ());
|
||||||
|
if(!mOutput->playSound3D(sound.get(), sfx->mHandle, offset))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if(sfx->mUses++ == 0)
|
if(sfx->mUses++ == 0)
|
||||||
{
|
{
|
||||||
|
@ -744,8 +734,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)
|
||||||
|
@ -762,28 +753,17 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::stopSound(const std::string& soundId)
|
|
||||||
{
|
|
||||||
if(!mOutput->isInitialized())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
|
|
||||||
if (!sfx) return;
|
|
||||||
|
|
||||||
stopSound(sfx, MWWorld::ConstPtr());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId)
|
void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId)
|
||||||
{
|
{
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
|
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
if (!sfx) return;
|
if (!sfx) return;
|
||||||
|
|
||||||
stopSound(sfx, ptr);
|
stopSound(sfx, ptr);
|
||||||
|
@ -795,14 +775,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)
|
||||||
|
@ -812,20 +792,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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,7 +815,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)
|
||||||
|
@ -852,7 +834,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;
|
||||||
|
@ -907,131 +889,69 @@ namespace MWSound
|
||||||
|
|
||||||
void SoundManager::updateRegionSound(float duration)
|
void SoundManager::updateRegionSound(float duration)
|
||||||
{
|
{
|
||||||
static float sTimeToNextEnvSound = 0.0f;
|
|
||||||
static int total = 0;
|
|
||||||
static std::string regionName = "";
|
|
||||||
static float sTimePassed = 0.0;
|
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||||
const ESM::Cell *cell = player.getCell()->getCell();
|
const ESM::Cell *cell = player.getCell()->getCell();
|
||||||
|
|
||||||
sTimePassed += duration;
|
if (!cell->isExterior())
|
||||||
if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float a = Misc::Rng::rollClosedProbability();
|
if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->mRegion, *world))
|
||||||
// NOTE: We should use the "Minimum Time Between Environmental Sounds" and
|
playSound(*next, 1.0f, 1.0f);
|
||||||
// "Maximum Time Between Environmental Sounds" fallback settings here.
|
|
||||||
sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a);
|
|
||||||
sTimePassed = 0;
|
|
||||||
|
|
||||||
if(regionName != cell->mRegion)
|
|
||||||
{
|
|
||||||
regionName = cell->mRegion;
|
|
||||||
total = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::Region *regn = world->getStore().get<ESM::Region>().search(regionName);
|
void SoundManager::updateWaterSound()
|
||||||
if(regn == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(total == 0)
|
|
||||||
{
|
{
|
||||||
for(const ESM::Region::SoundRef &sndref : regn->mSoundList)
|
|
||||||
total += (int)sndref.mChance;
|
|
||||||
if(total == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int r = Misc::Rng::rollDice(total);
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
for(const ESM::Region::SoundRef &sndref : regn->mSoundList)
|
|
||||||
{
|
|
||||||
if(r - pos < sndref.mChance)
|
|
||||||
{
|
|
||||||
playSound(sndref.mSound, 1.0f, 1.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos += sndref.mChance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundManager::updateWaterSound(float /*duration*/)
|
|
||||||
{
|
|
||||||
static const ESM::Cell *LastCell;
|
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||||
osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
|
||||||
const ESM::Cell *curcell = player.getCell()->getCell();
|
const ESM::Cell *curcell = player.getCell()->getCell();
|
||||||
|
const auto update = mWaterSoundUpdater.update(player, *world);
|
||||||
|
|
||||||
float volume = 0.0f;
|
WaterSoundAction action;
|
||||||
const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID;
|
Sound_Buffer* sfx;
|
||||||
|
std::tie(action, sfx) = getWaterSoundAction(update, curcell);
|
||||||
|
|
||||||
if (!mListenerUnderwater)
|
switch (action)
|
||||||
{
|
|
||||||
if (curcell->hasWater())
|
|
||||||
{
|
|
||||||
float dist = std::abs(player.getCell()->getWaterLevel() - pos.z());
|
|
||||||
|
|
||||||
if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance)
|
|
||||||
{
|
|
||||||
volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance;
|
|
||||||
|
|
||||||
if (mNearWaterPoints > 1)
|
|
||||||
{
|
|
||||||
int underwaterPoints = 0;
|
|
||||||
|
|
||||||
float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1);
|
|
||||||
|
|
||||||
for (int x = 0; x < mNearWaterPoints; x++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < mNearWaterPoints; y++)
|
|
||||||
{
|
|
||||||
float height = world->getTerrainHeightAt(
|
|
||||||
osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f));
|
|
||||||
|
|
||||||
if (height < 0)
|
|
||||||
underwaterPoints++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance)
|
|
||||||
{
|
|
||||||
volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
volume = 1.0f;
|
|
||||||
|
|
||||||
volume = std::min(volume, 1.0f);
|
|
||||||
|
|
||||||
if (mNearWaterSound)
|
|
||||||
{
|
|
||||||
if (volume == 0.0f)
|
|
||||||
{
|
{
|
||||||
|
case WaterSoundAction::DoNothing:
|
||||||
|
break;
|
||||||
|
case WaterSoundAction::SetVolume:
|
||||||
|
mNearWaterSound->setVolume(update.mVolume * sfx->mVolume);
|
||||||
|
break;
|
||||||
|
case WaterSoundAction::FinishSound:
|
||||||
mOutput->finishSound(mNearWaterSound);
|
mOutput->finishSound(mNearWaterSound);
|
||||||
mNearWaterSound = nullptr;
|
mNearWaterSound = nullptr;
|
||||||
|
break;
|
||||||
|
case WaterSoundAction::PlaySound:
|
||||||
|
if (mNearWaterSound)
|
||||||
|
mOutput->finishSound(mNearWaterSound);
|
||||||
|
mNearWaterSound = playSound(update.mId, update.mVolume, 1.0f, Type::Sfx, PlayMode::Loop);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
mLastCell = curcell;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<SoundManager::WaterSoundAction, Sound_Buffer*> SoundManager::getWaterSoundAction(
|
||||||
|
const WaterSoundUpdate& update, const ESM::Cell* cell) const
|
||||||
{
|
{
|
||||||
|
if (mNearWaterSound)
|
||||||
|
{
|
||||||
|
if (update.mVolume == 0.0f)
|
||||||
|
return {WaterSoundAction::FinishSound, nullptr};
|
||||||
|
|
||||||
bool soundIdChanged = false;
|
bool soundIdChanged = false;
|
||||||
|
|
||||||
Sound_Buffer *sfx = lookupSound(soundId);
|
Sound_Buffer* sfx = lookupSound(update.mId);
|
||||||
if(LastCell != curcell)
|
if (mLastCell != cell)
|
||||||
{
|
{
|
||||||
LastCell = curcell;
|
const auto snditer = mActiveSounds.find(MWWorld::ConstPtr());
|
||||||
SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr());
|
|
||||||
if (snditer != mActiveSounds.end())
|
if (snditer != mActiveSounds.end())
|
||||||
{
|
{
|
||||||
SoundBufferRefPairList::const_iterator 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;
|
||||||
|
@ -1039,19 +959,15 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
|
|
||||||
if (soundIdChanged)
|
if (soundIdChanged)
|
||||||
{
|
return {WaterSoundAction::PlaySound, nullptr};
|
||||||
mOutput->finishSound(mNearWaterSound);
|
|
||||||
mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop);
|
if (sfx)
|
||||||
}
|
return {WaterSoundAction::SetVolume, sfx};
|
||||||
else if (sfx)
|
|
||||||
mNearWaterSound->setVolume(volume * sfx->mVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (volume > 0.0f)
|
|
||||||
{
|
|
||||||
LastCell = curcell;
|
|
||||||
mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop);
|
|
||||||
}
|
}
|
||||||
|
else if (update.mVolume > 0.0f)
|
||||||
|
return {WaterSoundAction::PlaySound, nullptr};
|
||||||
|
|
||||||
|
return {WaterSoundAction::DoNothing, nullptr};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::updateSounds(float duration)
|
void SoundManager::updateSounds(float duration)
|
||||||
|
@ -1061,17 +977,19 @@ 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++);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float timePassed = 0.0;
|
mTimePassed += duration;
|
||||||
|
if (mTimePassed < sMinUpdateInterval)
|
||||||
timePassed += duration;
|
|
||||||
if(timePassed < (1.0f/30.0f))
|
|
||||||
return;
|
return;
|
||||||
duration = timePassed;
|
duration = mTimePassed;
|
||||||
timePassed = 0.0f;
|
mTimePassed = 0.0f;
|
||||||
|
|
||||||
// Make sure music is still playing
|
// Make sure music is still playing
|
||||||
if(!isMusicPlaying() && !mCurrentPlaylist.empty())
|
if(!isMusicPlaying() && !mCurrentPlaylist.empty())
|
||||||
|
@ -1104,10 +1022,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();
|
||||||
|
@ -1124,7 +1041,6 @@ 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)
|
||||||
|
@ -1151,7 +1067,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();
|
||||||
|
@ -1168,7 +1084,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
|
||||||
|
@ -1183,7 +1098,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);
|
||||||
|
@ -1214,7 +1129,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)
|
||||||
{
|
{
|
||||||
|
@ -1235,18 +1150,14 @@ namespace MWSound
|
||||||
MWBase::StateManager::State_NoGame)
|
MWBase::StateManager::State_NoGame)
|
||||||
{
|
{
|
||||||
updateRegionSound(duration);
|
updateRegionSound(duration);
|
||||||
updateWaterSound(duration);
|
updateWaterSound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SoundManager::processChangedSettings(const Settings::CategorySettingVector& settings)
|
void SoundManager::processChangedSettings(const Settings::CategorySettingVector& settings)
|
||||||
{
|
{
|
||||||
mMasterVolume = Settings::Manager::getFloat("master volume", "Sound");
|
mVolumeSettings.update();
|
||||||
mMusicVolume = Settings::Manager::getFloat("music volume", "Sound");
|
|
||||||
mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound");
|
|
||||||
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
|
||||||
mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound");
|
|
||||||
|
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized())
|
||||||
return;
|
return;
|
||||||
|
@ -1255,32 +1166,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();
|
||||||
}
|
}
|
||||||
|
@ -1292,6 +1203,8 @@ namespace MWSound
|
||||||
mListenerUp = up;
|
mListenerUp = up;
|
||||||
|
|
||||||
mListenerUnderwater = underwater;
|
mListenerUnderwater = underwater;
|
||||||
|
|
||||||
|
mWaterSoundUpdater.setUnderwater(underwater);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::updatePtr(const MWWorld::ConstPtr &old, const MWWorld::ConstPtr &updated)
|
void SoundManager::updatePtr(const MWWorld::ConstPtr &old, const MWWorld::ConstPtr &updated)
|
||||||
|
@ -1307,17 +1220,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1394,8 +1307,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);
|
||||||
|
@ -1406,24 +1318,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,11 +9,16 @@
|
||||||
#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"
|
||||||
|
|
||||||
|
#include "regionsoundselector.hpp"
|
||||||
|
#include "watersoundupdater.hpp"
|
||||||
|
#include "type.hpp"
|
||||||
|
#include "volumesettings.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
{
|
{
|
||||||
class Manager;
|
class Manager;
|
||||||
|
@ -22,6 +27,7 @@ namespace VFS
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Sound;
|
struct Sound;
|
||||||
|
struct Cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
|
@ -42,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;
|
||||||
|
@ -53,18 +62,10 @@ namespace MWSound
|
||||||
std::unordered_map<std::string, std::vector<int>> mMusicToPlay; // A list with music files not yet played
|
std::unordered_map<std::string, std::vector<int>> mMusicToPlay; // A list with music files not yet played
|
||||||
std::string mLastPlayedMusic; // The music file that was last played
|
std::string mLastPlayedMusic; // The music file that was last played
|
||||||
|
|
||||||
float mMasterVolume;
|
VolumeSettings mVolumeSettings;
|
||||||
float mSFXVolume;
|
|
||||||
float mMusicVolume;
|
WaterSoundUpdater mWaterSoundUpdater;
|
||||||
float mVoiceVolume;
|
|
||||||
float mFootstepsVolume;
|
|
||||||
|
|
||||||
int mNearWaterRadius;
|
|
||||||
int mNearWaterPoints;
|
|
||||||
float mNearWaterIndoorTolerance;
|
|
||||||
float mNearWaterOutdoorTolerance;
|
|
||||||
std::string mNearWaterIndoorID;
|
|
||||||
std::string mNearWaterOutdoorID;
|
|
||||||
typedef std::unique_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
typedef std::unique_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
||||||
// List of sound buffers, grown as needed. New enties are added to the
|
// List of sound buffers, grown as needed. New enties are added to the
|
||||||
// back, allowing existing Sound_Buffer references/pointers to remain
|
// back, allowing existing Sound_Buffer references/pointers to remain
|
||||||
|
@ -81,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;
|
||||||
|
@ -115,6 +114,12 @@ namespace MWSound
|
||||||
std::string mNextMusic;
|
std::string mNextMusic;
|
||||||
bool mPlaybackPaused;
|
bool mPlaybackPaused;
|
||||||
|
|
||||||
|
RegionSoundSelector mRegionSoundSelector;
|
||||||
|
|
||||||
|
float mTimePassed = 0;
|
||||||
|
|
||||||
|
const ESM::Cell *mLastCell = nullptr;
|
||||||
|
|
||||||
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
||||||
|
|
||||||
Sound_Buffer *lookupSound(const std::string &soundId) const;
|
Sound_Buffer *lookupSound(const std::string &soundId) const;
|
||||||
|
@ -123,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);
|
||||||
|
@ -134,11 +139,22 @@ namespace MWSound
|
||||||
|
|
||||||
void updateSounds(float duration);
|
void updateSounds(float duration);
|
||||||
void updateRegionSound(float duration);
|
void updateRegionSound(float duration);
|
||||||
void updateWaterSound(float duration);
|
void updateWaterSound();
|
||||||
void updateMusic(float duration);
|
void updateMusic(float duration);
|
||||||
|
|
||||||
float volumeFromType(Type type) const;
|
float volumeFromType(Type type) const;
|
||||||
|
|
||||||
|
enum class WaterSoundAction
|
||||||
|
{
|
||||||
|
DoNothing,
|
||||||
|
SetVolume,
|
||||||
|
FinishSound,
|
||||||
|
PlaySound,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::pair<WaterSoundAction, Sound_Buffer*> getWaterSoundAction(const WaterSoundUpdate& update,
|
||||||
|
const ESM::Cell* cell) const;
|
||||||
|
|
||||||
SoundManager(const SoundManager &rhs);
|
SoundManager(const SoundManager &rhs);
|
||||||
SoundManager& operator=(const SoundManager &rhs);
|
SoundManager& operator=(const SoundManager &rhs);
|
||||||
|
|
||||||
|
@ -233,9 +249,6 @@ namespace MWSound
|
||||||
virtual void stopSound(const MWWorld::CellStore *cell);
|
virtual void stopSound(const MWWorld::CellStore *cell);
|
||||||
///< Stop all sounds for the given cell.
|
///< Stop all sounds for the given cell.
|
||||||
|
|
||||||
virtual void stopSound(const std::string& soundId);
|
|
||||||
///< Stop a non-3d looping sound
|
|
||||||
|
|
||||||
virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration);
|
virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration);
|
||||||
///< Fade out given sound (that is already playing) of given object
|
///< Fade out given sound (that is already playing) of given object
|
||||||
///< @param reference Reference to object, whose sound is faded out
|
///< @param reference Reference to object, whose sound is faded out
|
||||||
|
|
17
apps/openmw/mwsound/type.hpp
Normal file
17
apps/openmw/mwsound/type.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef GAME_SOUND_TYPE_H
|
||||||
|
#define GAME_SOUND_TYPE_H
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Sfx = 1 << 4, /* Normal SFX sound */
|
||||||
|
Voice = 1 << 5, /* Voice sound */
|
||||||
|
Foot = 1 << 6, /* Footstep sound */
|
||||||
|
Music = 1 << 7, /* Music track */
|
||||||
|
Movie = 1 << 8, /* Movie audio track */
|
||||||
|
Mask = Sfx | Voice | Foot | Music | Movie
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
56
apps/openmw/mwsound/volumesettings.cpp
Normal file
56
apps/openmw/mwsound/volumesettings.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "volumesettings.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
float clamp(float value)
|
||||||
|
{
|
||||||
|
return std::max(0.0f, std::min(1.0f, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeSettings::VolumeSettings()
|
||||||
|
: mMasterVolume(clamp(Settings::Manager::getFloat("master volume", "Sound"))),
|
||||||
|
mSFXVolume(clamp(Settings::Manager::getFloat("sfx volume", "Sound"))),
|
||||||
|
mMusicVolume(clamp(Settings::Manager::getFloat("music volume", "Sound"))),
|
||||||
|
mVoiceVolume(clamp(Settings::Manager::getFloat("voice volume", "Sound"))),
|
||||||
|
mFootstepsVolume(clamp(Settings::Manager::getFloat("footsteps volume", "Sound")))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float VolumeSettings::getVolumeFromType(Type type) const
|
||||||
|
{
|
||||||
|
float volume = mMasterVolume;
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case Type::Sfx:
|
||||||
|
volume *= mSFXVolume;
|
||||||
|
break;
|
||||||
|
case Type::Voice:
|
||||||
|
volume *= mVoiceVolume;
|
||||||
|
break;
|
||||||
|
case Type::Foot:
|
||||||
|
volume *= mFootstepsVolume;
|
||||||
|
break;
|
||||||
|
case Type::Music:
|
||||||
|
volume *= mMusicVolume;
|
||||||
|
break;
|
||||||
|
case Type::Movie:
|
||||||
|
case Type::Mask:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeSettings::update()
|
||||||
|
{
|
||||||
|
*this = VolumeSettings();
|
||||||
|
}
|
||||||
|
}
|
26
apps/openmw/mwsound/volumesettings.hpp
Normal file
26
apps/openmw/mwsound/volumesettings.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef GAME_SOUND_VOLUMESETTINGS_H
|
||||||
|
#define GAME_SOUND_VOLUMESETTINGS_H
|
||||||
|
|
||||||
|
#include "type.hpp"
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
class VolumeSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VolumeSettings();
|
||||||
|
|
||||||
|
float getVolumeFromType(Type type) const;
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
float mMasterVolume;
|
||||||
|
float mSFXVolume;
|
||||||
|
float mMusicVolume;
|
||||||
|
float mVoiceVolume;
|
||||||
|
float mFootstepsVolume;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
71
apps/openmw/mwsound/watersoundupdater.cpp
Normal file
71
apps/openmw/mwsound/watersoundupdater.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "watersoundupdater.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
WaterSoundUpdater::WaterSoundUpdater(const WaterSoundUpdaterSettings& settings)
|
||||||
|
: mSettings(settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WaterSoundUpdate WaterSoundUpdater::update(const MWWorld::ConstPtr& player, const MWBase::World& world) const
|
||||||
|
{
|
||||||
|
WaterSoundUpdate result;
|
||||||
|
|
||||||
|
result.mId = player.getCell()->isExterior() ? mSettings.mNearWaterOutdoorID : mSettings.mNearWaterIndoorID;
|
||||||
|
result.mVolume = std::min(1.0f, getVolume(player, world));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WaterSoundUpdater::getVolume(const MWWorld::ConstPtr& player, const MWBase::World& world) const
|
||||||
|
{
|
||||||
|
if (mListenerUnderwater)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
const MWWorld::CellStore& cell = *player.getCell();
|
||||||
|
|
||||||
|
if (!cell.getCell()->hasWater())
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
||||||
|
const float dist = std::abs(cell.getWaterLevel() - pos.z());
|
||||||
|
|
||||||
|
if (cell.isExterior() && dist < mSettings.mNearWaterOutdoorTolerance)
|
||||||
|
{
|
||||||
|
if (mSettings.mNearWaterPoints <= 1)
|
||||||
|
return (mSettings.mNearWaterOutdoorTolerance - dist) / mSettings.mNearWaterOutdoorTolerance;
|
||||||
|
|
||||||
|
const float step = mSettings.mNearWaterRadius * 2.0f / (mSettings.mNearWaterPoints - 1);
|
||||||
|
|
||||||
|
int underwaterPoints = 0;
|
||||||
|
|
||||||
|
for (int x = 0; x < mSettings.mNearWaterPoints; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < mSettings.mNearWaterPoints; y++)
|
||||||
|
{
|
||||||
|
const float terrainX = pos.x() - mSettings.mNearWaterRadius + x * step;
|
||||||
|
const float terrainY = pos.y() - mSettings.mNearWaterRadius + y * step;
|
||||||
|
const float height = world.getTerrainHeightAt(osg::Vec3f(terrainX, terrainY, 0.0f));
|
||||||
|
|
||||||
|
if (height < 0)
|
||||||
|
underwaterPoints++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return underwaterPoints * 2.0f / (mSettings.mNearWaterPoints * mSettings.mNearWaterPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cell.isExterior() && dist < mSettings.mNearWaterIndoorTolerance)
|
||||||
|
return (mSettings.mNearWaterIndoorTolerance - dist) / mSettings.mNearWaterIndoorTolerance;
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
54
apps/openmw/mwsound/watersoundupdater.hpp
Normal file
54
apps/openmw/mwsound/watersoundupdater.hpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef GAME_SOUND_WATERSOUNDUPDATER_H
|
||||||
|
#define GAME_SOUND_WATERSOUNDUPDATER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace MWBase
|
||||||
|
{
|
||||||
|
class World;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class ConstPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWSound
|
||||||
|
{
|
||||||
|
struct WaterSoundUpdaterSettings
|
||||||
|
{
|
||||||
|
int mNearWaterRadius;
|
||||||
|
int mNearWaterPoints;
|
||||||
|
float mNearWaterIndoorTolerance;
|
||||||
|
float mNearWaterOutdoorTolerance;
|
||||||
|
std::string mNearWaterIndoorID;
|
||||||
|
std::string mNearWaterOutdoorID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WaterSoundUpdate
|
||||||
|
{
|
||||||
|
std::string mId;
|
||||||
|
float mVolume;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WaterSoundUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit WaterSoundUpdater(const WaterSoundUpdaterSettings& settings);
|
||||||
|
|
||||||
|
WaterSoundUpdate update(const MWWorld::ConstPtr& player, const MWBase::World& world) const;
|
||||||
|
|
||||||
|
void setUnderwater(bool value)
|
||||||
|
{
|
||||||
|
mListenerUnderwater = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const WaterSoundUpdaterSettings mSettings;
|
||||||
|
bool mListenerUnderwater = false;
|
||||||
|
|
||||||
|
float getVolume(const MWWorld::ConstPtr& player, const MWBase::World& world) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -47,7 +47,7 @@ void MWState::StateManager::cleanup (bool force)
|
||||||
MWBase::Environment::get().getSoundManager()->clear();
|
MWBase::Environment::get().getSoundManager()->clear();
|
||||||
MWBase::Environment::get().getDialogueManager()->clear();
|
MWBase::Environment::get().getDialogueManager()->clear();
|
||||||
MWBase::Environment::get().getJournal()->clear();
|
MWBase::Environment::get().getJournal()->clear();
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear();
|
MWBase::Environment::get().getScriptManager()->clear();
|
||||||
MWBase::Environment::get().getWorld()->clear();
|
MWBase::Environment::get().getWorld()->clear();
|
||||||
MWBase::Environment::get().getWindowManager()->clear();
|
MWBase::Environment::get().getWindowManager()->clear();
|
||||||
MWBase::Environment::get().getInputManager()->clear();
|
MWBase::Environment::get().getInputManager()->clear();
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
|
@ -741,15 +743,12 @@ namespace MWWorld
|
||||||
player.getClass().adjustPosition(player, true);
|
player.getClass().adjustPosition(player, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::MechanicsManager *mechMgr =
|
MWBase::Environment::get().getMechanicsManager()->updateCell(old, player);
|
||||||
MWBase::Environment::get().getMechanicsManager();
|
MWBase::Environment::get().getWindowManager()->watchActor(player);
|
||||||
|
|
||||||
mechMgr->updateCell(old, player);
|
|
||||||
mechMgr->watchActor(player);
|
|
||||||
|
|
||||||
mPhysics->updatePtr(old, player);
|
mPhysics->updatePtr(old, player);
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->adjustSky();
|
world->adjustSky();
|
||||||
|
|
||||||
mLastPlayerPos = player.getRefData().getPosition().asVec3();
|
mLastPlayerPos = player.getRefData().getPosition().asVec3();
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1142,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
loadingListener->setProgress(0);
|
loadingListener->setProgress(0);
|
||||||
OpenThreads::Thread::microSleep(5000);
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -954,6 +954,7 @@ namespace MWWorld
|
||||||
removeContainerScripts(getPlayerPtr());
|
removeContainerScripts(getPlayerPtr());
|
||||||
mWorldScene->changeToInteriorCell(cellName, position, adjustPlayerPos, changeEvent);
|
mWorldScene->changeToInteriorCell(cellName, position, adjustPlayerPos, changeEvent);
|
||||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||||
|
mRendering->getCamera()->skipFocalPointTransition();
|
||||||
|
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
auto* xrInput = MWVR::Environment::get().getInputManager();
|
auto* xrInput = MWVR::Environment::get().getInputManager();
|
||||||
|
@ -975,6 +976,7 @@ namespace MWWorld
|
||||||
removeContainerScripts(getPlayerPtr());
|
removeContainerScripts(getPlayerPtr());
|
||||||
mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent);
|
mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent);
|
||||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||||
|
mRendering->getCamera()->skipFocalPointTransition();
|
||||||
|
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
auto* xrInput = MWVR::Environment::get().getInputManager();
|
auto* xrInput = MWVR::Environment::get().getInputManager();
|
||||||
|
@ -1226,7 +1228,6 @@ namespace MWWorld
|
||||||
mRendering->updatePtr(ptr, newPtr);
|
mRendering->updatePtr(ptr, newPtr);
|
||||||
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
|
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
|
||||||
mPhysics->updatePtr(ptr, newPtr);
|
mPhysics->updatePtr(ptr, newPtr);
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().updatePtrs(ptr, newPtr);
|
|
||||||
|
|
||||||
MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();
|
MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();
|
||||||
mechMgr->updateCell(ptr, newPtr);
|
mechMgr->updateCell(ptr, newPtr);
|
||||||
|
@ -1242,6 +1243,9 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->updateConsoleObjectPtr(ptr, newPtr);
|
||||||
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().updatePtrs(ptr, newPtr);
|
||||||
}
|
}
|
||||||
if (haveToMove && newPtr.getRefData().getBaseNode())
|
if (haveToMove && newPtr.getRefData().getBaseNode())
|
||||||
{
|
{
|
||||||
|
@ -1431,6 +1435,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);
|
||||||
|
|
||||||
|
@ -1945,7 +1952,7 @@ namespace MWWorld
|
||||||
std::string enchantId = selectedEnchantItem.getClass().getEnchantment(selectedEnchantItem);
|
std::string enchantId = selectedEnchantItem.getClass().getEnchantment(selectedEnchantItem);
|
||||||
if (!enchantId.empty())
|
if (!enchantId.empty())
|
||||||
{
|
{
|
||||||
const ESM::Enchantment* ench = mStore.get<ESM::Enchantment>().search(selectedEnchantItem.getClass().getEnchantment(selectedEnchantItem));
|
const ESM::Enchantment* ench = mStore.get<ESM::Enchantment>().search(enchantId);
|
||||||
if (ench)
|
if (ench)
|
||||||
preloadEffects(&ench->mEffects);
|
preloadEffects(&ench->mEffects);
|
||||||
}
|
}
|
||||||
|
@ -2494,7 +2501,7 @@ namespace MWWorld
|
||||||
rotateObject(player, 0.f, 0.f, 0.f, MWBase::RotationFlag_inverseOrder | MWBase::RotationFlag_adjust);
|
rotateObject(player, 0.f, 0.f, 0.f, MWBase::RotationFlag_inverseOrder | MWBase::RotationFlag_adjust);
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr());
|
MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr());
|
||||||
MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr());
|
MWBase::Environment::get().getWindowManager()->watchActor(getPlayerPtr());
|
||||||
|
|
||||||
std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr());
|
std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr());
|
||||||
model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
|
model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
|
||||||
|
|
|
@ -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()
|
|
|
@ -210,7 +210,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})
|
||||||
|
|
||||||
|
@ -229,7 +229,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}
|
||||||
|
|
|
@ -2,11 +2,8 @@
|
||||||
#include "launchersettings.hpp"
|
#include "launchersettings.hpp"
|
||||||
|
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QTextStream>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QString>
|
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
|
||||||
|
@ -105,9 +102,9 @@ bool Config::GameSettings::readUserFile(QTextStream &stream)
|
||||||
return readFile(stream, mUserSettings);
|
return readFile(stream, mUserSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Config::GameSettings::readFile(QTextStream &stream, QMap<QString, QString> &settings)
|
bool Config::GameSettings::readFile(QTextStream &stream, QMultiMap<QString, QString> &settings)
|
||||||
{
|
{
|
||||||
QMap<QString, QString> cache;
|
QMultiMap<QString, QString> cache;
|
||||||
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
|
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
|
||||||
|
|
||||||
while (!stream.atEnd()) {
|
while (!stream.atEnd()) {
|
||||||
|
@ -151,7 +148,7 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap<QString, QString>
|
||||||
values.append(settings.values(key));
|
values.append(settings.values(key));
|
||||||
|
|
||||||
if (!values.contains(value)) {
|
if (!values.contains(value)) {
|
||||||
cache.insertMulti(key, value);
|
cache.insert(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,7 +365,7 @@ bool Config::GameSettings::writeFileWithComments(QFile &file)
|
||||||
*iter = QString(); // assume no match
|
*iter = QString(); // assume no match
|
||||||
QString key = settingRegex.cap(1);
|
QString key = settingRegex.cap(1);
|
||||||
QString keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2);
|
QString keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2);
|
||||||
QMap<QString, QString>::const_iterator i = mUserSettings.find(key);
|
QMultiMap<QString, QString>::const_iterator i = mUserSettings.find(key);
|
||||||
while (i != mUserSettings.end() && i.key() == key)
|
while (i != mUserSettings.end() && i.key() == key)
|
||||||
{
|
{
|
||||||
QString settingLine = i.key() + "=" + i.value();
|
QString settingLine = i.key() + "=" + i.value();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMap>
|
#include <QMultiMap>
|
||||||
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
@ -31,7 +31,9 @@ namespace Config
|
||||||
|
|
||||||
inline void setValue(const QString &key, const QString &value)
|
inline void setValue(const QString &key, const QString &value)
|
||||||
{
|
{
|
||||||
|
mSettings.remove(key);
|
||||||
mSettings.insert(key, value);
|
mSettings.insert(key, value);
|
||||||
|
mUserSettings.remove(key);
|
||||||
mUserSettings.insert(key, value);
|
mUserSettings.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +41,11 @@ namespace Config
|
||||||
{
|
{
|
||||||
QStringList values = mSettings.values(key);
|
QStringList values = mSettings.values(key);
|
||||||
if (!values.contains(value))
|
if (!values.contains(value))
|
||||||
mSettings.insertMulti(key, value);
|
mSettings.insert(key, value);
|
||||||
|
|
||||||
values = mUserSettings.values(key);
|
values = mUserSettings.values(key);
|
||||||
if (!values.contains(value))
|
if (!values.contains(value))
|
||||||
mUserSettings.insertMulti(key, value);
|
mUserSettings.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void remove(const QString &key)
|
inline void remove(const QString &key)
|
||||||
|
@ -63,7 +65,7 @@ namespace Config
|
||||||
QStringList values(const QString &key, const QStringList &defaultValues = QStringList()) const;
|
QStringList values(const QString &key, const QStringList &defaultValues = QStringList()) const;
|
||||||
|
|
||||||
bool readFile(QTextStream &stream);
|
bool readFile(QTextStream &stream);
|
||||||
bool readFile(QTextStream &stream, QMap<QString, QString> &settings);
|
bool readFile(QTextStream &stream, QMultiMap<QString, QString> &settings);
|
||||||
bool readUserFile(QTextStream &stream);
|
bool readUserFile(QTextStream &stream);
|
||||||
|
|
||||||
bool writeFile(QTextStream &stream);
|
bool writeFile(QTextStream &stream);
|
||||||
|
@ -78,8 +80,8 @@ namespace Config
|
||||||
Files::ConfigurationManager &mCfgMgr;
|
Files::ConfigurationManager &mCfgMgr;
|
||||||
|
|
||||||
void validatePaths();
|
void validatePaths();
|
||||||
QMap<QString, QString> mSettings;
|
QMultiMap<QString, QString> mSettings;
|
||||||
QMap<QString, QString> mUserSettings;
|
QMultiMap<QString, QString> mUserSettings;
|
||||||
|
|
||||||
QStringList mDataDirs;
|
QStringList mDataDirs;
|
||||||
QString mDataLocal;
|
QString mDataLocal;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
#include <QMap>
|
#include <QMultiMap>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ Config::LauncherSettings::~LauncherSettings()
|
||||||
|
|
||||||
QStringList Config::LauncherSettings::subKeys(const QString &key)
|
QStringList Config::LauncherSettings::subKeys(const QString &key)
|
||||||
{
|
{
|
||||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
QMultiMap<QString, QString> settings = SettingsBase::getSettings();
|
||||||
QStringList keys = settings.uniqueKeys();
|
QStringList keys = settings.uniqueKeys();
|
||||||
|
|
||||||
QRegExp keyRe("(.+)/");
|
QRegExp keyRe("(.+)/");
|
||||||
|
@ -54,7 +54,7 @@ bool Config::LauncherSettings::writeFile(QTextStream &stream)
|
||||||
{
|
{
|
||||||
QString sectionPrefix;
|
QString sectionPrefix;
|
||||||
QRegExp sectionRe("([^/]+)/(.+)$");
|
QRegExp sectionRe("([^/]+)/(.+)$");
|
||||||
QMap<QString, QString> settings = SettingsBase::getSettings();
|
QMultiMap<QString, QString> settings = SettingsBase::getSettings();
|
||||||
|
|
||||||
QMapIterator<QString, QString> i(settings);
|
QMapIterator<QString, QString> i(settings);
|
||||||
i.toBack();
|
i.toBack();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
class LauncherSettings : public SettingsBase<QMap<QString, QString> >
|
class LauncherSettings : public SettingsBase<QMultiMap<QString, QString> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LauncherSettings();
|
LauncherSettings();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
#include <QMap>
|
#include <QMultiMap>
|
||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ namespace Config
|
||||||
{
|
{
|
||||||
QStringList values = mSettings.values(key);
|
QStringList values = mSettings.values(key);
|
||||||
if (!values.contains(value))
|
if (!values.contains(value))
|
||||||
mSettings.insertMulti(key, value);
|
mSettings.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setMultiValueEnabled(bool enable)
|
inline void setMultiValueEnabled(bool enable)
|
||||||
|
@ -83,8 +83,9 @@ namespace Config
|
||||||
|
|
||||||
if (!values.contains(value)) {
|
if (!values.contains(value)) {
|
||||||
if (mMultiValue) {
|
if (mMultiValue) {
|
||||||
cache.insertMulti(key, value);
|
cache.insert(key, value);
|
||||||
} else {
|
} else {
|
||||||
|
cache.remove(key);
|
||||||
cache.insert(key, value);
|
cache.insert(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include <OpenThreads/ScopedLock>
|
|
||||||
|
|
||||||
#include <osg/Image>
|
#include <osg/Image>
|
||||||
#include <osg/Plane>
|
#include <osg/Plane>
|
||||||
|
|
||||||
|
@ -548,7 +546,7 @@ namespace ESMTerrain
|
||||||
|
|
||||||
Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)
|
Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mLayerInfoMutex);
|
std::lock_guard<std::mutex> lock(mLayerInfoMutex);
|
||||||
|
|
||||||
// Already have this cached?
|
// Already have this cached?
|
||||||
std::map<std::string, Terrain::LayerInfo>::iterator found = mLayerInfoMap.find(texture);
|
std::map<std::string, Terrain::LayerInfo>::iterator found = mLayerInfoMap.find(texture);
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
#define COMPONENTS_ESM_TERRAIN_STORAGE_H
|
#define COMPONENTS_ESM_TERRAIN_STORAGE_H
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <mutex>
|
||||||
#include <OpenThreads/Mutex>
|
|
||||||
|
|
||||||
#include <components/terrain/storage.hpp>
|
#include <components/terrain/storage.hpp>
|
||||||
|
|
||||||
|
@ -138,7 +137,7 @@ namespace ESMTerrain
|
||||||
std::string getTextureName (UniqueTextureId id);
|
std::string getTextureName (UniqueTextureId id);
|
||||||
|
|
||||||
std::map<std::string, Terrain::LayerInfo> mLayerInfoMap;
|
std::map<std::string, Terrain::LayerInfo> mLayerInfoMap;
|
||||||
OpenThreads::Mutex mLayerInfoMutex;
|
std::mutex mLayerInfoMutex;
|
||||||
|
|
||||||
std::string mNormalMapPattern;
|
std::string mNormalMapPattern;
|
||||||
std::string mNormalHeightMapPattern;
|
std::string mNormalHeightMapPattern;
|
||||||
|
|
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
|
|
@ -1,5 +1,7 @@
|
||||||
#include "nifloader.hpp"
|
#include "nifloader.hpp"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <osg/Matrixf>
|
#include <osg/Matrixf>
|
||||||
#include <osg/MatrixTransform>
|
#include <osg/MatrixTransform>
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
|
@ -923,15 +925,18 @@ namespace NifOsg
|
||||||
osg::BoundingBox box;
|
osg::BoundingBox box;
|
||||||
|
|
||||||
int i=0;
|
int i=0;
|
||||||
for (std::vector<Nif::NiParticleSystemController::Particle>::const_iterator it = partctrl->particles.begin();
|
for (const auto& particle : partctrl->particles)
|
||||||
i<particledata->activeCount && it != partctrl->particles.end(); ++it, ++i)
|
|
||||||
{
|
{
|
||||||
const Nif::NiParticleSystemController::Particle& particle = *it;
|
if (i++ >= particledata->activeCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (particle.lifespan <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime));
|
ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime));
|
||||||
|
|
||||||
osgParticle::Particle* created = partsys->createParticle(&particletemplate);
|
osgParticle::Particle* created = partsys->createParticle(&particletemplate);
|
||||||
created->setLifeTime(std::max(0.f, particle.lifespan));
|
created->setLifeTime(particle.lifespan);
|
||||||
|
|
||||||
// Note this position and velocity is not correct for a particle system with absolute reference frame,
|
// Note this position and velocity is not correct for a particle system with absolute reference frame,
|
||||||
// which can not be done in this loader since we are not attached to the scene yet. Will be fixed up post-load in the SceneManager.
|
// which can not be done in this loader since we are not attached to the scene yet. Will be fixed up post-load in the SceneManager.
|
||||||
|
@ -970,6 +975,8 @@ namespace NifOsg
|
||||||
osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter;
|
osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter;
|
||||||
if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust)
|
if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust)
|
||||||
counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate);
|
counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate);
|
||||||
|
else if (partctrl->lifetime == 0 && partctrl->lifetimeRandom == 0)
|
||||||
|
counter->setNumberOfParticlesPerSecondToCreate(0);
|
||||||
else
|
else
|
||||||
counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2));
|
counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2));
|
||||||
|
|
||||||
|
@ -1725,8 +1732,8 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
typedef std::set<osg::ref_ptr<Attribute>, CompareStateAttribute> Cache;
|
typedef std::set<osg::ref_ptr<Attribute>, CompareStateAttribute> Cache;
|
||||||
static Cache sCache;
|
static Cache sCache;
|
||||||
static OpenThreads::Mutex sMutex;
|
static std::mutex sMutex;
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(sMutex);
|
std::lock_guard<std::mutex> lock(sMutex);
|
||||||
typename Cache::iterator found = sCache.find(attr);
|
typename Cache::iterator found = sCache.find(attr);
|
||||||
if (found == sCache.end())
|
if (found == sCache.end())
|
||||||
found = sCache.insert(attr).first;
|
found = sCache.insert(attr).first;
|
||||||
|
|
|
@ -125,7 +125,7 @@ void ParticleShooter::shoot(osgParticle::Particle *particle) const
|
||||||
particle->setVelocity(dir * vel);
|
particle->setVelocity(dir * vel);
|
||||||
|
|
||||||
// Not supposed to set this here, but there doesn't seem to be a better way of doing it
|
// Not supposed to set this here, but there doesn't seem to be a better way of doing it
|
||||||
particle->setLifeTime(mLifetime + mLifetimeRandom * Misc::Rng::rollClosedProbability());
|
particle->setLifeTime(std::max(std::numeric_limits<float>::epsilon(), mLifetime + mLifetimeRandom * Misc::Rng::rollClosedProbability()));
|
||||||
}
|
}
|
||||||
|
|
||||||
GrowFadeAffector::GrowFadeAffector(float growTime, float fadeTime)
|
GrowFadeAffector::GrowFadeAffector(float growTime, float fadeTime)
|
||||||
|
@ -184,6 +184,7 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©,
|
||||||
|
|
||||||
void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */)
|
void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */)
|
||||||
{
|
{
|
||||||
|
assert(particle->getLifeTime() > 0);
|
||||||
float time = static_cast<float>(particle->getAge()/particle->getLifeTime());
|
float time = static_cast<float>(particle->getAge()/particle->getLifeTime());
|
||||||
osg::Vec4f color = mData.interpKey(time);
|
osg::Vec4f color = mData.interpKey(time);
|
||||||
float alpha = color.a();
|
float alpha = color.a();
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
std::vector<osg::ref_ptr<osg::Object> > objectsToRemove;
|
std::vector<osg::ref_ptr<osg::Object> > objectsToRemove;
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
|
|
||||||
// Remove unreferenced entries from object cache
|
// Remove unreferenced entries from object cache
|
||||||
ObjectCacheMap::iterator oitr = _objectCache.begin();
|
ObjectCacheMap::iterator oitr = _objectCache.begin();
|
||||||
|
@ -45,7 +45,7 @@ namespace Resource
|
||||||
|
|
||||||
void MultiObjectCache::clear()
|
void MultiObjectCache::clear()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
_objectCache.clear();
|
_objectCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,13 +56,13 @@ namespace Resource
|
||||||
OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl;
|
OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
_objectCache.insert(std::make_pair(filename, object));
|
_objectCache.insert(std::make_pair(filename, object));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Object> MultiObjectCache::takeFromObjectCache(const std::string &fileName)
|
osg::ref_ptr<osg::Object> MultiObjectCache::takeFromObjectCache(const std::string &fileName)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
ObjectCacheMap::iterator found = _objectCache.find(fileName);
|
ObjectCacheMap::iterator found = _objectCache.find(fileName);
|
||||||
if (found == _objectCache.end())
|
if (found == _objectCache.end())
|
||||||
return osg::ref_ptr<osg::Object>();
|
return osg::ref_ptr<osg::Object>();
|
||||||
|
@ -76,7 +76,7 @@ namespace Resource
|
||||||
|
|
||||||
void MultiObjectCache::releaseGLObjects(osg::State *state)
|
void MultiObjectCache::releaseGLObjects(osg::State *state)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
|
|
||||||
for(ObjectCacheMap::iterator itr = _objectCache.begin();
|
for(ObjectCacheMap::iterator itr = _objectCache.begin();
|
||||||
itr != _objectCache.end();
|
itr != _objectCache.end();
|
||||||
|
@ -89,7 +89,7 @@ namespace Resource
|
||||||
|
|
||||||
unsigned int MultiObjectCache::getCacheSize() const
|
unsigned int MultiObjectCache::getCacheSize() const
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
return _objectCache.size();
|
return _objectCache.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osg/Referenced>
|
#include <osg/Referenced>
|
||||||
|
@ -43,7 +44,7 @@ namespace Resource
|
||||||
typedef std::multimap<std::string, osg::ref_ptr<osg::Object> > ObjectCacheMap;
|
typedef std::multimap<std::string, osg::ref_ptr<osg::Object> > ObjectCacheMap;
|
||||||
|
|
||||||
ObjectCacheMap _objectCache;
|
ObjectCacheMap _objectCache;
|
||||||
mutable OpenThreads::Mutex _objectCacheMutex;
|
mutable std::mutex _objectCacheMutex;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
@ -53,7 +54,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime)
|
void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime)
|
||||||
{
|
{
|
||||||
// look for objects with external references and update their time stamp.
|
// look for objects with external references and update their time stamp.
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for(typename ObjectCacheMap::iterator itr=_objectCache.begin(); itr!=_objectCache.end(); ++itr)
|
for(typename ObjectCacheMap::iterator itr=_objectCache.begin(); itr!=_objectCache.end(); ++itr)
|
||||||
{
|
{
|
||||||
// If ref count is greater than 1, the object has an external reference.
|
// If ref count is greater than 1, the object has an external reference.
|
||||||
|
@ -71,7 +72,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
{
|
{
|
||||||
std::vector<osg::ref_ptr<osg::Object> > objectsToRemove;
|
std::vector<osg::ref_ptr<osg::Object> > objectsToRemove;
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
// Remove expired entries from object cache
|
// Remove expired entries from object cache
|
||||||
typename ObjectCacheMap::iterator oitr = _objectCache.begin();
|
typename ObjectCacheMap::iterator oitr = _objectCache.begin();
|
||||||
while(oitr != _objectCache.end())
|
while(oitr != _objectCache.end())
|
||||||
|
@ -92,21 +93,21 @@ class GenericObjectCache : public osg::Referenced
|
||||||
/** Remove all objects in the cache regardless of having external references or expiry times.*/
|
/** Remove all objects in the cache regardless of having external references or expiry times.*/
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
_objectCache.clear();
|
_objectCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add a key,object,timestamp triple to the Registry::ObjectCache.*/
|
/** Add a key,object,timestamp triple to the Registry::ObjectCache.*/
|
||||||
void addEntryToObjectCache(const KeyType& key, osg::Object* object, double timestamp = 0.0)
|
void addEntryToObjectCache(const KeyType& key, osg::Object* object, double timestamp = 0.0)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
_objectCache[key]=ObjectTimeStampPair(object,timestamp);
|
_objectCache[key]=ObjectTimeStampPair(object,timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove Object from cache.*/
|
/** Remove Object from cache.*/
|
||||||
void removeFromObjectCache(const KeyType& key)
|
void removeFromObjectCache(const KeyType& key)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
||||||
if (itr!=_objectCache.end()) _objectCache.erase(itr);
|
if (itr!=_objectCache.end()) _objectCache.erase(itr);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +115,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
/** Get an ref_ptr<Object> from the object cache*/
|
/** Get an ref_ptr<Object> from the object cache*/
|
||||||
osg::ref_ptr<osg::Object> getRefFromObjectCache(const KeyType& key)
|
osg::ref_ptr<osg::Object> getRefFromObjectCache(const KeyType& key)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
||||||
if (itr!=_objectCache.end())
|
if (itr!=_objectCache.end())
|
||||||
return itr->second.first;
|
return itr->second.first;
|
||||||
|
@ -124,7 +125,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
/** Check if an object is in the cache, and if it is, update its usage time stamp. */
|
/** Check if an object is in the cache, and if it is, update its usage time stamp. */
|
||||||
bool checkInObjectCache(const KeyType& key, double timeStamp)
|
bool checkInObjectCache(const KeyType& key, double timeStamp)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
||||||
if (itr!=_objectCache.end())
|
if (itr!=_objectCache.end())
|
||||||
{
|
{
|
||||||
|
@ -137,7 +138,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
/** call releaseGLObjects on all objects attached to the object cache.*/
|
/** call releaseGLObjects on all objects attached to the object cache.*/
|
||||||
void releaseGLObjects(osg::State* state)
|
void releaseGLObjects(osg::State* state)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for(typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
for(typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
||||||
{
|
{
|
||||||
osg::Object* object = itr->second.first.get();
|
osg::Object* object = itr->second.first.get();
|
||||||
|
@ -148,7 +149,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
/** call node->accept(nv); for all nodes in the objectCache. */
|
/** call node->accept(nv); for all nodes in the objectCache. */
|
||||||
void accept(osg::NodeVisitor& nv)
|
void accept(osg::NodeVisitor& nv)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for(typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
for(typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
||||||
{
|
{
|
||||||
osg::Object* object = itr->second.first.get();
|
osg::Object* object = itr->second.first.get();
|
||||||
|
@ -165,7 +166,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
template <class Functor>
|
template <class Functor>
|
||||||
void call(Functor& f)
|
void call(Functor& f)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for (typename ObjectCacheMap::iterator it = _objectCache.begin(); it != _objectCache.end(); ++it)
|
for (typename ObjectCacheMap::iterator it = _objectCache.begin(); it != _objectCache.end(); ++it)
|
||||||
f(it->first, it->second.first.get());
|
f(it->first, it->second.first.get());
|
||||||
}
|
}
|
||||||
|
@ -173,7 +174,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
/** Get the number of objects in the cache. */
|
/** Get the number of objects in the cache. */
|
||||||
unsigned int getCacheSize() const
|
unsigned int getCacheSize() const
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
return _objectCache.size();
|
return _objectCache.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +186,7 @@ class GenericObjectCache : public osg::Referenced
|
||||||
typedef std::map<KeyType, ObjectTimeStampPair > ObjectCacheMap;
|
typedef std::map<KeyType, ObjectTimeStampPair > ObjectCacheMap;
|
||||||
|
|
||||||
ObjectCacheMap _objectCache;
|
ObjectCacheMap _objectCache;
|
||||||
mutable OpenThreads::Mutex _objectCacheMutex;
|
mutable std::mutex _objectCacheMutex;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace Resource
|
||||||
|
|
||||||
void clearCache()
|
void clearCache()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_listMutex);
|
std::lock_guard<OpenThreads::Mutex> lock(_listMutex);
|
||||||
_sharedTextureList.clear();
|
_sharedTextureList.clear();
|
||||||
_sharedStateSetList.clear();
|
_sharedStateSetList.clear();
|
||||||
}
|
}
|
||||||
|
@ -625,7 +625,7 @@ namespace Resource
|
||||||
|
|
||||||
mShaderManager->releaseGLObjects(state);
|
mShaderManager->releaseGLObjects(state);
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mSharedStateMutex);
|
std::lock_guard<std::mutex> lock(mSharedStateMutex);
|
||||||
mSharedStateManager->releaseGLObjects(state);
|
mSharedStateManager->releaseGLObjects(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,7 +717,7 @@ namespace Resource
|
||||||
|
|
||||||
if (mIncrementalCompileOperation)
|
if (mIncrementalCompileOperation)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*mIncrementalCompileOperation->getToCompiledMutex());
|
std::lock_guard<OpenThreads::Mutex> lock(*mIncrementalCompileOperation->getToCompiledMutex());
|
||||||
osgUtil::IncrementalCompileOperation::CompileSets& sets = mIncrementalCompileOperation->getToCompile();
|
osgUtil::IncrementalCompileOperation::CompileSets& sets = mIncrementalCompileOperation->getToCompile();
|
||||||
for(osgUtil::IncrementalCompileOperation::CompileSets::iterator it = sets.begin(); it != sets.end();)
|
for(osgUtil::IncrementalCompileOperation::CompileSets::iterator it = sets.begin(); it != sets.end();)
|
||||||
{
|
{
|
||||||
|
@ -738,7 +738,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
ResourceManager::clearCache();
|
ResourceManager::clearCache();
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mSharedStateMutex);
|
std::lock_guard<std::mutex> lock(mSharedStateMutex);
|
||||||
mSharedStateManager->clearCache();
|
mSharedStateManager->clearCache();
|
||||||
mInstanceCache->clear();
|
mInstanceCache->clear();
|
||||||
}
|
}
|
||||||
|
@ -747,12 +747,12 @@ namespace Resource
|
||||||
{
|
{
|
||||||
if (mIncrementalCompileOperation)
|
if (mIncrementalCompileOperation)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*mIncrementalCompileOperation->getToCompiledMutex());
|
std::lock_guard<OpenThreads::Mutex> lock(*mIncrementalCompileOperation->getToCompiledMutex());
|
||||||
stats->setAttribute(frameNumber, "Compiling", mIncrementalCompileOperation->getToCompile().size());
|
stats->setAttribute(frameNumber, "Compiling", mIncrementalCompileOperation->getToCompile().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mSharedStateMutex);
|
std::lock_guard<std::mutex> lock(mSharedStateMutex);
|
||||||
stats->setAttribute(frameNumber, "Texture", mSharedStateManager->getNumSharedTextures());
|
stats->setAttribute(frameNumber, "Texture", mSharedStateManager->getNumSharedTextures());
|
||||||
stats->setAttribute(frameNumber, "StateSet", mSharedStateManager->getNumSharedStateSets());
|
stats->setAttribute(frameNumber, "StateSet", mSharedStateManager->getNumSharedStateSets());
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osg/Node>
|
#include <osg/Node>
|
||||||
|
@ -159,7 +160,7 @@ namespace Resource
|
||||||
osg::ref_ptr<MultiObjectCache> mInstanceCache;
|
osg::ref_ptr<MultiObjectCache> mInstanceCache;
|
||||||
|
|
||||||
osg::ref_ptr<Resource::SharedStateManager> mSharedStateManager;
|
osg::ref_ptr<Resource::SharedStateManager> mSharedStateManager;
|
||||||
mutable OpenThreads::Mutex mSharedStateMutex;
|
mutable std::mutex mSharedStateMutex;
|
||||||
|
|
||||||
Resource::ImageManager* mImageManager;
|
Resource::ImageManager* mImageManager;
|
||||||
Resource::NifFileManager* mNifFileManager;
|
Resource::NifFileManager* mNifFileManager;
|
||||||
|
|
|
@ -25,7 +25,7 @@ StatsHandler::StatsHandler():
|
||||||
_statsWidth(1280.0f),
|
_statsWidth(1280.0f),
|
||||||
_statsHeight(1024.0f),
|
_statsHeight(1024.0f),
|
||||||
_font(""),
|
_font(""),
|
||||||
_characterSize(20.0f)
|
_characterSize(18.0f)
|
||||||
{
|
{
|
||||||
_camera = new osg::Camera;
|
_camera = new osg::Camera;
|
||||||
_camera->getOrCreateStateSet()->setGlobalDefaults();
|
_camera->getOrCreateStateSet()->setGlobalDefaults();
|
||||||
|
@ -45,6 +45,8 @@ Profiler::Profiler()
|
||||||
else
|
else
|
||||||
_font = "";
|
_font = "";
|
||||||
|
|
||||||
|
_characterSize = 18;
|
||||||
|
|
||||||
setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3);
|
setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -891,7 +891,7 @@ MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData
|
||||||
|
|
||||||
MWShadowTechnique::ViewDependentData* MWShadowTechnique::getViewDependentData(osgUtil::CullVisitor* cv)
|
MWShadowTechnique::ViewDependentData* MWShadowTechnique::getViewDependentData(osgUtil::CullVisitor* cv)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDependentDataMapMutex);
|
std::lock_guard<std::mutex> lock(_viewDependentDataMapMutex);
|
||||||
ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv);
|
ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv);
|
||||||
if (itr!=_viewDependentDataMap.end()) return itr->second.get();
|
if (itr!=_viewDependentDataMap.end()) return itr->second.get();
|
||||||
|
|
||||||
|
@ -1435,7 +1435,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
|
||||||
std::string validRegionUniformName = "validRegionMatrix" + std::to_string(sm_i);
|
std::string validRegionUniformName = "validRegionMatrix" + std::to_string(sm_i);
|
||||||
osg::ref_ptr<osg::Uniform> validRegionUniform;
|
osg::ref_ptr<osg::Uniform> validRegionUniform;
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_accessUniformsAndProgramMutex);
|
std::lock_guard<std::mutex> lock(_accessUniformsAndProgramMutex);
|
||||||
|
|
||||||
for (auto uniform : _uniforms)
|
for (auto uniform : _uniforms)
|
||||||
{
|
{
|
||||||
|
@ -1560,7 +1560,7 @@ void MWShadowTechnique::createShaders()
|
||||||
|
|
||||||
unsigned int _baseTextureUnit = 0;
|
unsigned int _baseTextureUnit = 0;
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_accessUniformsAndProgramMutex);
|
std::lock_guard<std::mutex> lock(_accessUniformsAndProgramMutex);
|
||||||
|
|
||||||
_shadowCastingStateSet = new osg::StateSet;
|
_shadowCastingStateSet = new osg::StateSet;
|
||||||
|
|
||||||
|
@ -3073,7 +3073,7 @@ osg::StateSet* MWShadowTechnique::selectStateSetForRenderingShadow(ViewDependent
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> stateset = vdd.getStateSet();
|
osg::ref_ptr<osg::StateSet> stateset = vdd.getStateSet();
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_accessUniformsAndProgramMutex);
|
std::lock_guard<std::mutex> lock(_accessUniformsAndProgramMutex);
|
||||||
|
|
||||||
vdd.getStateSet()->clear();
|
vdd.getStateSet()->clear();
|
||||||
|
|
||||||
|
@ -3150,7 +3150,7 @@ void MWShadowTechnique::resizeGLObjectBuffers(unsigned int /*maxSize*/)
|
||||||
|
|
||||||
void MWShadowTechnique::releaseGLObjects(osg::State* state) const
|
void MWShadowTechnique::releaseGLObjects(osg::State* state) const
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDependentDataMapMutex);
|
std::lock_guard<std::mutex> lock(_viewDependentDataMapMutex);
|
||||||
for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin();
|
for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin();
|
||||||
itr != _viewDependentDataMap.end();
|
itr != _viewDependentDataMap.end();
|
||||||
++itr)
|
++itr)
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H
|
#ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H
|
||||||
#define COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H 1
|
#define COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H 1
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
#include <osg/Material>
|
#include <osg/Material>
|
||||||
#include <osg/MatrixTransform>
|
#include <osg/MatrixTransform>
|
||||||
|
@ -255,8 +257,8 @@ namespace SceneUtil {
|
||||||
virtual ~MWShadowTechnique();
|
virtual ~MWShadowTechnique();
|
||||||
|
|
||||||
typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr<ViewDependentData> > ViewDependentDataMap;
|
typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr<ViewDependentData> > ViewDependentDataMap;
|
||||||
|
mutable std::mutex _viewDependentDataMapMutex;
|
||||||
typedef std::map< std::string, osg::ref_ptr<ViewDependentData> > ViewDependentDataShareMap;
|
typedef std::map< std::string, osg::ref_ptr<ViewDependentData> > ViewDependentDataShareMap;
|
||||||
mutable OpenThreads::Mutex _viewDependentDataMapMutex;
|
|
||||||
ViewDependentDataMap _viewDependentDataMap;
|
ViewDependentDataMap _viewDependentDataMap;
|
||||||
ViewDependentDataShareMap _viewDependentDataShareMap;
|
ViewDependentDataShareMap _viewDependentDataShareMap;
|
||||||
|
|
||||||
|
@ -268,7 +270,7 @@ namespace SceneUtil {
|
||||||
osg::ref_ptr<osg::Texture2D> _fallbackShadowMapTexture;
|
osg::ref_ptr<osg::Texture2D> _fallbackShadowMapTexture;
|
||||||
|
|
||||||
typedef std::vector< osg::ref_ptr<osg::Uniform> > Uniforms;
|
typedef std::vector< osg::ref_ptr<osg::Uniform> > Uniforms;
|
||||||
mutable OpenThreads::Mutex _accessUniformsAndProgramMutex;
|
mutable std::mutex _accessUniformsAndProgramMutex;
|
||||||
Uniforms _uniforms;
|
Uniforms _uniforms;
|
||||||
osg::ref_ptr<osg::Program> _program;
|
osg::ref_ptr<osg::Program> _program;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::StateSet* stateset = mStateSets[nv->getTraversalNumber()%2];
|
osg::ref_ptr<osg::StateSet> stateset = mStateSets[nv->getTraversalNumber()%2];
|
||||||
apply(stateset, nv);
|
apply(stateset, nv);
|
||||||
|
|
||||||
if (!isCullVisitor)
|
if (!isCullVisitor)
|
||||||
|
|
|
@ -273,7 +273,7 @@ namespace Shader
|
||||||
|
|
||||||
osg::ref_ptr<osg::Shader> ShaderManager::getShader(const std::string &templateName, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType)
|
osg::ref_ptr<osg::Shader> ShaderManager::getShader(const std::string &templateName, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
// read the template if we haven't already
|
// read the template if we haven't already
|
||||||
TemplateMap::iterator templateIt = mShaderTemplates.find(templateName);
|
TemplateMap::iterator templateIt = mShaderTemplates.find(templateName);
|
||||||
|
@ -323,7 +323,7 @@ namespace Shader
|
||||||
|
|
||||||
osg::ref_ptr<osg::Program> ShaderManager::getProgram(osg::ref_ptr<osg::Shader> vertexShader, osg::ref_ptr<osg::Shader> fragmentShader)
|
osg::ref_ptr<osg::Program> ShaderManager::getProgram(osg::ref_ptr<osg::Shader> vertexShader, osg::ref_ptr<osg::Shader> fragmentShader)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
ProgramMap::iterator found = mPrograms.find(std::make_pair(vertexShader, fragmentShader));
|
ProgramMap::iterator found = mPrograms.find(std::make_pair(vertexShader, fragmentShader));
|
||||||
if (found == mPrograms.end())
|
if (found == mPrograms.end())
|
||||||
{
|
{
|
||||||
|
@ -362,7 +362,7 @@ namespace Shader
|
||||||
|
|
||||||
void ShaderManager::releaseGLObjects(osg::State *state)
|
void ShaderManager::releaseGLObjects(osg::State *state)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
for (auto shader : mShaders)
|
for (auto shader : mShaders)
|
||||||
{
|
{
|
||||||
if (shader.second != nullptr)
|
if (shader.second != nullptr)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
@ -10,8 +11,6 @@
|
||||||
|
|
||||||
#include <osgViewer/Viewer>
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
#include <OpenThreads/Mutex>
|
|
||||||
|
|
||||||
namespace Shader
|
namespace Shader
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -63,7 +62,7 @@ namespace Shader
|
||||||
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap;
|
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap;
|
||||||
ProgramMap mPrograms;
|
ProgramMap mPrograms;
|
||||||
|
|
||||||
OpenThreads::Mutex mMutex;
|
std::mutex mMutex;
|
||||||
|
|
||||||
const osg::ref_ptr<osg::Uniform> mShadowMapAlphaTestEnableUniform = new osg::Uniform();
|
const osg::ref_ptr<osg::Uniform> mShadowMapAlphaTestEnableUniform = new osg::Uniform();
|
||||||
const osg::ref_ptr<osg::Uniform> mShadowMapAlphaTestDisableUniform = new osg::Uniform();
|
const osg::ref_ptr<osg::Uniform> mShadowMapAlphaTestDisableUniform = new osg::Uniform();
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <OpenThreads/ScopedLock>
|
|
||||||
|
|
||||||
#include <osg/PrimitiveSet>
|
#include <osg/PrimitiveSet>
|
||||||
|
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
@ -180,7 +178,7 @@ namespace Terrain
|
||||||
|
|
||||||
osg::ref_ptr<osg::Vec2Array> BufferCache::getUVBuffer(unsigned int numVerts)
|
osg::ref_ptr<osg::Vec2Array> BufferCache::getUVBuffer(unsigned int numVerts)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex);
|
std::lock_guard<std::mutex> lock(mUvBufferMutex);
|
||||||
if (mUvBufferMap.find(numVerts) != mUvBufferMap.end())
|
if (mUvBufferMap.find(numVerts) != mUvBufferMap.end())
|
||||||
{
|
{
|
||||||
return mUvBufferMap[numVerts];
|
return mUvBufferMap[numVerts];
|
||||||
|
@ -210,7 +208,7 @@ namespace Terrain
|
||||||
osg::ref_ptr<osg::DrawElements> BufferCache::getIndexBuffer(unsigned int numVerts, unsigned int flags)
|
osg::ref_ptr<osg::DrawElements> BufferCache::getIndexBuffer(unsigned int numVerts, unsigned int flags)
|
||||||
{
|
{
|
||||||
std::pair<int, int> id = std::make_pair(numVerts, flags);
|
std::pair<int, int> id = std::make_pair(numVerts, flags);
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mIndexBufferMutex);
|
std::lock_guard<std::mutex> lock(mIndexBufferMutex);
|
||||||
|
|
||||||
if (mIndexBufferMap.find(id) != mIndexBufferMap.end())
|
if (mIndexBufferMap.find(id) != mIndexBufferMap.end())
|
||||||
{
|
{
|
||||||
|
@ -234,11 +232,11 @@ namespace Terrain
|
||||||
void BufferCache::clearCache()
|
void BufferCache::clearCache()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mIndexBufferMutex);
|
std::lock_guard<std::mutex> lock(mIndexBufferMutex);
|
||||||
mIndexBufferMap.clear();
|
mIndexBufferMap.clear();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex);
|
std::lock_guard<std::mutex> lock(mUvBufferMutex);
|
||||||
mUvBufferMap.clear();
|
mUvBufferMap.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,12 +244,12 @@ namespace Terrain
|
||||||
void BufferCache::releaseGLObjects(osg::State *state)
|
void BufferCache::releaseGLObjects(osg::State *state)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mIndexBufferMutex);
|
std::lock_guard<std::mutex> lock(mIndexBufferMutex);
|
||||||
for (auto indexbuffer : mIndexBufferMap)
|
for (auto indexbuffer : mIndexBufferMap)
|
||||||
indexbuffer.second->releaseGLObjects(state);
|
indexbuffer.second->releaseGLObjects(state);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex);
|
std::lock_guard<std::mutex> lock(mUvBufferMutex);
|
||||||
for (auto uvbuffer : mUvBufferMap)
|
for (auto uvbuffer : mUvBufferMap)
|
||||||
uvbuffer.second->releaseGLObjects(state);
|
uvbuffer.second->releaseGLObjects(state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <osg/PrimitiveSet>
|
#include <osg/PrimitiveSet>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
@ -30,10 +31,10 @@ namespace Terrain
|
||||||
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
|
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
|
||||||
// combination of LOD deltas and index buffer LOD we may need.
|
// combination of LOD deltas and index buffer LOD we may need.
|
||||||
std::map<std::pair<int, int>, osg::ref_ptr<osg::DrawElements> > mIndexBufferMap;
|
std::map<std::pair<int, int>, osg::ref_ptr<osg::DrawElements> > mIndexBufferMap;
|
||||||
OpenThreads::Mutex mIndexBufferMutex;
|
std::mutex mIndexBufferMutex;
|
||||||
|
|
||||||
std::map<int, osg::ref_ptr<osg::Vec2Array> > mUvBufferMap;
|
std::map<int, osg::ref_ptr<osg::Vec2Array> > mUvBufferMap;
|
||||||
OpenThreads::Mutex mUvBufferMutex;
|
std::mutex mUvBufferMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue