From 109a7c3daf5d4044d15fafebb3d217b9342bfa62 Mon Sep 17 00:00:00 2001 From: psi29a Date: Fri, 2 Jul 2021 06:27:17 +0000 Subject: [PATCH 01/13] Merge branch 'base64-fixes' into 'master' Base64 fixes Closes #6111 See merge request OpenMW/openmw!965 (cherry picked from commit 07c3ed16d0e05df8724b1f45696e9d17a2111938) 873b3b48 Handle empty strings. d38126ef Pack default CS config --- CMakeLists.txt | 6 +++--- apps/opencs/CMakeLists.txt | 4 ++-- apps/opencs/model/prefs/state.cpp | 8 ++++---- apps/opencs/model/prefs/state.hpp | 1 + extern/Base64/Base64.h | 6 ++++++ 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee7e29bd7..705b95f82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,8 +458,8 @@ else () "${OpenMW_BINARY_DIR}/openmw.cfg") endif () -configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg - "${OpenMW_BINARY_DIR}" "openmw-cs.cfg") +pack_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg + "${OpenMW_BINARY_DIR}" "defaults-cs.bin") # Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate. copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters @@ -928,7 +928,7 @@ elseif(NOT APPLE) INSTALL(FILES "${INSTALL_SOURCE}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${INSTALL_SOURCE}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") + INSTALL(FILES "${INSTALL_SOURCE}/defaults-cs.bin" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 19c32df60..88c4233c9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -158,7 +158,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(APPLE) set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns") - set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg") + set (OPENCS_CFG "${OpenMW_BINARY_DIR}/defaults-cs.bin") set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters") set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg") else() @@ -270,7 +270,7 @@ if (WIN32) SET(INSTALL_SOURCE "${OpenMW_BINARY_DIR}") endif () - INSTALL(FILES "${INSTALL_SOURCE}/openmw-cs.cfg" DESTINATION ".") + INSTALL(FILES "${INSTALL_SOURCE}/defaults-cs.bin" DESTINATION ".") endif() if (MSVC) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 0958fa8d4..58a0f296e 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -17,15 +17,15 @@ CSMPrefs::State *CSMPrefs::State::sThis = nullptr; void CSMPrefs::State::load() { // default settings file - boost::filesystem::path local = mConfigurationManager.getLocalPath() / mConfigFile; - boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mConfigFile; + boost::filesystem::path local = mConfigurationManager.getLocalPath() / mDefaultConfigFile; + boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mDefaultConfigFile; if (boost::filesystem::exists (local)) mSettings.loadDefault (local.string()); else if (boost::filesystem::exists (global)) mSettings.loadDefault (global.string()); else - throw std::runtime_error ("No default settings file found! Make sure the file \"openmw-cs.cfg\" was properly installed."); + throw std::runtime_error ("No default settings file found! Make sure the file \"" + mDefaultConfigFile + "\" was properly installed."); // user settings file boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; @@ -641,7 +641,7 @@ void CSMPrefs::State::setDefault (const std::string& key, const std::string& def } CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) -: mConfigFile ("openmw-cs.cfg"), mConfigurationManager (configurationManager), +: mConfigFile ("openmw-cs.cfg"), mDefaultConfigFile("defaults-cs.bin"), mConfigurationManager (configurationManager), mCurrentCategory (mCategories.end()) { if (sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index aa63de595..7c9fcbecd 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -48,6 +48,7 @@ namespace CSMPrefs private: const std::string mConfigFile; + const std::string mDefaultConfigFile; const Files::ConfigurationManager& mConfigurationManager; ShortcutManager mShortcutManager; Settings::Manager mSettings; diff --git a/extern/Base64/Base64.h b/extern/Base64/Base64.h index 4e9f51747..49b2d29e3 100644 --- a/extern/Base64/Base64.h +++ b/extern/Base64/Base64.h @@ -95,6 +95,12 @@ class Base64 { size_t in_len = input.size(); if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; + if (in_len == 0) + { + out = ""; + return ""; + } + size_t out_len = in_len / 4 * 3; if (input[in_len - 1] == '=') out_len--; if (input[in_len - 2] == '=') out_len--; From dfacaa3711f221bc942e6391682dcea349b71671 Mon Sep 17 00:00:00 2001 From: psi29a Date: Mon, 5 Jul 2021 07:30:32 +0000 Subject: [PATCH 02/13] Merge branch 'fix_navmesh_update' into 'master' Fix navmesh update on opening/closing door See merge request OpenMW/openmw!995 (cherry picked from commit 9123db3a5954dd082f501151cba0a08bfe3ff908) c7c0d11c Trigger navmesh update when any navigator object has been updated --- apps/openmw/mwworld/worldimp.cpp | 24 +++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cfcfea1ea..1338781c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1223,7 +1223,7 @@ namespace MWWorld if (movePhysics) { if (const auto object = mPhysics->getObject(ptr)) - updateNavigatorObject(object); + updateNavigatorObject(*object); } } @@ -1282,7 +1282,7 @@ namespace MWWorld if (mPhysics->getActor(ptr)) mNavigator->addAgent(getPathfindingHalfExtents(ptr)); else if (const auto object = mPhysics->getObject(ptr)) - mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; + updateNavigatorObject(*object); } void World::rotateObjectImp(const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags) @@ -1331,7 +1331,7 @@ namespace MWWorld mWorldScene->updateObjectRotation(ptr, order); if (const auto object = mPhysics->getObject(ptr)) - updateNavigatorObject(object); + updateNavigatorObject(*object); } } @@ -1423,7 +1423,7 @@ namespace MWWorld mPhysics->updateRotation(ptr); if (const auto object = mPhysics->getObject(ptr)) - updateNavigatorObject(object); + updateNavigatorObject(*object); } } @@ -1543,14 +1543,11 @@ namespace MWWorld void World::updateNavigator() { - mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) - { - mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; - }); + mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) { updateNavigatorObject(*object); }); for (const auto& door : mDoorStates) if (const auto object = mPhysics->getObject(door.first)) - mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; + updateNavigatorObject(*object); if (mShouldUpdateNavigator) { @@ -1559,13 +1556,14 @@ namespace MWWorld } } - bool World::updateNavigatorObject(const MWPhysics::Object* object) + void World::updateNavigatorObject(const MWPhysics::Object& object) { const DetourNavigator::ObjectShapes shapes { - *object->getShapeInstance()->getCollisionShape(), - object->getShapeInstance()->getAvoidCollisionShape() + *object.getShapeInstance()->getCollisionShape(), + object.getShapeInstance()->getAvoidCollisionShape() }; - return mNavigator->updateObject(DetourNavigator::ObjectId(object), shapes, object->getTransform()); + mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform()) + || mShouldUpdateNavigator; } const MWPhysics::RayCastingInterface* World::getRayCasting() const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c8f17109e..2ed69aabd 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -156,7 +156,7 @@ namespace MWWorld void updateNavigator(); - bool updateNavigatorObject(const MWPhysics::Object* object); + void updateNavigatorObject(const MWPhysics::Object& object); void ensureNeededRecords(); From d6a2838c8bdb45bd9b93d4d2981b3556d2ab730b Mon Sep 17 00:00:00 2001 From: psi29a Date: Mon, 5 Jul 2021 08:15:17 +0000 Subject: [PATCH 03/13] Merge branch 'even-fixier-alpha' into 'master' Correctly track added and removed state to fix various alpha testing issues Closes #6119 See merge request OpenMW/openmw!989 (cherry picked from commit 94be4eba18d328391a2c2aea85bb029e80b32cee) 0e57622b Correctly track added and removed state e42b3bf9 Adapt destination alpha factor for AMD 84a9face Disable coverage adjustment for blended objects --- components/nifosg/nifloader.cpp | 5 + components/sceneutil/mwshadowtechnique.cpp | 1 + components/shader/shadervisitor.cpp | 180 ++++++++++++++++++--- files/shaders/alpha.glsl | 2 +- 4 files changed, 168 insertions(+), 20 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ab25fd744..702ab3366 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -2011,6 +2011,11 @@ namespace NifOsg { osg::ref_ptr blendFunc (new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf), getBlendMode((alphaprop->flags>>5)&0xf))); + // on AMD hardware, alpha still seems to be stored with an RGBA framebuffer with OpenGL. + // This might be mandated by the OpenGL 2.1 specification section 2.14.9, or might be a bug. + // Either way, D3D8.1 doesn't do that, so adapt the destination factor. + if (blendFunc->getDestination() == GL_DST_ALPHA) + blendFunc->setDestination(GL_ONE); blendFunc = shareAttribute(blendFunc); stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON); diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 88d44d2f6..745d93daf 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -904,6 +904,7 @@ void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & sh program->addShader(castingVertexShader); program->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", { {"alphaFunc", std::to_string(alphaFunc)}, {"alphaToCoverage", "0"}, + {"adjustCoverage", "1"}, {"useGPUShader4", useGPUShader4} }, osg::Shader::FRAGMENT)); } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index c21593f35..ebf9d40c4 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -22,6 +22,68 @@ namespace Shader { + class AddedState : public osg::Object + { + public: + AddedState() = default; + AddedState(const AddedState& rhs, const osg::CopyOp& copyOp) + : osg::Object(rhs, copyOp) + , mUniforms(rhs.mUniforms) + , mModes(rhs.mModes) + , mAttributes(rhs.mAttributes) + { + } + + void addUniform(const std::string& name) { mUniforms.emplace(name); } + void setMode(osg::StateAttribute::GLMode mode) { mModes.emplace(mode); } + void setAttribute(osg::StateAttribute::TypeMemberPair typeMemberPair) { mAttributes.emplace(typeMemberPair); } + + void setAttribute(const osg::StateAttribute* attribute) + { + mAttributes.emplace(attribute->getTypeMemberPair()); + } + template + void setAttribute(osg::ref_ptr attribute) { setAttribute(attribute.get()); } + + void setAttributeAndModes(const osg::StateAttribute* attribute) + { + setAttribute(attribute); + InterrogateModesHelper helper(this); + attribute->getModeUsage(helper); + } + template + void setAttributeAndModes(osg::ref_ptr attribute) { setAttributeAndModes(attribute.get()); } + + bool hasUniform(const std::string& name) { return mUniforms.count(name); } + bool hasMode(osg::StateAttribute::GLMode mode) { return mModes.count(mode); } + bool hasAttribute(osg::StateAttribute::TypeMemberPair typeMemberPair) { return mAttributes.count(typeMemberPair); } + bool hasAttribute(osg::StateAttribute::Type type, unsigned int member) { return hasAttribute(osg::StateAttribute::TypeMemberPair(type, member)); } + + const std::set& getAttributes() { return mAttributes; } + + bool empty() + { + return mUniforms.empty() && mModes.empty() && mAttributes.empty(); + } + + META_Object(Shader, AddedState) + + private: + class InterrogateModesHelper : public osg::StateAttribute::ModeUsage + { + public: + InterrogateModesHelper(AddedState* tracker) : mTracker(tracker) {} + void usesMode(osg::StateAttribute::GLMode mode) override { mTracker->setMode(mode); } + void usesTextureMode(osg::StateAttribute::GLMode mode) override {} + + private: + AddedState* mTracker; + }; + + std::unordered_set mUniforms; + std::unordered_set mModes; + std::set mAttributes; + }; ShaderVisitor::ShaderRequirements::ShaderRequirements() : mShaderRequired(false) @@ -105,14 +167,32 @@ namespace Shader return static_cast(stateSet.getUserDataContainer()->getUserObject("removedState")); } - void updateRemovedState(osg::UserDataContainer& userData, osg::StateSet* stateSet) + void updateRemovedState(osg::UserDataContainer& userData, osg::StateSet* removedState) { unsigned int index = userData.getUserObjectIndex("removedState"); if (index < userData.getNumUserObjects()) - userData.setUserObject(index, stateSet); + userData.setUserObject(index, removedState); else - userData.addUserObject(stateSet); - stateSet->setName("removedState"); + userData.addUserObject(removedState); + removedState->setName("removedState"); + } + + AddedState* getAddedState(osg::StateSet& stateSet) + { + if (!stateSet.getUserDataContainer()) + return nullptr; + + return static_cast(stateSet.getUserDataContainer()->getUserObject("addedState")); + } + + void updateAddedState(osg::UserDataContainer& userData, AddedState* addedState) + { + unsigned int index = userData.getUserObjectIndex("addedState"); + if (index < userData.getNumUserObjects()) + userData.setUserObject(index, addedState); + else + userData.addUserObject(addedState); + addedState->setName("addedState"); } const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap" }; @@ -280,11 +360,13 @@ namespace Shader osg::StateSet::AttributeList removedAttributes; if (osg::ref_ptr removedState = getRemovedState(*stateset)) removedAttributes = removedState->getAttributeList(); + osg::ref_ptr addedState = getAddedState(*stateset); + for (const auto* attributeMap : std::initializer_list{ &attributes, &removedAttributes }) { for (osg::StateSet::AttributeList::const_iterator it = attributeMap->begin(); it != attributeMap->end(); ++it) { - if (attributeMap != &removedAttributes && removedAttributes.count(it->first)) + if (addedState && attributeMap != &removedAttributes && addedState->hasAttribute(it->first)) continue; if (it->first.first == osg::StateAttribute::MATERIAL) { @@ -296,9 +378,6 @@ namespace Shader const osg::Material* mat = static_cast(it->second.first.get()); - if (!writableStateSet) - writableStateSet = getWritableStateSet(node); - int colorMode; switch (mat->getColorMode()) { @@ -376,6 +455,10 @@ namespace Shader writableStateSet = node.getOrCreateStateSet(); else writableStateSet = getWritableStateSet(node); + osg::ref_ptr addedState = new AddedState; + osg::ref_ptr previousAddedState = getAddedState(*writableStateSet); + if (!previousAddedState) + previousAddedState = new AddedState; ShaderManager::DefineMap defineMap; for (unsigned int i=0; iaddUniform(new osg::Uniform("colorMode", reqs.mColorMode)); + addedState->addUniform("colorMode"); defineMap["alphaFunc"] = std::to_string(reqs.mAlphaFunc); @@ -403,26 +487,35 @@ namespace Shader removedState = new osg::StateSet(); defineMap["alphaToCoverage"] = "0"; + defineMap["adjustCoverage"] = "0"; if (reqs.mAlphaFunc != osg::AlphaFunc::ALWAYS) { writableStateSet->addUniform(new osg::Uniform("alphaRef", reqs.mAlphaRef)); + addedState->addUniform("alphaRef"); if (!removedState->getAttributePair(osg::StateAttribute::ALPHAFUNC)) { const auto* alphaFunc = writableStateSet->getAttributePair(osg::StateAttribute::ALPHAFUNC); - if (alphaFunc) + if (alphaFunc && !previousAddedState->hasAttribute(osg::StateAttribute::ALPHAFUNC, 0)) removedState->setAttribute(alphaFunc->first, alphaFunc->second); } // This prevents redundant glAlphaFunc calls while letting the shadows bin still see the test writableStateSet->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + addedState->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc)); // Blending won't work with A2C as we use the alpha channel for coverage. gl_SampleCoverage from ARB_sample_shading would save the day, but requires GLSL 130 if (mConvertAlphaTestToAlphaToCoverage && !reqs.mAlphaBlend) { writableStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, osg::StateAttribute::ON); + addedState->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); defineMap["alphaToCoverage"] = "1"; } + // Adjusting coverage isn't safe with blending on as blending requires the alpha to be intact. + // Maybe we could also somehow (e.g. userdata) detect when the diffuse map has coverage-preserving mip maps in the future + if (!reqs.mAlphaBlend) + defineMap["adjustCoverage"] = "1"; + // Preventing alpha tested stuff shrinking as lower mip levels are used requires knowing the texture size osg::ref_ptr exts = osg::GLExtensions::Get(0, false); if (exts && exts->isGpuShader4Supported) @@ -430,10 +523,11 @@ namespace Shader // We could fall back to a texture size uniform if EXT_gpu_shader4 is missing } - if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT) + if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT && !previousAddedState->hasMode(GL_ALPHA_TEST)) removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST)); // This disables the deprecated fixed-function alpha test writableStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED); + addedState->setMode(GL_ALPHA_TEST); if (!removedState->getModeList().empty() || !removedState->getAttributeList().empty()) { @@ -447,6 +541,18 @@ namespace Shader updateRemovedState(*writableUserData, removedState); } + if (!addedState->empty()) + { + // user data is normally shallow copied so shared with the original stateset + osg::ref_ptr writableUserData; + if (mAllowedToModifyStateSets) + writableUserData = writableStateSet->getOrCreateUserDataContainer(); + else + writableUserData = getWritableUserDataContainer(*writableStateSet); + + updateAddedState(*writableUserData, addedState); + } + defineMap["translucentFramebuffer"] = mTranslucentFramebuffer ? "1" : "0"; std::string shaderPrefix; @@ -458,11 +564,14 @@ namespace Shader if (vertexShader && fragmentShader) { - writableStateSet->setAttributeAndModes(mShaderManager.getProgram(vertexShader, fragmentShader), osg::StateAttribute::ON); + auto program = mShaderManager.getProgram(vertexShader, fragmentShader); + writableStateSet->setAttributeAndModes(program, osg::StateAttribute::ON); + addedState->setAttributeAndModes(program); for (std::map::const_iterator texIt = reqs.mTextures.begin(); texIt != reqs.mTextures.end(); ++texIt) { writableStateSet->addUniform(new osg::Uniform(texIt->second.c_str(), texIt->first), osg::StateAttribute::ON); + addedState->addUniform(texIt->second); } } } @@ -477,24 +586,57 @@ namespace Shader else writableStateSet = getWritableStateSet(node); - writableStateSet->removeAttribute(osg::StateAttribute::PROGRAM); + // user data is normally shallow copied so shared with the original stateset - we'll need to copy before edits + osg::ref_ptr writableUserData; + + if (osg::ref_ptr addedState = getAddedState(*writableStateSet)) + { + if (mAllowedToModifyStateSets) + writableUserData = writableStateSet->getUserDataContainer(); + else + writableUserData = getWritableUserDataContainer(*writableStateSet); + + unsigned int index = writableUserData->getUserObjectIndex("addedState"); + writableUserData->removeUserObject(index); + + // O(n log n) to use StateSet::removeX, but this is O(n) + for (auto itr = writableStateSet->getUniformList().begin(); itr != writableStateSet->getUniformList().end();) + { + if (addedState->hasUniform(itr->first)) + writableStateSet->getUniformList().erase(itr); + else + ++itr; + } + + for (auto itr = writableStateSet->getModeList().begin(); itr != writableStateSet->getModeList().end();) + { + if (addedState->hasMode(itr->first)) + writableStateSet->getModeList().erase(itr); + else + ++itr; + } + + // StateAttributes track the StateSets they're attached to + // We don't have access to the function to do that, and can't call removeAttribute with an iterator + for (const auto& [type, member] : addedState->getAttributes()) + writableStateSet->removeAttribute(type, member); + } + if (osg::ref_ptr removedState = getRemovedState(*writableStateSet)) { - // user data is normally shallow copied so shared with the original stateset - osg::ref_ptr writableUserData; + if (!writableUserData) + { if (mAllowedToModifyStateSets) writableUserData = writableStateSet->getUserDataContainer(); else writableUserData = getWritableUserDataContainer(*writableStateSet); + } + unsigned int index = writableUserData->getUserObjectIndex("removedState"); writableUserData->removeUserObject(index); - for (const auto& [mode, value] : removedState->getModeList()) - writableStateSet->setMode(mode, value); - - for (const auto& attribute : removedState->getAttributeList()) - writableStateSet->setAttribute(attribute.second.first, attribute.second.second); + writableStateSet->merge(*removedState); } } diff --git a/files/shaders/alpha.glsl b/files/shaders/alpha.glsl index 05be801e9..46b748236 100644 --- a/files/shaders/alpha.glsl +++ b/files/shaders/alpha.glsl @@ -22,7 +22,7 @@ float mipmapLevel(vec2 scaleduv) float coveragePreservingAlphaScale(sampler2D diffuseMap, vec2 uv) { - #if @alphaFunc != FUNC_ALWAYS && @alphaFunc != FUNC_NEVER + #if @adjustCoverage vec2 textureSize; #if @useGPUShader4 textureSize = textureSize2D(diffuseMap, 0); From 74aa7cdd487dcc9cbd5e4b8e0bebec06654075bb Mon Sep 17 00:00:00 2001 From: psi29a Date: Mon, 5 Jul 2021 08:17:46 +0000 Subject: [PATCH 04/13] Merge branch 'fix_door_freeze' into 'master' Fix slow AiPackage::getTarget calls (#6136) Closes #6136 See merge request OpenMW/openmw!990 (cherry picked from commit 6a4eeeb39bbe025625273dffc9754d29733e570a) 8d1eb7e2 Fix slow AiPackage::getTarget calls --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/aipackage.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce01b7293..88d6049f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,7 @@ Bug #6036: OpenMW-CS: Terrain selection at the border of cells omits certain corner vertices Bug #6043: Actor can have torch missing when torch animation is played Bug #6047: Mouse bindings can be triggered during save loading + Bug #6136: Game freezes when NPCs try to open doors that are about to be closed Feature #390: 3rd person look "over the shoulder" Feature #832: OpenMW-CS: Handle deleted references Feature #1536: Show more information about level on menu diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 523949179..8ad944751 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -55,6 +55,11 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const if (mTargetActorId == -1) { + if (mTargetActorRefId.empty()) + { + mTargetActorId = -2; + return MWWorld::Ptr(); + } MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetActorRefId, false); if (target.isEmpty()) { From a21da63464e035cc32e060a57fdfb3c950c97c5d Mon Sep 17 00:00:00 2001 From: psi29a Date: Sat, 10 Jul 2021 21:03:04 +0000 Subject: [PATCH 05/13] Merge branch 'FixLODIssueWithObjectPaging' into 'master' LOD issue with object paging See merge request OpenMW/openmw!1007 (cherry picked from commit 5688b7b4d8df93fbf28307d2259c57f8d878eeb8) 269cd310 Use same world coordinates to compute distances --- apps/openmw/mwrender/objectpaging.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 8e29f0af4..8c8d2a6ab 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -477,8 +477,7 @@ namespace MWRender constexpr auto copyMask = ~Mask_UpdateVisitor; AnalyzeVisitor analyzeVisitor(copyMask); - osg::Vec3f center3 = { center.x(), center.y(), 0.f }; - analyzeVisitor.mCurrentDistance = (viewPoint - center3).length2(); + analyzeVisitor.mCurrentDistance = (viewPoint - worldCenter).length2(); float minSize = mMinSize; if (mMinSizeMergeFactor) minSize *= mMinSizeMergeFactor; From 8530bc5cf5f9d7c0722752cf179601722fe1a394 Mon Sep 17 00:00:00 2001 From: psi29a Date: Mon, 12 Jul 2021 08:59:07 +0000 Subject: [PATCH 06/13] Merge branch 'fix_debugbatch_colors' into 'master' Fix black objects in object paging debug view See merge request OpenMW/openmw!1011 (cherry picked from commit 5287c9627c92b77c25581dbb9ac9d0b0dc4c9698) 389b8300 fix black objects with OP batch debug due to unitialized uniform --- apps/openmw/mwrender/objectpaging.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 8c8d2a6ab..6ab7ac4ce 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -364,6 +364,7 @@ namespace MWRender osg::ref_ptr stateset = node.getStateSet() ? osg::clone(node.getStateSet(), osg::CopyOp::SHALLOW_COPY) : new osg::StateSet; stateset->setAttribute(m); stateset->addUniform(new osg::Uniform("colorMode", 0)); + stateset->addUniform(new osg::Uniform("emissiveMult", 1.f)); node.setStateSet(stateset); } }; From d1c0cfa5248f6be8a3e905f0ad52cb3889f14eab Mon Sep 17 00:00:00 2001 From: psi29a Date: Mon, 12 Jul 2021 14:11:14 +0000 Subject: [PATCH 07/13] Merge branch 'lifetime' into 'master' Maybe fix #6071 Closes #6071 See merge request OpenMW/openmw!1010 (cherry picked from commit 64750820957773a00d449d29551bb15fbf5fe08b) 1650dabe Assign the return value of weak_ptr::lock() to a variable, so that the --- apps/openmw/mwphysics/mtphysics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 9b98e7e8f..29d1e0b7c 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -599,7 +599,7 @@ namespace MWPhysics if (!mRemainingSteps) return; for (auto& data : mActorsFrameData) - if (data.mActor.lock()) + if (const auto actor = data.mActor.lock()) { std::unique_lock lock(mCollisionWorldMutex); MovementSolver::unstuck(data, mCollisionWorld); From 59da0a0da99e0640303df2c674408b7c0ef18aef Mon Sep 17 00:00:00 2001 From: psi29a Date: Fri, 16 Jul 2021 07:50:26 +0000 Subject: [PATCH 08/13] Merge branch 'skip_async' into 'master' Don't put player in the air after going out of tcl See merge request OpenMW/openmw!1009 (cherry picked from commit 6d08a1d7318ae076839738d173b884fcc7b1a348) 6ad2cf8e Skip simulation result after calling Actor::updatePosition(). Otherwise --- apps/openmw/mwphysics/actor.cpp | 4 +++- apps/openmw/mwphysics/actor.hpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index f0bc23413..66c0208d8 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -124,11 +124,13 @@ void Actor::updatePosition() mPositionOffset = osg::Vec3f(); mStandingOnPtr = nullptr; mSkipCollisions = true; + mSkipSimulation = true; } void Actor::setSimulationPosition(const osg::Vec3f& position) { - mSimulationPosition = position; + if (!std::exchange(mSkipSimulation, false)) + mSimulationPosition = position; } osg::Vec3f Actor::getSimulationPosition() const diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 7b53e8812..6859022d4 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -204,6 +204,7 @@ namespace MWPhysics osg::Vec3f mVelocity; bool mWorldPositionChanged; bool mSkipCollisions; + bool mSkipSimulation; btTransform mLocalTransform; mutable std::mutex mPositionMutex; From db39b4e7d4e4b96d1fba56528aa08011dfd44d5d Mon Sep 17 00:00:00 2001 From: psi29a Date: Tue, 20 Jul 2021 18:44:44 +0000 Subject: [PATCH 09/13] Merge branch 'fix-iterator-badness' into 'master' Actually increment iterators to be erased. Closes #6163 See merge request OpenMW/openmw!1027 (cherry picked from commit 7c246b28e7cb8c514b22214309fc9fed7fc40edc) 5ec2ddb4 Actually increment iterators to be erased. --- components/shader/shadervisitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index ebf9d40c4..9550c903a 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -603,7 +603,7 @@ namespace Shader for (auto itr = writableStateSet->getUniformList().begin(); itr != writableStateSet->getUniformList().end();) { if (addedState->hasUniform(itr->first)) - writableStateSet->getUniformList().erase(itr); + writableStateSet->getUniformList().erase(itr++); else ++itr; } @@ -611,7 +611,7 @@ namespace Shader for (auto itr = writableStateSet->getModeList().begin(); itr != writableStateSet->getModeList().end();) { if (addedState->hasMode(itr->first)) - writableStateSet->getModeList().erase(itr); + writableStateSet->getModeList().erase(itr++); else ++itr; } From 8861d53809bd5c3626fc53b42136e76928493e4f Mon Sep 17 00:00:00 2001 From: fredzio Date: Sat, 17 Jul 2021 08:54:20 +0200 Subject: [PATCH 10/13] Do not store a btTransform into Actor class: reduce its size by 128 bytes --- apps/openmw/mwphysics/actor.cpp | 14 ++++++++------ apps/openmw/mwphysics/actor.hpp | 7 +++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 66c0208d8..92956770e 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -147,18 +147,20 @@ 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); + osg::Vec3f newPosition = getScaledMeshTranslation() + mPosition; + + auto& trans = mCollisionObject->getWorldTransform(); + trans.setOrigin(Misc::Convert::toBullet(newPosition)); + trans.setRotation(Misc::Convert::toBullet(mRotation)); + mCollisionObject->setWorldTransform(trans); + mWorldPositionChanged = false; } osg::Vec3f Actor::getCollisionObjectPosition() const { std::scoped_lock lock(mPositionMutex); - return Misc::Convert::toOsg(mLocalTransform.getOrigin()); + return getScaledMeshTranslation() + mPosition; } bool Actor::setPosition(const osg::Vec3f& position) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 6859022d4..c6c8beb75 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -74,9 +74,6 @@ namespace MWPhysics */ osg::Vec3f getOriginalHalfExtents() const; - /// Returns the mesh translation, scaled and rotated as necessary - osg::Vec3f getScaledMeshTranslation() const; - /** * Returns the position of the collision body * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. @@ -181,6 +178,9 @@ namespace MWPhysics void addCollisionMask(int collisionMask); int getCollisionMask() const; + /// Returns the mesh translation, scaled and rotated as necessary + osg::Vec3f getScaledMeshTranslation() const; + bool mCanWaterWalk; std::atomic mWalkingOnWater; @@ -205,7 +205,6 @@ namespace MWPhysics bool mWorldPositionChanged; bool mSkipCollisions; bool mSkipSimulation; - btTransform mLocalTransform; mutable std::mutex mPositionMutex; unsigned int mStuckFrames; From 20aefb5f5ff40a8523713aa7a0c0bff97e72c389 Mon Sep 17 00:00:00 2001 From: fredzio Date: Sat, 17 Jul 2021 08:55:39 +0200 Subject: [PATCH 11/13] Do not store btTransform into Object class: reduce its size by 104 bytes --- apps/openmw/mwphysics/object.cpp | 22 ++++++++++++++-------- apps/openmw/mwphysics/object.hpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index 636306532..1e69136ab 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -27,8 +27,8 @@ namespace MWPhysics mCollisionObject->setUserPointer(this); setScale(ptr.getCellRef().getScale()); - setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); - setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3())); + setRotation(ptr.getRefData().getBaseNode()->getAttitude()); + updatePosition(); commitPositionChange(); mTaskScheduler->addCollisionObject(mCollisionObject.get(), collisionType, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); @@ -51,17 +51,17 @@ namespace MWPhysics mScaleUpdatePending = true; } - void Object::setRotation(const btQuaternion& quat) + void Object::setRotation(const osg::Quat& quat) { std::unique_lock lock(mPositionMutex); - mLocalTransform.setRotation(quat); + mRotation = quat; mTransformUpdatePending = true; } - void Object::setOrigin(const btVector3& vec) + void Object::updatePosition() { std::unique_lock lock(mPositionMutex); - mLocalTransform.setOrigin(vec); + mPosition = mPtr.getRefData().getPosition().asVec3(); mTransformUpdatePending = true; } @@ -75,7 +75,10 @@ namespace MWPhysics } if (mTransformUpdatePending) { - mCollisionObject->setWorldTransform(mLocalTransform); + btTransform trans; + trans.setOrigin(Misc::Convert::toBullet(mPosition)); + trans.setRotation(Misc::Convert::toBullet(mRotation)); + mCollisionObject->setWorldTransform(trans); mTransformUpdatePending = false; } } @@ -93,7 +96,10 @@ namespace MWPhysics btTransform Object::getTransform() const { std::unique_lock lock(mPositionMutex); - return mLocalTransform; + btTransform trans; + trans.setOrigin(Misc::Convert::toBullet(mPosition)); + trans.setRotation(Misc::Convert::toBullet(mRotation)); + return trans; } bool Object::isSolid() const diff --git a/apps/openmw/mwphysics/object.hpp b/apps/openmw/mwphysics/object.hpp index cae877180..c640318c7 100644 --- a/apps/openmw/mwphysics/object.hpp +++ b/apps/openmw/mwphysics/object.hpp @@ -16,7 +16,6 @@ namespace Resource } class btCollisionObject; -class btQuaternion; class btVector3; namespace MWPhysics @@ -31,8 +30,8 @@ namespace MWPhysics const Resource::BulletShapeInstance* getShapeInstance() const; void setScale(float scale); - void setRotation(const btQuaternion& quat); - void setOrigin(const btVector3& vec); + void setRotation(const osg::Quat& quat); + void updatePosition(); void commitPositionChange(); btCollisionObject* getCollisionObject(); const btCollisionObject* getCollisionObject() const; @@ -51,7 +50,8 @@ namespace MWPhysics std::map mRecIndexToNodePath; bool mSolid; btVector3 mScale; - btTransform mLocalTransform; + osg::Vec3f mPosition; + osg::Quat mRotation; bool mScaleUpdatePending; bool mTransformUpdatePending; mutable std::mutex mPositionMutex; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 833bb9a16..0e616e741 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -630,7 +630,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - found->second->setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + found->second->setRotation(ptr.getRefData().getBaseNode()->getAttitude()); mTaskScheduler->updateSingleAabb(found->second); return; } @@ -651,7 +651,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - found->second->setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3())); + found->second->updatePosition(); mTaskScheduler->updateSingleAabb(found->second); return; } From 744cfc6a5174ec27397e80a945a79e0f52ce4adc Mon Sep 17 00:00:00 2001 From: fredzio Date: Sat, 17 Jul 2021 08:56:43 +0200 Subject: [PATCH 12/13] Do not store a btTransform into Projectile class: reduce its size by 112 bytes --- apps/openmw/mwphysics/projectile.cpp | 11 +++++------ apps/openmw/mwphysics/projectile.hpp | 5 +++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/projectile.cpp b/apps/openmw/mwphysics/projectile.cpp index 252da0a68..0e233562c 100644 --- a/apps/openmw/mwphysics/projectile.cpp +++ b/apps/openmw/mwphysics/projectile.cpp @@ -3,14 +3,11 @@ #include #include -#include - #include #include "../mwworld/class.hpp" #include "collisiontype.hpp" -#include "memory" #include "mtphysics.hpp" #include "projectile.hpp" @@ -55,7 +52,9 @@ void Projectile::commitPositionChange() std::scoped_lock lock(mMutex); if (mTransformUpdatePending) { - mCollisionObject->setWorldTransform(mLocalTransform); + auto& trans = mCollisionObject->getWorldTransform(); + trans.setOrigin(Misc::Convert::toBullet(mPosition)); + mCollisionObject->setWorldTransform(trans); mTransformUpdatePending = false; } } @@ -63,14 +62,14 @@ void Projectile::commitPositionChange() void Projectile::setPosition(const osg::Vec3f &position) { std::scoped_lock lock(mMutex); - mLocalTransform.setOrigin(Misc::Convert::toBullet(position)); + mPosition = position; mTransformUpdatePending = true; } osg::Vec3f Projectile::getPosition() const { std::scoped_lock lock(mMutex); - return Misc::Convert::toOsg(mLocalTransform.getOrigin()); + return mPosition; } bool Projectile::canTraverseWater() const diff --git a/apps/openmw/mwphysics/projectile.hpp b/apps/openmw/mwphysics/projectile.hpp index 81c33d2a5..2ce1a72d5 100644 --- a/apps/openmw/mwphysics/projectile.hpp +++ b/apps/openmw/mwphysics/projectile.hpp @@ -6,12 +6,13 @@ #include #include +#include + #include "ptrholder.hpp" class btCollisionObject; class btCollisionShape; class btConvexShape; -class btVector3; namespace osg { @@ -76,7 +77,6 @@ namespace MWPhysics btConvexShape* mConvexShape; std::unique_ptr mCollisionObject; - btTransform mLocalTransform; bool mTransformUpdatePending; bool mCanCrossWaterSurface; bool mCrossedWaterSurface; @@ -84,6 +84,7 @@ namespace MWPhysics MWWorld::Ptr mCaster; MWWorld::Ptr mHitTarget; std::optional mWaterHitPosition; + osg::Vec3f mPosition; btVector3 mHitPosition; btVector3 mHitNormal; From 9d17cece3a3af96b7011180f75620f40007ac56e Mon Sep 17 00:00:00 2001 From: fredzio Date: Fri, 23 Jul 2021 17:59:54 +0200 Subject: [PATCH 13/13] Set mCanWaterWalk and mOnGround when adding Actor to the scene. mCanWaterWalk was set to false and updated during next frame's simulation mOnGround is set to true but then was updated as part of the scene loading logic. --- apps/openmw/mwphysics/actor.cpp | 4 ++-- apps/openmw/mwphysics/actor.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 10 +++++++++- apps/openmw/mwworld/scene.cpp | 6 ------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 92956770e..ef9ac57b9 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -19,8 +19,8 @@ namespace MWPhysics { -Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler) - : mStandingOnPtr(nullptr), mCanWaterWalk(false), mWalkingOnWater(false) +Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk) + : mStandingOnPtr(nullptr), mCanWaterWalk(canWaterWalk), mWalkingOnWater(false) , mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBox.center), mHalfExtents(shape->mCollisionBox.extents) , mVelocity(0,0,0), mStuckFrames(0), mLastStuckPosition{0, 0, 0} , mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index c6c8beb75..99f625394 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -27,7 +27,7 @@ namespace MWPhysics class Actor final : public PtrHolder { public: - Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler); + Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk); ~Actor() override; /** diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 0e616e741..43653c9e5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -681,7 +681,15 @@ namespace MWPhysics if (!shape) return; - auto actor = std::make_shared(ptr, shape, mTaskScheduler.get()); + // check if Actor should spawn above water + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + const bool canWaterWalk = effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() > 0; + + auto actor = std::make_shared(ptr, shape, mTaskScheduler.get(), canWaterWalk); + + // check if Actor is on the ground or in the air + traceDown(ptr, ptr.getRefData().getPosition().asVec3(), 10.f); + mActors.emplace(ptr, std::move(actor)); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 85b312dd5..5467cc747 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -446,12 +446,6 @@ namespace MWWorld const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - // By default the player is grounded, with the scene fully loaded, we validate and correct this. - if (player.mCell == cell) // Only run once, during initial cell load. - { - mPhysics->traceDown(player, player.getRefData().getPosition().asVec3(), 10.f); - } - navigator->update(player.getRefData().getPosition().asVec3()); if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))