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

pull/615/head
Mads Buvik Sandvei 4 years ago
commit 49e76fa077

@ -37,6 +37,8 @@ Debian_GCC:
CC: gcc
CXX: g++
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:
extends: .Debian
@ -96,7 +98,7 @@ variables: &cs-targets
- windows
before_script:
- 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 7zip -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
}
- 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:
key: ninja-v2
paths:
@ -186,7 +190,7 @@ Windows_Ninja_CS_RelWithDebInfo:
- windows
before_script:
- 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 7zip -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
}
- 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:
key: msbuild-v2
paths:
@ -299,4 +305,4 @@ Debian_AndroidNDK_arm64-v8a:
- ccache -s
artifacts:
paths:
- build/install/
- build/install/

@ -2,19 +2,12 @@ language: cpp
branches:
only:
- master
- coverity_scan
- /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
addons:
apt:
sources:
- sourceline: 'ppa:openmw/openmw'
# - ubuntu-toolchain-r-test # for GCC-10
packages: [
# Dev
build-essential, cmake, clang-tools, ccache,
@ -23,32 +16,21 @@ addons:
# FFmpeg
libavcodec-dev, libavformat-dev, libavutil-dev, libswresample-dev, libswscale-dev,
# 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
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:
include:
- name: OpenMW (all) on MacOS 10.15 with Xcode 11.6
os: osx
osx_image: xcode11.6
if: branch != coverity_scan
- name: OpenMW (all) on Ubuntu Focal with GCC
os: linux
dist: focal
if: branch != coverity_scan
- name: OpenMW (tests only) on Ubuntu Focal with GCC
os: linux
dist: focal
if: branch != coverity_scan
env:
- BUILD_TESTS_ONLY: 1
- name: OpenMW (openmw) on Ubuntu Focal with Clang's Static Analysis
@ -57,30 +39,21 @@ matrix:
env:
- MATRIX_EVAL="CC=clang && CXX=clang++"
- ANALYZE="scan-build --force-analyze-debug-code --use-cc clang --use-c++ clang++"
if: branch != coverity_scan
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:
- 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:
- ccache -z
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_script.${TRAVIS_OS_NAME}.sh; fi
- ./CI/before_script.${TRAVIS_OS_NAME}.sh
script:
- cd ./build
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ${ANALYZE} make -j3; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then ../CI/check_package.osx.sh; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ] && [ "${BUILD_TESTS_ONLY}" ]; then ./openmw_test_suite; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
- ${ANALYZE} make -j3;
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ../CI/check_package.osx.sh; fi
- if [ "${TRAVIS_OS_NAME}" = "linux" ] && [ "${BUILD_TESTS_ONLY}" ]; then ./openmw_test_suite; fi
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
- cd "${TRAVIS_BUILD_DIR}"
- ccache -s
deploy:

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

@ -7,12 +7,15 @@
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
Bug #2473: Unable to overstock merchants
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 #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 #3929: Leveled list merchant containers respawn on barter
Bug #4021: Attributes and skills are not stored as floats
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 #4631: Setting MSAA level too high doesn't fall back to highest supported level
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 #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 #5422: The player loses all spells when resurrected
Bug #5424: Creatures do not headtrack player
Bug #5425: Poison effect only appears for one frame
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 #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 #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 #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 #2386: Distant Statics in the form of Object Paging
Feature #2404: Levelled List can not be placed into a container
@ -78,6 +86,8 @@
Feature #5610: Actors movement should be smoother
Feature #5642: Ability to attach arrows to actor skeleton instead of bow mesh
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 #5520: Improve cell name autocompleter implementation

@ -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 qmake >/dev/null 2>&1 || brew install qt
brew link --overwrite lz4 # overwrite system lz4; use brew
brew reinstall lz4
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-ef2462c.zip -o ~/openmw-deps.zip
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-f8918dd.zip -o ~/openmw-deps.zip
unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null

@ -917,7 +917,7 @@ printf "LZ4 1.9.2... "
printf "Exists. "
elif [ -z $SKIP_EXTRACT ]; then
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
export LZ4DIR="$(real_pwd)/LZ4_1.9.2"
add_cmake_opts -DLZ4_INCLUDE_DIR="${LZ4DIR}/include" \

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

@ -1,5 +1,7 @@
project(OpenMW)
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
if(POLICY CMP0069)
@ -307,7 +309,7 @@ endif()
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(SDL2 2.0.9 REQUIRED)
find_package(OpenAL REQUIRED)
@ -394,9 +396,6 @@ if (NOT WIN32 AND NOT APPLE)
"${OpenMW_BINARY_DIR}/org.openmw.cs.desktop")
endif()
# CXX Compiler settings
set(CMAKE_CXX_STANDARD 17)
if(OPENMW_LTO_BUILD)
if(NOT CMAKE_VERSION VERSION_LESS 3.9)
include(CheckIPOSupported)

@ -6,7 +6,8 @@
#include <boost/filesystem.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
@ -25,16 +26,6 @@ struct Arguments
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)
{
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;
}
int list(Bsa::BSAFile& bsa, Arguments& info);
int extract(Bsa::BSAFile& bsa, Arguments& info);
int extractAll(Bsa::BSAFile& bsa, Arguments& info);
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
int main(int argc, char** argv)
{
@ -157,8 +148,16 @@ int main(int argc, char** argv)
return 1;
// Open file
Bsa::BSAFile bsa;
bsa.open(info.filename);
std::unique_ptr<Bsa::BSAFile> bsa;
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")
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
const Bsa::BSAFile::FileList &files = bsa.getList();
const Bsa::BSAFile::FileList &files = bsa->getList();
for (const auto& file : files)
{
if(info.longformat)
@ -201,15 +200,15 @@ int list(Bsa::BSAFile& bsa, Arguments& info)
return 0;
}
int extract(Bsa::BSAFile& bsa, Arguments& info)
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
{
std::string archivePath = info.extractfile;
replaceAll(archivePath, "/", "\\");
Misc::StringUtils::replaceAll(archivePath, "/", "\\");
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 << "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
Files::IStreamPtr stream = bsa.getFile(archivePath.c_str());
Files::IStreamPtr stream = bsa->getFile(archivePath.c_str());
bfs::ofstream out(target, std::ios::binary);
@ -250,12 +249,12 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
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);
replaceAll(extractPath, "\\", "/");
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
// Get the target path (the path the file will be extracted to)
bfs::path target (info.outdir);
@ -273,7 +272,7 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
// Get a stream for the file to extract
// (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);
// Write the file to disk

@ -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.
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
}
// Bug fixes
@ -277,6 +278,7 @@ void Launcher::AdvancedPage::saveSettings()
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
}
// Bug fixes

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

@ -645,7 +645,7 @@ MwIniImporter::MwIniImporter()
}
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);
if (time != defaultTime)
{
contentFiles.push_back({time, path});
contentFiles.emplace_back(time, std::move(path));
found = true;
break;
}
@ -985,14 +985,7 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename
std::time_t writeTime(defaultTime);
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);
#else
boost::filesystem::path resolved = filename;
#endif
writeTime = boost::filesystem::last_write_time(resolved);
// print timestamp

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

@ -89,10 +89,10 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
desc.add_options()
("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))
("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>()->
default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken())
("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));
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>())
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>()));
}
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.front() == '\"')
local = local.substr(1, local.length() - 2);
dataLocal.push_back(Files::PathContainer::value_type(local));
}
dataLocal.push_back(local);
mCfgMgr.processPaths (dataDirs);
mCfgMgr.processPaths (dataLocal, true);
@ -229,7 +224,7 @@ void CS::Editor::openFiles (const boost::filesystem::path &savePath, const std::
if(discoveredFiles.empty())
{
for (const QString &path : mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData());
files.emplace_back(path.toUtf8().constData());
}
else
{
@ -246,7 +241,7 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
std::vector<boost::filesystem::path> files;
for (const QString &path : mFileDialog.selectedFilePaths()) {
files.push_back(path.toUtf8().constData());
files.emplace_back(path.toUtf8().constData());
}
files.push_back (savePath);

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

@ -127,7 +127,7 @@ void CSMDoc::Loader::load()
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)

@ -57,7 +57,7 @@ void CSMDoc::Operation::run()
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)

@ -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)
{
mValues.push_back (EnumValue (value, tooltip));
mValues.emplace_back(value, tooltip);
return *this;
}

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

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

@ -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 (oldRow < 0 || plugin == 0)
{
results.recordMapping.push_back(std::make_pair(id, id));
results.recordMapping.emplace_back(id, id);
continue;
}
@ -366,7 +366,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
auto searchIt = reverseLookupMap.find(texture);
if (searchIt != reverseLookupMap.end())
{
results.recordMapping.push_back(std::make_pair(id, searchIt->second));
results.recordMapping.emplace_back(id, searchIt->second);
continue;
}
@ -381,7 +381,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
// Id not taken, clone it
cloneRecord(id, newId, UniversalId::Type_LandTexture);
results.createdRecords.push_back(newId);
results.recordMapping.push_back(std::make_pair(id, newId));
results.recordMapping.emplace_back(id, newId);
reverseLookupMap.emplace(texture, newId);
break;
}

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

@ -40,45 +40,45 @@ CSMWorld::RefIdCollection::RefIdCollection()
{
BaseColumns baseColumns;
mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_Id,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
mColumns.emplace_back(Columns::ColumnId_Id, ColumnBase::Display_Id,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false);
baseColumns.mId = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true, false));
mColumns.emplace_back(Columns::ColumnId_Modification, ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true, false);
baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
mColumns.emplace_back(Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false);
baseColumns.mType = &mColumns.back();
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();
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Script, ColumnBase::Display_Script));
mColumns.emplace_back(Columns::ColumnId_Script, ColumnBase::Display_Script);
nameColumns.mScript = &mColumns.back();
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Weight, ColumnBase::Display_Float));
mColumns.emplace_back(Columns::ColumnId_Weight, ColumnBase::Display_Float);
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();
IngredientColumns ingredientColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
ingredientColumns.mEffects = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> ingredientEffectsMap;
ingredientEffectsMap.insert(std::make_pair(UniversalId::Type_Ingredient,
new IngredEffectRefIdAdapter ()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap));
mNestedAdapters.emplace_back(&mColumns.back(), ingredientEffectsMap);
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_IngredEffectId));
mColumns.back().addColumn(
@ -88,13 +88,13 @@ CSMWorld::RefIdCollection::RefIdCollection()
// nested table
PotionColumns potionColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp
std::map<UniversalId::Type, NestedRefIdAdapterBase*> effectsMap;
effectsMap.insert(std::make_pair(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(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
mColumns.back().addColumn(
@ -114,67 +114,67 @@ CSMWorld::RefIdCollection::RefIdCollection()
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer));
mColumns.emplace_back(Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer);
enchantableColumns.mEnchantmentPoints = &mColumns.back();
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Charges, ColumnBase::Display_Integer));
mColumns.emplace_back(Columns::ColumnId_Charges, ColumnBase::Display_Integer);
toolsColumns.mUses = &mColumns.back();
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8));
mColumns.emplace_back(Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_UnsignedInteger8));
mColumns.emplace_back(Columns::ColumnId_AiAlarm, ColumnBase::Display_UnsignedInteger8);
actorsColumns.mAlarm = &mColumns.back();
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_ActorInventory,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mInventory = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> inventoryMap;
inventoryMap.insert(std::make_pair(UniversalId::Type_Npc,
new NestedInventoryRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
inventoryMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_SpellList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mSpells = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> spellsMap;
spellsMap.insert(std::make_pair(UniversalId::Type_Npc,
new NestedSpellRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
spellsMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_NpcDestinations,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mDestinations = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> destMap;
destMap.insert(std::make_pair(UniversalId::Type_Npc,
new NestedTravelRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
destMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell));
mColumns.back().addColumn(
@ -191,15 +191,15 @@ CSMWorld::RefIdCollection::RefIdCollection()
new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Double));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_AiPackageList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
actorsColumns.mAiPackages = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> aiMap;
aiMap.insert(std::make_pair(UniversalId::Type_Npc,
new ActorAiRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc)));
aiMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_AiPackageType, CSMWorld::ColumnBase::Display_AiPackageType));
mColumns.back().addColumn(
@ -270,56 +270,56 @@ CSMWorld::RefIdCollection::RefIdCollection()
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));
}
mColumns.push_back (RefIdColumn (Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
mColumns.emplace_back(Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh);
const RefIdColumn *autoCalc = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_ApparatusType,
ColumnBase::Display_ApparatusType));
mColumns.emplace_back(Columns::ColumnId_ApparatusType,
ColumnBase::Display_ApparatusType);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Health, ColumnBase::Display_Integer));
mColumns.emplace_back(Columns::ColumnId_Health, ColumnBase::Display_Integer);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_BookType, ColumnBase::Display_BookType));
mColumns.emplace_back(Columns::ColumnId_BookType, ColumnBase::Display_BookType);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Text, ColumnBase::Display_LongString));
mColumns.emplace_back(Columns::ColumnId_Text, ColumnBase::Display_LongString);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeightCapacity, ColumnBase::Display_Float));
mColumns.emplace_back(Columns::ColumnId_WeightCapacity, ColumnBase::Display_Float);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean));
mColumns.emplace_back(Columns::ColumnId_Respawn, ColumnBase::Display_Boolean);
const RefIdColumn *respawn = &mColumns.back();
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_ContainerContent,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
const RefIdColumn *content = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> contMap;
contMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
@ -327,11 +327,11 @@ CSMWorld::RefIdCollection::RefIdCollection()
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float));
mColumns.emplace_back(Columns::ColumnId_Scale, ColumnBase::Display_Float);
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();
static const struct
@ -354,7 +354,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
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));
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.
const RefIdColumn *bloodType = &mColumns.back();
creatureColumns.mBloodType = bloodType;
@ -371,24 +371,24 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_CreatureAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
creatureColumns.mAttributes = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaAttrMap;
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(
new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttack,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_CreatureAttack,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
creatureColumns.mAttacks = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> attackMap;
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(
new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false));
mColumns.back().addColumn(
@ -397,12 +397,12 @@ CSMWorld::RefIdCollection::RefIdCollection()
new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer));
// Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List));
mColumns.emplace_back(Columns::ColumnId_CreatureMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List);
creatureColumns.mMisc = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaMiscMap;
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(
new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer,
ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
@ -423,27 +423,27 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.back().addColumn(
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_CloseSound, ColumnBase::Display_Sound));
mColumns.emplace_back(Columns::ColumnId_CloseSound, ColumnBase::Display_Sound);
const RefIdColumn *closeSound = &mColumns.back();
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Radius, ColumnBase::Display_Integer));
mColumns.emplace_back(Columns::ColumnId_Radius, ColumnBase::Display_Integer);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_Sound));
mColumns.emplace_back(Columns::ColumnId_Sound, ColumnBase::Display_Sound);
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();
static const struct
@ -462,31 +462,31 @@ CSMWorld::RefIdCollection::RefIdCollection()
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));
}
mColumns.push_back (RefIdColumn (Columns::ColumnId_IsKey, ColumnBase::Display_Boolean));
mColumns.emplace_back(Columns::ColumnId_IsKey, ColumnBase::Display_Boolean);
const RefIdColumn *key = &mColumns.back();
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_Class));
mColumns.emplace_back(Columns::ColumnId_Class, ColumnBase::Display_Class);
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();
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart));
mColumns.emplace_back(Columns::Columnid_Hair, ColumnBase::Display_BodyPart);
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Gender, ColumnBase::Display_GenderNpc));
mColumns.emplace_back(Columns::ColumnId_Gender, ColumnBase::Display_GenderNpc);
npcColumns.mGender = &mColumns.back();
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.
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_NpcAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
npcColumns.mAttributes = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> attrMap;
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(
new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_UnsignedInteger8));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcSkills,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_NpcSkills,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
npcColumns.mSkills = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> skillsMap;
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(
new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_UnsignedInteger8));
// Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List));
mColumns.emplace_back(Columns::ColumnId_NpcMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List);
npcColumns.mMisc = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> miscMap;
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(
new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_SignedInteger16));
mColumns.back().addColumn(
@ -554,15 +554,15 @@ CSMWorld::RefIdCollection::RefIdCollection()
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.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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float));
mColumns.emplace_back(Columns::ColumnId_WeaponReach, ColumnBase::Display_Float);
weaponColumns.mReach = &mColumns.back();
for (int i=0; i<3; ++i)
@ -572,8 +572,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
for (int j=0; j<2; ++j)
{
mColumns.push_back (
RefIdColumn (Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer));
mColumns.emplace_back(Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer);
column[j] = &mColumns.back();
}
}
@ -591,19 +590,19 @@ CSMWorld::RefIdCollection::RefIdCollection()
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));
}
// 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();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> partMap;
partMap.insert(std::make_pair(UniversalId::Type_Armor,
new BodyPartRefIdAdapter<ESM::Armor> (UniversalId::Type_Armor)));
partMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType));
mColumns.back().addColumn(
@ -614,30 +613,30 @@ CSMWorld::RefIdCollection::RefIdCollection()
LevListColumns levListColumns (baseColumns);
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
mColumns.emplace_back(Columns::ColumnId_LevelledList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue);
levListColumns.mLevList = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> levListMap;
levListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList,
new NestedLevListRefIdAdapter<ESM::CreatureLevList> (UniversalId::Type_CreatureLevelledList)));
levListMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer));
// Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List));
mColumns.emplace_back(Columns::ColumnId_LevelledList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List);
levListColumns.mNestedListLevList = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> nestedListLevListMap;
nestedListLevListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList,
new NestedListLevListRefIdAdapter<ESM::CreatureLevList> (UniversalId::Type_CreatureLevelledList)));
nestedListLevListMap.insert(std::make_pair(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(
new RefIdColumn (Columns::ColumnId_LevelledItemTypeEach, CSMWorld::ColumnBase::Display_Boolean));
mColumns.back().addColumn(

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

@ -59,38 +59,38 @@ namespace CSVRender
/// Editmode for terrain shape grid
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
void primaryEditPressed (const WorldspaceHitResult& hit) final;
void primaryEditPressed (const WorldspaceHitResult& hit) override;
/// 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 deactivate(CSVWidget::SceneToolbar*) final;
void activate(CSVWidget::SceneToolbar*) override;
void deactivate(CSVWidget::SceneToolbar*) override;
/// Start shape editing command macro
bool primaryEditStartDrag (const QPoint& pos) final;
bool primaryEditStartDrag (const QPoint& pos) override;
bool secondaryEditStartDrag (const QPoint& pos) final;
bool primarySelectStartDrag (const QPoint& pos) final;
bool secondarySelectStartDrag (const QPoint& pos) final;
bool secondaryEditStartDrag (const QPoint& pos) override;
bool primarySelectStartDrag (const QPoint& pos) override;
bool secondarySelectStartDrag (const QPoint& pos) override;
/// 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
void dragCompleted(const QPoint& pos) final;
void dragCompleted(const QPoint& pos) override;
/// Cancel shape editing, and reset all pending changes
void dragAborted() final;
void dragAborted() override;
void dragWheel (int diff, double speedFactor) final;
void dragMoveEvent (QDragMoveEvent *event) final;
void mouseMoveEvent (QMouseEvent *event) final;
void dragWheel (int diff, double speedFactor) override;
void dragMoveEvent (QDragMoveEvent *event) override;
void mouseMoveEvent (QMouseEvent *event) override;
private:

@ -27,10 +27,10 @@ namespace CSVRender
const CSMWorld::Data& mData;
std::array<float, ESM::Land::LAND_SIZE * ESM::Land::LAND_SIZE> mAlteredHeight;
osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY) final;
const ESM::LandTexture* getLandTexture(int index, short plugin) final;
osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY) override;
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 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 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;
float getAlteredHeight(int col, int row) 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 override;
};
}

@ -53,37 +53,37 @@ namespace CSVRender
/// \brief Editmode for terrain texture grid
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
void primaryEditPressed (const WorldspaceHitResult& hit) final;
void primaryEditPressed (const WorldspaceHitResult& hit) override;
/// \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 deactivate(CSVWidget::SceneToolbar*) final;
void activate(CSVWidget::SceneToolbar*) override;
void deactivate(CSVWidget::SceneToolbar*) override;
/// \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 primarySelectStartDrag (const QPoint& pos) final;
bool secondarySelectStartDrag (const QPoint& pos) final;
bool secondaryEditStartDrag (const QPoint& pos) override;
bool primarySelectStartDrag (const QPoint& pos) override;
bool secondarySelectStartDrag (const QPoint& pos) override;
/// \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
void dragCompleted(const QPoint& pos) final;
void dragCompleted(const QPoint& pos) override;
void dragAborted() final;
void dragWheel (int diff, double speedFactor) final;
void dragMoveEvent (QDragMoveEvent *event) final;
void dragAborted() override;
void dragWheel (int diff, double speedFactor) override;
void dragMoveEvent (QDragMoveEvent *event) override;
void mouseMoveEvent (QMouseEvent *event) final;
void mouseMoveEvent (QMouseEvent *event) override;
private:
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.

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

@ -32,7 +32,7 @@ void CSVWorld::DataDisplayDelegate::buildPixmaps ()
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;
}
}

@ -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);
}

@ -345,18 +345,16 @@ std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() co
std::vector<CSMWorld::UniversalId> ids;
for (const QModelIndex& it : selected)
{
ids.push_back(
CSMWorld::UniversalId(
ids.emplace_back(
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);
for (const QModelIndex& it : selected)
{
ids.push_back(
CSMWorld::UniversalId(
ids.emplace_back(
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;
}

@ -452,7 +452,7 @@ std::vector<std::string> CSVWorld::Table::getSelectedIds() const
++iter)
{
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;
}
@ -784,7 +784,7 @@ std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::Column
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;

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

@ -100,6 +100,7 @@ namespace
Script,
Mechanics,
Physics,
PhysicsWorker,
World,
Gui,
@ -130,6 +131,9 @@ namespace
template <>
const UserStats UserStatsValue<UserStatsType::Physics>::sValue {"Phys", "physics"};
template <>
const UserStats UserStatsValue<UserStatsType::PhysicsWorker>::sValue {" -Async", "physicsworker"};
template <>
const UserStats UserStatsValue<UserStatsType::World>::sValue {"World", "world"};
@ -209,6 +213,10 @@ namespace
profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier,
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)
{
mEnvironment.getWorld()->updatePhysics(frametime, guiActive);
mEnvironment.getWorld()->updatePhysics(frametime, guiActive, frameStart, frameNumber, *stats);
}
}

@ -21,22 +21,6 @@
#include <unistd.h>
#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;
@ -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")
->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)")
("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")
("start", bpo::value<Files::EscapeHashString>()->default_value(""),
("start", bpo::value<Files::EscapeHashString>()->default_value(""),
"set initial cell")
("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)
->default_value(false), "disable all sounds")
@ -90,7 +74,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("script-console", bpo::value<bool>()->implicit_value(true)
->default_value(false), "enable console-only script functionality")
("script-run", bpo::value<Files::EscapeHashString>()->default_value(""),
("script-run", bpo::value<Files::EscapeHashString>()->default_value(""),
"select a file containing a list of console commands that is executed on startup")
("script-warn", bpo::value<int>()->implicit_value (1)
@ -101,12 +85,12 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
"\t2 - treat warnings as errors")
("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)
->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)")
("skip-menu", bpo::value<bool>()->implicit_value(true)
@ -118,14 +102,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("fs-strict", bpo::value<bool>()->implicit_value(true)
->default_value(false), "strict file system handling (no case folding)")
("encoding", bpo::value<Files::EscapeHashString>()->
("encoding", bpo::value<Files::EscapeHashString>()->
default_value("win1252"),
"Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
"\n\twin1252 - Western European (Latin) alphabet, used by default")
("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
->multitoken()->composing(), "fallback values")
("no-grab", bpo::value<bool>()->implicit_value(true)->default_value(false), "Don't grab mouse cursor")
@ -159,14 +143,16 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
{
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;
return false;
}
bpo::variables_map composingVariables = cfgMgr.separateComposingVariables(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;
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>()));
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.front() == '\"')
local = local.substr(1, local.length() - 2);
dataDirs.push_back(Files::PathContainer::value_type(local));
}
dataDirs.push_back(local);
cfgMgr.processPaths(dataDirs);
engine.setResourceDir(variables["resources"].as<Files::EscapeHashString>().toStdString());
engine.setResourceDir(variables["resources"].as<Files::EscapePath>().mPath);
engine.setDataDirs(dataDirs);
// 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.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
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
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);

@ -11,6 +11,8 @@
#include <components/esm/cellid.hpp>
#include <osg/Timer>
#include "../mwworld/ptr.hpp"
#include "../mwworld/doorstate.hpp"
@ -398,7 +400,7 @@ namespace MWBase
/// \return pointer to created record
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;

@ -132,11 +132,11 @@ namespace MWClass
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;
};
}

@ -432,12 +432,12 @@ namespace MWClass
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);
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
models.push_back("meshes/xargonian_swimkna.nif");
models.push_back("meshes/xbase_anim_female.nif");
models.push_back("meshes/xbase_anim.nif");
models.emplace_back("meshes/xargonian_swimkna.nif");
models.emplace_back("meshes/xbase_anim_female.nif");
models.emplace_back("meshes/xbase_anim.nif");
if (!npc->mBase->mModel.empty())
models.push_back("meshes/"+npc->mBase->mModel);

@ -166,11 +166,11 @@ namespace MWClass
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;
};
}

@ -468,7 +468,7 @@ namespace MWDialogue
void DialogueManager::addChoice (const std::string& text, int choice)
{
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()

@ -73,9 +73,9 @@ namespace MWDialogue
bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) 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;

@ -30,7 +30,7 @@ namespace MWDialogue
tokenizeKeywords(text.substr(iteration_pos, pos_begin - iteration_pos), result);
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;
}
@ -65,7 +65,7 @@ namespace MWDialogue
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);
}
}

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

@ -147,7 +147,7 @@ namespace MWGui
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);

@ -524,9 +524,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
break;
if ( lead != origin )
mPartialWhitespace.push_back (PartialText (style, lead, origin, space_width));
mPartialWhitespace.emplace_back(style, lead, origin, space_width);
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);
}
void setVisible (bool newVisible) final
void setVisible (bool newVisible) override
{
if (mVisible == newVisible)
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;
@ -1242,9 +1242,9 @@ public:
// ISubWidget should not necessarily be a drawitem
// in this case, it is not...
void doRender() final { }
void doRender() override { }
void _updateView () final
void _updateView () override
{
_checkMargin();
@ -1253,7 +1253,7 @@ public:
mNode->outOfDate (i->second->mRenderItem);
}
void _correctView() final
void _correctView() override
{
_checkMargin ();
@ -1263,7 +1263,7 @@ public:
}
void destroyDrawItem() final
void destroyDrawItem() override
{
for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i)
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);
}
void adviseLinkClicked (std::function <void (InteractiveId)> linkClicked) final
void adviseLinkClicked (std::function <void (InteractiveId)> linkClicked) override
{
mPageDisplay->mLinkClicked = linkClicked;
}
void unadviseLinkClicked () final
void unadviseLinkClicked () override
{
mPageDisplay->mLinkClicked = std::function <void (InteractiveId)> ();
}
protected:
void initialiseOverride() final
void initialiseOverride() override
{
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).
// Child widgets may already be destroyed! So be careful.
mPageDisplay->onMouseLostFocus ();
}
void onMouseMove(int left, int top) final
void onMouseMove(int left, int top) override
{
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);
}
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);
}

@ -217,7 +217,7 @@ namespace MWGui
if (store.get<ESM::Class>().isDynamic(classInfo.mId))
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);

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

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

@ -49,14 +49,14 @@ ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSour
for(const MWWorld::Ptr& source : itemSources)
{
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)
{
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

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

@ -20,10 +20,10 @@ namespace MWGui
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 setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) final;
void setImage(MyGUI::ImageBox* _image) override;
void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) override;
//and now for the whole point of this class, allow us to get
//the hot spot, the image and the size of the cursor.

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

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

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

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

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

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

@ -358,7 +358,7 @@ namespace MWGui
if (!playable) // Only display playable races
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);

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

@ -244,7 +244,7 @@ namespace MWGui
{
SDL_DisplayMode 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);
for (std::pair<int, int>& resolution : resolutions)

@ -31,18 +31,18 @@ namespace
{
// this defines the sorting order of types. types that are first in the vector appear before other types.
std::vector<std::string> mapping;
mapping.push_back( typeid(ESM::Weapon).name() );
mapping.push_back( typeid(ESM::Armor).name() );
mapping.push_back( typeid(ESM::Clothing).name() );
mapping.push_back( typeid(ESM::Potion).name() );
mapping.push_back( typeid(ESM::Ingredient).name() );
mapping.push_back( typeid(ESM::Apparatus).name() );
mapping.push_back( typeid(ESM::Book).name() );
mapping.push_back( typeid(ESM::Light).name() );
mapping.push_back( typeid(ESM::Miscellaneous).name() );
mapping.push_back( typeid(ESM::Lockpick).name() );
mapping.push_back( typeid(ESM::Repair).name() );
mapping.push_back( typeid(ESM::Probe).name() );
mapping.emplace_back(typeid(ESM::Weapon).name() );
mapping.emplace_back(typeid(ESM::Armor).name() );
mapping.emplace_back(typeid(ESM::Clothing).name() );
mapping.emplace_back(typeid(ESM::Potion).name() );
mapping.emplace_back(typeid(ESM::Ingredient).name() );
mapping.emplace_back(typeid(ESM::Apparatus).name() );
mapping.emplace_back(typeid(ESM::Book).name() );
mapping.emplace_back(typeid(ESM::Light).name() );
mapping.emplace_back(typeid(ESM::Miscellaneous).name() );
mapping.emplace_back(typeid(ESM::Lockpick).name() );
mapping.emplace_back(typeid(ESM::Repair).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(), type2) != mapping.end() );
@ -166,7 +166,7 @@ namespace MWGui
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()

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

@ -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()
{
mSpells.clear();
@ -61,8 +99,9 @@ namespace MWGui
continue;
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;
Spell newSpell;
@ -103,7 +142,8 @@ namespace MWGui
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;
Spell newSpell;

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

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

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

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

@ -84,7 +84,7 @@ namespace MWGui
{
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);

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

@ -199,7 +199,7 @@ namespace MWMechanics
if (sourceId != mSpellId)
return;
mMagnitudes.push_back(std::make_pair(key, magnitude));
mMagnitudes.emplace_back(key, magnitude);
}
std::vector<std::pair<MWMechanics::EffectKey, float>> mMagnitudes;
@ -590,7 +590,9 @@ namespace MWMechanics
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);
float deltaAngle = Misc::normalizeAngle(angle - actor.getRefData().getPosition().rot[2]);
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)
{
CreatureStats &creatureStats = ptr.getClass().getCreatureStats(ptr);
const MagicEffects &effects = creatureStats.getMagicEffects();
bool godmode = ptr == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
applyCureEffects(ptr);
bool wasDead = creatureStats.isDead();
if (duration > 0)
@ -1687,6 +1731,9 @@ namespace MWMechanics
void Actors::predictAndAvoidCollisions()
{
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
return;
const float minGap = 10.f;
const float maxDistForPartialAvoiding = 200.f;
const float maxDistForStrictAvoiding = 100.f;
@ -1723,7 +1770,7 @@ namespace MWMechanics
shouldAvoidCollision = true;
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;
}
else if (package->getTypeId() == AiPackageTypeId::Combat || package->getTypeId() == AiPackageTypeId::Pursue)

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

@ -24,15 +24,15 @@ namespace MWMechanics
public:
/// Constructor
/** \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; }
void writeState(ESM::AiSequence::AiSequence& sequence) const final;
void writeState(ESM::AiSequence::AiSequence& sequence) const override;
private:
const std::string mObjectId;

@ -20,9 +20,9 @@ namespace MWMechanics
{
public:
/// 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; }

@ -10,7 +10,7 @@ namespace MWMechanics
class AiBreathe final : public TypedAiPackage<AiBreathe>
{
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; }

@ -15,11 +15,11 @@ namespace MWMechanics
public:
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; }
MWWorld::Ptr getTarget() const final;
MWWorld::Ptr getTarget() const override;
static constexpr Options makeDefaultOptions()
{

@ -96,13 +96,13 @@ namespace MWMechanics
public:
///Constructor
/** \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();
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; }
@ -116,9 +116,9 @@ namespace MWMechanics
}
///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:
/// Returns true if combat should end

@ -30,7 +30,7 @@ namespace MWMechanics
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; }
@ -42,11 +42,11 @@ namespace MWMechanics
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:
const std::string mCellId;

@ -10,7 +10,7 @@ namespace MWMechanics
public:
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; }

@ -53,7 +53,7 @@ namespace MWMechanics
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; }
@ -69,15 +69,15 @@ namespace MWMechanics
/// Returns the actor being followed
std::string getFollowedActor();
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
void writeState (ESM::AiSequence::AiSequence& sequence) const override;
bool isCommanded() 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();
if (target.isEmpty())

@ -26,7 +26,7 @@ namespace MWMechanics
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; }
@ -38,9 +38,9 @@ namespace MWMechanics
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

@ -25,14 +25,14 @@ namespace MWMechanics
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
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; }
@ -44,7 +44,7 @@ namespace MWMechanics
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:
const float mX;
@ -62,7 +62,7 @@ namespace MWMechanics
static constexpr AiPackageTypeId getTypeId() { return AiPackageTypeId::InternalTravel; }
std::unique_ptr<AiPackage> clone() const final;
std::unique_ptr<AiPackage> clone() const override;
};
}

@ -89,9 +89,9 @@ namespace MWMechanics
\param repeat Repeat wander or not **/
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; }
@ -103,13 +103,13 @@ namespace MWMechanics
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)
return osg::Vec3f(0, 0, 0);

@ -276,6 +276,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
mCurrentHit = "shield";
MWRender::Animation::AnimPriority priorityBlock (Priority_Hit);
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);
}
@ -295,6 +296,8 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
mUpperBodyState = UpperCharState_Nothing;
}
}
if (mHitState != CharState_None)
idle = CharState_None;
}
else if(!mAnimation->isPlaying(mCurrentHit))
{
@ -314,8 +317,6 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
mAnimation->disable(mCurrentHit);
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)

@ -971,7 +971,7 @@ namespace MWMechanics
{
const OwnerMap& owners = it->second;
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;
}
}

@ -205,24 +205,6 @@ namespace MWMechanics
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:
return false;
}

@ -12,6 +12,7 @@ namespace MWMechanics
struct EffectKey;
/// 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?
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey& effectKey, float magnitude);
}

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

@ -57,13 +57,20 @@ namespace MWPhysics
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.
*/
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 commitPositionChange();
/**
* 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.
* 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;
@ -137,7 +145,11 @@ namespace MWPhysics
void setWalkingOnWater(bool walkingOnWater);
bool isWalkingOnWater() const;
MWWorld::Ptr getStandingOnPtr() const;
void setStandingOnPtr(const MWWorld::Ptr& ptr);
private:
MWWorld::Ptr mStandingOnPtr;
/// Removes then re-adds the collision object to the dynamics world
void updateCollisionMask();
void addCollisionMask(int collisionMask);
@ -159,11 +171,11 @@ namespace MWPhysics
osg::Vec3f mScale;
osg::Vec3f mRenderingScale;
osg::Vec3f mWorldPosition;
osg::Vec3f mNextPosition;
osg::Vec3f mPosition;
osg::Vec3f mPreviousPosition;
btTransform mLocalTransform;
bool mScaleUpdatePending;
bool mTransformUpdatePending;
mutable std::mutex mPositionMutex;
osg::Vec3f mForce;

@ -2,6 +2,8 @@
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include "components/misc/convert.hpp"
#include "ptrholder.hpp"
namespace MWPhysics
@ -20,7 +22,7 @@ namespace MWPhysics
collisionObject = col1Wrap->m_collisionObject;
PtrHolder* holder = static_cast<PtrHolder*>(collisionObject->getUserPointer());
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;
}

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

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

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

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

@ -1,6 +1,8 @@
#include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
#include <osg/Stats>
#include "components/debug/debuglog.hpp"
#include <components/misc/barrier.hpp>
#include "components/misc/convert.hpp"
@ -82,14 +84,6 @@ namespace
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)
{
if (actorData.mDidJump)
@ -102,9 +96,18 @@ namespace
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;
// 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);
}
@ -142,6 +145,7 @@ namespace MWPhysics
{
PhysicsTaskScheduler::PhysicsTaskScheduler(float physicsDt, std::shared_ptr<btCollisionWorld> collisionWorld)
: mPhysicsDt(physicsDt)
, mTimeAccum(0.f)
, mCollisionWorld(std::move(collisionWorld))
, mNumJobs(0)
, mRemainingSteps(0)
@ -152,6 +156,8 @@ namespace MWPhysics
, mQuit(false)
, mNextJob(0)
, mNextLOS(0)
, mFrameNumber(0)
, mTimer(osg::Timer::instance())
{
mNumThreads = Config::computeNumThreads(mThreadSafeBullet);
@ -181,22 +187,22 @@ namespace MWPhysics
mPostSimBarrier = std::make_unique<Misc::Barrier>(mNumThreads, [&]()
{
udpateActorsAabbs();
mNewFrame = false;
if (mLOSCacheExpiry >= 0)
{
std::unique_lock<std::shared_timed_mutex> lock(mLOSCacheMutex);
std::unique_lock lock(mLOSCacheMutex);
mLOSCache.erase(
std::remove_if(mLOSCache.begin(), mLOSCache.end(),
[](const LOSRequest& req) { return req.mStale; }),
mLOSCache.end());
}
mTimeEnd = mTimer->tick();
});
}
PhysicsTaskScheduler::~PhysicsTaskScheduler()
{
std::unique_lock<std::shared_timed_mutex> lock(mSimulationMutex);
std::unique_lock lock(mSimulationMutex);
mQuit = true;
mNumJobs = 0;
mRemainingSteps = 0;
@ -206,19 +212,16 @@ namespace MWPhysics
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.
// 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
if (mNumThreads != 0)
{
if (mAdvanceSimulation)
standingCollisions.clear();
for (auto& data : mActorsFrameData)
{
// Ignore actors that were deleted while the background thread was running
@ -227,8 +230,21 @@ namespace MWPhysics
updateMechanics(data);
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
@ -244,18 +260,17 @@ namespace MWPhysics
if (mAdvanceSimulation)
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)
// just return the actors' reference position without applying the movements
if (skipSimulation)
{
standingCollisions.clear();
mMovementResults.clear();
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;
}
@ -264,11 +279,12 @@ namespace MWPhysics
mMovementResults.clear();
syncComputation();
if (mAdvanceSimulation)
for (auto& data : mActorsFrameData)
{
standingCollisions.clear();
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;
}
@ -294,25 +310,25 @@ namespace MWPhysics
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);
}
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);
}
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);
}
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
btTransform rayTo;
rayTo.setIdentity();
@ -323,37 +339,37 @@ namespace MWPhysics
mCollisionWorld->rayTestSingle(from, rayTo, target, target->getCollisionShape(), target->getWorldTransform(), cb);
if (!cb.hasHit())
// 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};
}
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);
}
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);
}
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;
}
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);
}
void PhysicsTaskScheduler::removeCollisionObject(btCollisionObject* collisionObject)
{
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex);
std::unique_lock lock(mCollisionWorldMutex);
mCollisionWorld->removeCollisionObject(collisionObject);
}
@ -361,19 +377,19 @@ namespace MWPhysics
{
if (mDeferAabbUpdate)
{
std::unique_lock<std::mutex> lock(mUpdateAabbMutex);
std::unique_lock lock(mUpdateAabbMutex);
mUpdateAabb.insert(std::move(ptr));
}
else
{
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex);
std::unique_lock lock(mCollisionWorldMutex);
updatePtrAabb(ptr);
}
}
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 actorPtr2 = actor2.lock();
@ -395,7 +411,7 @@ namespace MWPhysics
void PhysicsTaskScheduler::refreshLOSCache()
{
std::shared_lock<std::shared_timed_mutex> lock(mLOSCacheMutex);
std::shared_lock lock(mLOSCacheMutex);
int job = 0;
int numLOS = mLOSCache.size();
while ((job = mNextLOS.fetch_add(1, std::memory_order_relaxed)) < numLOS)
@ -414,9 +430,7 @@ namespace MWPhysics
void PhysicsTaskScheduler::updateAabbs()
{
std::unique_lock<std::shared_timed_mutex> lock1(mCollisionWorldMutex, std::defer_lock);
std::unique_lock<std::mutex> lock2(mUpdateAabbMutex, std::defer_lock);
std::lock(lock1, lock2);
std::scoped_lock lock(mCollisionWorldMutex, mUpdateAabbMutex);
std::for_each(mUpdateAabb.begin(), mUpdateAabb.end(),
[this](const std::weak_ptr<PtrHolder>& ptr) { updatePtrAabb(ptr); });
mUpdateAabb.clear();
@ -428,7 +442,7 @@ namespace MWPhysics
{
if (const auto actor = std::dynamic_pointer_cast<Actor>(p))
{
actor->commitPositionChange();
actor->updateCollisionObjectPosition();
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
}
else if (const auto object = std::dynamic_pointer_cast<Object>(p))
@ -441,7 +455,7 @@ namespace MWPhysics
void PhysicsTaskScheduler::worker()
{
std::shared_lock<std::shared_timed_mutex> lock(mSimulationMutex);
std::shared_lock lock(mSimulationMutex);
while (!mQuit)
{
if (!mNewFrame)
@ -453,7 +467,7 @@ namespace MWPhysics
int job = 0;
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())
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld.get(), *mWorldFrameData);
}
@ -481,33 +495,22 @@ namespace MWPhysics
void PhysicsTaskScheduler::updateActorsPositions()
{
std::unique_lock<std::shared_timed_mutex> lock(mCollisionWorldMutex);
std::unique_lock lock(mCollisionWorldMutex);
for (auto& actorData : mActorsFrameData)
{
if(const auto actor = actorData.mActor.lock())
{
if (actorData.mPosition == actor->getPosition())
actor->setPosition(actorData.mPosition, false); // update previous position to make sure interpolation is correct
else
bool positionChanged = actorData.mPosition != actorData.mActorRaw->getPosition();
actorData.mActorRaw->setPosition(actorData.mPosition);
if (positionChanged)
{
actorData.mPositionChanged = true;
actor->setPosition(actorData.mPosition);
actor->updateCollisionObjectPosition();
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
}
}
}
}
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());
}
}
bool PhysicsTaskScheduler::hasLineOfSight(const Actor* actor1, const Actor* actor2)
{
btVector3 pos1 = Misc::Convert::toBullet(actor1->getCollisionObjectPosition() + osg::Vec3f(0,0,actor1->getHalfExtents().z() * 0.9)); // eye level
@ -517,7 +520,7 @@ namespace MWPhysics
resultCallback.m_collisionFilterGroup = 0xFF;
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);
return !resultCallback.hasHit();
@ -539,6 +542,5 @@ namespace MWPhysics
mMovementResults[actorData.mPtr] = interpolateMovements(actorData, mTimeAccum, mPhysicsDt);
updateMechanics(actorData);
}
udpateActorsAabbs();
}
}

@ -3,12 +3,14 @@
#include <atomic>
#include <condition_variable>
#include <thread>
#include <optional>
#include <shared_mutex>
#include <thread>
#include <boost/optional/optional.hpp>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <osg/Timer>
#include "physicssystem.hpp"
#include "ptrholder.hpp"
@ -30,13 +32,13 @@ namespace MWPhysics
/// @param timeAccum accumulated time from previous run to interpolate movements
/// @param actorsData per actor data needed to compute new positions
/// @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
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 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 getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max);
void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask);
@ -49,7 +51,6 @@ namespace MWPhysics
void syncComputation();
void worker();
void updateActorsPositions();
void udpateActorsAabbs();
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
void refreshLOSCache();
void updateAabbs();
@ -83,11 +84,17 @@ namespace MWPhysics
std::atomic<int> mNextLOS;
std::vector<std::thread> mThreads;
mutable std::shared_timed_mutex mSimulationMutex;
mutable std::shared_timed_mutex mCollisionWorldMutex;
mutable std::shared_timed_mutex mLOSCacheMutex;
mutable std::shared_mutex mSimulationMutex;
mutable std::shared_mutex mCollisionWorldMutex;
mutable std::shared_mutex mLOSCacheMutex;
mutable std::mutex mUpdateAabbMutex;
std::condition_variable_any mHasJob;
unsigned int mFrameNumber;
const osg::Timer* mTimer;
osg::Timer_t mTimeBegin;
osg::Timer_t mTimeEnd;
osg::Timer_t mFrameStart;
};
}

@ -1,7 +1,11 @@
#include "physicssystem.hpp"
#include <LinearMath/btIDebugDraw.h>
#include <LinearMath/btVector3.h>
#include <memory>
#include <osg/Group>
#include <osg/Stats>
#include <osg/Timer>
#include <BulletCollision/CollisionShapes/btConeShape.h>
#include <BulletCollision/CollisionShapes/btSphereShape.h>
@ -90,6 +94,7 @@ namespace MWPhysics
}
mTaskScheduler = std::make_unique<PhysicsTaskScheduler>(mPhysicsDt, mCollisionWorld);
mDebugDrawer = std::make_unique<MWRender::DebugDrawer>(mParentNode, mCollisionWorld.get(), mDebugDrawEnabled);
}
PhysicsSystem::~PhysicsSystem()
@ -124,14 +129,8 @@ namespace MWPhysics
{
mDebugDrawEnabled = !mDebugDrawEnabled;
if (mDebugDrawEnabled && !mDebugDrawer)
{
mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mCollisionWorld.get()));
mCollisionWorld->setDebugDrawer(mDebugDrawer.get());
mDebugDrawer->setDebugMode(mDebugDrawEnabled);
}
else if (mDebugDrawer)
mDebugDrawer->setDebugMode(mDebugDrawEnabled);
mCollisionWorld->setDebugDrawer(mDebugDrawEnabled ? mDebugDrawer.get() : nullptr);
mDebugDrawer->setDebugMode(mDebugDrawEnabled);
return mDebugDrawEnabled;
}
@ -150,11 +149,11 @@ namespace MWPhysics
if (!physactor || !physactor->getOnGround())
return false;
CollisionMap::const_iterator found = mStandingCollisions.find(actor);
if (found == mStandingCollisions.end())
const auto obj = physactor->getStandingOnPtr();
if (obj.isEmpty())
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())
return false;
@ -175,6 +174,7 @@ namespace MWPhysics
if (result.mHit)
{
reportCollision(Misc::Convert::toBullet(result.mHitPos), Misc::Convert::toBullet(result.mHitNormal));
return std::make_pair(result.mHitObject, result.mHitPos);
}
@ -219,7 +219,10 @@ namespace MWPhysics
{
PtrHolder* holder = static_cast<PtrHolder*>(resultCallback.mObject->getUserPointer());
if (holder)
{
reportCollision(resultCallback.mContactPoint, resultCallback.mContactNormal);
return std::make_pair(holder->getPtr(), Misc::Convert::toOsg(resultCallback.mContactPoint));
}
}
return std::make_pair(MWWorld::Ptr(), osg::Vec3f());
}
@ -239,7 +242,7 @@ namespace MWPhysics
auto hitpoint = mTaskScheduler->getHitPoint(rayFrom, targetCollisionObj);
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
return 0.f;
@ -401,15 +404,15 @@ namespace MWPhysics
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;
ObjectMap::const_iterator found = mObjects.find(ptr);
auto found = mObjects.find(ptr);
if (found != mObjects.end())
me = found->second->getCollisionObject();
else
return std::vector<MWWorld::Ptr>();
return {};
ContactTestResultCallback resultCallback (me);
resultCallback.m_collisionFilterGroup = collisionGroup;
@ -418,13 +421,21 @@ namespace MWPhysics
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)
{
ActorMap::iterator found = mActors.find(ptr);
if (found == mActors.end())
return ptr.getRefData().getPosition().asVec3();
else
return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight);
found->second->resetPosition();
return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight);
}
void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject)
@ -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)
{
ObjectMap::iterator found = mObjects.find(old);
@ -527,7 +522,11 @@ namespace MWPhysics
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)
@ -648,27 +647,26 @@ namespace MWPhysics
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)
{
if (movementItem.first == ptr)
{
movementItem.second = movement;
movementItem.second = velocity;
return;
}
}
mMovementQueue.emplace_back(ptr, movement);
mMovementQueue.emplace_back(ptr, velocity);
}
void PhysicsSystem::clearQueuedMovement()
{
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;
@ -678,24 +676,20 @@ namespace MWPhysics
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;
actorsFrameData.reserve(mMovementQueue.size());
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);
if (foundActor == mActors.end()) // actor was already removed from the scene
{
mStandingCollisions.erase(character);
continue;
}
auto physicActor = foundActor->second;
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)
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();
return actorsFrameData;
@ -755,26 +754,24 @@ namespace MWPhysics
void PhysicsSystem::debugDraw()
{
if (mDebugDrawer)
if (mDebugDrawEnabled)
mDebugDrawer->step();
}
bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const
{
for (const auto& standingActor : mStandingCollisions)
{
if (standingActor.first == actor && standingActor.second == object)
return true;
}
const auto physActor = mActors.find(actor);
if (physActor != mActors.end())
return physActor->second->getStandingOnPtr() == object;
return false;
}
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)
out.push_back(standingActor.first);
if (actor->getStandingOnPtr() == object)
out.emplace_back(actor->getPtr());
}
}
@ -861,10 +858,16 @@ namespace MWPhysics
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,
bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel)
: 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()
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
@ -874,10 +877,9 @@ namespace MWPhysics
mWantJump = mPtr.getClass().getMovementSettings(mPtr).mPosition[2] != 0;
mIsDead = mPtr.getClass().getCreatureStats(mPtr).isDead();
mWasOnGround = actor->getOnGround();
}
void ActorFrameData::updatePosition()
{
mActorRaw->updatePosition();
mOrigin = mActorRaw->getNextPosition();
mPosition = mActorRaw->getPosition();
if (mMoveToWaterSurface)
{

@ -10,6 +10,7 @@
#include <osg/Quat>
#include <osg/BoundingBox>
#include <osg/ref_ptr>
#include <osg/Timer>
#include "../mwworld/ptr.hpp"
@ -45,17 +46,24 @@ class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
class btCollisionObject;
class btCollisionShape;
class btVector3;
namespace MWPhysics
{
using PtrPositionList = std::map<MWWorld::Ptr, osg::Vec3f>;
using CollisionMap = std::map<MWWorld::Ptr, MWWorld::Ptr>;
class HeightField;
class Object;
class Actor;
class PhysicsTaskScheduler;
struct ContactPoint
{
MWWorld::Ptr mObject;
osg::Vec3f mPoint;
osg::Vec3f mNormal;
};
struct LOSRequest
{
LOSRequest(const std::weak_ptr<Actor>& a1, const std::weak_ptr<Actor>& a2);
@ -70,14 +78,12 @@ namespace MWPhysics
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);
void updatePosition();
std::weak_ptr<Actor> mActor;
Actor* mActorRaw;
MWWorld::Ptr mPtr;
MWWorld::Ptr mStandingOn;
bool mFlying;
bool mSwimming;
bool mPositionChanged;
bool mWasOnGround;
bool mWantJump;
bool mDidJump;
@ -89,6 +95,7 @@ namespace MWPhysics
float mOldHeight;
float mFallHeight;
osg::Vec3f mMovement;
osg::Vec3f mOrigin;
osg::Vec3f mPosition;
ESM::Position mRefpos;
};
@ -144,6 +151,7 @@ namespace MWPhysics
void debugDraw();
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);
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.
/// 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.
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.
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>(),
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.
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);
@ -193,7 +201,7 @@ namespace MWPhysics
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
/// 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.
void clearQueuedMovement();
@ -232,12 +240,13 @@ namespace MWPhysics
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const;
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
void reportCollision(const btVector3& position, const btVector3& normal);
private:
void updateWater();
std::vector<ActorFrameData> prepareFrameData();
std::vector<ActorFrameData> prepareFrameData(int numSteps);
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
@ -263,13 +272,6 @@ namespace MWPhysics
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>>;
PtrVelocityList mMovementQueue;

@ -16,7 +16,6 @@
#include <components/resource/scenemanager.hpp>
#include <components/resource/keyframemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/misc/constants.hpp>
#include <components/misc/resourcehelpers.hpp>
@ -37,8 +36,6 @@
#include <components/settings/settings.hpp>
#include <components/shader/shadermanager.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
@ -66,7 +63,7 @@ namespace
void apply(osg::Node &node) override
{
if (dynamic_cast<osgParticle::ParticleProcessor*>(&node))
mToRemove.push_back(&node);
mToRemove.emplace_back(&node);
traverse(node);
}
@ -74,7 +71,7 @@ namespace
void apply(osg::Drawable& drw) override
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
mToRemove.push_back(partsys);
mToRemove.emplace_back(partsys);
}
void remove()
@ -278,7 +275,7 @@ namespace
if (vfxCallback)
{
if (vfxCallback->mFinished)
mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0)));
mToRemove.emplace_back(group.asNode(), group.getParent(0));
else
mHasMagicEffects = true;
}
@ -331,7 +328,7 @@ namespace
{
bool toRemove = mEffectId < 0 || vfxCallback->mParams.mEffectId == mEffectId;
if (toRemove)
mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0)));
mToRemove.emplace_back(group.asNode(), group.getParent(0));
else
mHasMagicEffects = true;
}
@ -432,7 +429,7 @@ namespace
node.setStateSet(nullptr);
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
traverse(node);
}
@ -450,12 +447,12 @@ namespace
osg::Group* parentParent = static_cast<osg::Group*>(*(parent - 1));
if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC)
{
mToRemove.push_back(std::make_pair(parentGroup, parentParent));
mToRemove.emplace_back(parentGroup, parentParent);
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));
// 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
{
public:
TransparencyUpdater(const float alpha, osg::ref_ptr<osg::Uniform> shadowUniform)
TransparencyUpdater(const float alpha)
: mAlpha(alpha)
, mShadowUniform(shadowUniform)
{
}
@ -510,9 +506,6 @@ namespace MWRender
{
osg::BlendFunc* blendfunc (new osg::BlendFunc);
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->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
@ -534,7 +527,6 @@ namespace MWRender
private:
float mAlpha;
osg::ref_ptr<osg::Uniform> mShadowUniform;
};
struct Animation::AnimSource
@ -1827,7 +1819,7 @@ namespace MWRender
{
if (mTransparencyUpdater == nullptr)
{
mTransparencyUpdater = new TransparencyUpdater(alpha, mResourceSystem->getSceneManager()->getShaderManager().getShadowMapAlphaTestEnableUniform());
mTransparencyUpdater = new TransparencyUpdater(alpha);
mObjectRoot->addCullCallback(mTransparencyUpdater);
}
else

@ -1,4 +1,4 @@
#include "bulletdebugdraw.hpp"
#include <algorithm>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
@ -6,27 +6,19 @@
#include <osg/Group>
#include <components/debug/debuglog.hpp>
#include <components/misc/convert.hpp>
#include "bulletdebugdraw.hpp"
#include "vismask.hpp"
namespace
{
osg::Vec3f toOsg(const btVector3& vec)
{
return osg::Vec3f(vec.x(), vec.y(), vec.z());
}
}
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),
mWorld(world),
mDebugOn(true)
mWorld(world)
{
createGeometry();
setDebugMode(debugMode);
}
void DebugDrawer::createGeometry()
@ -37,11 +29,14 @@ void DebugDrawer::createGeometry()
mGeometry->setNodeMask(Mask_Debug);
mVertices = new osg::Vec3Array;
mColors = new osg::Vec4Array;
mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES);
mGeometry->setUseDisplayList(false);
mGeometry->setVertexArray(mVertices);
mGeometry->setColorArray(mColors);
mGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
mGeometry->setDataVariance(osg::Object::DYNAMIC);
mGeometry->addPrimitiveSet(mDrawArrays);
@ -70,23 +65,53 @@ void DebugDrawer::step()
if (mDebugOn)
{
mVertices->clear();
mColors->clear();
mWorld->debugDrawWorld();
showCollisions();
mDrawArrays->setCount(mVertices->size());
mVertices->dirty();
mColors->dirty();
mGeometry->dirtyBound();
}
}
void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color)
{
mVertices->push_back(toOsg(from));
mVertices->push_back(toOsg(to));
mVertices->push_back(Misc::Convert::toOsg(from));
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)
{
mVertices->push_back(toOsg(PointOnB));
mVertices->push_back(toOsg(PointOnB) + (toOsg(normalOnB) * distance * 20));
mVertices->push_back(Misc::Convert::toOsg(PointOnB));
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)
@ -96,7 +121,7 @@ void DebugDrawer::reportErrorWarning(const char *warningString)
void DebugDrawer::setDebugMode(int isOn)
{
mDebugOn = (isOn == 0) ? false : true;
mDebugOn = (isOn != 0);
if (!mDebugOn)
destroyGeometry();
@ -109,6 +134,4 @@ int DebugDrawer::getDebugMode() const
return mDebugOn;
}
}

@ -1,6 +1,9 @@
#ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H
#define OPENMW_MWRENDER_BULLETDEBUGDRAW_H
#include <chrono>
#include <vector>
#include <osg/ref_ptr>
#include <osg/Array>
#include <osg/PrimitiveSet>
@ -20,11 +23,22 @@ namespace MWRender
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:
osg::ref_ptr<osg::Group> mParentNode;
btCollisionWorld *mWorld;
osg::ref_ptr<osg::Geometry> mGeometry;
osg::ref_ptr<osg::Vec3Array> mVertices;
osg::ref_ptr<osg::Vec4Array> mColors;
osg::ref_ptr<osg::DrawArrays> mDrawArrays;
bool mDebugOn;
@ -34,13 +48,17 @@ protected:
public:
DebugDrawer(osg::ref_ptr<osg::Group> parentNode, btCollisionWorld *world);
DebugDrawer(osg::ref_ptr<osg::Group> parentNode, btCollisionWorld *world, int debugMode = 1);
~DebugDrawer();
void step();
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 reportErrorWarning(const char* warningString) override;

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

Loading…
Cancel
Save