1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-06-19 21:41:39 +00:00

Merge remote-tracking branch 'remotes/origin/master' into openxr_vr

This commit is contained in:
Mads Buvik Sandvei 2020-11-27 00:36:10 +01:00
commit 49e76fa077
267 changed files with 2785 additions and 1671 deletions

View file

@ -37,6 +37,8 @@ Debian_GCC:
CC: gcc CC: gcc
CXX: g++ CXX: g++
CCACHE_SIZE: 3G CCACHE_SIZE: 3G
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
timeout: 2h
Debian_GCC_tests: Debian_GCC_tests:
extends: .Debian extends: .Debian
@ -96,7 +98,7 @@ variables: &cs-targets
- windows - windows
before_script: before_script:
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1" - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolately/" --priority=1 - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
- choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install git --force --params "/GitAndUnixToolsOnPath" -y
- choco install 7zip -y - choco install 7zip -y
- choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y
@ -120,6 +122,8 @@ variables: &cs-targets
Get-ChildItem -Recurse *.pdb | Remove-Item Get-ChildItem -Recurse *.pdb | Remove-Item
} }
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*' - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
after_script:
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache: cache:
key: ninja-v2 key: ninja-v2
paths: paths:
@ -186,7 +190,7 @@ Windows_Ninja_CS_RelWithDebInfo:
- windows - windows
before_script: before_script:
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1" - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolately/" --priority=1 - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
- choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install git --force --params "/GitAndUnixToolsOnPath" -y
- choco install 7zip -y - choco install 7zip -y
- choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y
@ -208,6 +212,8 @@ Windows_Ninja_CS_RelWithDebInfo:
Get-ChildItem -Recurse *.pdb | Remove-Item Get-ChildItem -Recurse *.pdb | Remove-Item
} }
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*' - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
after_script:
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache: cache:
key: msbuild-v2 key: msbuild-v2
paths: paths:

View file

@ -2,19 +2,12 @@ language: cpp
branches: branches:
only: only:
- master - master
- coverity_scan
- /openmw-.*$/ - /openmw-.*$/
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE="
cache: ccache cache: ccache
addons: addons:
apt: apt:
sources: sources:
- sourceline: 'ppa:openmw/openmw' - sourceline: 'ppa:openmw/openmw'
# - ubuntu-toolchain-r-test # for GCC-10
packages: [ packages: [
# Dev # Dev
build-essential, cmake, clang-tools, ccache, build-essential, cmake, clang-tools, ccache,
@ -23,32 +16,21 @@ addons:
# FFmpeg # FFmpeg
libavcodec-dev, libavformat-dev, libavutil-dev, libswresample-dev, libswscale-dev, libavcodec-dev, libavformat-dev, libavutil-dev, libswresample-dev, libswscale-dev,
# Audio, Video and Misc. deps # Audio, Video and Misc. deps
libsdl2-dev, libqt5opengl5-dev, libopenal-dev, libunshield-dev, libtinyxml-dev, liblz4-dev libsdl2-dev, libqt5opengl5-dev, libopenal-dev, libunshield-dev, libtinyxml-dev, liblz4-dev,
# The other ones from OpenMW ppa # The other ones from OpenMW ppa
libbullet-dev, libopenscenegraph-dev, libmygui-dev libbullet-dev, libopenscenegraph-dev, libmygui-dev
] ]
coverity_scan: # TODO: currently takes too long, disabled openmw/openmw-cs for now.
project:
name: "OpenMW/openmw"
description: "<Your project description here>"
branch_pattern: coverity_scan
notification_email: 1122069+psi29a@users.noreply.github.com
build_command_prepend: "cov-configure --comptype gcc --compiler gcc-5 --template; cmake . -DBUILD_OPENMW=FALSE -DBUILD_OPENCS=FALSE"
build_command: "make VERBOSE=1 -j3"
matrix: matrix:
include: include:
- name: OpenMW (all) on MacOS 10.15 with Xcode 11.6 - name: OpenMW (all) on MacOS 10.15 with Xcode 11.6
os: osx os: osx
osx_image: xcode11.6 osx_image: xcode11.6
if: branch != coverity_scan
- name: OpenMW (all) on Ubuntu Focal with GCC - name: OpenMW (all) on Ubuntu Focal with GCC
os: linux os: linux
dist: focal dist: focal
if: branch != coverity_scan
- name: OpenMW (tests only) on Ubuntu Focal with GCC - name: OpenMW (tests only) on Ubuntu Focal with GCC
os: linux os: linux
dist: focal dist: focal
if: branch != coverity_scan
env: env:
- BUILD_TESTS_ONLY: 1 - BUILD_TESTS_ONLY: 1
- name: OpenMW (openmw) on Ubuntu Focal with Clang's Static Analysis - name: OpenMW (openmw) on Ubuntu Focal with Clang's Static Analysis
@ -57,30 +39,21 @@ matrix:
env: env:
- MATRIX_EVAL="CC=clang && CXX=clang++" - MATRIX_EVAL="CC=clang && CXX=clang++"
- ANALYZE="scan-build --force-analyze-debug-code --use-cc clang --use-c++ clang++" - ANALYZE="scan-build --force-analyze-debug-code --use-cc clang --use-c++ clang++"
if: branch != coverity_scan
compiler: clang compiler: clang
- name: OpenMW Components Coverity Scan
os: linux
dist: focal
if: branch = coverity_scan
# allow_failures:
# - name: OpenMW (openmw) on Ubuntu Focal with GCC-10
# env:
# - MATRIX_EVAL="CC=gcc-10 && CXX=g++-10"
before_install: before_install:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then eval "${MATRIX_EVAL}"; fi - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then eval "${MATRIX_EVAL}"; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_install.${TRAVIS_OS_NAME}.sh; fi - ./CI/before_install.${TRAVIS_OS_NAME}.sh
before_script: before_script:
- ccache -z - ccache -z
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_script.${TRAVIS_OS_NAME}.sh; fi - ./CI/before_script.${TRAVIS_OS_NAME}.sh
script: script:
- cd ./build - cd ./build
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ${ANALYZE} make -j3; fi - ${ANALYZE} make -j3;
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - if [ "${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 [ "${TRAVIS_OS_NAME}" = "osx" ]; then ../CI/check_package.osx.sh; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ] && [ "${BUILD_TESTS_ONLY}" ]; then ./openmw_test_suite; fi - if [ "${TRAVIS_OS_NAME}" = "linux" ] && [ "${BUILD_TESTS_ONLY}" ]; then ./openmw_test_suite; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
- cd "${TRAVIS_BUILD_DIR}" - cd "${TRAVIS_BUILD_DIR}"
- ccache -s - ccache -s
deploy: deploy:

View file

@ -96,6 +96,7 @@ Programmers
Jan Borsodi (am0s) Jan Borsodi (am0s)
Jason Hooks (jhooks) Jason Hooks (jhooks)
jeaye jeaye
jefetienne
Jeffrey Haines (Jyby) Jeffrey Haines (Jyby)
Jengerer Jengerer
Jiří Kuneš (kunesj) Jiří Kuneš (kunesj)

View file

@ -7,12 +7,15 @@
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
Bug #2473: Unable to overstock merchants Bug #2473: Unable to overstock merchants
Bug #2798: Mutable ESM records Bug #2798: Mutable ESM records
Bug #2976 [reopened]: Issues combining settings from the command line and both config files
Bug #3676: NiParticleColorModifier isn't applied properly Bug #3676: NiParticleColorModifier isn't applied properly
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 #3789: Crash in visitEffectSources while in battle
Bug #3862: Random container contents behave differently than vanilla Bug #3862: Random container contents behave differently than vanilla
Bug #3929: Leveled list merchant containers respawn on barter Bug #3929: Leveled list merchant containers respawn on barter
Bug #4021: Attributes and skills are not stored as floats Bug #4021: Attributes and skills are not stored as floats
Bug #4055: Local scripts don't inherit variables from their base record Bug #4055: Local scripts don't inherit variables from their base record
Bug #4083: Door animation freezes when colliding with actors
Bug #4623: Corprus implementation is incorrect Bug #4623: Corprus implementation is incorrect
Bug #4631: Setting MSAA level too high doesn't fall back to highest supported level Bug #4631: Setting MSAA level too high doesn't fall back to highest supported level
Bug #4764: Data race in osg ParticleSystem Bug #4764: Data race in osg ParticleSystem
@ -33,6 +36,7 @@
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
Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work
Bug #5416: Junk non-node records before the root node are not handled gracefully Bug #5416: Junk non-node records before the root node are not handled gracefully
Bug #5422: The player loses all spells when resurrected
Bug #5424: Creatures do not headtrack player Bug #5424: Creatures do not headtrack player
Bug #5425: Poison effect only appears for one frame Bug #5425: Poison effect only appears for one frame
Bug #5427: GetDistance unknown ID error is misleading Bug #5427: GetDistance unknown ID error is misleading
@ -56,8 +60,12 @@
Bug #5603: Setting constant effect cast style doesn't correct effects view Bug #5603: Setting constant effect cast style doesn't correct effects view
Bug #5611: Usable items with "0 Uses" should be used only once Bug #5611: Usable items with "0 Uses" should be used only once
Bug #5622: Can't properly interact with the console when in pause menu Bug #5622: Can't properly interact with the console when in pause menu
Bug #5633: Damage Spells in effect before god mode is enabled continue to hurt the player character and can kill them
Bug #5639: Tooltips cover Messageboxes Bug #5639: Tooltips cover Messageboxes
Bug #5644: Summon effects running on the player during game initialization cause crashes Bug #5644: Summon effects running on the player during game initialization cause crashes
Bug #5656: Sneaking characters block hits while standing
Bug #5661: Region sounds don't play at the right interval
Bug #5688: Water shader broken indoors with enable indoor shadows = false
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 #2404: Levelled List can not be placed into a container Feature #2404: Levelled List can not be placed into a container
@ -78,6 +86,8 @@
Feature #5610: Actors movement should be smoother Feature #5610: Actors movement should be smoother
Feature #5642: Ability to attach arrows to actor skeleton instead of bow mesh Feature #5642: Ability to attach arrows to actor skeleton instead of bow mesh
Feature #5649: Skyrim SE compressed BSA format support Feature #5649: Skyrim SE compressed BSA format support
Feature #5672: Make stretch menu background configuration more accessible
Feature #5692: Improve spell/magic item search to factor in magic effect names
Task #5480: Drop Qt4 support Task #5480: Drop Qt4 support
Task #5520: Improve cell name autocompleter implementation Task #5520: Improve cell name autocompleter implementation

View file

@ -5,8 +5,5 @@ command -v ccache >/dev/null 2>&1 || brew install ccache
command -v cmake >/dev/null 2>&1 || brew install cmake command -v cmake >/dev/null 2>&1 || brew install cmake
command -v qmake >/dev/null 2>&1 || brew install qt command -v qmake >/dev/null 2>&1 || brew install qt
brew link --overwrite lz4 # overwrite system lz4; use brew curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-f8918dd.zip -o ~/openmw-deps.zip
brew reinstall lz4
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-ef2462c.zip -o ~/openmw-deps.zip
unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null

View file

@ -917,7 +917,7 @@ printf "LZ4 1.9.2... "
printf "Exists. " printf "Exists. "
elif [ -z $SKIP_EXTRACT ]; then elif [ -z $SKIP_EXTRACT ]; then
rm -rf LZ4_1.9.2 rm -rf LZ4_1.9.2
eval 7z x -y lz4_win${BITS}_v1_9_2.7z -o./LZ4_1.9.2 $STRIP eval 7z x -y lz4_win${BITS}_v1_9_2.7z -o$(real_pwd)/LZ4_1.9.2 $STRIP
fi fi
export LZ4DIR="$(real_pwd)/LZ4_1.9.2" export LZ4DIR="$(real_pwd)/LZ4_1.9.2"
add_cmake_opts -DLZ4_INCLUDE_DIR="${LZ4DIR}/include" \ add_cmake_opts -DLZ4_INCLUDE_DIR="${LZ4DIR}/include" \

View file

@ -25,5 +25,6 @@ cmake \
-D BUILD_BSATOOL=TRUE \ -D BUILD_BSATOOL=TRUE \
-D BUILD_ESSIMPORTER=TRUE \ -D BUILD_ESSIMPORTER=TRUE \
-D BUILD_NIFTEST=TRUE \ -D BUILD_NIFTEST=TRUE \
-D BULLET_USE_DOUBLES=TRUE \
-G"Unix Makefiles" \ -G"Unix Makefiles" \
.. ..

View file

@ -1,5 +1,7 @@
project(OpenMW) project(OpenMW)
cmake_minimum_required(VERSION 3.1.0) cmake_minimum_required(VERSION 3.1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# for link time optimization, remove if cmake version is >= 3.9 # for link time optimization, remove if cmake version is >= 3.9
if(POLICY CMP0069) if(POLICY CMP0069)
@ -307,7 +309,7 @@ endif()
set(Boost_NO_BOOST_CMAKE ON) set(Boost_NO_BOOST_CMAKE ON)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Boost 1.6.2 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(MyGUI 3.2.2 REQUIRED) find_package(MyGUI 3.2.2 REQUIRED)
find_package(SDL2 2.0.9 REQUIRED) find_package(SDL2 2.0.9 REQUIRED)
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
@ -394,9 +396,6 @@ if (NOT WIN32 AND NOT APPLE)
"${OpenMW_BINARY_DIR}/org.openmw.cs.desktop") "${OpenMW_BINARY_DIR}/org.openmw.cs.desktop")
endif() endif()
# CXX Compiler settings
set(CMAKE_CXX_STANDARD 17)
if(OPENMW_LTO_BUILD) if(OPENMW_LTO_BUILD)
if(NOT CMAKE_VERSION VERSION_LESS 3.9) if(NOT CMAKE_VERSION VERSION_LESS 3.9)
include(CheckIPOSupported) include(CheckIPOSupported)

View file

@ -6,7 +6,8 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <components/bsa/bsa_file.hpp> #include <components/bsa/compressedbsafile.hpp>
#include <components/misc/stringops.hpp>
#define BSATOOL_VERSION 1.1 #define BSATOOL_VERSION 1.1
@ -25,16 +26,6 @@ struct Arguments
bool fullpath; bool fullpath;
}; };
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
{
size_t pos = str.find(needle);
while(pos != std::string::npos)
{
str.replace(pos, needle.size(), substitute);
pos = str.find(needle);
}
}
bool parseOptions (int argc, char** argv, Arguments &info) bool parseOptions (int argc, char** argv, Arguments &info)
{ {
bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n" bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n"
@ -144,9 +135,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
return true; return true;
} }
int list(Bsa::BSAFile& bsa, Arguments& info); int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
int extract(Bsa::BSAFile& bsa, Arguments& info); int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
int extractAll(Bsa::BSAFile& bsa, Arguments& info); int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
@ -157,8 +148,16 @@ int main(int argc, char** argv)
return 1; return 1;
// Open file // Open file
Bsa::BSAFile bsa; std::unique_ptr<Bsa::BSAFile> bsa;
bsa.open(info.filename);
Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(info.filename);
if (bsaVersion == Bsa::BSAVER_COMPRESSED)
bsa = std::make_unique<Bsa::CompressedBSAFile>(Bsa::CompressedBSAFile());
else
bsa = std::make_unique<Bsa::BSAFile>(Bsa::BSAFile());
bsa->open(info.filename);
if (info.mode == "list") if (info.mode == "list")
return list(bsa, info); return list(bsa, info);
@ -179,10 +178,10 @@ int main(int argc, char** argv)
} }
} }
int list(Bsa::BSAFile& bsa, Arguments& info) int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
{ {
// List all files // List all files
const Bsa::BSAFile::FileList &files = bsa.getList(); const Bsa::BSAFile::FileList &files = bsa->getList();
for (const auto& file : files) for (const auto& file : files)
{ {
if(info.longformat) if(info.longformat)
@ -201,15 +200,15 @@ int list(Bsa::BSAFile& bsa, Arguments& info)
return 0; return 0;
} }
int extract(Bsa::BSAFile& bsa, Arguments& info) int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
{ {
std::string archivePath = info.extractfile; std::string archivePath = info.extractfile;
replaceAll(archivePath, "/", "\\"); Misc::StringUtils::replaceAll(archivePath, "/", "\\");
std::string extractPath = info.extractfile; std::string extractPath = info.extractfile;
replaceAll(extractPath, "\\", "/"); Misc::StringUtils::replaceAll(extractPath, "\\", "/");
if (!bsa.exists(archivePath.c_str())) if (!bsa->exists(archivePath.c_str()))
{ {
std::cout << "ERROR: file '" << archivePath << "' not found\n"; std::cout << "ERROR: file '" << archivePath << "' not found\n";
std::cout << "In archive: " << info.filename << std::endl; std::cout << "In archive: " << info.filename << std::endl;
@ -237,7 +236,7 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
} }
// Get a stream for the file to extract // Get a stream for the file to extract
Files::IStreamPtr stream = bsa.getFile(archivePath.c_str()); Files::IStreamPtr stream = bsa->getFile(archivePath.c_str());
bfs::ofstream out(target, std::ios::binary); bfs::ofstream out(target, std::ios::binary);
@ -250,12 +249,12 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
return 0; return 0;
} }
int extractAll(Bsa::BSAFile& bsa, Arguments& info) int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
{ {
for (const auto &file : bsa.getList()) for (const auto &file : bsa->getList())
{ {
std::string extractPath(file.name); std::string extractPath(file.name);
replaceAll(extractPath, "\\", "/"); Misc::StringUtils::replaceAll(extractPath, "\\", "/");
// Get the target path (the path the file will be extracted to) // Get the target path (the path the file will be extracted to)
bfs::path target (info.outdir); bfs::path target (info.outdir);
@ -273,7 +272,7 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
// Get a stream for the file to extract // Get a stream for the file to extract
// (inefficient because getFile iter on the list again) // (inefficient because getFile iter on the list again)
Files::IStreamPtr data = bsa.getFile(file.name); Files::IStreamPtr data = bsa->getFile(file.name);
bfs::ofstream out(target, std::ios::binary); bfs::ofstream out(target, std::ios::binary);
// Write the file to disk // Write the file to disk

View file

@ -152,6 +152,7 @@ bool Launcher::AdvancedPage::loadSettings()
// Match the index with the option (only 0, 1, 2, or 3 are valid). Will default to 0 if invalid. // Match the index with the option (only 0, 1, 2, or 3 are valid). Will default to 0 if invalid.
if (showOwnedIndex >= 0 && showOwnedIndex <= 3) if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex); showOwnedComboBox->setCurrentIndex(showOwnedIndex);
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
} }
// Bug fixes // Bug fixes
@ -277,6 +278,7 @@ void Launcher::AdvancedPage::saveSettings()
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex(); int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game")) if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex); mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
} }
// Bug fixes // Bug fixes

View file

@ -211,10 +211,10 @@ void Launcher::MainDialog::setVersionLabel()
versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10)));
// Add the compile date and time // Add the compile date and time
versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), auto compileDate = QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), QLatin1String("MMM d yyyy"));
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), auto compileTime = QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), QLatin1String("hh:mm:ss"));
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale::system().toString(compileDate, QLocale::LongFormat),
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); QLocale::system().toString(compileTime, QLocale::ShortFormat)));
} }
bool Launcher::MainDialog::setup() bool Launcher::MainDialog::setup()

View file

@ -645,7 +645,7 @@ MwIniImporter::MwIniImporter()
} }
for(int i=0; fallback[i]; i++) { for(int i=0; fallback[i]; i++) {
mMergeFallback.push_back(fallback[i]); mMergeFallback.emplace_back(fallback[i]);
} }
} }
@ -910,7 +910,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
std::time_t time = lastWriteTime(path, defaultTime); std::time_t time = lastWriteTime(path, defaultTime);
if (time != defaultTime) if (time != defaultTime)
{ {
contentFiles.push_back({time, path}); contentFiles.emplace_back(time, std::move(path));
found = true; found = true;
break; break;
} }
@ -985,14 +985,7 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename
std::time_t writeTime(defaultTime); std::time_t writeTime(defaultTime);
if (boost::filesystem::exists(filename)) if (boost::filesystem::exists(filename))
{ {
// FixMe: remove #if when Boost dependency for Linux builds updated
// This allows Linux to build until then
#if (BOOST_VERSION >= 104800)
// need to resolve any symlinks so that we get time of file, not symlink
boost::filesystem::path resolved = boost::filesystem::canonical(filename); boost::filesystem::path resolved = boost::filesystem::canonical(filename);
#else
boost::filesystem::path resolved = filename;
#endif
writeTime = boost::filesystem::last_write_time(resolved); writeTime = boost::filesystem::last_write_time(resolved);
// print timestamp // print timestamp

View file

@ -132,6 +132,7 @@ int main(int argc, char **argv)
if(!parseOptions (argc, argv, files)) if(!parseOptions (argc, argv, files))
return 1; return 1;
Nif::NIFFile::setLoadUnsupportedFiles(true);
// std::cout << "Reading Files" << std::endl; // std::cout << "Reading Files" << std::endl;
for(std::vector<std::string>::const_iterator it=files.begin(); it!=files.end(); ++it) for(std::vector<std::string>::const_iterator it=files.begin(); it!=files.end(); ++it)
{ {

View file

@ -89,10 +89,10 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
desc.add_options() desc.add_options()
("data", boost::program_options::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing()) ("data", boost::program_options::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing())
("data-local", boost::program_options::value<Files::EscapeHashString>()->default_value("")) ("data-local", boost::program_options::value<Files::EscapePath>()->default_value(Files::EscapePath(), ""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false)) ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<Files::EscapeHashString>()->default_value("win1252")) ("encoding", boost::program_options::value<Files::EscapeHashString>()->default_value("win1252"))
("resources", boost::program_options::value<Files::EscapeHashString>()->default_value("resources")) ("resources", boost::program_options::value<Files::EscapePath>()->default_value(Files::EscapePath(), "resources"))
("fallback-archive", boost::program_options::value<Files::EscapeStringVector>()-> ("fallback-archive", boost::program_options::value<Files::EscapeStringVector>()->
default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken()) default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken())
("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "") ("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")
@ -112,7 +112,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName)); mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName));
mFileDialog.setEncoding (QString::fromUtf8(mEncodingName.c_str())); mFileDialog.setEncoding (QString::fromUtf8(mEncodingName.c_str()));
mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapeHashString>().toStdString()); mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapePath>().mPath);
if (variables["script-blacklist-use"].as<bool>()) if (variables["script-blacklist-use"].as<bool>())
mDocumentManager.setBlacklistedScripts ( mDocumentManager.setBlacklistedScripts (
@ -125,14 +125,9 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>())); dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>()));
} }
std::string local = variables["data-local"].as<Files::EscapeHashString>().toStdString(); Files::PathContainer::value_type local(variables["data-local"].as<Files::EscapePath>().mPath);
if (!local.empty()) if (!local.empty())
{ dataLocal.push_back(local);
if (local.front() == '\"')
local = local.substr(1, local.length() - 2);
dataLocal.push_back(Files::PathContainer::value_type(local));
}
mCfgMgr.processPaths (dataDirs); mCfgMgr.processPaths (dataDirs);
mCfgMgr.processPaths (dataLocal, true); mCfgMgr.processPaths (dataLocal, true);
@ -229,7 +224,7 @@ void CS::Editor::openFiles (const boost::filesystem::path &savePath, const std::
if(discoveredFiles.empty()) if(discoveredFiles.empty())
{ {
for (const QString &path : mFileDialog.selectedFilePaths()) for (const QString &path : mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData()); files.emplace_back(path.toUtf8().constData());
} }
else else
{ {
@ -246,7 +241,7 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
std::vector<boost::filesystem::path> files; std::vector<boost::filesystem::path> files;
for (const QString &path : mFileDialog.selectedFilePaths()) { for (const QString &path : mFileDialog.selectedFilePaths()) {
files.push_back(path.toUtf8().constData()); files.emplace_back(path.toUtf8().constData());
} }
files.push_back (savePath); files.push_back (savePath);

View file

@ -47,9 +47,6 @@ int runApplication(int argc, char *argv[])
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0); setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
#endif #endif
// To allow background thread drawing in OSG
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
Q_INIT_RESOURCE (resources); Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string"); qRegisterMetaType<std::string> ("std::string");

View file

@ -127,7 +127,7 @@ void CSMDoc::Loader::load()
void CSMDoc::Loader::loadDocument (CSMDoc::Document *document) void CSMDoc::Loader::loadDocument (CSMDoc::Document *document)
{ {
mDocuments.push_back (std::make_pair (document, Stage())); mDocuments.emplace_back (document, Stage());
} }
void CSMDoc::Loader::abortLoading (CSMDoc::Document *document) void CSMDoc::Loader::abortLoading (CSMDoc::Document *document)

View file

@ -57,7 +57,7 @@ void CSMDoc::Operation::run()
void CSMDoc::Operation::appendStage (Stage *stage) void CSMDoc::Operation::appendStage (Stage *stage)
{ {
mStages.push_back (std::make_pair (stage, 0)); mStages.emplace_back (stage, 0);
} }
void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity) void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity)

View file

@ -35,7 +35,7 @@ CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const EnumValue& value)
CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const std::string& value, const std::string& tooltip) CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const std::string& value, const std::string& tooltip)
{ {
mValues.push_back (EnumValue (value, tooltip)); mValues.emplace_back(value, tooltip);
return *this; return *this;
} }

View file

@ -182,7 +182,7 @@ namespace CSMPrefs
} }
else if (pos == lastPos) else if (pos == lastPos)
{ {
potentials.push_back(std::make_pair(result, shortcut)); potentials.emplace_back(result, shortcut);
} }
} }
} }

View file

@ -127,7 +127,7 @@ std::vector<CSMWorld::UniversalId> CSMWorld::CommandDispatcher::getExtendedTypes
if (mId==UniversalId::Type_Cells) if (mId==UniversalId::Type_Cells)
{ {
tables.push_back (mId); tables.push_back (mId);
tables.push_back (UniversalId::Type_References); tables.emplace_back(UniversalId::Type_References);
/// \todo add other cell-specific types /// \todo add other cell-specific types
} }

View file

@ -355,7 +355,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
// If it does not exist or it is in the current plugin, it can be skipped. // If it does not exist or it is in the current plugin, it can be skipped.
if (oldRow < 0 || plugin == 0) if (oldRow < 0 || plugin == 0)
{ {
results.recordMapping.push_back(std::make_pair(id, id)); results.recordMapping.emplace_back(id, id);
continue; continue;
} }
@ -366,7 +366,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
auto searchIt = reverseLookupMap.find(texture); auto searchIt = reverseLookupMap.find(texture);
if (searchIt != reverseLookupMap.end()) if (searchIt != reverseLookupMap.end())
{ {
results.recordMapping.push_back(std::make_pair(id, searchIt->second)); results.recordMapping.emplace_back(id, searchIt->second);
continue; continue;
} }
@ -381,7 +381,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
// Id not taken, clone it // Id not taken, clone it
cloneRecord(id, newId, UniversalId::Type_LandTexture); cloneRecord(id, newId, UniversalId::Type_LandTexture);
results.createdRecords.push_back(newId); results.createdRecords.push_back(newId);
results.recordMapping.push_back(std::make_pair(id, newId)); results.recordMapping.emplace_back(id, newId);
reverseLookupMap.emplace(texture, newId); reverseLookupMap.emplace(texture, newId);
break; break;
} }

View file

@ -64,6 +64,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
// ignore content file number // ignore content file number
std::map<ESM::RefNum, std::string>::iterator iter = cache.begin(); std::map<ESM::RefNum, std::string>::iterator iter = cache.begin();
ref.mRefNum.mIndex = ref.mRefNum.mIndex & 0x00ffffff;
for (; iter != cache.end(); ++iter) for (; iter != cache.end(); ++iter)
{ {
if (ref.mRefNum.mIndex == iter->first.mIndex) if (ref.mRefNum.mIndex == iter->first.mIndex)

View file

@ -40,45 +40,45 @@ CSMWorld::RefIdCollection::RefIdCollection()
{ {
BaseColumns baseColumns; BaseColumns baseColumns;
mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_Id, mColumns.emplace_back(Columns::ColumnId_Id, ColumnBase::Display_Id,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false);
baseColumns.mId = &mColumns.back(); baseColumns.mId = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState, mColumns.emplace_back(Columns::ColumnId_Modification, ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true, false);
baseColumns.mModified = &mColumns.back(); baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType, mColumns.emplace_back(Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false);
baseColumns.mType = &mColumns.back(); baseColumns.mType = &mColumns.back();
ModelColumns modelColumns (baseColumns); ModelColumns modelColumns (baseColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Model, ColumnBase::Display_Mesh)); mColumns.emplace_back(Columns::ColumnId_Model, ColumnBase::Display_Mesh);
modelColumns.mModel = &mColumns.back(); modelColumns.mModel = &mColumns.back();
NameColumns nameColumns (modelColumns); NameColumns nameColumns (modelColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Name, ColumnBase::Display_String)); mColumns.emplace_back(Columns::ColumnId_Name, ColumnBase::Display_String);
nameColumns.mName = &mColumns.back(); nameColumns.mName = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Script, ColumnBase::Display_Script)); mColumns.emplace_back(Columns::ColumnId_Script, ColumnBase::Display_Script);
nameColumns.mScript = &mColumns.back(); nameColumns.mScript = &mColumns.back();
InventoryColumns inventoryColumns (nameColumns); InventoryColumns inventoryColumns (nameColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Icon, ColumnBase::Display_Icon)); mColumns.emplace_back(Columns::ColumnId_Icon, ColumnBase::Display_Icon);
inventoryColumns.mIcon = &mColumns.back(); inventoryColumns.mIcon = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Weight, ColumnBase::Display_Float)); mColumns.emplace_back(Columns::ColumnId_Weight, ColumnBase::Display_Float);
inventoryColumns.mWeight = &mColumns.back(); inventoryColumns.mWeight = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_CoinValue, ColumnBase::Display_Integer);
inventoryColumns.mValue = &mColumns.back(); inventoryColumns.mValue = &mColumns.back();
IngredientColumns ingredientColumns (inventoryColumns); IngredientColumns ingredientColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, mColumns.emplace_back(Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
ingredientColumns.mEffects = &mColumns.back(); ingredientColumns.mEffects = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> ingredientEffectsMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> ingredientEffectsMap;
ingredientEffectsMap.insert(std::make_pair(UniversalId::Type_Ingredient, ingredientEffectsMap.insert(std::make_pair(UniversalId::Type_Ingredient,
new IngredEffectRefIdAdapter ())); new IngredEffectRefIdAdapter ()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap)); mNestedAdapters.emplace_back(&mColumns.back(), ingredientEffectsMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_IngredEffectId)); new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_IngredEffectId));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -88,13 +88,13 @@ CSMWorld::RefIdCollection::RefIdCollection()
// nested table // nested table
PotionColumns potionColumns (inventoryColumns); PotionColumns potionColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, mColumns.emplace_back(Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp
std::map<UniversalId::Type, NestedRefIdAdapterBase*> effectsMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> effectsMap;
effectsMap.insert(std::make_pair(UniversalId::Type_Potion, effectsMap.insert(std::make_pair(UniversalId::Type_Potion,
new EffectsRefIdAdapter<ESM::Potion> (UniversalId::Type_Potion))); new EffectsRefIdAdapter<ESM::Potion> (UniversalId::Type_Potion)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); mNestedAdapters.emplace_back(&mColumns.back(), effectsMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -114,67 +114,67 @@ CSMWorld::RefIdCollection::RefIdCollection()
EnchantableColumns enchantableColumns (inventoryColumns); EnchantableColumns enchantableColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment)); mColumns.emplace_back(Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment);
enchantableColumns.mEnchantment = &mColumns.back(); enchantableColumns.mEnchantment = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer);
enchantableColumns.mEnchantmentPoints = &mColumns.back(); enchantableColumns.mEnchantmentPoints = &mColumns.back();
ToolColumns toolsColumns (inventoryColumns); ToolColumns toolsColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Quality, ColumnBase::Display_Float)); mColumns.emplace_back(Columns::ColumnId_Quality, ColumnBase::Display_Float);
toolsColumns.mQuality = &mColumns.back(); toolsColumns.mQuality = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Charges, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_Charges, ColumnBase::Display_Integer);
toolsColumns.mUses = &mColumns.back(); toolsColumns.mUses = &mColumns.back();
ActorColumns actorsColumns (nameColumns); ActorColumns actorsColumns (nameColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger16)); mColumns.emplace_back(Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger16);
actorsColumns.mHello = &mColumns.back(); actorsColumns.mHello = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8)); mColumns.emplace_back(Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8);
actorsColumns.mFlee = &mColumns.back(); actorsColumns.mFlee = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFight, ColumnBase::Display_UnsignedInteger8)); mColumns.emplace_back(Columns::ColumnId_AiFight, ColumnBase::Display_UnsignedInteger8);
actorsColumns.mFight = &mColumns.back(); actorsColumns.mFight = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_UnsignedInteger8)); mColumns.emplace_back(Columns::ColumnId_AiAlarm, ColumnBase::Display_UnsignedInteger8);
actorsColumns.mAlarm = &mColumns.back(); actorsColumns.mAlarm = &mColumns.back();
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, mColumns.emplace_back(Columns::ColumnId_ActorInventory,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mInventory = &mColumns.back(); actorsColumns.mInventory = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> inventoryMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> inventoryMap;
inventoryMap.insert(std::make_pair(UniversalId::Type_Npc, inventoryMap.insert(std::make_pair(UniversalId::Type_Npc,
new NestedInventoryRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc))); new NestedInventoryRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
inventoryMap.insert(std::make_pair(UniversalId::Type_Creature, inventoryMap.insert(std::make_pair(UniversalId::Type_Creature,
new NestedInventoryRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new NestedInventoryRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mNestedAdapters.emplace_back(&mColumns.back(), inventoryMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, mColumns.emplace_back(Columns::ColumnId_SpellList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mSpells = &mColumns.back(); actorsColumns.mSpells = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> spellsMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> spellsMap;
spellsMap.insert(std::make_pair(UniversalId::Type_Npc, spellsMap.insert(std::make_pair(UniversalId::Type_Npc,
new NestedSpellRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc))); new NestedSpellRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
spellsMap.insert(std::make_pair(UniversalId::Type_Creature, spellsMap.insert(std::make_pair(UniversalId::Type_Creature,
new NestedSpellRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new NestedSpellRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mNestedAdapters.emplace_back(&mColumns.back(), spellsMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell)); new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, mColumns.emplace_back(Columns::ColumnId_NpcDestinations,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mDestinations = &mColumns.back(); actorsColumns.mDestinations = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> destMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> destMap;
destMap.insert(std::make_pair(UniversalId::Type_Npc, destMap.insert(std::make_pair(UniversalId::Type_Npc,
new NestedTravelRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc))); new NestedTravelRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
destMap.insert(std::make_pair(UniversalId::Type_Creature, destMap.insert(std::make_pair(UniversalId::Type_Creature,
new NestedTravelRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new NestedTravelRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mNestedAdapters.emplace_back(&mColumns.back(), destMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell)); new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -191,15 +191,15 @@ CSMWorld::RefIdCollection::RefIdCollection()
new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Double)); new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Double));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, mColumns.emplace_back(Columns::ColumnId_AiPackageList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mAiPackages = &mColumns.back(); actorsColumns.mAiPackages = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> aiMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> aiMap;
aiMap.insert(std::make_pair(UniversalId::Type_Npc, aiMap.insert(std::make_pair(UniversalId::Type_Npc,
new ActorAiRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc))); new ActorAiRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
aiMap.insert(std::make_pair(UniversalId::Type_Creature, aiMap.insert(std::make_pair(UniversalId::Type_Creature,
new ActorAiRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new ActorAiRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); mNestedAdapters.emplace_back(&mColumns.back(), aiMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AiPackageType, CSMWorld::ColumnBase::Display_AiPackageType)); new RefIdColumn (Columns::ColumnId_AiPackageType, CSMWorld::ColumnBase::Display_AiPackageType));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -270,56 +270,56 @@ CSMWorld::RefIdCollection::RefIdCollection()
for (int i=0; sServiceTable[i].mName!=-1; ++i) for (int i=0; sServiceTable[i].mName!=-1; ++i)
{ {
mColumns.push_back (RefIdColumn (sServiceTable[i].mName, ColumnBase::Display_Boolean)); mColumns.emplace_back(sServiceTable[i].mName, ColumnBase::Display_Boolean);
actorsColumns.mServices.insert (std::make_pair (&mColumns.back(), sServiceTable[i].mFlag)); actorsColumns.mServices.insert (std::make_pair (&mColumns.back(), sServiceTable[i].mFlag));
} }
mColumns.push_back (RefIdColumn (Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean, mColumns.emplace_back(Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh);
const RefIdColumn *autoCalc = &mColumns.back(); const RefIdColumn *autoCalc = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_ApparatusType, mColumns.emplace_back(Columns::ColumnId_ApparatusType,
ColumnBase::Display_ApparatusType)); ColumnBase::Display_ApparatusType);
const RefIdColumn *apparatusType = &mColumns.back(); const RefIdColumn *apparatusType = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_ArmorType, ColumnBase::Display_ArmorType)); mColumns.emplace_back(Columns::ColumnId_ArmorType, ColumnBase::Display_ArmorType);
const RefIdColumn *armorType = &mColumns.back(); const RefIdColumn *armorType = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Health, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_Health, ColumnBase::Display_Integer);
const RefIdColumn *health = &mColumns.back(); const RefIdColumn *health = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_ArmorValue, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_ArmorValue, ColumnBase::Display_Integer);
const RefIdColumn *armor = &mColumns.back(); const RefIdColumn *armor = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_BookType, ColumnBase::Display_BookType)); mColumns.emplace_back(Columns::ColumnId_BookType, ColumnBase::Display_BookType);
const RefIdColumn *bookType = &mColumns.back(); const RefIdColumn *bookType = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mColumns.emplace_back(Columns::ColumnId_Skill, ColumnBase::Display_SkillId);
const RefIdColumn *skill = &mColumns.back(); const RefIdColumn *skill = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Text, ColumnBase::Display_LongString)); mColumns.emplace_back(Columns::ColumnId_Text, ColumnBase::Display_LongString);
const RefIdColumn *text = &mColumns.back(); const RefIdColumn *text = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_ClothingType, ColumnBase::Display_ClothingType)); mColumns.emplace_back(Columns::ColumnId_ClothingType, ColumnBase::Display_ClothingType);
const RefIdColumn *clothingType = &mColumns.back(); const RefIdColumn *clothingType = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeightCapacity, ColumnBase::Display_Float)); mColumns.emplace_back(Columns::ColumnId_WeightCapacity, ColumnBase::Display_Float);
const RefIdColumn *weightCapacity = &mColumns.back(); const RefIdColumn *weightCapacity = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_OrganicContainer, ColumnBase::Display_Boolean)); mColumns.emplace_back(Columns::ColumnId_OrganicContainer, ColumnBase::Display_Boolean);
const RefIdColumn *organic = &mColumns.back(); const RefIdColumn *organic = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); mColumns.emplace_back(Columns::ColumnId_Respawn, ColumnBase::Display_Boolean);
const RefIdColumn *respawn = &mColumns.back(); const RefIdColumn *respawn = &mColumns.back();
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, mColumns.emplace_back(Columns::ColumnId_ContainerContent,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
const RefIdColumn *content = &mColumns.back(); const RefIdColumn *content = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> contMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> contMap;
contMap.insert(std::make_pair(UniversalId::Type_Container, contMap.insert(std::make_pair(UniversalId::Type_Container,
new NestedInventoryRefIdAdapter<ESM::Container> (UniversalId::Type_Container))); new NestedInventoryRefIdAdapter<ESM::Container> (UniversalId::Type_Container)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); mNestedAdapters.emplace_back(&mColumns.back(), contMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -327,11 +327,11 @@ CSMWorld::RefIdCollection::RefIdCollection()
CreatureColumns creatureColumns (actorsColumns); CreatureColumns creatureColumns (actorsColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); mColumns.emplace_back(Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType);
creatureColumns.mType = &mColumns.back(); creatureColumns.mType = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); mColumns.emplace_back(Columns::ColumnId_Scale, ColumnBase::Display_Float);
creatureColumns.mScale = &mColumns.back(); creatureColumns.mScale = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_ParentCreature, ColumnBase::Display_Creature)); mColumns.emplace_back(Columns::ColumnId_ParentCreature, ColumnBase::Display_Creature);
creatureColumns.mOriginal = &mColumns.back(); creatureColumns.mOriginal = &mColumns.back();
static const struct static const struct
@ -354,7 +354,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
for (int i=0; sCreatureFlagTable[i].mName!=-1; ++i) for (int i=0; sCreatureFlagTable[i].mName!=-1; ++i)
{ {
mColumns.push_back (RefIdColumn (sCreatureFlagTable[i].mName, ColumnBase::Display_Boolean)); mColumns.emplace_back(sCreatureFlagTable[i].mName, ColumnBase::Display_Boolean);
creatureColumns.mFlags.insert (std::make_pair (&mColumns.back(), sCreatureFlagTable[i].mFlag)); creatureColumns.mFlags.insert (std::make_pair (&mColumns.back(), sCreatureFlagTable[i].mFlag));
switch (sCreatureFlagTable[i].mFlag) switch (sCreatureFlagTable[i].mFlag)
@ -363,7 +363,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
} }
} }
mColumns.push_back(RefIdColumn(Columns::ColumnId_BloodType, ColumnBase::Display_BloodType)); mColumns.emplace_back(Columns::ColumnId_BloodType, ColumnBase::Display_BloodType);
// For re-use in NPC records. // For re-use in NPC records.
const RefIdColumn *bloodType = &mColumns.back(); const RefIdColumn *bloodType = &mColumns.back();
creatureColumns.mBloodType = bloodType; creatureColumns.mBloodType = bloodType;
@ -371,24 +371,24 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttributes, mColumns.emplace_back(Columns::ColumnId_CreatureAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
creatureColumns.mAttributes = &mColumns.back(); creatureColumns.mAttributes = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaAttrMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaAttrMap;
creaAttrMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttributesRefIdAdapter())); creaAttrMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttributesRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaAttrMap)); mNestedAdapters.emplace_back(&mColumns.back(), creaAttrMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttack, mColumns.emplace_back(Columns::ColumnId_CreatureAttack,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
creatureColumns.mAttacks = &mColumns.back(); creatureColumns.mAttacks = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> attackMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> attackMap;
attackMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttackRefIdAdapter())); attackMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttackRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attackMap)); mNestedAdapters.emplace_back(&mColumns.back(), attackMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false)); new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -397,12 +397,12 @@ CSMWorld::RefIdCollection::RefIdCollection()
new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer));
// Nested list // Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureMisc, mColumns.emplace_back(Columns::ColumnId_CreatureMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List);
creatureColumns.mMisc = &mColumns.back(); creatureColumns.mMisc = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaMiscMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaMiscMap;
creaMiscMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureMiscRefIdAdapter())); creaMiscMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureMiscRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaMiscMap)); mNestedAdapters.emplace_back(&mColumns.back(), creaMiscMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer, new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer,
ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
@ -423,27 +423,27 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer));
mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound)); mColumns.emplace_back(Columns::ColumnId_OpenSound, ColumnBase::Display_Sound);
const RefIdColumn *openSound = &mColumns.back(); const RefIdColumn *openSound = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_CloseSound, ColumnBase::Display_Sound)); mColumns.emplace_back(Columns::ColumnId_CloseSound, ColumnBase::Display_Sound);
const RefIdColumn *closeSound = &mColumns.back(); const RefIdColumn *closeSound = &mColumns.back();
LightColumns lightColumns (inventoryColumns); LightColumns lightColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_Duration, ColumnBase::Display_Integer);
lightColumns.mTime = &mColumns.back(); lightColumns.mTime = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Radius, ColumnBase::Display_Integer)); mColumns.emplace_back(Columns::ColumnId_Radius, ColumnBase::Display_Integer);
lightColumns.mRadius = &mColumns.back(); lightColumns.mRadius = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Colour)); mColumns.emplace_back(Columns::ColumnId_Colour, ColumnBase::Display_Colour);
lightColumns.mColor = &mColumns.back(); lightColumns.mColor = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_Sound)); mColumns.emplace_back(Columns::ColumnId_Sound, ColumnBase::Display_Sound);
lightColumns.mSound = &mColumns.back(); lightColumns.mSound = &mColumns.back();
mColumns.push_back(RefIdColumn(Columns::ColumnId_EmitterType, ColumnBase::Display_EmitterType)); mColumns.emplace_back(Columns::ColumnId_EmitterType, ColumnBase::Display_EmitterType);
lightColumns.mEmitterType = &mColumns.back(); lightColumns.mEmitterType = &mColumns.back();
static const struct static const struct
@ -462,31 +462,31 @@ CSMWorld::RefIdCollection::RefIdCollection()
for (int i=0; sLightFlagTable[i].mName!=-1; ++i) for (int i=0; sLightFlagTable[i].mName!=-1; ++i)
{ {
mColumns.push_back (RefIdColumn (sLightFlagTable[i].mName, ColumnBase::Display_Boolean)); mColumns.emplace_back(sLightFlagTable[i].mName, ColumnBase::Display_Boolean);
lightColumns.mFlags.insert (std::make_pair (&mColumns.back(), sLightFlagTable[i].mFlag)); lightColumns.mFlags.insert (std::make_pair (&mColumns.back(), sLightFlagTable[i].mFlag));
} }
mColumns.push_back (RefIdColumn (Columns::ColumnId_IsKey, ColumnBase::Display_Boolean)); mColumns.emplace_back(Columns::ColumnId_IsKey, ColumnBase::Display_Boolean);
const RefIdColumn *key = &mColumns.back(); const RefIdColumn *key = &mColumns.back();
NpcColumns npcColumns (actorsColumns); NpcColumns npcColumns (actorsColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Race, ColumnBase::Display_Race)); mColumns.emplace_back(Columns::ColumnId_Race, ColumnBase::Display_Race);
npcColumns.mRace = &mColumns.back(); npcColumns.mRace = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_Class)); mColumns.emplace_back(Columns::ColumnId_Class, ColumnBase::Display_Class);
npcColumns.mClass = &mColumns.back(); npcColumns.mClass = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); mColumns.emplace_back(Columns::ColumnId_Faction, ColumnBase::Display_Faction);
npcColumns.mFaction = &mColumns.back(); npcColumns.mFaction = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart)); mColumns.emplace_back(Columns::Columnid_Hair, ColumnBase::Display_BodyPart);
npcColumns.mHair = &mColumns.back(); npcColumns.mHair = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart)); mColumns.emplace_back(Columns::ColumnId_Head, ColumnBase::Display_BodyPart);
npcColumns.mHead = &mColumns.back(); npcColumns.mHead = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Gender, ColumnBase::Display_GenderNpc)); mColumns.emplace_back(Columns::ColumnId_Gender, ColumnBase::Display_GenderNpc);
npcColumns.mGender = &mColumns.back(); npcColumns.mGender = &mColumns.back();
npcColumns.mFlags.insert (std::make_pair (essential, ESM::NPC::Essential)); npcColumns.mFlags.insert (std::make_pair (essential, ESM::NPC::Essential));
@ -503,36 +503,36 @@ CSMWorld::RefIdCollection::RefIdCollection()
// These needs to be driven from the autocalculated setting. // These needs to be driven from the autocalculated setting.
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcAttributes, mColumns.emplace_back(Columns::ColumnId_NpcAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
npcColumns.mAttributes = &mColumns.back(); npcColumns.mAttributes = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> attrMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> attrMap;
attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter())); attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap)); mNestedAdapters.emplace_back(&mColumns.back(), attrMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_UnsignedInteger8)); new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_UnsignedInteger8));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcSkills, mColumns.emplace_back(Columns::ColumnId_NpcSkills,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
npcColumns.mSkills = &mColumns.back(); npcColumns.mSkills = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> skillsMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> skillsMap;
skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); mNestedAdapters.emplace_back(&mColumns.back(), skillsMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false)); new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_UnsignedInteger8)); new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_UnsignedInteger8));
// Nested list // Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcMisc, mColumns.emplace_back(Columns::ColumnId_NpcMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List);
npcColumns.mMisc = &mColumns.back(); npcColumns.mMisc = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> miscMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> miscMap;
miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter())); miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); mNestedAdapters.emplace_back(&mColumns.back(), miscMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_SignedInteger16)); new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_SignedInteger16));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -554,15 +554,15 @@ CSMWorld::RefIdCollection::RefIdCollection()
WeaponColumns weaponColumns (enchantableColumns); WeaponColumns weaponColumns (enchantableColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); mColumns.emplace_back(Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType);
weaponColumns.mType = &mColumns.back(); weaponColumns.mType = &mColumns.back();
weaponColumns.mHealth = health; weaponColumns.mHealth = health;
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponSpeed, ColumnBase::Display_Float)); mColumns.emplace_back(Columns::ColumnId_WeaponSpeed, ColumnBase::Display_Float);
weaponColumns.mSpeed = &mColumns.back(); weaponColumns.mSpeed = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float)); mColumns.emplace_back(Columns::ColumnId_WeaponReach, ColumnBase::Display_Float);
weaponColumns.mReach = &mColumns.back(); weaponColumns.mReach = &mColumns.back();
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
@ -572,8 +572,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
for (int j=0; j<2; ++j) for (int j=0; j<2; ++j)
{ {
mColumns.push_back ( mColumns.emplace_back(Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer);
RefIdColumn (Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer));
column[j] = &mColumns.back(); column[j] = &mColumns.back();
} }
} }
@ -591,19 +590,19 @@ CSMWorld::RefIdCollection::RefIdCollection()
for (int i=0; sWeaponFlagTable[i].mName!=-1; ++i) for (int i=0; sWeaponFlagTable[i].mName!=-1; ++i)
{ {
mColumns.push_back (RefIdColumn (sWeaponFlagTable[i].mName, ColumnBase::Display_Boolean)); mColumns.emplace_back(sWeaponFlagTable[i].mName, ColumnBase::Display_Boolean);
weaponColumns.mFlags.insert (std::make_pair (&mColumns.back(), sWeaponFlagTable[i].mFlag)); weaponColumns.mFlags.insert (std::make_pair (&mColumns.back(), sWeaponFlagTable[i].mFlag));
} }
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_PartRefList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); mColumns.emplace_back(Columns::ColumnId_PartRefList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
const RefIdColumn *partRef = &mColumns.back(); const RefIdColumn *partRef = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> partMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> partMap;
partMap.insert(std::make_pair(UniversalId::Type_Armor, partMap.insert(std::make_pair(UniversalId::Type_Armor,
new BodyPartRefIdAdapter<ESM::Armor> (UniversalId::Type_Armor))); new BodyPartRefIdAdapter<ESM::Armor> (UniversalId::Type_Armor)));
partMap.insert(std::make_pair(UniversalId::Type_Clothing, partMap.insert(std::make_pair(UniversalId::Type_Clothing,
new BodyPartRefIdAdapter<ESM::Clothing> (UniversalId::Type_Clothing))); new BodyPartRefIdAdapter<ESM::Clothing> (UniversalId::Type_Clothing)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); mNestedAdapters.emplace_back(&mColumns.back(), partMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -614,30 +613,30 @@ CSMWorld::RefIdCollection::RefIdCollection()
LevListColumns levListColumns (baseColumns); LevListColumns levListColumns (baseColumns);
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList, mColumns.emplace_back(Columns::ColumnId_LevelledList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
levListColumns.mLevList = &mColumns.back(); levListColumns.mLevList = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> levListMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> levListMap;
levListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList, levListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList,
new NestedLevListRefIdAdapter<ESM::CreatureLevList> (UniversalId::Type_CreatureLevelledList))); new NestedLevListRefIdAdapter<ESM::CreatureLevList> (UniversalId::Type_CreatureLevelledList)));
levListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList, levListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList,
new NestedLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList))); new NestedLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); mNestedAdapters.emplace_back(&mColumns.back(), levListMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable)); new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer));
// Nested list // Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList, mColumns.emplace_back(Columns::ColumnId_LevelledList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List);
levListColumns.mNestedListLevList = &mColumns.back(); levListColumns.mNestedListLevList = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> nestedListLevListMap; std::map<UniversalId::Type, NestedRefIdAdapterBase*> nestedListLevListMap;
nestedListLevListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList, nestedListLevListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList,
new NestedListLevListRefIdAdapter<ESM::CreatureLevList> (UniversalId::Type_CreatureLevelledList))); new NestedListLevListRefIdAdapter<ESM::CreatureLevList> (UniversalId::Type_CreatureLevelledList)));
nestedListLevListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList, nestedListLevListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList,
new NestedListLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList))); new NestedListLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), nestedListLevListMap)); mNestedAdapters.emplace_back(&mColumns.back(), nestedListLevListMap);
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemTypeEach, CSMWorld::ColumnBase::Display_Boolean)); new RefIdColumn (Columns::ColumnId_LevelledItemTypeEach, CSMWorld::ColumnBase::Display_Boolean));
mColumns.back().addColumn( mColumns.back().addColumn(

View file

@ -553,7 +553,7 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
result.push_back (iter->second->getTag()); result.push_back (iter->second->getTag());
if (mPathgrid && elementMask & Mask_Pathgrid) if (mPathgrid && elementMask & Mask_Pathgrid)
if (mPathgrid->isSelected()) if (mPathgrid->isSelected())
result.push_back(mPathgrid->getTag()); result.emplace_back(mPathgrid->getTag());
return result; return result;
} }

View file

@ -59,38 +59,38 @@ namespace CSVRender
/// Editmode for terrain shape grid /// Editmode for terrain shape grid
TerrainShapeMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr); TerrainShapeMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr);
void primaryOpenPressed (const WorldspaceHitResult& hit) final; void primaryOpenPressed (const WorldspaceHitResult& hit) override;
/// Create single command for one-click shape editing /// Create single command for one-click shape editing
void primaryEditPressed (const WorldspaceHitResult& hit) final; void primaryEditPressed (const WorldspaceHitResult& hit) override;
/// Open brush settings window /// Open brush settings window
void primarySelectPressed(const WorldspaceHitResult&) final; void primarySelectPressed(const WorldspaceHitResult&) override;
void secondarySelectPressed(const WorldspaceHitResult&) final; void secondarySelectPressed(const WorldspaceHitResult&) override;
void activate(CSVWidget::SceneToolbar*) final; void activate(CSVWidget::SceneToolbar*) override;
void deactivate(CSVWidget::SceneToolbar*) final; void deactivate(CSVWidget::SceneToolbar*) override;
/// Start shape editing command macro /// Start shape editing command macro
bool primaryEditStartDrag (const QPoint& pos) final; bool primaryEditStartDrag (const QPoint& pos) override;
bool secondaryEditStartDrag (const QPoint& pos) final; bool secondaryEditStartDrag (const QPoint& pos) override;
bool primarySelectStartDrag (const QPoint& pos) final; bool primarySelectStartDrag (const QPoint& pos) override;
bool secondarySelectStartDrag (const QPoint& pos) final; bool secondarySelectStartDrag (const QPoint& pos) override;
/// Handle shape edit behavior during dragging /// Handle shape edit behavior during dragging
void drag (const QPoint& pos, int diffX, int diffY, double speedFactor) final; void drag (const QPoint& pos, int diffX, int diffY, double speedFactor) override;
/// End shape editing command macro /// End shape editing command macro
void dragCompleted(const QPoint& pos) final; void dragCompleted(const QPoint& pos) override;
/// Cancel shape editing, and reset all pending changes /// Cancel shape editing, and reset all pending changes
void dragAborted() final; void dragAborted() override;
void dragWheel (int diff, double speedFactor) final; void dragWheel (int diff, double speedFactor) override;
void dragMoveEvent (QDragMoveEvent *event) final; void dragMoveEvent (QDragMoveEvent *event) override;
void mouseMoveEvent (QMouseEvent *event) final; void mouseMoveEvent (QMouseEvent *event) override;
private: private:

View file

@ -27,10 +27,10 @@ namespace CSVRender
const CSMWorld::Data& mData; const CSMWorld::Data& mData;
std::array<float, ESM::Land::LAND_SIZE * ESM::Land::LAND_SIZE> mAlteredHeight; std::array<float, ESM::Land::LAND_SIZE * ESM::Land::LAND_SIZE> mAlteredHeight;
osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY) final; osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY) override;
const ESM::LandTexture* getLandTexture(int index, short plugin) final; const ESM::LandTexture* getLandTexture(int index, short plugin) override;
void getBounds(float& minX, float& maxX, float& minY, float& maxY) final; void getBounds(float& minX, float& maxX, float& minY, float& maxY) override;
int getThisHeight(int col, int row, const ESM::Land::LandData *heightData) const; int getThisHeight(int col, int row, const ESM::Land::LandData *heightData) const;
int getLeftHeight(int col, int row, const ESM::Land::LandData *heightData) const; int getLeftHeight(int col, int row, const ESM::Land::LandData *heightData) const;
@ -44,8 +44,8 @@ namespace CSVRender
bool leftOrUpIsOverTheLimit(int col, int row, int heightWarningLimit, const ESM::Land::LandData *heightData) const; bool leftOrUpIsOverTheLimit(int col, int row, int heightWarningLimit, const ESM::Land::LandData *heightData) const;
bool rightOrDownIsOverTheLimit(int col, int row, int heightWarningLimit, const ESM::Land::LandData *heightData) const; bool rightOrDownIsOverTheLimit(int col, int row, int heightWarningLimit, const ESM::Land::LandData *heightData) const;
void adjustColor(int col, int row, const ESM::Land::LandData *heightData, osg::Vec4ub& color) const final; void adjustColor(int col, int row, const ESM::Land::LandData *heightData, osg::Vec4ub& color) const override;
float getAlteredHeight(int col, int row) const final; float getAlteredHeight(int col, int row) const override;
}; };
} }

View file

@ -53,37 +53,37 @@ namespace CSVRender
/// \brief Editmode for terrain texture grid /// \brief Editmode for terrain texture grid
TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr); TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr);
void primaryOpenPressed (const WorldspaceHitResult& hit) final; void primaryOpenPressed (const WorldspaceHitResult& hit) override;
/// \brief Create single command for one-click texture editing /// \brief Create single command for one-click texture editing
void primaryEditPressed (const WorldspaceHitResult& hit) final; void primaryEditPressed (const WorldspaceHitResult& hit) override;
/// \brief Open brush settings window /// \brief Open brush settings window
void primarySelectPressed(const WorldspaceHitResult&) final; void primarySelectPressed(const WorldspaceHitResult&) override;
void secondarySelectPressed(const WorldspaceHitResult&) final; void secondarySelectPressed(const WorldspaceHitResult&) override;
void activate(CSVWidget::SceneToolbar*) final; void activate(CSVWidget::SceneToolbar*) override;
void deactivate(CSVWidget::SceneToolbar*) final; void deactivate(CSVWidget::SceneToolbar*) override;
/// \brief Start texture editing command macro /// \brief Start texture editing command macro
bool primaryEditStartDrag (const QPoint& pos) final; bool primaryEditStartDrag (const QPoint& pos) override;
bool secondaryEditStartDrag (const QPoint& pos) final; bool secondaryEditStartDrag (const QPoint& pos) override;
bool primarySelectStartDrag (const QPoint& pos) final; bool primarySelectStartDrag (const QPoint& pos) override;
bool secondarySelectStartDrag (const QPoint& pos) final; bool secondarySelectStartDrag (const QPoint& pos) override;
/// \brief Handle texture edit behavior during dragging /// \brief Handle texture edit behavior during dragging
void drag (const QPoint& pos, int diffX, int diffY, double speedFactor) final; void drag (const QPoint& pos, int diffX, int diffY, double speedFactor) override;
/// \brief End texture editing command macro /// \brief End texture editing command macro
void dragCompleted(const QPoint& pos) final; void dragCompleted(const QPoint& pos) override;
void dragAborted() final; void dragAborted() override;
void dragWheel (int diff, double speedFactor) final; void dragWheel (int diff, double speedFactor) override;
void dragMoveEvent (QDragMoveEvent *event) final; void dragMoveEvent (QDragMoveEvent *event) override;
void mouseMoveEvent (QMouseEvent *event) final; void mouseMoveEvent (QMouseEvent *event) override;
private: private:
/// \brief Handle brush mechanics, maths regarding worldspace hit etc. /// \brief Handle brush mechanics, maths regarding worldspace hit etc.

View file

@ -255,8 +255,7 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
bool default_ = debugProfiles.data (debugProfiles.index (i, defaultColumn)).toInt(); bool default_ = debugProfiles.data (debugProfiles.index (i, defaultColumn)).toInt();
if (state!=CSMWorld::RecordBase::State_Deleted && default_) if (state!=CSMWorld::RecordBase::State_Deleted && default_)
profiles.push_back ( profiles.emplace_back(debugProfiles.data (debugProfiles.index (i, idColumn)).
debugProfiles.data (debugProfiles.index (i, idColumn)).
toString().toUtf8().constData()); toString().toUtf8().constData());
} }

View file

@ -32,7 +32,7 @@ void CSVWorld::DataDisplayDelegate::buildPixmaps ()
while (it != mIcons.end()) while (it != mIcons.end())
{ {
mPixmaps.push_back (std::make_pair (it->mValue, it->mIcon.pixmap (mIconSize) ) ); mPixmaps.emplace_back (it->mValue, it->mIcon.pixmap (mIconSize) );
++it; ++it;
} }
} }

View file

@ -181,5 +181,5 @@ void CSVWorld::EnumDelegateFactory::add (int value, const QString& name)
} }
} }
mValues.push_back(std::make_pair (value, name)); mValues.emplace_back (value, name);
} }

View file

@ -345,18 +345,16 @@ std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() co
std::vector<CSMWorld::UniversalId> ids; std::vector<CSMWorld::UniversalId> ids;
for (const QModelIndex& it : selected) for (const QModelIndex& it : selected)
{ {
ids.push_back( ids.emplace_back(
CSMWorld::UniversalId(
CSMWorld::UniversalId::Type_Cell, CSMWorld::UniversalId::Type_Cell,
model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData())); model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData());
} }
selected = getSelectedCells(false, true); selected = getSelectedCells(false, true);
for (const QModelIndex& it : selected) for (const QModelIndex& it : selected)
{ {
ids.push_back( ids.emplace_back(
CSMWorld::UniversalId(
CSMWorld::UniversalId::Type_Cell_Missing, CSMWorld::UniversalId::Type_Cell_Missing,
model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData())); model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData());
} }
return ids; return ids;
} }

View file

@ -452,7 +452,7 @@ std::vector<std::string> CSVWorld::Table::getSelectedIds() const
++iter) ++iter)
{ {
int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row();
ids.push_back (mModel->data (mModel->index (row, columnIndex)).toString().toUtf8().constData()); ids.emplace_back(mModel->data (mModel->index (row, columnIndex)).toString().toUtf8().constData());
} }
return ids; return ids;
} }
@ -784,7 +784,7 @@ std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::Column
if (display == columndisplay) if (display == columndisplay)
{ {
titles.push_back(mModel->headerData (i, Qt::Horizontal).toString().toUtf8().constData()); titles.emplace_back(mModel->headerData (i, Qt::Horizontal).toString().toUtf8().constData());
} }
} }
return titles; return titles;

View file

@ -133,12 +133,12 @@ void CSVWorld::TableSubView::createFilterRequest (std::vector< CSMWorld::Univers
std::vector<std::string> col = mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(type)); std::vector<std::string> col = mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(type));
if(!col.empty()) if(!col.empty())
{ {
filterSource.push_back(std::make_pair(it->getId(), col)); filterSource.emplace_back(it->getId(), col);
} }
if(hasRefIdDisplay && CSMWorld::TableMimeData::isReferencable(type)) if(hasRefIdDisplay && CSMWorld::TableMimeData::isReferencable(type))
{ {
filterSource.push_back(std::make_pair(it->getId(), refIdColumns)); filterSource.emplace_back(it->getId(), refIdColumns);
} }
} }

View file

@ -100,6 +100,7 @@ namespace
Script, Script,
Mechanics, Mechanics,
Physics, Physics,
PhysicsWorker,
World, World,
Gui, Gui,
@ -130,6 +131,9 @@ namespace
template <> template <>
const UserStats UserStatsValue<UserStatsType::Physics>::sValue {"Phys", "physics"}; const UserStats UserStatsValue<UserStatsType::Physics>::sValue {"Phys", "physics"};
template <>
const UserStats UserStatsValue<UserStatsType::PhysicsWorker>::sValue {" -Async", "physicsworker"};
template <> template <>
const UserStats UserStatsValue<UserStatsType::World>::sValue {"World", "world"}; const UserStats UserStatsValue<UserStatsType::World>::sValue {"World", "world"};
@ -209,6 +213,10 @@ namespace
profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier, profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier,
average, averageInInverseSpace, v.mBegin, v.mEnd, maxValue); average, averageInInverseSpace, v.mBegin, v.mEnd, maxValue);
}); });
// the forEachUserStatsValue loop is "run" at compile time, hence the settings manager is not available.
// Unconditionnally add the async physics stats, and then remove it at runtime if necessary
if (Settings::Manager::getInt("async num threads", "Physics") == 0)
profiler.removeUserStatsLine(" -Async");
} }
} }
@ -324,7 +332,7 @@ bool OMW::Engine::frame(float frametime)
if (mEnvironment.getStateManager()->getState() != MWBase::StateManager::State_NoGame) if (mEnvironment.getStateManager()->getState() != MWBase::StateManager::State_NoGame)
{ {
mEnvironment.getWorld()->updatePhysics(frametime, guiActive); mEnvironment.getWorld()->updatePhysics(frametime, guiActive, frameStart, frameNumber, *stats);
} }
} }

View file

@ -21,22 +21,6 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
#if (BOOST_VERSION <= 104600)
namespace boost
{
template<>
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
{
return boost::filesystem::path(arg);
}
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
using namespace Fallback; using namespace Fallback;
@ -63,20 +47,20 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("data", bpo::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data") ("data", bpo::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")
->multitoken()->composing(), "set data directories (later directories have higher priority)") ->multitoken()->composing(), "set data directories (later directories have higher priority)")
("data-local", bpo::value<Files::EscapeHashString>()->default_value(""), ("data-local", bpo::value<Files::EscapePath>()->default_value(Files::EscapePath(), ""),
"set local data directory (highest priority)") "set local data directory (highest priority)")
("fallback-archive", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "fallback-archive") ("fallback-archive", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "fallback-archive")
->multitoken(), "set fallback BSA archives (later archives have higher priority)") ->multitoken()->composing(), "set fallback BSA archives (later archives have higher priority)")
("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"), ("resources", bpo::value<Files::EscapePath>()->default_value(Files::EscapePath(), "resources"),
"set resources directory") "set resources directory")
("start", bpo::value<Files::EscapeHashString>()->default_value(""), ("start", bpo::value<Files::EscapeHashString>()->default_value(""),
"set initial cell") "set initial cell")
("content", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "") ("content", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") ->multitoken()->composing(), "content file(s): esm/esp, or omwgame/omwaddon")
("no-sound", bpo::value<bool>()->implicit_value(true) ("no-sound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds") ->default_value(false), "disable all sounds")
@ -101,12 +85,12 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
"\t2 - treat warnings as errors") "\t2 - treat warnings as errors")
("script-blacklist", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "") ("script-blacklist", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)") ->multitoken()->composing(), "ignore the specified script (if the use of the blacklist is enabled)")
("script-blacklist-use", bpo::value<bool>()->implicit_value(true) ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting") ->default_value(true), "enable script blacklisting")
("load-savegame", bpo::value<Files::EscapeHashString>()->default_value(""), ("load-savegame", bpo::value<Files::EscapePath>()->default_value(Files::EscapePath(), ""),
"load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
("skip-menu", bpo::value<bool>()->implicit_value(true) ("skip-menu", bpo::value<bool>()->implicit_value(true)
@ -159,14 +143,16 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
{ {
cfgMgr.readConfiguration(variables, desc, true); cfgMgr.readConfiguration(variables, desc, true);
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString()); Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapePath>().mPath.string());
std::cout << v.describe() << std::endl; std::cout << v.describe() << std::endl;
return false; return false;
} }
bpo::variables_map composingVariables = cfgMgr.separateComposingVariables(variables, desc);
cfgMgr.readConfiguration(variables, desc); cfgMgr.readConfiguration(variables, desc);
cfgMgr.mergeComposingVariables(variables, composingVariables, desc);
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString()); Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapePath>().mPath.string());
std::cout << v.describe() << std::endl; std::cout << v.describe() << std::endl;
engine.setGrabMouse(!variables["no-grab"].as<bool>()); engine.setGrabMouse(!variables["no-grab"].as<bool>());
@ -181,18 +167,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
Files::PathContainer dataDirs(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>())); Files::PathContainer dataDirs(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>()));
std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString()); Files::PathContainer::value_type local(variables["data-local"].as<Files::EscapePath>().mPath);
if (!local.empty()) if (!local.empty())
{ dataDirs.push_back(local);
if (local.front() == '\"')
local = local.substr(1, local.length() - 2);
dataDirs.push_back(Files::PathContainer::value_type(local));
}
cfgMgr.processPaths(dataDirs); cfgMgr.processPaths(dataDirs);
engine.setResourceDir(variables["resources"].as<Files::EscapeHashString>().toStdString()); engine.setResourceDir(variables["resources"].as<Files::EscapePath>().mPath);
engine.setDataDirs(dataDirs); engine.setDataDirs(dataDirs);
// fallback archives // fallback archives
@ -230,7 +211,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setWarningsMode (variables["script-warn"].as<int>()); engine.setWarningsMode (variables["script-warn"].as<int>());
engine.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector()); engine.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapeHashString>().toStdString()); engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapePath>().mPath.string());
// other settings // other settings
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap); Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);

View file

@ -11,6 +11,8 @@
#include <components/esm/cellid.hpp> #include <components/esm/cellid.hpp>
#include <osg/Timer>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/doorstate.hpp" #include "../mwworld/doorstate.hpp"
@ -398,7 +400,7 @@ namespace MWBase
/// \return pointer to created record /// \return pointer to created record
virtual void update (float duration, bool paused) = 0; virtual void update (float duration, bool paused) = 0;
virtual void updatePhysics (float duration, bool paused) = 0; virtual void updatePhysics (float duration, bool paused, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats) = 0;
virtual void updateWindowManager () = 0; virtual void updateWindowManager () = 0;

View file

@ -132,11 +132,11 @@ namespace MWClass
void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const override; void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const override;
float getWalkSpeed(const MWWorld::Ptr& ptr) const final; float getWalkSpeed(const MWWorld::Ptr& ptr) const override;
float getRunSpeed(const MWWorld::Ptr& ptr) const final; float getRunSpeed(const MWWorld::Ptr& ptr) const override;
float getSwimSpeed(const MWWorld::Ptr& ptr) const final; float getSwimSpeed(const MWWorld::Ptr& ptr) const override;
}; };
} }

View file

@ -432,12 +432,12 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::NPC> *npc = ptr.get<ESM::NPC>(); const MWWorld::LiveCellRef<ESM::NPC> *npc = ptr.get<ESM::NPC>();
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().search(npc->mBase->mRace); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().search(npc->mBase->mRace);
if(race && race->mData.mFlags & ESM::Race::Beast) if(race && race->mData.mFlags & ESM::Race::Beast)
models.push_back("meshes\\base_animkna.nif"); models.emplace_back("meshes\\base_animkna.nif");
// keep these always loaded just in case // keep these always loaded just in case
models.push_back("meshes/xargonian_swimkna.nif"); models.emplace_back("meshes/xargonian_swimkna.nif");
models.push_back("meshes/xbase_anim_female.nif"); models.emplace_back("meshes/xbase_anim_female.nif");
models.push_back("meshes/xbase_anim.nif"); models.emplace_back("meshes/xbase_anim.nif");
if (!npc->mBase->mModel.empty()) if (!npc->mBase->mModel.empty())
models.push_back("meshes/"+npc->mBase->mModel); models.push_back("meshes/"+npc->mBase->mModel);

View file

@ -166,11 +166,11 @@ namespace MWClass
void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const override; void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const override;
float getWalkSpeed(const MWWorld::Ptr& ptr) const final; float getWalkSpeed(const MWWorld::Ptr& ptr) const override;
float getRunSpeed(const MWWorld::Ptr& ptr) const final; float getRunSpeed(const MWWorld::Ptr& ptr) const override;
float getSwimSpeed(const MWWorld::Ptr& ptr) const final; float getSwimSpeed(const MWWorld::Ptr& ptr) const override;
}; };
} }

View file

@ -468,7 +468,7 @@ namespace MWDialogue
void DialogueManager::addChoice (const std::string& text, int choice) void DialogueManager::addChoice (const std::string& text, int choice)
{ {
mIsInChoice = true; mIsInChoice = true;
mChoices.push_back(std::make_pair(text, choice)); mChoices.emplace_back(text, choice);
} }
const std::vector<std::pair<std::string, int> >& DialogueManager::getChoices() const std::vector<std::pair<std::string, int> >& DialogueManager::getChoices()

View file

@ -73,9 +73,9 @@ namespace MWDialogue
bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) override; bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) override;
std::list<std::string> getAvailableTopics() override; std::list<std::string> getAvailableTopics() override;
int getTopicFlag(const std::string& topicId) final; int getTopicFlag(const std::string& topicId) override;
bool inJournal (const std::string& topicId, const std::string& infoId) final; bool inJournal (const std::string& topicId, const std::string& infoId) override;
void addTopic (const std::string& topic) override; void addTopic (const std::string& topic) override;

View file

@ -30,7 +30,7 @@ namespace MWDialogue
tokenizeKeywords(text.substr(iteration_pos, pos_begin - iteration_pos), result); tokenizeKeywords(text.substr(iteration_pos, pos_begin - iteration_pos), result);
std::string link = text.substr(pos_begin + 1, pos_end - pos_begin - 1); std::string link = text.substr(pos_begin + 1, pos_end - pos_begin - 1);
result.push_back(Token(link, Token::ExplicitLink)); result.emplace_back(link, Token::ExplicitLink);
iteration_pos = pos_end + 1; iteration_pos = pos_end + 1;
} }
@ -65,7 +65,7 @@ namespace MWDialogue
for (std::vector<KeywordSearch<std::string, int /*unused*/>::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it) for (std::vector<KeywordSearch<std::string, int /*unused*/>::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it)
{ {
tokens.push_back(Token(std::string(it->mBeg, it->mEnd), Token::ImplicitKeyword)); tokens.emplace_back(std::string(it->mBeg, it->mEnd), Token::ImplicitKeyword);
} }
} }

View file

@ -22,8 +22,8 @@ namespace MWGui
*/ */
void setBackgroundImage (const std::string& image, bool fixedRatio=true, bool stretch=true); void setBackgroundImage (const std::string& image, bool fixedRatio=true, bool stretch=true);
void setSize (const MyGUI::IntSize &_value) final; void setSize (const MyGUI::IntSize &_value) override;
void setCoord (const MyGUI::IntCoord &_value) final; void setCoord (const MyGUI::IntCoord &_value) override;
private: private:
MyGUI::ImageBox* mChild; MyGUI::ImageBox* mChild;

View file

@ -147,7 +147,7 @@ namespace MWGui
for (const ESM::BirthSign& sign : signs) for (const ESM::BirthSign& sign : signs)
{ {
birthSigns.push_back(std::make_pair(sign.mId, &sign)); birthSigns.emplace_back(sign.mId, &sign);
} }
std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns);

View file

@ -524,9 +524,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
break; break;
if ( lead != origin ) if ( lead != origin )
mPartialWhitespace.push_back (PartialText (style, lead, origin, space_width)); mPartialWhitespace.emplace_back(style, lead, origin, space_width);
if ( origin != extent ) if ( origin != extent )
mPartialWord.push_back (PartialText (style, origin, extent, word_width)); mPartialWord.emplace_back(style, origin, extent, word_width);
} }
} }
@ -1152,7 +1152,7 @@ public:
i->second->createDrawItem (mNode); i->second->createDrawItem (mNode);
} }
void setVisible (bool newVisible) final void setVisible (bool newVisible) override
{ {
if (mVisible == newVisible) if (mVisible == newVisible)
return; return;
@ -1174,7 +1174,7 @@ public:
} }
} }
void createDrawItem(MyGUI::ITexture* texture, MyGUI::ILayerNode* node) final void createDrawItem(MyGUI::ITexture* texture, MyGUI::ILayerNode* node) override
{ {
mNode = node; mNode = node;
@ -1242,9 +1242,9 @@ public:
// ISubWidget should not necessarily be a drawitem // ISubWidget should not necessarily be a drawitem
// in this case, it is not... // in this case, it is not...
void doRender() final { } void doRender() override { }
void _updateView () final void _updateView () override
{ {
_checkMargin(); _checkMargin();
@ -1253,7 +1253,7 @@ public:
mNode->outOfDate (i->second->mRenderItem); mNode->outOfDate (i->second->mRenderItem);
} }
void _correctView() final void _correctView() override
{ {
_checkMargin (); _checkMargin ();
@ -1263,7 +1263,7 @@ public:
} }
void destroyDrawItem() final void destroyDrawItem() override
{ {
for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i)
i->second->destroyDrawItem (mNode); i->second->destroyDrawItem (mNode);
@ -1283,24 +1283,24 @@ public:
{ {
} }
void showPage (TypesetBook::Ptr book, size_t page) final void showPage (TypesetBook::Ptr book, size_t page) override
{ {
mPageDisplay->showPage (book, page); mPageDisplay->showPage (book, page);
} }
void adviseLinkClicked (std::function <void (InteractiveId)> linkClicked) final void adviseLinkClicked (std::function <void (InteractiveId)> linkClicked) override
{ {
mPageDisplay->mLinkClicked = linkClicked; mPageDisplay->mLinkClicked = linkClicked;
} }
void unadviseLinkClicked () final void unadviseLinkClicked () override
{ {
mPageDisplay->mLinkClicked = std::function <void (InteractiveId)> (); mPageDisplay->mLinkClicked = std::function <void (InteractiveId)> ();
} }
protected: protected:
void initialiseOverride() final void initialiseOverride() override
{ {
Base::initialiseOverride(); Base::initialiseOverride();
@ -1314,24 +1314,24 @@ protected:
} }
} }
void onMouseLostFocus(Widget* _new) final void onMouseLostFocus(Widget* _new) override
{ {
// NOTE: MyGUI also fires eventMouseLostFocus for widgets that are about to be destroyed (if they had focus). // NOTE: MyGUI also fires eventMouseLostFocus for widgets that are about to be destroyed (if they had focus).
// Child widgets may already be destroyed! So be careful. // Child widgets may already be destroyed! So be careful.
mPageDisplay->onMouseLostFocus (); mPageDisplay->onMouseLostFocus ();
} }
void onMouseMove(int left, int top) final void onMouseMove(int left, int top) override
{ {
mPageDisplay->onMouseMove (left, top); mPageDisplay->onMouseMove (left, top);
} }
void onMouseButtonPressed (int left, int top, MyGUI::MouseButton id) final void onMouseButtonPressed (int left, int top, MyGUI::MouseButton id) override
{ {
mPageDisplay->onMouseButtonPressed (left, top, id); mPageDisplay->onMouseButtonPressed (left, top, id);
} }
void onMouseButtonReleased(int left, int top, MyGUI::MouseButton id) final void onMouseButtonReleased(int left, int top, MyGUI::MouseButton id) override
{ {
mPageDisplay->onMouseButtonReleased (left, top, id); mPageDisplay->onMouseButtonReleased (left, top, id);
} }

View file

@ -217,7 +217,7 @@ namespace MWGui
if (store.get<ESM::Class>().isDynamic(classInfo.mId)) if (store.get<ESM::Class>().isDynamic(classInfo.mId))
continue; // custom-made class not relevant for this dialog continue; // custom-made class not relevant for this dialog
items.push_back(std::make_pair(classInfo.mId, classInfo.mName)); items.emplace_back(classInfo.mId, classInfo.mName);
} }
std::sort(items.begin(), items.end(), sortClasses); std::sort(items.begin(), items.end(), sortClasses);

View file

@ -163,8 +163,8 @@ bool CompanionWindow::exit()
if (mModel && mModel->hasProfit(mPtr) && getProfit(mPtr) < 0) if (mModel && mModel->hasProfit(mPtr) && getProfit(mPtr) < 0)
{ {
std::vector<std::string> buttons; std::vector<std::string> buttons;
buttons.push_back("#{sCompanionWarningButtonOne}"); buttons.emplace_back("#{sCompanionWarningButtonOne}");
buttons.push_back("#{sCompanionWarningButtonTwo}"); buttons.emplace_back("#{sCompanionWarningButtonTwo}");
mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons); mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons);
mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked); mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked);
return false; return false;

View file

@ -167,6 +167,10 @@ namespace MWGui
{ {
WindowBase::onClose(); WindowBase::onClose();
// Make sure the window was actually closed and not temporarily hidden.
if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Container))
return;
if (mModel) if (mModel)
mModel->onClose(); mModel->onClose();
@ -189,6 +193,7 @@ namespace MWGui
// transfer everything into the player's inventory // transfer everything into the player's inventory
ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel();
assert(mModel);
mModel->update(); mModel->update();
// unequip all items to avoid unequipping/reequipping // unequip all items to avoid unequipping/reequipping

View file

@ -49,14 +49,14 @@ ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSour
for(const MWWorld::Ptr& source : itemSources) for(const MWWorld::Ptr& source : itemSources)
{ {
MWWorld::ContainerStore& store = source.getClass().getContainerStore(source); MWWorld::ContainerStore& store = source.getClass().getContainerStore(source);
mItemSources.push_back(std::make_pair(source, store.resolveTemporarily())); mItemSources.emplace_back(source, store.resolveTemporarily());
} }
} }
ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source) : mTrading(false) ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source) : mTrading(false)
{ {
MWWorld::ContainerStore& store = source.getClass().getContainerStore(source); MWWorld::ContainerStore& store = source.getClass().getContainerStore(source);
mItemSources.push_back(std::make_pair(source, store.resolveTemporarily())); mItemSources.emplace_back(source, store.resolveTemporarily());
} }
bool ContainerItemModel::allowedToUseItems() const bool ContainerItemModel::allowedToUseItems() const

View file

@ -9,21 +9,17 @@ namespace MyGUI
class Widget; class Widget;
} }
namespace MWGui namespace MWGui::Controllers
{
namespace Controllers
{ {
/// Automatically positions a widget below the mouse cursor. /// Automatically positions a widget below the mouse cursor.
class ControllerFollowMouse final : class ControllerFollowMouse final : public MyGUI::ControllerItem
public MyGUI::ControllerItem
{ {
MYGUI_RTTI_DERIVED( ControllerFollowMouse ) MYGUI_RTTI_DERIVED( ControllerFollowMouse )
private: private:
bool addTime(MyGUI::Widget* _widget, float _time) final; bool addTime(MyGUI::Widget* _widget, float _time) override;
void prepareItem(MyGUI::Widget* _widget) final; void prepareItem(MyGUI::Widget* _widget) override;
}; };
} }
}
#endif #endif

View file

@ -20,10 +20,10 @@ namespace MWGui
ResourceImageSetPointerFix(); ResourceImageSetPointerFix();
virtual ~ResourceImageSetPointerFix(); virtual ~ResourceImageSetPointerFix();
void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) final; void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) override;
void setImage(MyGUI::ImageBox* _image) final; void setImage(MyGUI::ImageBox* _image) override;
void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) final; void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) override;
//and now for the whole point of this class, allow us to get //and now for the whole point of this class, allow us to get
//the hot spot, the image and the size of the cursor. //the hot spot, the image and the size of the cursor.

View file

@ -36,7 +36,7 @@ namespace MWGui
/// Register needed components with MyGUI's factory manager /// Register needed components with MyGUI's factory manager
static void registerComponents(); static void registerComponents();
void initialiseOverride() final; void initialiseOverride() override;
/// Takes ownership of \a model /// Takes ownership of \a model
void setModel(ItemModel* model); void setModel(ItemModel* model);
@ -47,8 +47,8 @@ namespace MWGui
void layoutWidgets(); void layoutWidgets();
void resetScrollbars(); void resetScrollbars();
void setSize(const MyGUI::IntSize& value) final; void setSize(const MyGUI::IntSize& value) override;
void setCoord(const MyGUI::IntCoord& value) final; void setCoord(const MyGUI::IntCoord& value) override;
MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked; MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked;

View file

@ -13,7 +13,7 @@ namespace MWGui
MYGUI_RTTI_DERIVED(ItemView) MYGUI_RTTI_DERIVED(ItemView)
public: public:
ItemView(); ItemView();
virtual ~ItemView(); ~ItemView() override;
/// Register needed components with MyGUI's factory manager /// Register needed components with MyGUI's factory manager
static void registerComponents (); static void registerComponents ();
@ -33,12 +33,12 @@ namespace MWGui
void resetScrollBars(); void resetScrollBars();
private: private:
void initialiseOverride() final; void initialiseOverride() override;
void layoutWidgets(); void layoutWidgets();
void setSize(const MyGUI::IntSize& _value) final; void setSize(const MyGUI::IntSize& _value) override;
void setCoord(const MyGUI::IntCoord& _value) final; void setCoord(const MyGUI::IntCoord& _value) override;
void onSelectedItem (MyGUI::Widget* sender); void onSelectedItem (MyGUI::Widget* sender);
void onSelectedBackground (MyGUI::Widget* sender); void onSelectedBackground (MyGUI::Widget* sender);

View file

@ -41,7 +41,7 @@ namespace MWGui
void setFrame (const std::string& frame, const MyGUI::IntCoord& coord); void setFrame (const std::string& frame, const MyGUI::IntCoord& coord);
protected: protected:
void initialiseOverride() final; void initialiseOverride() override;
MyGUI::ImageBox* mItem; MyGUI::ImageBox* mItem;
MyGUI::ImageBox* mItemShadow; MyGUI::ImageBox* mItemShadow;

View file

@ -123,7 +123,7 @@ namespace MWGui
} }
std::vector<std::string> buttons; std::vector<std::string> buttons;
buttons.push_back("#{sOk}"); buttons.emplace_back("#{sOk}");
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons);
} }
} }

View file

@ -231,25 +231,25 @@ namespace MWGui
std::vector<std::string> buttons; std::vector<std::string> buttons;
if (state==MWBase::StateManager::State_Running) if (state==MWBase::StateManager::State_Running)
buttons.push_back("return"); buttons.emplace_back("return");
buttons.push_back("newgame"); buttons.emplace_back("newgame");
if (state==MWBase::StateManager::State_Running && if (state==MWBase::StateManager::State_Running &&
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 && MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 &&
MWBase::Environment::get().getWindowManager()->isSavingAllowed()) MWBase::Environment::get().getWindowManager()->isSavingAllowed())
buttons.push_back("savegame"); buttons.emplace_back("savegame");
if (MWBase::Environment::get().getStateManager()->characterBegin()!= if (MWBase::Environment::get().getStateManager()->characterBegin()!=
MWBase::Environment::get().getStateManager()->characterEnd()) MWBase::Environment::get().getStateManager()->characterEnd())
buttons.push_back("loadgame"); buttons.emplace_back("loadgame");
buttons.push_back("options"); buttons.emplace_back("options");
if (state==MWBase::StateManager::State_NoGame) if (state==MWBase::StateManager::State_NoGame)
buttons.push_back("credits"); buttons.emplace_back("credits");
buttons.push_back("exitgame"); buttons.emplace_back("exitgame");
// Create new buttons if needed // Create new buttons if needed
std::vector<std::string> allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; std::vector<std::string> allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"};

View file

@ -74,12 +74,12 @@ namespace
MyGUI::Colour mNormalColour; MyGUI::Colour mNormalColour;
MyGUI::Colour mHoverColour; MyGUI::Colour mHoverColour;
void onMouseLostFocus(MyGUI::Widget* _new) final void onMouseLostFocus(MyGUI::Widget* _new) override
{ {
setColour(mNormalColour); setColour(mNormalColour);
} }
void onMouseSetFocus(MyGUI::Widget* _old) final void onMouseSetFocus(MyGUI::Widget* _old) override
{ {
setColour(mHoverColour); setColour(mHoverColour);
} }

View file

@ -358,7 +358,7 @@ namespace MWGui
if (!playable) // Only display playable races if (!playable) // Only display playable races
continue; continue;
items.push_back(std::make_pair(race.mId, race.mName)); items.emplace_back(race.mId, race.mName);
} }
std::sort(items.begin(), items.end(), sortRaces); std::sort(items.begin(), items.end(), sortRaces);

View file

@ -10,7 +10,7 @@ namespace MWGui
MYGUI_RTTI_DERIVED( AutoSizedResourceSkin ) MYGUI_RTTI_DERIVED( AutoSizedResourceSkin )
public: public:
void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) final; void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) override;
}; };
} }

View file

@ -244,7 +244,7 @@ namespace MWGui
{ {
SDL_DisplayMode mode; SDL_DisplayMode mode;
SDL_GetDisplayMode(screen, i, &mode); SDL_GetDisplayMode(screen, i, &mode);
resolutions.push_back(std::make_pair(mode.w, mode.h)); resolutions.emplace_back(mode.w, mode.h);
} }
std::sort(resolutions.begin(), resolutions.end(), sortResolutions); std::sort(resolutions.begin(), resolutions.end(), sortResolutions);
for (std::pair<int, int>& resolution : resolutions) for (std::pair<int, int>& resolution : resolutions)

View file

@ -31,18 +31,18 @@ namespace
{ {
// this defines the sorting order of types. types that are first in the vector appear before other types. // this defines the sorting order of types. types that are first in the vector appear before other types.
std::vector<std::string> mapping; std::vector<std::string> mapping;
mapping.push_back( typeid(ESM::Weapon).name() ); mapping.emplace_back(typeid(ESM::Weapon).name() );
mapping.push_back( typeid(ESM::Armor).name() ); mapping.emplace_back(typeid(ESM::Armor).name() );
mapping.push_back( typeid(ESM::Clothing).name() ); mapping.emplace_back(typeid(ESM::Clothing).name() );
mapping.push_back( typeid(ESM::Potion).name() ); mapping.emplace_back(typeid(ESM::Potion).name() );
mapping.push_back( typeid(ESM::Ingredient).name() ); mapping.emplace_back(typeid(ESM::Ingredient).name() );
mapping.push_back( typeid(ESM::Apparatus).name() ); mapping.emplace_back(typeid(ESM::Apparatus).name() );
mapping.push_back( typeid(ESM::Book).name() ); mapping.emplace_back(typeid(ESM::Book).name() );
mapping.push_back( typeid(ESM::Light).name() ); mapping.emplace_back(typeid(ESM::Light).name() );
mapping.push_back( typeid(ESM::Miscellaneous).name() ); mapping.emplace_back(typeid(ESM::Miscellaneous).name() );
mapping.push_back( typeid(ESM::Lockpick).name() ); mapping.emplace_back(typeid(ESM::Lockpick).name() );
mapping.push_back( typeid(ESM::Repair).name() ); mapping.emplace_back(typeid(ESM::Repair).name() );
mapping.push_back( typeid(ESM::Probe).name() ); mapping.emplace_back(typeid(ESM::Probe).name() );
assert( std::find(mapping.begin(), mapping.end(), type1) != mapping.end() ); assert( std::find(mapping.begin(), mapping.end(), type1) != mapping.end() );
assert( std::find(mapping.begin(), mapping.end(), type2) != mapping.end() ); assert( std::find(mapping.begin(), mapping.end(), type2) != mapping.end() );
@ -166,7 +166,7 @@ namespace MWGui
void SortFilterItemModel::addDragItem (const MWWorld::Ptr& dragItem, size_t count) void SortFilterItemModel::addDragItem (const MWWorld::Ptr& dragItem, size_t count)
{ {
mDragItems.push_back(std::make_pair(dragItem, count)); mDragItems.emplace_back(dragItem, count);
} }
void SortFilterItemModel::clearDragItems() void SortFilterItemModel::clearDragItems()

View file

@ -12,8 +12,8 @@ namespace MWGui
{ {
mSoulgem = soulgem; mSoulgem = soulgem;
std::vector<std::string> buttons; std::vector<std::string> buttons;
buttons.push_back("#{sRechargeEnchantment}"); buttons.emplace_back("#{sRechargeEnchantment}");
buttons.push_back("#{sMake Enchantment}"); buttons.emplace_back("#{sMake Enchantment}");
mManager->createInteractiveMessageBox("#{sDoYouWantTo}", buttons); mManager->createInteractiveMessageBox("#{sDoYouWantTo}", buttons);
mManager->eventButtonPressed += MyGUI::newDelegate(this, &SoulgemDialog::onButtonPressed); mManager->eventButtonPressed += MyGUI::newDelegate(this, &SoulgemDialog::onButtonPressed);
} }

View file

@ -42,6 +42,44 @@ namespace MWGui
{ {
} }
bool SpellModel::matchingEffectExists(std::string filter, const ESM::EffectList &effects)
{
auto wm = MWBase::Environment::get().getWindowManager();
const MWWorld::ESMStore &store =
MWBase::Environment::get().getWorld()->getStore();
for (unsigned int i = 0; i < effects.mList.size(); ++i)
{
short effectId = effects.mList[i].mEffectID;
if (effectId != -1)
{
const ESM::MagicEffect *magicEffect =
store.get<ESM::MagicEffect>().search(effectId);
std::string effectIDStr = ESM::MagicEffect::effectIdToString(effectId);
std::string fullEffectName = wm->getGameSettingString(effectIDStr, "");
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill && effects.mList[i].mSkill != -1)
{
fullEffectName += " " + wm->getGameSettingString(ESM::Skill::sSkillNameIds[effects.mList[i].mSkill], "");
}
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute && effects.mList[i].mAttribute != -1)
{
fullEffectName += " " + wm->getGameSettingString(ESM::Attribute::sGmstAttributeIds[effects.mList[i].mAttribute], "");
}
std::string convert = Misc::StringUtils::lowerCaseUtf8(fullEffectName);
if (convert.find(filter) != std::string::npos)
{
return true;
}
}
}
return false;
}
void SpellModel::update() void SpellModel::update()
{ {
mSpells.clear(); mSpells.clear();
@ -62,7 +100,8 @@ namespace MWGui
std::string name = Misc::StringUtils::lowerCaseUtf8(spell->mName); std::string name = Misc::StringUtils::lowerCaseUtf8(spell->mName);
if (name.find(filter) == std::string::npos) if (name.find(filter) == std::string::npos
&& !matchingEffectExists(filter, spell->mEffects))
continue; continue;
Spell newSpell; Spell newSpell;
@ -103,7 +142,8 @@ namespace MWGui
std::string name = Misc::StringUtils::lowerCaseUtf8(item.getClass().getName(item)); std::string name = Misc::StringUtils::lowerCaseUtf8(item.getClass().getName(item));
if (name.find(filter) == std::string::npos) if (name.find(filter) == std::string::npos
&& !matchingEffectExists(filter, enchant->mEffects))
continue; continue;
Spell newSpell; Spell newSpell;

View file

@ -2,6 +2,7 @@
#define OPENMW_GUI_SPELLMODEL_H #define OPENMW_GUI_SPELLMODEL_H
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include <components/esm/effectlist.hpp>
namespace MWGui namespace MWGui
{ {
@ -57,6 +58,8 @@ namespace MWGui
std::vector<Spell> mSpells; std::vector<Spell> mSpells;
std::string mFilter; std::string mFilter;
bool matchingEffectExists(std::string filter, const ESM::EffectList &effects);
}; };
} }

View file

@ -128,10 +128,10 @@ namespace MWGui
group.push_back(costChance); group.push_back(costChance);
Gui::SharedStateButton::createButtonGroup(group); Gui::SharedStateButton::createButtonGroup(group);
mLines.push_back(LineInfo(t, costChance, i)); mLines.emplace_back(t, costChance, i);
} }
else else
mLines.push_back(LineInfo(t, (MyGUI::Widget*)nullptr, i)); mLines.emplace_back(t, (MyGUI::Widget*)nullptr, i);
t->setStateSelected(spell.mSelected); t->setStateSelected(spell.mSelected);
} }
@ -236,7 +236,7 @@ namespace MWGui
MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18),
MyGUI::Align::Left | MyGUI::Align::Top); MyGUI::Align::Left | MyGUI::Align::Top);
separator->setNeedMouseFocus(false); separator->setNeedMouseFocus(false);
mLines.push_back(LineInfo(separator, (MyGUI::Widget*)nullptr, NoSpellIndex)); mLines.emplace_back(separator, (MyGUI::Widget*)nullptr, NoSpellIndex);
} }
MyGUI::TextBox* groupWidget = mScrollView->createWidget<Gui::TextBox>("SandBrightText", MyGUI::TextBox* groupWidget = mScrollView->createWidget<Gui::TextBox>("SandBrightText",
@ -255,10 +255,10 @@ namespace MWGui
groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setTextAlign(MyGUI::Align::Right);
groupWidget2->setNeedMouseFocus(false); groupWidget2->setNeedMouseFocus(false);
mLines.push_back(LineInfo(groupWidget, groupWidget2, NoSpellIndex)); mLines.emplace_back(groupWidget, groupWidget2, NoSpellIndex);
} }
else else
mLines.push_back(LineInfo(groupWidget, (MyGUI::Widget*)nullptr, NoSpellIndex)); mLines.emplace_back(groupWidget, (MyGUI::Widget*)nullptr, NoSpellIndex);
} }

View file

@ -47,10 +47,10 @@ namespace MWGui
/// Fired when a spell was clicked /// Fired when a spell was clicked
EventHandle_ModelIndex eventSpellClicked; EventHandle_ModelIndex eventSpellClicked;
void initialiseOverride() final; void initialiseOverride() override;
void setSize(const MyGUI::IntSize& _value) final; void setSize(const MyGUI::IntSize& _value) override;
void setCoord(const MyGUI::IntCoord& _value) final; void setCoord(const MyGUI::IntCoord& _value) override;
void resetScrollbars(); void resetScrollbars();

View file

@ -523,6 +523,9 @@ namespace MWGui
void TradeWindow::onClose() void TradeWindow::onClose()
{ {
// Make sure the window was actually closed and not temporarily hidden.
if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Barter))
return;
resetReference(); resetReference();
} }
} }

View file

@ -84,7 +84,7 @@ namespace MWGui
{ {
float value = getSkillForTraining(actorStats, i); float value = getSkillForTraining(actorStats, i);
skills.push_back(std::make_pair(i, value)); skills.emplace_back(i, value);
} }
std::sort(skills.begin(), skills.end(), sortSkills); std::sort(skills.begin(), skills.end(), sortSkills);

View file

@ -116,7 +116,7 @@ namespace MWGui
protected: protected:
virtual ~MWSkill(); virtual ~MWSkill();
void initialiseOverride() final; void initialiseOverride() override;
void onClicked(MyGUI::Widget* _sender); void onClicked(MyGUI::Widget* _sender);
@ -156,7 +156,7 @@ namespace MWGui
protected: protected:
virtual ~MWAttribute(); virtual ~MWAttribute();
void initialiseOverride() final; void initialiseOverride() override;
void onClicked(MyGUI::Widget* _sender); void onClicked(MyGUI::Widget* _sender);
@ -199,7 +199,7 @@ namespace MWGui
protected: protected:
virtual ~MWSpell(); virtual ~MWSpell();
void initialiseOverride() final; void initialiseOverride() override;
private: private:
void updateWidgets(); void updateWidgets();
@ -241,7 +241,7 @@ namespace MWGui
protected: protected:
virtual ~MWEffectList(); virtual ~MWEffectList();
void initialiseOverride() final; void initialiseOverride() override;
private: private:
void updateWidgets(); void updateWidgets();
@ -265,7 +265,7 @@ namespace MWGui
protected: protected:
virtual ~MWSpellEffect(); virtual ~MWSpellEffect();
void initialiseOverride() final; void initialiseOverride() override;
private: private:
static const int sIconOffset = 24; static const int sIconOffset = 24;
@ -294,7 +294,7 @@ namespace MWGui
protected: protected:
virtual ~MWDynamicStat(); virtual ~MWDynamicStat();
void initialiseOverride() final; void initialiseOverride() override;
private: private:

View file

@ -199,7 +199,7 @@ namespace MWMechanics
if (sourceId != mSpellId) if (sourceId != mSpellId)
return; return;
mMagnitudes.push_back(std::make_pair(key, magnitude)); mMagnitudes.emplace_back(key, magnitude);
} }
std::vector<std::pair<MWMechanics::EffectKey, float>> mMagnitudes; std::vector<std::pair<MWMechanics::EffectKey, float>> mMagnitudes;
@ -590,7 +590,9 @@ namespace MWMechanics
if (!actorState.isTurningToPlayer()) if (!actorState.isTurningToPlayer())
{ {
float angle = std::atan2(dir.x(), dir.y()); float from = dir.x();
float to = dir.y();
float angle = std::atan2(from, to);
actorState.setAngleToPlayer(angle); actorState.setAngleToPlayer(angle);
float deltaAngle = Misc::normalizeAngle(angle - actor.getRefData().getPosition().rot[2]); float deltaAngle = Misc::normalizeAngle(angle - actor.getRefData().getPosition().rot[2]);
if (!mSmoothMovement || std::abs(deltaAngle) > osg::DegreesToRadians(60.f)) if (!mSmoothMovement || std::abs(deltaAngle) > osg::DegreesToRadians(60.f))
@ -914,12 +916,54 @@ namespace MWMechanics
} }
}; };
void Actors::applyCureEffects(const MWWorld::Ptr& actor)
{
CreatureStats &creatureStats = actor.getClass().getCreatureStats(actor);
const MagicEffects &effects = creatureStats.getMagicEffects();
if (effects.get(ESM::MagicEffect::CurePoison).getModifier() > 0)
{
creatureStats.getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
creatureStats.getSpells().purgeEffect(ESM::MagicEffect::Poison);
if (actor.getClass().hasInventoryStore(actor))
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Poison);
}
else if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0)
{
creatureStats.getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze);
creatureStats.getSpells().purgeEffect(ESM::MagicEffect::Paralyze);
if (actor.getClass().hasInventoryStore(actor))
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Paralyze);
}
else if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0)
{
creatureStats.getSpells().purgeCommonDisease();
}
else if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0)
{
creatureStats.getSpells().purgeBlightDisease();
}
else if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0)
{
creatureStats.getActiveSpells().purgeCorprusDisease();
creatureStats.getSpells().purgeCorprusDisease();
if (actor.getClass().hasInventoryStore(actor))
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Corprus, true);
}
else if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0)
{
creatureStats.getSpells().purgeCurses();
}
}
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration) void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration)
{ {
CreatureStats &creatureStats = ptr.getClass().getCreatureStats(ptr); CreatureStats &creatureStats = ptr.getClass().getCreatureStats(ptr);
const MagicEffects &effects = creatureStats.getMagicEffects(); const MagicEffects &effects = creatureStats.getMagicEffects();
bool godmode = ptr == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); bool godmode = ptr == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
applyCureEffects(ptr);
bool wasDead = creatureStats.isDead(); bool wasDead = creatureStats.isDead();
if (duration > 0) if (duration > 0)
@ -1687,6 +1731,9 @@ namespace MWMechanics
void Actors::predictAndAvoidCollisions() void Actors::predictAndAvoidCollisions()
{ {
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
return;
const float minGap = 10.f; const float minGap = 10.f;
const float maxDistForPartialAvoiding = 200.f; const float maxDistForPartialAvoiding = 200.f;
const float maxDistForStrictAvoiding = 100.f; const float maxDistForStrictAvoiding = 100.f;
@ -1723,7 +1770,7 @@ namespace MWMechanics
shouldAvoidCollision = true; shouldAvoidCollision = true;
else if (package->getTypeId() == AiPackageTypeId::Wander && giveWayWhenIdle) else if (package->getTypeId() == AiPackageTypeId::Wander && giveWayWhenIdle)
{ {
if (!dynamic_cast<const AiWander*>(package.get())->isStationary()) if (!static_cast<const AiWander*>(package.get())->isStationary())
shouldAvoidCollision = true; shouldAvoidCollision = true;
} }
else if (package->getTypeId() == AiPackageTypeId::Combat || package->getTypeId() == AiPackageTypeId::Pursue) else if (package->getTypeId() == AiPackageTypeId::Combat || package->getTypeId() == AiPackageTypeId::Pursue)

View file

@ -206,6 +206,7 @@ namespace MWMechanics
private: private:
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl); void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl);
void applyCureEffects (const MWWorld::Ptr& actor);
PtrActorMap mActors; PtrActorMap mActors;
float mTimerDisposeSummonsCorpses; float mTimerDisposeSummonsCorpses;

View file

@ -24,15 +24,15 @@ namespace MWMechanics
public: public:
/// Constructor /// Constructor
/** \param objectId Reference to object to activate **/ /** \param objectId Reference to object to activate **/
AiActivate(const std::string &objectId); explicit AiActivate(const std::string &objectId);
AiActivate(const ESM::AiSequence::AiActivate* activate); explicit AiActivate(const ESM::AiSequence::AiActivate* activate);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Activate; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Activate; }
void writeState(ESM::AiSequence::AiSequence& sequence) const final; void writeState(ESM::AiSequence::AiSequence& sequence) const override;
private: private:
const std::string mObjectId; const std::string mObjectId;

View file

@ -20,9 +20,9 @@ namespace MWMechanics
{ {
public: public:
/// Avoid door until the door is fully open /// Avoid door until the door is fully open
AiAvoidDoor(const MWWorld::ConstPtr& doorPtr); explicit AiAvoidDoor(const MWWorld::ConstPtr& doorPtr);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::AvoidDoor; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::AvoidDoor; }

View file

@ -10,7 +10,7 @@ namespace MWMechanics
class AiBreathe final : public TypedAiPackage<AiBreathe> class AiBreathe final : public TypedAiPackage<AiBreathe>
{ {
public: public:
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Breathe; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Breathe; }

View file

@ -15,11 +15,11 @@ namespace MWMechanics
public: public:
AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false); AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Cast; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Cast; }
MWWorld::Ptr getTarget() const final; MWWorld::Ptr getTarget() const override;
static constexpr Options makeDefaultOptions() static constexpr Options makeDefaultOptions()
{ {

View file

@ -96,13 +96,13 @@ namespace MWMechanics
public: public:
///Constructor ///Constructor
/** \param actor Actor to fight **/ /** \param actor Actor to fight **/
AiCombat(const MWWorld::Ptr& actor); explicit AiCombat(const MWWorld::Ptr& actor);
AiCombat (const ESM::AiSequence::AiCombat* combat); explicit AiCombat (const ESM::AiSequence::AiCombat* combat);
void init(); void init();
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Combat; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Combat; }
@ -116,9 +116,9 @@ namespace MWMechanics
} }
///Returns target ID ///Returns target ID
MWWorld::Ptr getTarget() const final; MWWorld::Ptr getTarget() const override;
void writeState(ESM::AiSequence::AiSequence &sequence) const final; void writeState(ESM::AiSequence::AiSequence &sequence) const override;
private: private:
/// Returns true if combat should end /// Returns true if combat should end

View file

@ -30,7 +30,7 @@ namespace MWMechanics
AiEscort(const ESM::AiSequence::AiEscort* escort); AiEscort(const ESM::AiSequence::AiEscort* escort);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Escort; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Escort; }
@ -42,11 +42,11 @@ namespace MWMechanics
return options; return options;
} }
void writeState(ESM::AiSequence::AiSequence &sequence) const final; void writeState(ESM::AiSequence::AiSequence &sequence) const override;
void fastForward(const MWWorld::Ptr& actor, AiState& state) final; void fastForward(const MWWorld::Ptr& actor, AiState& state) override;
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); } osg::Vec3f getDestination() const override { return osg::Vec3f(mX, mY, mZ); }
private: private:
const std::string mCellId; const std::string mCellId;

View file

@ -10,7 +10,7 @@ namespace MWMechanics
public: public:
AiFace(float targetX, float targetY); AiFace(float targetX, float targetY);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Face; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Face; }

View file

@ -53,7 +53,7 @@ namespace MWMechanics
AiFollow(const ESM::AiSequence::AiFollow* follow); AiFollow(const ESM::AiSequence::AiFollow* follow);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Follow; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Follow; }
@ -69,15 +69,15 @@ namespace MWMechanics
/// Returns the actor being followed /// Returns the actor being followed
std::string getFollowedActor(); std::string getFollowedActor();
void writeState (ESM::AiSequence::AiSequence& sequence) const final; void writeState (ESM::AiSequence::AiSequence& sequence) const override;
bool isCommanded() const; bool isCommanded() const;
int getFollowIndex() const; int getFollowIndex() const;
void fastForward(const MWWorld::Ptr& actor, AiState& state) final; void fastForward(const MWWorld::Ptr& actor, AiState& state) override;
osg::Vec3f getDestination() const final osg::Vec3f getDestination() const override
{ {
MWWorld::Ptr target = getTarget(); MWWorld::Ptr target = getTarget();
if (target.isEmpty()) if (target.isEmpty())

View file

@ -26,7 +26,7 @@ namespace MWMechanics
AiPursue(const ESM::AiSequence::AiPursue* pursue); AiPursue(const ESM::AiSequence::AiPursue* pursue);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Pursue; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Pursue; }
@ -38,9 +38,9 @@ namespace MWMechanics
return options; return options;
} }
MWWorld::Ptr getTarget() const final; MWWorld::Ptr getTarget() const override;
void writeState (ESM::AiSequence::AiSequence& sequence) const final; void writeState (ESM::AiSequence::AiSequence& sequence) const override;
}; };
} }
#endif #endif

View file

@ -25,14 +25,14 @@ namespace MWMechanics
AiTravel(float x, float y, float z); AiTravel(float x, float y, float z);
AiTravel(const ESM::AiSequence::AiTravel* travel); explicit AiTravel(const ESM::AiSequence::AiTravel* travel);
/// Simulates the passing of time /// Simulates the passing of time
void fastForward(const MWWorld::Ptr& actor, AiState& state) final; void fastForward(const MWWorld::Ptr& actor, AiState& state) override;
void writeState(ESM::AiSequence::AiSequence &sequence) const final; void writeState(ESM::AiSequence::AiSequence &sequence) const override;
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Travel; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Travel; }
@ -44,7 +44,7 @@ namespace MWMechanics
return options; return options;
} }
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); } osg::Vec3f getDestination() const override { return osg::Vec3f(mX, mY, mZ); }
private: private:
const float mX; const float mX;
@ -62,7 +62,7 @@ namespace MWMechanics
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::InternalTravel; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::InternalTravel; }
std::unique_ptr<AiPackage> clone() const final; std::unique_ptr<AiPackage> clone() const override;
}; };
} }

View file

@ -89,9 +89,9 @@ namespace MWMechanics
\param repeat Repeat wander or not **/ \param repeat Repeat wander or not **/
AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat); AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat);
AiWander (const ESM::AiSequence::AiWander* wander); explicit AiWander (const ESM::AiSequence::AiWander* wander);
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) override;
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Wander; } static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::Wander; }
@ -103,13 +103,13 @@ namespace MWMechanics
return options; return options;
} }
void writeState(ESM::AiSequence::AiSequence &sequence) const final; void writeState(ESM::AiSequence::AiSequence &sequence) const override;
void fastForward(const MWWorld::Ptr& actor, AiState& state) final; void fastForward(const MWWorld::Ptr& actor, AiState& state) override;
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final; osg::Vec3f getDestination(const MWWorld::Ptr& actor) const override;
osg::Vec3f getDestination() const final osg::Vec3f getDestination() const override
{ {
if (!mHasDestination) if (!mHasDestination)
return osg::Vec3f(0, 0, 0); return osg::Vec3f(0, 0, 0);

View file

@ -276,6 +276,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
mCurrentHit = "shield"; mCurrentHit = "shield";
MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); MWRender::Animation::AnimPriority priorityBlock (Priority_Hit);
priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block;
priorityBlock[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0);
} }
@ -295,6 +296,8 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
mUpperBodyState = UpperCharState_Nothing; mUpperBodyState = UpperCharState_Nothing;
} }
} }
if (mHitState != CharState_None)
idle = CharState_None;
} }
else if(!mAnimation->isPlaying(mCurrentHit)) else if(!mAnimation->isPlaying(mCurrentHit))
{ {
@ -314,8 +317,6 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
mAnimation->disable(mCurrentHit); mAnimation->disable(mCurrentHit);
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0);
} }
if (mHitState != CharState_None)
idle = CharState_None;
} }
void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force) void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force)

View file

@ -971,7 +971,7 @@ namespace MWMechanics
{ {
const OwnerMap& owners = it->second; const OwnerMap& owners = it->second;
for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt) for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt)
result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second)); result.emplace_back(ownerIt->first.first, ownerIt->second);
return result; return result;
} }
} }

View file

@ -205,24 +205,6 @@ namespace MWMechanics
break; break;
} }
case ESM::MagicEffect::CurePoison:
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
break;
case ESM::MagicEffect::CureParalyzation:
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze);
break;
case ESM::MagicEffect::CureCommonDisease:
actor.getClass().getCreatureStats(actor).getSpells().purgeCommonDisease();
break;
case ESM::MagicEffect::CureBlightDisease:
actor.getClass().getCreatureStats(actor).getSpells().purgeBlightDisease();
break;
case ESM::MagicEffect::CureCorprusDisease:
actor.getClass().getCreatureStats(actor).getSpells().purgeCorprusDisease();
break;
case ESM::MagicEffect::RemoveCurse:
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
break;
default: default:
return false; return false;
} }

View file

@ -12,6 +12,7 @@ namespace MWMechanics
struct EffectKey; struct EffectKey;
/// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed /// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed
/// Note: this function works in loop, so magic effects should not be removed here to avoid iterator invalidation.
/// @return Was the effect a tickable effect with a magnitude? /// @return Was the effect a tickable effect with a magnitude?
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey& effectKey, float magnitude); bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey& effectKey, float magnitude);
} }

View file

@ -19,7 +19,7 @@ namespace MWPhysics
Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler) Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler)
: mCanWaterWalk(false), mWalkingOnWater(false) : mStandingOnPtr(nullptr), mCanWaterWalk(false), mWalkingOnWater(false)
, mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBoxTranslate), mHalfExtents(shape->mCollisionBoxHalfExtents) , mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBoxTranslate), mHalfExtents(shape->mCollisionBoxHalfExtents)
, mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
, mInternalCollisionMode(true) , mInternalCollisionMode(true)
@ -74,10 +74,8 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
updateRotation(); updateRotation();
updateScale(); updateScale();
updatePosition(); resetPosition();
addCollisionMask(getCollisionMask()); addCollisionMask(getCollisionMask());
commitPositionChange();
} }
Actor::~Actor() Actor::~Actor()
@ -122,88 +120,80 @@ int Actor::getCollisionMask() const
void Actor::updatePosition() void Actor::updatePosition()
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
osg::Vec3f position = mPtr.getRefData().getPosition().asVec3(); mWorldPosition = mPtr.getRefData().getPosition().asVec3();
}
mPosition = position; osg::Vec3f Actor::getWorldPosition() const
mPreviousPosition = position; {
std::scoped_lock lock(mPositionMutex);
return mWorldPosition;
}
mTransformUpdatePending = true; void Actor::setNextPosition(const osg::Vec3f& position)
updateCollisionObjectPosition(); {
mNextPosition = position;
}
osg::Vec3f Actor::getNextPosition() const
{
return mNextPosition;
} }
void Actor::updateCollisionObjectPosition() void Actor::updateCollisionObjectPosition()
{ {
std::scoped_lock lock(mPositionMutex);
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale); osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale);
osg::Vec3f newPosition = scaledTranslation + mPosition; osg::Vec3f newPosition = scaledTranslation + mPosition;
mLocalTransform.setOrigin(Misc::Convert::toBullet(newPosition)); mLocalTransform.setOrigin(Misc::Convert::toBullet(newPosition));
mLocalTransform.setRotation(Misc::Convert::toBullet(mRotation)); mLocalTransform.setRotation(Misc::Convert::toBullet(mRotation));
}
void Actor::commitPositionChange()
{
std::unique_lock<std::mutex> lock(mPositionMutex);
if (mScaleUpdatePending)
{
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
mScaleUpdatePending = false;
}
if (mTransformUpdatePending)
{
mCollisionObject->setWorldTransform(mLocalTransform); mCollisionObject->setWorldTransform(mLocalTransform);
mTransformUpdatePending = false;
}
} }
osg::Vec3f Actor::getCollisionObjectPosition() const osg::Vec3f Actor::getCollisionObjectPosition() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
return Misc::Convert::toOsg(mLocalTransform.getOrigin()); return Misc::Convert::toOsg(mLocalTransform.getOrigin());
} }
void Actor::setPosition(const osg::Vec3f &position, bool updateCollisionObject) void Actor::setPosition(const osg::Vec3f& position)
{ {
std::unique_lock<std::mutex> lock(mPositionMutex);
if (mTransformUpdatePending)
{
mCollisionObject->setWorldTransform(mLocalTransform);
mTransformUpdatePending = false;
}
else
{
mPreviousPosition = mPosition; mPreviousPosition = mPosition;
mPosition = position; mPosition = position;
if (updateCollisionObject) }
{
void Actor::adjustPosition(const osg::Vec3f& offset)
{
mPosition += offset;
mPreviousPosition += offset;
}
void Actor::resetPosition()
{
updatePosition();
mPreviousPosition = mWorldPosition;
mPosition = mWorldPosition;
mNextPosition = mWorldPosition;
updateCollisionObjectPosition(); updateCollisionObjectPosition();
mCollisionObject->setWorldTransform(mLocalTransform);
}
}
} }
osg::Vec3f Actor::getPosition() const osg::Vec3f Actor::getPosition() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex);
return mPosition; return mPosition;
} }
osg::Vec3f Actor::getPreviousPosition() const osg::Vec3f Actor::getPreviousPosition() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex);
return mPreviousPosition; return mPreviousPosition;
} }
void Actor::updateRotation () void Actor::updateRotation ()
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
if (mRotation == mPtr.getRefData().getBaseNode()->getAttitude()) if (mRotation == mPtr.getRefData().getBaseNode()->getAttitude())
return; return;
mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); mRotation = mPtr.getRefData().getBaseNode()->getAttitude();
mTransformUpdatePending = true;
updateCollisionObjectPosition();
} }
bool Actor::isRotationallyInvariant() const bool Actor::isRotationallyInvariant() const
@ -213,37 +203,33 @@ bool Actor::isRotationallyInvariant() const
void Actor::updateScale() void Actor::updateScale()
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
float scale = mPtr.getCellRef().getScale(); float scale = mPtr.getCellRef().getScale();
osg::Vec3f scaleVec(scale,scale,scale); osg::Vec3f scaleVec(scale,scale,scale);
mPtr.getClass().adjustScale(mPtr, scaleVec, false); mPtr.getClass().adjustScale(mPtr, scaleVec, false);
mScale = scaleVec; mScale = scaleVec;
mScaleUpdatePending = true;
scaleVec = osg::Vec3f(scale,scale,scale); scaleVec = osg::Vec3f(scale,scale,scale);
mPtr.getClass().adjustScale(mPtr, scaleVec, true); mPtr.getClass().adjustScale(mPtr, scaleVec, true);
mRenderingScale = scaleVec; mRenderingScale = scaleVec;
mTransformUpdatePending = true;
updateCollisionObjectPosition();
} }
osg::Vec3f Actor::getHalfExtents() const osg::Vec3f Actor::getHalfExtents() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
return osg::componentMultiply(mHalfExtents, mScale); return osg::componentMultiply(mHalfExtents, mScale);
} }
osg::Vec3f Actor::getOriginalHalfExtents() const osg::Vec3f Actor::getOriginalHalfExtents() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
return mHalfExtents; return mHalfExtents;
} }
osg::Vec3f Actor::getRenderingHalfExtents() const osg::Vec3f Actor::getRenderingHalfExtents() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
return osg::componentMultiply(mHalfExtents, mRenderingScale); return osg::componentMultiply(mHalfExtents, mRenderingScale);
} }
@ -274,7 +260,7 @@ void Actor::setWalkingOnWater(bool walkingOnWater)
void Actor::setCanWaterWalk(bool waterWalk) void Actor::setCanWaterWalk(bool waterWalk)
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
if (waterWalk != mCanWaterWalk) if (waterWalk != mCanWaterWalk)
{ {
mCanWaterWalk = waterWalk; mCanWaterWalk = waterWalk;
@ -282,4 +268,16 @@ void Actor::setCanWaterWalk(bool waterWalk)
} }
} }
MWWorld::Ptr Actor::getStandingOnPtr() const
{
std::scoped_lock lock(mPositionMutex);
return mStandingOnPtr;
}
void Actor::setStandingOnPtr(const MWWorld::Ptr& ptr)
{
std::scoped_lock lock(mPositionMutex);
mStandingOnPtr = ptr;
}
} }

View file

@ -57,13 +57,20 @@ namespace MWPhysics
bool isRotationallyInvariant() const; bool isRotationallyInvariant() const;
/** /**
* Set mPosition and mPreviousPosition to the position in the Ptr's RefData. This should be used * Set mWorldPosition to the position in the Ptr's RefData. This is used by the physics simulation to account for
* when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation. * when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation.
*/ */
void updatePosition(); void updatePosition();
osg::Vec3f getWorldPosition() const;
/**
* Used by the physics simulation to store the simulation result. Used in conjunction with mWorldPosition
* to account for e.g. scripted movements
*/
void setNextPosition(const osg::Vec3f& position);
osg::Vec3f getNextPosition() const;
void updateCollisionObjectPosition(); void updateCollisionObjectPosition();
void commitPositionChange();
/** /**
* Returns the half extents of the collision body (scaled according to collision scale) * Returns the half extents of the collision body (scaled according to collision scale)
@ -83,9 +90,10 @@ namespace MWPhysics
/** /**
* Store the current position into mPreviousPosition, then move to this position. * Store the current position into mPreviousPosition, then move to this position.
* Optionally, inform the physics engine about the change of position.
*/ */
void setPosition(const osg::Vec3f& position, bool updateCollisionObject=true); void setPosition(const osg::Vec3f& position);
void resetPosition();
void adjustPosition(const osg::Vec3f& offset);
osg::Vec3f getPosition() const; osg::Vec3f getPosition() const;
@ -137,7 +145,11 @@ namespace MWPhysics
void setWalkingOnWater(bool walkingOnWater); void setWalkingOnWater(bool walkingOnWater);
bool isWalkingOnWater() const; bool isWalkingOnWater() const;
MWWorld::Ptr getStandingOnPtr() const;
void setStandingOnPtr(const MWWorld::Ptr& ptr);
private: private:
MWWorld::Ptr mStandingOnPtr;
/// Removes then re-adds the collision object to the dynamics world /// Removes then re-adds the collision object to the dynamics world
void updateCollisionMask(); void updateCollisionMask();
void addCollisionMask(int collisionMask); void addCollisionMask(int collisionMask);
@ -159,11 +171,11 @@ namespace MWPhysics
osg::Vec3f mScale; osg::Vec3f mScale;
osg::Vec3f mRenderingScale; osg::Vec3f mRenderingScale;
osg::Vec3f mWorldPosition;
osg::Vec3f mNextPosition;
osg::Vec3f mPosition; osg::Vec3f mPosition;
osg::Vec3f mPreviousPosition; osg::Vec3f mPreviousPosition;
btTransform mLocalTransform; btTransform mLocalTransform;
bool mScaleUpdatePending;
bool mTransformUpdatePending;
mutable std::mutex mPositionMutex; mutable std::mutex mPositionMutex;
osg::Vec3f mForce; osg::Vec3f mForce;

View file

@ -2,6 +2,8 @@
#include <BulletCollision/CollisionDispatch/btCollisionObject.h> #include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include "components/misc/convert.hpp"
#include "ptrholder.hpp" #include "ptrholder.hpp"
namespace MWPhysics namespace MWPhysics
@ -20,7 +22,7 @@ namespace MWPhysics
collisionObject = col1Wrap->m_collisionObject; collisionObject = col1Wrap->m_collisionObject;
PtrHolder* holder = static_cast<PtrHolder*>(collisionObject->getUserPointer()); PtrHolder* holder = static_cast<PtrHolder*>(collisionObject->getUserPointer());
if (holder) if (holder)
mResult.push_back(holder->getPtr()); mResult.emplace_back(ContactPoint{holder->getPtr(), Misc::Convert::toOsg(cp.m_positionWorldOnB), Misc::Convert::toOsg(cp.m_normalWorldOnB)});
return 0.f; return 0.f;
} }

View file

@ -7,6 +7,8 @@
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "physicssystem.hpp"
class btCollisionObject; class btCollisionObject;
struct btCollisionObjectWrapper; struct btCollisionObjectWrapper;
@ -23,7 +25,7 @@ namespace MWPhysics
const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col0Wrap,int partId0,int index0,
const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) override; const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) override;
std::vector<MWWorld::Ptr> mResult; std::vector<ContactPoint> mResult;
}; };
} }

View file

@ -39,6 +39,7 @@ namespace MWPhysics
mObject = collisionObject; mObject = collisionObject;
mLeastDistSqr = distsqr; mLeastDistSqr = distsqr;
mContactPoint = cp.getPositionWorldOnA(); mContactPoint = cp.getPositionWorldOnA();
mContactNormal = cp.m_normalWorldOnB;
} }
} }

View file

@ -20,6 +20,7 @@ namespace MWPhysics
public: public:
const btCollisionObject *mObject{nullptr}; const btCollisionObject *mObject{nullptr};
btVector3 mContactPoint{0,0,0}; btVector3 mContactPoint{0,0,0};
btVector3 mContactNormal{0,0,0};
btScalar mLeastDistSqr; btScalar mLeastDistSqr;
DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector<const btCollisionObject*>& targets, const btVector3 &origin); DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector<const btCollisionObject*>& targets, const btVector3 &origin);

View file

@ -35,7 +35,7 @@ namespace MWPhysics
{ {
} }
bool process(const btBroadphaseProxy* proxy) final bool process(const btBroadphaseProxy* proxy) override
{ {
if (mResult) if (mResult)
return false; return false;

View file

@ -1,6 +1,8 @@
#include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h> #include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
#include <BulletCollision/CollisionShapes/btCollisionShape.h> #include <BulletCollision/CollisionShapes/btCollisionShape.h>
#include <osg/Stats>
#include "components/debug/debuglog.hpp" #include "components/debug/debuglog.hpp"
#include <components/misc/barrier.hpp> #include <components/misc/barrier.hpp>
#include "components/misc/convert.hpp" #include "components/misc/convert.hpp"
@ -82,14 +84,6 @@ namespace
ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0;
} }
void updateStandingCollision(MWPhysics::ActorFrameData& actorData, MWPhysics::CollisionMap& standingCollisions)
{
if (!actorData.mStandingOn.isEmpty())
standingCollisions[actorData.mPtr] = actorData.mStandingOn;
else
standingCollisions.erase(actorData.mPtr);
}
void updateMechanics(MWPhysics::ActorFrameData& actorData) void updateMechanics(MWPhysics::ActorFrameData& actorData)
{ {
if (actorData.mDidJump) if (actorData.mDidJump)
@ -102,9 +96,18 @@ namespace
stats.addToFallHeight(-actorData.mFallHeight); stats.addToFallHeight(-actorData.mFallHeight);
} }
osg::Vec3f interpolateMovements(const MWPhysics::ActorFrameData& actorData, float timeAccum, float physicsDt) osg::Vec3f interpolateMovements(MWPhysics::ActorFrameData& actorData, float timeAccum, float physicsDt)
{ {
const float interpolationFactor = timeAccum / physicsDt; const float interpolationFactor = timeAccum / physicsDt;
// account for force change of actor's position in the main thread
const auto correction = actorData.mActorRaw->getWorldPosition() - actorData.mOrigin;
if (correction.length() != 0)
{
actorData.mActorRaw->adjustPosition(correction);
actorData.mPosition = actorData.mActorRaw->getPosition();
}
return actorData.mPosition * interpolationFactor + actorData.mActorRaw->getPreviousPosition() * (1.f - interpolationFactor); return actorData.mPosition * interpolationFactor + actorData.mActorRaw->getPreviousPosition() * (1.f - interpolationFactor);
} }
@ -142,6 +145,7 @@ namespace MWPhysics
{ {
PhysicsTaskScheduler::PhysicsTaskScheduler(float physicsDt, std::shared_ptr<btCollisionWorld> collisionWorld) PhysicsTaskScheduler::PhysicsTaskScheduler(float physicsDt, std::shared_ptr<btCollisionWorld> collisionWorld)
: mPhysicsDt(physicsDt) : mPhysicsDt(physicsDt)
, mTimeAccum(0.f)
, mCollisionWorld(std::move(collisionWorld)) , mCollisionWorld(std::move(collisionWorld))
, mNumJobs(0) , mNumJobs(0)
, mRemainingSteps(0) , mRemainingSteps(0)
@ -152,6 +156,8 @@ namespace MWPhysics
, mQuit(false) , mQuit(false)
, mNextJob(0) , mNextJob(0)
, mNextLOS(0) , mNextLOS(0)
, mFrameNumber(0)
, mTimer(osg::Timer::instance())
{ {
mNumThreads = Config::computeNumThreads(mThreadSafeBullet); mNumThreads = Config::computeNumThreads(mThreadSafeBullet);
@ -181,22 +187,22 @@ namespace MWPhysics
mPostSimBarrier = std::make_unique<Misc::Barrier>(mNumThreads, [&]() mPostSimBarrier = std::make_unique<Misc::Barrier>(mNumThreads, [&]()
{ {
udpateActorsAabbs();
mNewFrame = false; mNewFrame = false;
if (mLOSCacheExpiry >= 0) if (mLOSCacheExpiry >= 0)
{ {
std::unique_lock<std::shared_timed_mutex> lock(mLOSCacheMutex); std::unique_lock lock(mLOSCacheMutex);
mLOSCache.erase( mLOSCache.erase(
std::remove_if(mLOSCache.begin(), mLOSCache.end(), std::remove_if(mLOSCache.begin(), mLOSCache.end(),
[](const LOSRequest& req) { return req.mStale; }), [](const LOSRequest& req) { return req.mStale; }),
mLOSCache.end()); mLOSCache.end());
} }
mTimeEnd = mTimer->tick();
}); });
} }
PhysicsTaskScheduler::~PhysicsTaskScheduler() PhysicsTaskScheduler::~PhysicsTaskScheduler()
{ {
std::unique_lock<std::shared_timed_mutex> lock(mSimulationMutex); std::unique_lock lock(mSimulationMutex);
mQuit = true; mQuit = true;
mNumJobs = 0; mNumJobs = 0;
mRemainingSteps = 0; mRemainingSteps = 0;
@ -206,19 +212,16 @@ namespace MWPhysics
thread.join(); thread.join();
} }
const PtrPositionList& PhysicsTaskScheduler::moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, CollisionMap& standingCollisions, bool skipSimulation) const PtrPositionList& PhysicsTaskScheduler::moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{ {
// This function run in the main thread. // This function run in the main thread.
// While the mSimulationMutex is held, background physics threads can't run. // While the mSimulationMutex is held, background physics threads can't run.
std::unique_lock<std::shared_timed_mutex> lock(mSimulationMutex); std::unique_lock lock(mSimulationMutex);
// start by finishing previous background computation // start by finishing previous background computation
if (mNumThreads != 0) if (mNumThreads != 0)
{ {
if (mAdvanceSimulation)
standingCollisions.clear();
for (auto& data : mActorsFrameData) for (auto& data : mActorsFrameData)
{ {
// Ignore actors that were deleted while the background thread was running // Ignore actors that were deleted while the background thread was running
@ -227,8 +230,21 @@ namespace MWPhysics
updateMechanics(data); updateMechanics(data);
if (mAdvanceSimulation) if (mAdvanceSimulation)
updateStandingCollision(data, standingCollisions); data.mActorRaw->setStandingOnPtr(data.mStandingOn);
if (mMovementResults.find(data.mPtr) != mMovementResults.end())
data.mActorRaw->setNextPosition(mMovementResults[data.mPtr]);
} }
if (mFrameNumber == frameNumber - 1)
{
stats.setAttribute(mFrameNumber, "physicsworker_time_begin", mTimer->delta_s(mFrameStart, mTimeBegin));
stats.setAttribute(mFrameNumber, "physicsworker_time_taken", mTimer->delta_s(mTimeBegin, mTimeEnd));
stats.setAttribute(mFrameNumber, "physicsworker_time_end", mTimer->delta_s(mFrameStart, mTimeEnd));
}
mFrameStart = frameStart;
mTimeBegin = mTimer->tick();
mFrameNumber = frameNumber;
} }
// init // init
@ -244,18 +260,17 @@ namespace MWPhysics
if (mAdvanceSimulation) if (mAdvanceSimulation)
mWorldFrameData = std::make_unique<WorldFrameData>(); mWorldFrameData = std::make_unique<WorldFrameData>();
// update each actor position based on latest data
for (auto& data : mActorsFrameData)
data.updatePosition();
// we are asked to skip the simulation (load a savegame for instance) // we are asked to skip the simulation (load a savegame for instance)
// just return the actors' reference position without applying the movements // just return the actors' reference position without applying the movements
if (skipSimulation) if (skipSimulation)
{ {
standingCollisions.clear();
mMovementResults.clear(); mMovementResults.clear();
for (const auto& m : mActorsFrameData) for (const auto& m : mActorsFrameData)
mMovementResults[m.mPtr] = m.mPosition; {
m.mActorRaw->setStandingOnPtr(nullptr);
m.mActorRaw->resetPosition();
mMovementResults[m.mPtr] = m.mActorRaw->getWorldPosition();
}
return mMovementResults; return mMovementResults;
} }
@ -264,11 +279,12 @@ namespace MWPhysics
mMovementResults.clear(); mMovementResults.clear();
syncComputation(); syncComputation();
if (mAdvanceSimulation)
{
standingCollisions.clear();
for (auto& data : mActorsFrameData) for (auto& data : mActorsFrameData)
updateStandingCollision(data, standingCollisions); {
if (mAdvanceSimulation)
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
if (mMovementResults.find(data.mPtr) != mMovementResults.end())
data.mActorRaw->setNextPosition(mMovementResults[data.mPtr]);
} }
return mMovementResults; return mMovementResults;
} }
@ -294,25 +310,25 @@ namespace MWPhysics
void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
{ {
MaybeSharedLock<std::shared_timed_mutex> lock(mCollisionWorldMutex, mThreadSafeBullet); MaybeSharedLock lock(mCollisionWorldMutex, mThreadSafeBullet);
mCollisionWorld->rayTest(rayFromWorld, rayToWorld, resultCallback); mCollisionWorld->rayTest(rayFromWorld, rayToWorld, resultCallback);
} }
void PhysicsTaskScheduler::convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, btCollisionWorld::ConvexResultCallback& resultCallback) const void PhysicsTaskScheduler::convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, btCollisionWorld::ConvexResultCallback& resultCallback) const
{ {
MaybeSharedLock<std::shared_timed_mutex> lock(mCollisionWorldMutex, mThreadSafeBullet); MaybeSharedLock lock(mCollisionWorldMutex, mThreadSafeBullet);
mCollisionWorld->convexSweepTest(castShape, from, to, resultCallback); mCollisionWorld->convexSweepTest(castShape, from, to, resultCallback);
} }
void PhysicsTaskScheduler::contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback) void PhysicsTaskScheduler::contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback)
{ {
std::shared_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::shared_lock lock(mCollisionWorldMutex);
mCollisionWorld->contactTest(colObj, resultCallback); mCollisionWorld->contactTest(colObj, resultCallback);
} }
boost::optional<btVector3> PhysicsTaskScheduler::getHitPoint(const btTransform& from, btCollisionObject* target) std::optional<btVector3> PhysicsTaskScheduler::getHitPoint(const btTransform& from, btCollisionObject* target)
{ {
MaybeSharedLock<std::shared_timed_mutex> lock(mCollisionWorldMutex, mThreadSafeBullet); MaybeSharedLock lock(mCollisionWorldMutex, mThreadSafeBullet);
// target the collision object's world origin, this should be the center of the collision object // target the collision object's world origin, this should be the center of the collision object
btTransform rayTo; btTransform rayTo;
rayTo.setIdentity(); rayTo.setIdentity();
@ -323,37 +339,37 @@ namespace MWPhysics
mCollisionWorld->rayTestSingle(from, rayTo, target, target->getCollisionShape(), target->getWorldTransform(), cb); mCollisionWorld->rayTestSingle(from, rayTo, target, target->getCollisionShape(), target->getWorldTransform(), cb);
if (!cb.hasHit()) if (!cb.hasHit())
// didn't hit the target. this could happen if point is already inside the collision box // didn't hit the target. this could happen if point is already inside the collision box
return boost::none; return std::nullopt;
return {cb.m_hitPointWorld}; return {cb.m_hitPointWorld};
} }
void PhysicsTaskScheduler::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) void PhysicsTaskScheduler::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback)
{ {
std::shared_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::shared_lock lock(mCollisionWorldMutex);
mCollisionWorld->getBroadphase()->aabbTest(aabbMin, aabbMax, callback); mCollisionWorld->getBroadphase()->aabbTest(aabbMin, aabbMax, callback);
} }
void PhysicsTaskScheduler::getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max) void PhysicsTaskScheduler::getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max)
{ {
std::shared_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::shared_lock lock(mCollisionWorldMutex);
obj->getCollisionShape()->getAabb(obj->getWorldTransform(), min, max); obj->getCollisionShape()->getAabb(obj->getWorldTransform(), min, max);
} }
void PhysicsTaskScheduler::setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask) void PhysicsTaskScheduler::setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask)
{ {
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::unique_lock lock(mCollisionWorldMutex);
collisionObject->getBroadphaseHandle()->m_collisionFilterMask = collisionFilterMask; collisionObject->getBroadphaseHandle()->m_collisionFilterMask = collisionFilterMask;
} }
void PhysicsTaskScheduler::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask) void PhysicsTaskScheduler::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask)
{ {
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::unique_lock lock(mCollisionWorldMutex);
mCollisionWorld->addCollisionObject(collisionObject, collisionFilterGroup, collisionFilterMask); mCollisionWorld->addCollisionObject(collisionObject, collisionFilterGroup, collisionFilterMask);
} }
void PhysicsTaskScheduler::removeCollisionObject(btCollisionObject* collisionObject) void PhysicsTaskScheduler::removeCollisionObject(btCollisionObject* collisionObject)
{ {
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::unique_lock lock(mCollisionWorldMutex);
mCollisionWorld->removeCollisionObject(collisionObject); mCollisionWorld->removeCollisionObject(collisionObject);
} }
@ -361,19 +377,19 @@ namespace MWPhysics
{ {
if (mDeferAabbUpdate) if (mDeferAabbUpdate)
{ {
std::unique_lock<std::mutex> lock(mUpdateAabbMutex); std::unique_lock lock(mUpdateAabbMutex);
mUpdateAabb.insert(std::move(ptr)); mUpdateAabb.insert(std::move(ptr));
} }
else else
{ {
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::unique_lock lock(mCollisionWorldMutex);
updatePtrAabb(ptr); updatePtrAabb(ptr);
} }
} }
bool PhysicsTaskScheduler::getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2) bool PhysicsTaskScheduler::getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2)
{ {
std::unique_lock<std::shared_timed_mutex> lock(mLOSCacheMutex); std::unique_lock lock(mLOSCacheMutex);
auto actorPtr1 = actor1.lock(); auto actorPtr1 = actor1.lock();
auto actorPtr2 = actor2.lock(); auto actorPtr2 = actor2.lock();
@ -395,7 +411,7 @@ namespace MWPhysics
void PhysicsTaskScheduler::refreshLOSCache() void PhysicsTaskScheduler::refreshLOSCache()
{ {
std::shared_lock<std::shared_timed_mutex> lock(mLOSCacheMutex); std::shared_lock lock(mLOSCacheMutex);
int job = 0; int job = 0;
int numLOS = mLOSCache.size(); int numLOS = mLOSCache.size();
while ((job = mNextLOS.fetch_add(1, std::memory_order_relaxed)) < numLOS) while ((job = mNextLOS.fetch_add(1, std::memory_order_relaxed)) < numLOS)
@ -414,9 +430,7 @@ namespace MWPhysics
void PhysicsTaskScheduler::updateAabbs() void PhysicsTaskScheduler::updateAabbs()
{ {
std::unique_lock<std::shared_timed_mutex> lock1(mCollisionWorldMutex, std::defer_lock); std::scoped_lock lock(mCollisionWorldMutex, mUpdateAabbMutex);
std::unique_lock<std::mutex> lock2(mUpdateAabbMutex, std::defer_lock);
std::lock(lock1, lock2);
std::for_each(mUpdateAabb.begin(), mUpdateAabb.end(), std::for_each(mUpdateAabb.begin(), mUpdateAabb.end(),
[this](const std::weak_ptr<PtrHolder>& ptr) { updatePtrAabb(ptr); }); [this](const std::weak_ptr<PtrHolder>& ptr) { updatePtrAabb(ptr); });
mUpdateAabb.clear(); mUpdateAabb.clear();
@ -428,7 +442,7 @@ namespace MWPhysics
{ {
if (const auto actor = std::dynamic_pointer_cast<Actor>(p)) if (const auto actor = std::dynamic_pointer_cast<Actor>(p))
{ {
actor->commitPositionChange(); actor->updateCollisionObjectPosition();
mCollisionWorld->updateSingleAabb(actor->getCollisionObject()); mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
} }
else if (const auto object = std::dynamic_pointer_cast<Object>(p)) else if (const auto object = std::dynamic_pointer_cast<Object>(p))
@ -441,7 +455,7 @@ namespace MWPhysics
void PhysicsTaskScheduler::worker() void PhysicsTaskScheduler::worker()
{ {
std::shared_lock<std::shared_timed_mutex> lock(mSimulationMutex); std::shared_lock lock(mSimulationMutex);
while (!mQuit) while (!mQuit)
{ {
if (!mNewFrame) if (!mNewFrame)
@ -453,7 +467,7 @@ namespace MWPhysics
int job = 0; int job = 0;
while (mRemainingSteps && (job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs) while (mRemainingSteps && (job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
{ {
MaybeSharedLock<std::shared_timed_mutex> lockColWorld(mCollisionWorldMutex, mThreadSafeBullet); MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
if(const auto actor = mActorsFrameData[job].mActor.lock()) if(const auto actor = mActorsFrameData[job].mActor.lock())
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld.get(), *mWorldFrameData); MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld.get(), *mWorldFrameData);
} }
@ -481,32 +495,21 @@ namespace MWPhysics
void PhysicsTaskScheduler::updateActorsPositions() void PhysicsTaskScheduler::updateActorsPositions()
{ {
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex); std::unique_lock lock(mCollisionWorldMutex);
for (auto& actorData : mActorsFrameData) for (auto& actorData : mActorsFrameData)
{ {
if(const auto actor = actorData.mActor.lock()) if(const auto actor = actorData.mActor.lock())
{ {
if (actorData.mPosition == actor->getPosition()) bool positionChanged = actorData.mPosition != actorData.mActorRaw->getPosition();
actor->setPosition(actorData.mPosition, false); // update previous position to make sure interpolation is correct actorData.mActorRaw->setPosition(actorData.mPosition);
else if (positionChanged)
{ {
actorData.mPositionChanged = true; actor->updateCollisionObjectPosition();
actor->setPosition(actorData.mPosition);
}
}
}
}
void PhysicsTaskScheduler::udpateActorsAabbs()
{
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex);
for (const auto& actorData : mActorsFrameData)
if (actorData.mPositionChanged)
{
if(const auto actor = actorData.mActor.lock())
mCollisionWorld->updateSingleAabb(actor->getCollisionObject()); mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
} }
} }
}
}
bool PhysicsTaskScheduler::hasLineOfSight(const Actor* actor1, const Actor* actor2) bool PhysicsTaskScheduler::hasLineOfSight(const Actor* actor1, const Actor* actor2)
{ {
@ -517,7 +520,7 @@ namespace MWPhysics
resultCallback.m_collisionFilterGroup = 0xFF; resultCallback.m_collisionFilterGroup = 0xFF;
resultCallback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door; resultCallback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door;
MaybeSharedLock<std::shared_timed_mutex> lockColWorld(mCollisionWorldMutex, mThreadSafeBullet); MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
mCollisionWorld->rayTest(pos1, pos2, resultCallback); mCollisionWorld->rayTest(pos1, pos2, resultCallback);
return !resultCallback.hasHit(); return !resultCallback.hasHit();
@ -539,6 +542,5 @@ namespace MWPhysics
mMovementResults[actorData.mPtr] = interpolateMovements(actorData, mTimeAccum, mPhysicsDt); mMovementResults[actorData.mPtr] = interpolateMovements(actorData, mTimeAccum, mPhysicsDt);
updateMechanics(actorData); updateMechanics(actorData);
} }
udpateActorsAabbs();
} }
} }

View file

@ -3,12 +3,14 @@
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <thread> #include <optional>
#include <shared_mutex> #include <shared_mutex>
#include <thread>
#include <boost/optional/optional.hpp>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h> #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <osg/Timer>
#include "physicssystem.hpp" #include "physicssystem.hpp"
#include "ptrholder.hpp" #include "ptrholder.hpp"
@ -30,13 +32,13 @@ namespace MWPhysics
/// @param timeAccum accumulated time from previous run to interpolate movements /// @param timeAccum accumulated time from previous run to interpolate movements
/// @param actorsData per actor data needed to compute new positions /// @param actorsData per actor data needed to compute new positions
/// @return new position of each actor /// @return new position of each actor
const PtrPositionList& moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, CollisionMap& standingCollisions, bool skip); const PtrPositionList& moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, bool skip, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
// Thread safe wrappers // Thread safe wrappers
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const; void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
void convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, btCollisionWorld::ConvexResultCallback& resultCallback) const; void convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, btCollisionWorld::ConvexResultCallback& resultCallback) const;
void contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback); void contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback);
boost::optional<btVector3> getHitPoint(const btTransform& from, btCollisionObject* target); std::optional<btVector3> getHitPoint(const btTransform& from, btCollisionObject* target);
void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback);
void getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max); void getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max);
void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask); void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask);
@ -49,7 +51,6 @@ namespace MWPhysics
void syncComputation(); void syncComputation();
void worker(); void worker();
void updateActorsPositions(); void updateActorsPositions();
void udpateActorsAabbs();
bool hasLineOfSight(const Actor* actor1, const Actor* actor2); bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
void refreshLOSCache(); void refreshLOSCache();
void updateAabbs(); void updateAabbs();
@ -83,11 +84,17 @@ namespace MWPhysics
std::atomic<int> mNextLOS; std::atomic<int> mNextLOS;
std::vector<std::thread> mThreads; std::vector<std::thread> mThreads;
mutable std::shared_timed_mutex mSimulationMutex; mutable std::shared_mutex mSimulationMutex;
mutable std::shared_timed_mutex mCollisionWorldMutex; mutable std::shared_mutex mCollisionWorldMutex;
mutable std::shared_timed_mutex mLOSCacheMutex; mutable std::shared_mutex mLOSCacheMutex;
mutable std::mutex mUpdateAabbMutex; mutable std::mutex mUpdateAabbMutex;
std::condition_variable_any mHasJob; std::condition_variable_any mHasJob;
unsigned int mFrameNumber;
const osg::Timer* mTimer;
osg::Timer_t mTimeBegin;
osg::Timer_t mTimeEnd;
osg::Timer_t mFrameStart;
}; };
} }

View file

@ -1,7 +1,11 @@
#include "physicssystem.hpp" #include "physicssystem.hpp"
#include <LinearMath/btIDebugDraw.h>
#include <LinearMath/btVector3.h>
#include <memory>
#include <osg/Group> #include <osg/Group>
#include <osg/Stats> #include <osg/Stats>
#include <osg/Timer>
#include <BulletCollision/CollisionShapes/btConeShape.h> #include <BulletCollision/CollisionShapes/btConeShape.h>
#include <BulletCollision/CollisionShapes/btSphereShape.h> #include <BulletCollision/CollisionShapes/btSphereShape.h>
@ -90,6 +94,7 @@ namespace MWPhysics
} }
mTaskScheduler = std::make_unique<PhysicsTaskScheduler>(mPhysicsDt, mCollisionWorld); mTaskScheduler = std::make_unique<PhysicsTaskScheduler>(mPhysicsDt, mCollisionWorld);
mDebugDrawer = std::make_unique<MWRender::DebugDrawer>(mParentNode, mCollisionWorld.get(), mDebugDrawEnabled);
} }
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
@ -124,13 +129,7 @@ namespace MWPhysics
{ {
mDebugDrawEnabled = !mDebugDrawEnabled; mDebugDrawEnabled = !mDebugDrawEnabled;
if (mDebugDrawEnabled && !mDebugDrawer) mCollisionWorld->setDebugDrawer(mDebugDrawEnabled ? mDebugDrawer.get() : nullptr);
{
mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mCollisionWorld.get()));
mCollisionWorld->setDebugDrawer(mDebugDrawer.get());
mDebugDrawer->setDebugMode(mDebugDrawEnabled);
}
else if (mDebugDrawer)
mDebugDrawer->setDebugMode(mDebugDrawEnabled); mDebugDrawer->setDebugMode(mDebugDrawEnabled);
return mDebugDrawEnabled; return mDebugDrawEnabled;
} }
@ -150,11 +149,11 @@ namespace MWPhysics
if (!physactor || !physactor->getOnGround()) if (!physactor || !physactor->getOnGround())
return false; return false;
CollisionMap::const_iterator found = mStandingCollisions.find(actor); const auto obj = physactor->getStandingOnPtr();
if (found == mStandingCollisions.end()) if (obj.isEmpty())
return true; // assume standing on terrain (which is a non-object, so not collision tracked) return true; // assume standing on terrain (which is a non-object, so not collision tracked)
ObjectMap::const_iterator foundObj = mObjects.find(found->second); ObjectMap::const_iterator foundObj = mObjects.find(obj);
if (foundObj == mObjects.end()) if (foundObj == mObjects.end())
return false; return false;
@ -175,6 +174,7 @@ namespace MWPhysics
if (result.mHit) if (result.mHit)
{ {
reportCollision(Misc::Convert::toBullet(result.mHitPos), Misc::Convert::toBullet(result.mHitNormal));
return std::make_pair(result.mHitObject, result.mHitPos); return std::make_pair(result.mHitObject, result.mHitPos);
} }
@ -219,8 +219,11 @@ namespace MWPhysics
{ {
PtrHolder* holder = static_cast<PtrHolder*>(resultCallback.mObject->getUserPointer()); PtrHolder* holder = static_cast<PtrHolder*>(resultCallback.mObject->getUserPointer());
if (holder) if (holder)
{
reportCollision(resultCallback.mContactPoint, resultCallback.mContactNormal);
return std::make_pair(holder->getPtr(), Misc::Convert::toOsg(resultCallback.mContactPoint)); return std::make_pair(holder->getPtr(), Misc::Convert::toOsg(resultCallback.mContactPoint));
} }
}
return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); return std::make_pair(MWWorld::Ptr(), osg::Vec3f());
} }
@ -239,7 +242,7 @@ namespace MWPhysics
auto hitpoint = mTaskScheduler->getHitPoint(rayFrom, targetCollisionObj); auto hitpoint = mTaskScheduler->getHitPoint(rayFrom, targetCollisionObj);
if (hitpoint) if (hitpoint)
return (point - Misc::Convert::toOsg(hitpoint.get())).length(); return (point - Misc::Convert::toOsg(*hitpoint)).length();
// didn't hit the target. this could happen if point is already inside the collision box // didn't hit the target. this could happen if point is already inside the collision box
return 0.f; return 0.f;
@ -401,15 +404,15 @@ namespace MWPhysics
return osg::Vec3f(); return osg::Vec3f();
} }
std::vector<MWWorld::Ptr> PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const std::vector<ContactPoint> PhysicsSystem::getCollisionsPoints(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const
{ {
btCollisionObject* me = nullptr; btCollisionObject* me = nullptr;
ObjectMap::const_iterator found = mObjects.find(ptr); auto found = mObjects.find(ptr);
if (found != mObjects.end()) if (found != mObjects.end())
me = found->second->getCollisionObject(); me = found->second->getCollisionObject();
else else
return std::vector<MWWorld::Ptr>(); return {};
ContactTestResultCallback resultCallback (me); ContactTestResultCallback resultCallback (me);
resultCallback.m_collisionFilterGroup = collisionGroup; resultCallback.m_collisionFilterGroup = collisionGroup;
@ -418,12 +421,20 @@ namespace MWPhysics
return resultCallback.mResult; return resultCallback.mResult;
} }
std::vector<MWWorld::Ptr> PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const
{
std::vector<MWWorld::Ptr> actors;
for (auto& [actor, point, normal] : getCollisionsPoints(ptr, collisionGroup, collisionMask))
actors.emplace_back(actor);
return actors;
}
osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight) osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight)
{ {
ActorMap::iterator found = mActors.find(ptr); ActorMap::iterator found = mActors.find(ptr);
if (found == mActors.end()) if (found == mActors.end())
return ptr.getRefData().getPosition().asVec3(); return ptr.getRefData().getPosition().asVec3();
else found->second->resetPosition();
return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight); return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight);
} }
@ -491,22 +502,6 @@ namespace MWPhysics
} }
} }
void PhysicsSystem::updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated)
{
CollisionMap::iterator found = map.find(old);
if (found != map.end())
{
map[updated] = found->second;
map.erase(found);
}
for (auto& collision : map)
{
if (collision.second == old)
collision.second = updated;
}
}
void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated)
{ {
ObjectMap::iterator found = mObjects.find(old); ObjectMap::iterator found = mObjects.find(old);
@ -527,7 +522,11 @@ namespace MWPhysics
mActors.emplace(updated, std::move(actor)); mActors.emplace(updated, std::move(actor));
} }
updateCollisionMapPtr(mStandingCollisions, old, updated); for (auto& [_, actor] : mActors)
{
if (actor->getStandingOnPtr() == old)
actor->setStandingOnPtr(updated);
}
} }
Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr)
@ -648,27 +647,26 @@ namespace MWPhysics
return false; return false;
} }
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement) void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity)
{ {
for(auto& movementItem : mMovementQueue) for(auto& movementItem : mMovementQueue)
{ {
if (movementItem.first == ptr) if (movementItem.first == ptr)
{ {
movementItem.second = movement; movementItem.second = velocity;
return; return;
} }
} }
mMovementQueue.emplace_back(ptr, movement); mMovementQueue.emplace_back(ptr, velocity);
} }
void PhysicsSystem::clearQueuedMovement() void PhysicsSystem::clearQueuedMovement()
{ {
mMovementQueue.clear(); mMovementQueue.clear();
mStandingCollisions.clear();
} }
const PtrPositionList& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation) const PtrPositionList& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{ {
mTimeAccum += dt; mTimeAccum += dt;
@ -678,24 +676,20 @@ namespace MWPhysics
mTimeAccum -= numSteps * mPhysicsDt; mTimeAccum -= numSteps * mPhysicsDt;
return mTaskScheduler->moveActors(numSteps, mTimeAccum, prepareFrameData(), mStandingCollisions, skipSimulation); return mTaskScheduler->moveActors(numSteps, mTimeAccum, prepareFrameData(numSteps), skipSimulation, frameStart, frameNumber, stats);
} }
std::vector<ActorFrameData> PhysicsSystem::prepareFrameData() std::vector<ActorFrameData> PhysicsSystem::prepareFrameData(int numSteps)
{ {
std::vector<ActorFrameData> actorsFrameData; std::vector<ActorFrameData> actorsFrameData;
actorsFrameData.reserve(mMovementQueue.size()); actorsFrameData.reserve(mMovementQueue.size());
const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWBase::World *world = MWBase::Environment::get().getWorld();
for (const auto& m : mMovementQueue) for (const auto& [character, movement] : mMovementQueue)
{ {
const auto& character = m.first;
const auto& movement = m.second;
const auto foundActor = mActors.find(character); const auto foundActor = mActors.find(character);
if (foundActor == mActors.end()) // actor was already removed from the scene if (foundActor == mActors.end()) // actor was already removed from the scene
{
mStandingCollisions.erase(character);
continue; continue;
}
auto physicActor = foundActor->second; auto physicActor = foundActor->second;
float waterlevel = -std::numeric_limits<float>::max(); float waterlevel = -std::numeric_limits<float>::max();
@ -723,7 +717,12 @@ namespace MWPhysics
// Slow fall reduces fall speed by a factor of (effect magnitude / 200) // Slow fall reduces fall speed by a factor of (effect magnitude / 200)
const float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); const float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f));
actorsFrameData.emplace_back(std::move(physicActor), character, mStandingCollisions[character], moveToWaterSurface, movement, slowFall, waterlevel); // Ue current value only if we don't advance the simulation. Otherwise we might get a stale value.
MWWorld::Ptr standingOn;
if (numSteps == 0)
standingOn = physicActor->getStandingOnPtr();
actorsFrameData.emplace_back(std::move(physicActor), character, standingOn, moveToWaterSurface, movement, slowFall, waterlevel);
} }
mMovementQueue.clear(); mMovementQueue.clear();
return actorsFrameData; return actorsFrameData;
@ -755,26 +754,24 @@ namespace MWPhysics
void PhysicsSystem::debugDraw() void PhysicsSystem::debugDraw()
{ {
if (mDebugDrawer) if (mDebugDrawEnabled)
mDebugDrawer->step(); mDebugDrawer->step();
} }
bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const
{ {
for (const auto& standingActor : mStandingCollisions) const auto physActor = mActors.find(actor);
{ if (physActor != mActors.end())
if (standingActor.first == actor && standingActor.second == object) return physActor->second->getStandingOnPtr() == object;
return true;
}
return false; return false;
} }
void PhysicsSystem::getActorsStandingOn(const MWWorld::ConstPtr &object, std::vector<MWWorld::Ptr> &out) const void PhysicsSystem::getActorsStandingOn(const MWWorld::ConstPtr &object, std::vector<MWWorld::Ptr> &out) const
{ {
for (const auto& standingActor : mStandingCollisions) for (const auto& [_, actor] : mActors)
{ {
if (standingActor.second == object) if (actor->getStandingOnPtr() == object)
out.push_back(standingActor.first); out.emplace_back(actor->getPtr());
} }
} }
@ -861,10 +858,16 @@ namespace MWPhysics
stats.setAttribute(frameNumber, "Physics HeightFields", mHeightFields.size()); stats.setAttribute(frameNumber, "Physics HeightFields", mHeightFields.size());
} }
void PhysicsSystem::reportCollision(const btVector3& position, const btVector3& normal)
{
if (mDebugDrawEnabled)
mDebugDrawer->addCollision(position, normal);
}
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn,
bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel) bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel)
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn), : mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
mPositionChanged(false), mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface), mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface),
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos() mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos()
{ {
const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWBase::World *world = MWBase::Environment::get().getWorld();
@ -874,10 +877,9 @@ namespace MWPhysics
mWantJump = mPtr.getClass().getMovementSettings(mPtr).mPosition[2] != 0; mWantJump = mPtr.getClass().getMovementSettings(mPtr).mPosition[2] != 0;
mIsDead = mPtr.getClass().getCreatureStats(mPtr).isDead(); mIsDead = mPtr.getClass().getCreatureStats(mPtr).isDead();
mWasOnGround = actor->getOnGround(); mWasOnGround = actor->getOnGround();
}
void ActorFrameData::updatePosition() mActorRaw->updatePosition();
{ mOrigin = mActorRaw->getNextPosition();
mPosition = mActorRaw->getPosition(); mPosition = mActorRaw->getPosition();
if (mMoveToWaterSurface) if (mMoveToWaterSurface)
{ {

View file

@ -10,6 +10,7 @@
#include <osg/Quat> #include <osg/Quat>
#include <osg/BoundingBox> #include <osg/BoundingBox>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Timer>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
@ -45,17 +46,24 @@ class btDefaultCollisionConfiguration;
class btCollisionDispatcher; class btCollisionDispatcher;
class btCollisionObject; class btCollisionObject;
class btCollisionShape; class btCollisionShape;
class btVector3;
namespace MWPhysics namespace MWPhysics
{ {
using PtrPositionList = std::map<MWWorld::Ptr, osg::Vec3f>; using PtrPositionList = std::map<MWWorld::Ptr, osg::Vec3f>;
using CollisionMap = std::map<MWWorld::Ptr, MWWorld::Ptr>;
class HeightField; class HeightField;
class Object; class Object;
class Actor; class Actor;
class PhysicsTaskScheduler; class PhysicsTaskScheduler;
struct ContactPoint
{
MWWorld::Ptr mObject;
osg::Vec3f mPoint;
osg::Vec3f mNormal;
};
struct LOSRequest struct LOSRequest
{ {
LOSRequest(const std::weak_ptr<Actor>& a1, const std::weak_ptr<Actor>& a2); LOSRequest(const std::weak_ptr<Actor>& a1, const std::weak_ptr<Actor>& a2);
@ -70,14 +78,12 @@ namespace MWPhysics
struct ActorFrameData struct ActorFrameData
{ {
ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel); ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel);
void updatePosition();
std::weak_ptr<Actor> mActor; std::weak_ptr<Actor> mActor;
Actor* mActorRaw; Actor* mActorRaw;
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
MWWorld::Ptr mStandingOn; MWWorld::Ptr mStandingOn;
bool mFlying; bool mFlying;
bool mSwimming; bool mSwimming;
bool mPositionChanged;
bool mWasOnGround; bool mWasOnGround;
bool mWantJump; bool mWantJump;
bool mDidJump; bool mDidJump;
@ -89,6 +95,7 @@ namespace MWPhysics
float mOldHeight; float mOldHeight;
float mFallHeight; float mFallHeight;
osg::Vec3f mMovement; osg::Vec3f mMovement;
osg::Vec3f mOrigin;
osg::Vec3f mPosition; osg::Vec3f mPosition;
ESM::Position mRefpos; ESM::Position mRefpos;
}; };
@ -144,6 +151,7 @@ namespace MWPhysics
void debugDraw(); void debugDraw();
std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with
std::vector<ContactPoint> getCollisionsPoints(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const;
osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight); osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight);
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor, std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor,
@ -156,17 +164,17 @@ namespace MWPhysics
/// target vector hits the collision shape and then calculates distance from the intersection point. /// target vector hits the collision shape and then calculates distance from the intersection point.
/// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful. /// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful.
/// \note Only Actor targets are supported at the moment. /// \note Only Actor targets are supported at the moment.
float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const final; float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const override;
/// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all other actors. /// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all other actors.
RayCastingResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), RayCastingResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(),
std::vector<MWWorld::Ptr> targets = std::vector<MWWorld::Ptr>(), std::vector<MWWorld::Ptr> targets = std::vector<MWWorld::Ptr>(),
int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const final; int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const override;
RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const final; RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const override;
/// Return true if actor1 can see actor2. /// Return true if actor1 can see actor2.
bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const final; bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const override;
bool isOnGround (const MWWorld::Ptr& actor); bool isOnGround (const MWWorld::Ptr& actor);
@ -193,7 +201,7 @@ namespace MWPhysics
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
/// Apply all queued movements, then clear the list. /// Apply all queued movements, then clear the list.
const PtrPositionList& applyQueuedMovement(float dt, bool skipSimulation); const PtrPositionList& applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
/// Clear the queued movements list without applying. /// Clear the queued movements list without applying.
void clearQueuedMovement(); void clearQueuedMovement();
@ -232,12 +240,13 @@ namespace MWPhysics
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const; bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const;
void reportStats(unsigned int frameNumber, osg::Stats& stats) const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
void reportCollision(const btVector3& position, const btVector3& normal);
private: private:
void updateWater(); void updateWater();
std::vector<ActorFrameData> prepareFrameData(); std::vector<ActorFrameData> prepareFrameData(int numSteps);
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue; osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
@ -263,13 +272,6 @@ namespace MWPhysics
bool mDebugDrawEnabled; bool mDebugDrawEnabled;
// Tracks standing collisions happening during a single frame. <actor handle, collided handle>
// This will detect standing on an object, but won't detect running e.g. against a wall.
CollisionMap mStandingCollisions;
// replaces all occurrences of 'old' in the map by 'updated', no matter if it's a key or value
void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated);
using PtrVelocityList = std::vector<std::pair<MWWorld::Ptr, osg::Vec3f>>; using PtrVelocityList = std::vector<std::pair<MWWorld::Ptr, osg::Vec3f>>;
PtrVelocityList mMovementQueue; PtrVelocityList mMovementQueue;

View file

@ -16,7 +16,6 @@
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/resource/keyframemanager.hpp> #include <components/resource/keyframemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
@ -37,8 +36,6 @@
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/shader/shadermanager.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -66,7 +63,7 @@ namespace
void apply(osg::Node &node) override void apply(osg::Node &node) override
{ {
if (dynamic_cast<osgParticle::ParticleProcessor*>(&node)) if (dynamic_cast<osgParticle::ParticleProcessor*>(&node))
mToRemove.push_back(&node); mToRemove.emplace_back(&node);
traverse(node); traverse(node);
} }
@ -74,7 +71,7 @@ namespace
void apply(osg::Drawable& drw) override void apply(osg::Drawable& drw) override
{ {
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw)) if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
mToRemove.push_back(partsys); mToRemove.emplace_back(partsys);
} }
void remove() void remove()
@ -278,7 +275,7 @@ namespace
if (vfxCallback) if (vfxCallback)
{ {
if (vfxCallback->mFinished) if (vfxCallback->mFinished)
mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0))); mToRemove.emplace_back(group.asNode(), group.getParent(0));
else else
mHasMagicEffects = true; mHasMagicEffects = true;
} }
@ -331,7 +328,7 @@ namespace
{ {
bool toRemove = mEffectId < 0 || vfxCallback->mParams.mEffectId == mEffectId; bool toRemove = mEffectId < 0 || vfxCallback->mParams.mEffectId == mEffectId;
if (toRemove) if (toRemove)
mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0))); mToRemove.emplace_back(group.asNode(), group.getParent(0));
else else
mHasMagicEffects = true; mHasMagicEffects = true;
} }
@ -432,7 +429,7 @@ namespace
node.setStateSet(nullptr); node.setStateSet(nullptr);
if (node.getNodeMask() == 0x1 && node.getNumParents() == 1) if (node.getNodeMask() == 0x1 && node.getNumParents() == 1)
mToRemove.push_back(std::make_pair(&node, node.getParent(0))); mToRemove.emplace_back(&node, node.getParent(0));
else else
traverse(node); traverse(node);
} }
@ -450,12 +447,12 @@ namespace
osg::Group* parentParent = static_cast<osg::Group*>(*(parent - 1)); osg::Group* parentParent = static_cast<osg::Group*>(*(parent - 1));
if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC) if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC)
{ {
mToRemove.push_back(std::make_pair(parentGroup, parentParent)); mToRemove.emplace_back(parentGroup, parentParent);
return; return;
} }
} }
mToRemove.push_back(std::make_pair(&node, parentGroup)); mToRemove.emplace_back(&node, parentGroup);
} }
}; };
@ -483,7 +480,7 @@ namespace
{ {
osg::Group* parent = static_cast<osg::Group*>(*(getNodePath().end()-2)); osg::Group* parent = static_cast<osg::Group*>(*(getNodePath().end()-2));
// Not safe to remove in apply(), since the visitor is still iterating the child list // Not safe to remove in apply(), since the visitor is still iterating the child list
mToRemove.push_back(std::make_pair(&node, parent)); mToRemove.emplace_back(&node, parent);
} }
} }
}; };
@ -494,9 +491,8 @@ namespace MWRender
class TransparencyUpdater : public SceneUtil::StateSetUpdater class TransparencyUpdater : public SceneUtil::StateSetUpdater
{ {
public: public:
TransparencyUpdater(const float alpha, osg::ref_ptr<osg::Uniform> shadowUniform) TransparencyUpdater(const float alpha)
: mAlpha(alpha) : mAlpha(alpha)
, mShadowUniform(shadowUniform)
{ {
} }
@ -510,9 +506,6 @@ namespace MWRender
{ {
osg::BlendFunc* blendfunc (new osg::BlendFunc); osg::BlendFunc* blendfunc (new osg::BlendFunc);
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
// TODO: don't do this anymore once custom shadow renderbin is handling it
if (mShadowUniform)
stateset->addUniform(mShadowUniform);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
@ -534,7 +527,6 @@ namespace MWRender
private: private:
float mAlpha; float mAlpha;
osg::ref_ptr<osg::Uniform> mShadowUniform;
}; };
struct Animation::AnimSource struct Animation::AnimSource
@ -1827,7 +1819,7 @@ namespace MWRender
{ {
if (mTransparencyUpdater == nullptr) if (mTransparencyUpdater == nullptr)
{ {
mTransparencyUpdater = new TransparencyUpdater(alpha, mResourceSystem->getSceneManager()->getShaderManager().getShadowMapAlphaTestEnableUniform()); mTransparencyUpdater = new TransparencyUpdater(alpha);
mObjectRoot->addCullCallback(mTransparencyUpdater); mObjectRoot->addCullCallback(mTransparencyUpdater);
} }
else else

View file

@ -1,4 +1,4 @@
#include "bulletdebugdraw.hpp" #include <algorithm>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h> #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
@ -6,27 +6,19 @@
#include <osg/Group> #include <osg/Group>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/convert.hpp>
#include "bulletdebugdraw.hpp"
#include "vismask.hpp" #include "vismask.hpp"
namespace
{
osg::Vec3f toOsg(const btVector3& vec)
{
return osg::Vec3f(vec.x(), vec.y(), vec.z());
}
}
namespace MWRender namespace MWRender
{ {
DebugDrawer::DebugDrawer(osg::ref_ptr<osg::Group> parentNode, btCollisionWorld *world) DebugDrawer::DebugDrawer(osg::ref_ptr<osg::Group> parentNode, btCollisionWorld *world, int debugMode)
: mParentNode(parentNode), : mParentNode(parentNode),
mWorld(world), mWorld(world)
mDebugOn(true)
{ {
setDebugMode(debugMode);
createGeometry();
} }
void DebugDrawer::createGeometry() void DebugDrawer::createGeometry()
@ -37,11 +29,14 @@ void DebugDrawer::createGeometry()
mGeometry->setNodeMask(Mask_Debug); mGeometry->setNodeMask(Mask_Debug);
mVertices = new osg::Vec3Array; mVertices = new osg::Vec3Array;
mColors = new osg::Vec4Array;
mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES);
mGeometry->setUseDisplayList(false); mGeometry->setUseDisplayList(false);
mGeometry->setVertexArray(mVertices); mGeometry->setVertexArray(mVertices);
mGeometry->setColorArray(mColors);
mGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
mGeometry->setDataVariance(osg::Object::DYNAMIC); mGeometry->setDataVariance(osg::Object::DYNAMIC);
mGeometry->addPrimitiveSet(mDrawArrays); mGeometry->addPrimitiveSet(mDrawArrays);
@ -70,23 +65,53 @@ void DebugDrawer::step()
if (mDebugOn) if (mDebugOn)
{ {
mVertices->clear(); mVertices->clear();
mColors->clear();
mWorld->debugDrawWorld(); mWorld->debugDrawWorld();
showCollisions();
mDrawArrays->setCount(mVertices->size()); mDrawArrays->setCount(mVertices->size());
mVertices->dirty(); mVertices->dirty();
mColors->dirty();
mGeometry->dirtyBound(); mGeometry->dirtyBound();
} }
} }
void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color)
{ {
mVertices->push_back(toOsg(from)); mVertices->push_back(Misc::Convert::toOsg(from));
mVertices->push_back(toOsg(to)); mVertices->push_back(Misc::Convert::toOsg(to));
mColors->push_back({1,1,1,1});
mColors->push_back({1,1,1,1});
}
void DebugDrawer::addCollision(const btVector3& orig, const btVector3& normal)
{
mCollisionViews.emplace_back(orig, normal);
}
void DebugDrawer::showCollisions()
{
const auto now = std::chrono::steady_clock::now();
for (auto& [from, to , created] : mCollisionViews)
{
if (now - created < std::chrono::seconds(2))
{
mVertices->push_back(Misc::Convert::toOsg(from));
mVertices->push_back(Misc::Convert::toOsg(to));
mColors->push_back({1,0,0,1});
mColors->push_back({1,0,0,1});
}
}
mCollisionViews.erase(std::remove_if(mCollisionViews.begin(), mCollisionViews.end(),
[&now](const CollisionView& view) { return now - view.mCreated >= std::chrono::seconds(2); }),
mCollisionViews.end());
} }
void DebugDrawer::drawContactPoint(const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color) void DebugDrawer::drawContactPoint(const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color)
{ {
mVertices->push_back(toOsg(PointOnB)); mVertices->push_back(Misc::Convert::toOsg(PointOnB));
mVertices->push_back(toOsg(PointOnB) + (toOsg(normalOnB) * distance * 20)); mVertices->push_back(Misc::Convert::toOsg(PointOnB) + (Misc::Convert::toOsg(normalOnB) * distance * 20));
mColors->push_back({1,1,1,1});
mColors->push_back({1,1,1,1});
} }
void DebugDrawer::reportErrorWarning(const char *warningString) void DebugDrawer::reportErrorWarning(const char *warningString)
@ -96,7 +121,7 @@ void DebugDrawer::reportErrorWarning(const char *warningString)
void DebugDrawer::setDebugMode(int isOn) void DebugDrawer::setDebugMode(int isOn)
{ {
mDebugOn = (isOn == 0) ? false : true; mDebugOn = (isOn != 0);
if (!mDebugOn) if (!mDebugOn)
destroyGeometry(); destroyGeometry();
@ -109,6 +134,4 @@ int DebugDrawer::getDebugMode() const
return mDebugOn; return mDebugOn;
} }
} }

View file

@ -1,6 +1,9 @@
#ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H #ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H
#define OPENMW_MWRENDER_BULLETDEBUGDRAW_H #define OPENMW_MWRENDER_BULLETDEBUGDRAW_H
#include <chrono>
#include <vector>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Array> #include <osg/Array>
#include <osg/PrimitiveSet> #include <osg/PrimitiveSet>
@ -20,11 +23,22 @@ namespace MWRender
class DebugDrawer : public btIDebugDraw class DebugDrawer : public btIDebugDraw
{ {
private:
struct CollisionView
{
btVector3 mOrig;
btVector3 mEnd;
std::chrono::time_point<std::chrono::steady_clock> mCreated;
CollisionView(btVector3 orig, btVector3 normal) : mOrig(orig), mEnd(orig + normal * 20), mCreated(std::chrono::steady_clock::now()) {};
};
std::vector<CollisionView> mCollisionViews;
protected: protected:
osg::ref_ptr<osg::Group> mParentNode; osg::ref_ptr<osg::Group> mParentNode;
btCollisionWorld *mWorld; btCollisionWorld *mWorld;
osg::ref_ptr<osg::Geometry> mGeometry; osg::ref_ptr<osg::Geometry> mGeometry;
osg::ref_ptr<osg::Vec3Array> mVertices; osg::ref_ptr<osg::Vec3Array> mVertices;
osg::ref_ptr<osg::Vec4Array> mColors;
osg::ref_ptr<osg::DrawArrays> mDrawArrays; osg::ref_ptr<osg::DrawArrays> mDrawArrays;
bool mDebugOn; bool mDebugOn;
@ -34,13 +48,17 @@ protected:
public: public:
DebugDrawer(osg::ref_ptr<osg::Group> parentNode, btCollisionWorld *world); DebugDrawer(osg::ref_ptr<osg::Group> parentNode, btCollisionWorld *world, int debugMode = 1);
~DebugDrawer(); ~DebugDrawer();
void step(); void step();
void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) override; void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) override;
void addCollision(const btVector3& orig, const btVector3& normal);
void showCollisions();
void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) override; void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) override;
void reportErrorWarning(const char* warningString) override; void reportErrorWarning(const char* warningString) override;

Some files were not shown because too many files have changed in this diff Show more