From 8aa57a745a121ac3c7dc32007aa425d6a381e557 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 14 Jul 2020 13:19:51 +0200 Subject: [PATCH 01/40] Fix --- components/sdlutil/sdlvideowrapper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index c2963be86..c64c651bc 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -88,6 +88,14 @@ namespace SDLUtil { SDL_SetWindowSize(mWindow, width, height); SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); + + // Some display managers will automatically maximize windows whose resolution matches its current display. + // This breaks the SDL window if we don't move the window to the corner of that display. + auto index = SDL_GetWindowDisplayIndex(mWindow); + SDL_Rect rect{}; + SDL_GetDisplayBounds(index, &rect); + if (width == rect.w && height == rect.h) + SDL_SetWindowPosition(mWindow, rect.x, rect.y); } } From 8323f7f68dfd9cfff1cbfcc39c471ece67590f90 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 14 Jul 2020 19:54:50 +0200 Subject: [PATCH 02/40] Alternative fix --- components/sdlutil/sdlvideowrapper.cpp | 37 +++++++++++++++++++++----- components/sdlutil/sdlvideowrapper.hpp | 2 ++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index c64c651bc..462afc075 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -89,14 +89,37 @@ namespace SDLUtil SDL_SetWindowSize(mWindow, width, height); SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); - // Some display managers will automatically maximize windows whose resolution matches its current display. - // This breaks the SDL window if we don't move the window to the corner of that display. - auto index = SDL_GetWindowDisplayIndex(mWindow); - SDL_Rect rect{}; - SDL_GetDisplayBounds(index, &rect); - if (width == rect.w && height == rect.h) - SDL_SetWindowPosition(mWindow, rect.x, rect.y); + centerWindow(); } } + void VideoWrapper::centerWindow() + { + + SDL_Rect rect{}; + int x = 0; + int y = 0; + int w = 0; + int h = 0; + auto index = SDL_GetWindowDisplayIndex(mWindow); + bool reposition = false; + SDL_GetDisplayBounds(index, &rect); + SDL_GetWindowSize(mWindow, &w, &h); + + x = rect.x; + y = rect.y; + + // Center dimensions that do not fill the screen + if (w < rect.w) + { + x = rect.x + rect.w / 2 - w / 2; + } + if (h < rect.h) + { + y = rect.y + rect.h / 2 - h / 2; + } + + SDL_SetWindowPosition(mWindow, x, y); + } + } diff --git a/components/sdlutil/sdlvideowrapper.hpp b/components/sdlutil/sdlvideowrapper.hpp index 77f0b8039..3866c3ec3 100644 --- a/components/sdlutil/sdlvideowrapper.hpp +++ b/components/sdlutil/sdlvideowrapper.hpp @@ -27,6 +27,8 @@ namespace SDLUtil void setVideoMode(int width, int height, bool fullscreen, bool windowBorder); + void centerWindow(); + private: SDL_Window* mWindow; osg::ref_ptr mViewer; From e40b309d83aa0c3995c3186c58ab0604b44ccb53 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Fri, 17 Jul 2020 16:23:12 +0200 Subject: [PATCH 03/40] move project/cmake to top; set OpenGL_GL_PREFERENCE to LEGACY since we use GL2 and GLNVD is for GL3 and up (https://github.com/openscenegraph/OpenSceneGraph/issues/639); set our RTD to point to stable and not master, stable follows our latest stable release --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbe28fd84..a3b02a65c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,6 @@ +project(OpenMW) +cmake_minimum_required(VERSION 3.1.0) + # Apps and tools option(BUILD_OPENMW "Build OpenMW" ON) option(BUILD_LAUNCHER "Build Launcher" ON) @@ -13,17 +16,14 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) option(BULLET_USE_DOUBLES "Use double precision for Bullet" OFF) +set(OpenGL_GL_PREFERENCE LEGACY) # Use LEGACY as we use GL2; GLNVD is for GL3 and up. + if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) set(USE_QT FALSE) else() set(USE_QT TRUE) endif() -# set the minimum required version across the board -cmake_minimum_required(VERSION 3.1.0) - -project(OpenMW) - # If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING @@ -58,7 +58,7 @@ set(OPENMW_VERSION_COMMITDATE "") set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") -set(OPENMW_DOC_BASEURL "https://openmw.readthedocs.io/en/master/") +set(OPENMW_DOC_BASEURL "https://openmw.readthedocs.io/en/stable/") set(GIT_CHECKOUT FALSE) if(EXISTS ${PROJECT_SOURCE_DIR}/.git) From 90c30893709113cc2705e0eb6913c653b53095fc Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Wed, 22 Jul 2020 12:17:03 +0000 Subject: [PATCH 04/40] Update sdlvideowrapper.cpp --- components/sdlutil/sdlvideowrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index 462afc075..57d1e2985 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -95,7 +95,7 @@ namespace SDLUtil void VideoWrapper::centerWindow() { - + // Resize breaks the sdl window in some cases; see issue: #5539 SDL_Rect rect{}; int x = 0; int y = 0; From 073a7f2b2db447fba66b954f91923ea9faf8a14e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 30 Jul 2020 21:39:04 +0200 Subject: [PATCH 05/40] Comments to explain the arcane workings of Morrowind --- apps/openmw/mwmechanics/spelllist.hpp | 8 ++++++++ apps/openmw/mwworld/esmstore.hpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/apps/openmw/mwmechanics/spelllist.hpp b/apps/openmw/mwmechanics/spelllist.hpp index 87420082f..b01722fe8 100644 --- a/apps/openmw/mwmechanics/spelllist.hpp +++ b/apps/openmw/mwmechanics/spelllist.hpp @@ -26,6 +26,14 @@ namespace MWMechanics class Spells; + /// Multiple instances of the same actor share the same spell list in Morrowind. + /// The most obvious result of this is that adding a spell or ability to one instance adds it to all instances. + /// @note The original game will only update visual effects associated with any added abilities for the originally targeted actor, + /// changing cells applies the update to all actors. + /// Aside from sharing the same active spell list, changes made to this list are also written to the actor's base record. + /// Interestingly, it is not just scripted changes that are persisted to the base record. Curing one instance's disease will cure all instances. + /// @note The original game is inconsistent in persisting this example; + /// saving and loading the game might reapply the cured disease depending on which instance was cured. class SpellList { const std::string mId; diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index ceb05ca80..99db96ac1 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -264,8 +264,11 @@ namespace MWWorld // To be called when we are done with dynamic record loading void checkPlayer(); + /// @return The number of instances defined in the base files. Excludes changes from the save file. int getRefCount(const std::string& id) const; + /// Actors with the same ID share spells, abilities, etc. + /// @return The shared spell list to use for this actor and whether or not it has already been initialized. std::pair, bool> getSpellList(const std::string& id) const; }; From 02167474cfc60b837c87b0dd6cb038dcbdeb8fb0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 4 Aug 2020 13:18:40 +0000 Subject: [PATCH 06/40] Avoid using CMake 3.18.1 for Ninja builds to see if that fixes Windows_Ninja_CS_RelWithDebInfo --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e16aefcc1..e9da9f00a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ variables: &cs-targets - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1" - choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install 7zip -y - - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y + - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' --version=3.18.0 -y - choco install vswhere -y - choco install ninja -y - choco install python -y From 144a7f330f2126b9a6ccbb0f62c4843e7c9c39c5 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 4 Aug 2020 18:28:10 +0200 Subject: [PATCH 07/40] Fix a regression that meant missing spells would prevent a save from being loaded --- apps/openmw/mwmechanics/spells.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 4bffcab9b..32cd19c5b 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -455,8 +455,7 @@ namespace MWMechanics bool result; std::tie(mSpellList, result) = MWBase::Environment::get().getWorld()->getStore().getSpellList(actorId); mSpellList->addListener(this); - for(const auto& id : mSpellList->getSpells()) - addSpell(SpellList::getSpell(id)); + addAllToInstance(mSpellList->getSpells()); return result; } From ca4330f753f9a213e651b2405d75e2f53b6a2bc8 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Wed, 5 Aug 2020 00:58:39 +0200 Subject: [PATCH 08/40] Tune algorithm of "auto switch shoulder" --- apps/openmw/mwrender/viewovershoulder.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/viewovershoulder.cpp b/apps/openmw/mwrender/viewovershoulder.cpp index 39599bfea..799e34c99 100644 --- a/apps/openmw/mwrender/viewovershoulder.cpp +++ b/apps/openmw/mwrender/viewovershoulder.cpp @@ -89,17 +89,21 @@ namespace MWRender MWBase::World* world = MWBase::Environment::get().getWorld(); osg::Vec3d sideOffset = orient * osg::Vec3d(world->getHalfExtents(mCamera->getTrackingPtr()).x() - 1, 0, 0); float rayRight = world->getDistToNearestRayHit( - playerPos + sideOffset, orient * osg::Vec3d(1, 1, 0), limitToSwitchBack + 1); + playerPos + sideOffset, orient * osg::Vec3d(1, 0, 0), limitToSwitchBack + 1); float rayLeft = world->getDistToNearestRayHit( - playerPos - sideOffset, orient * osg::Vec3d(-1, 1, 0), limitToSwitchBack + 1); - float rayForward = world->getDistToNearestRayHit( - playerPos, orient * osg::Vec3d(0, 1, 0), limitToSwitchBack + 1); + playerPos - sideOffset, orient * osg::Vec3d(-1, 0, 0), limitToSwitchBack + 1); + float rayRightForward = world->getDistToNearestRayHit( + playerPos + sideOffset, orient * osg::Vec3d(1, 3, 0), limitToSwitchBack + 1); + float rayLeftForward = world->getDistToNearestRayHit( + playerPos - sideOffset, orient * osg::Vec3d(-1, 3, 0), limitToSwitchBack + 1); + float distRight = std::min(rayRight, rayRightForward); + float distLeft = std::min(rayLeft, rayLeftForward); - if (rayLeft < limitToSwitch && rayRight > limitToSwitchBack) + if (distLeft < limitToSwitch && distRight > limitToSwitchBack) mMode = Mode::RightShoulder; - else if (rayRight < limitToSwitch && rayLeft > limitToSwitchBack) + else if (distRight < limitToSwitch && distLeft > limitToSwitchBack) mMode = Mode::LeftShoulder; - else if (rayLeft > limitToSwitchBack && rayRight > limitToSwitchBack && rayForward > limitToSwitchBack) + else if (distRight > limitToSwitchBack && distLeft > limitToSwitchBack) mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; } From 243638665b61a066a72a02455325fd4c67edb9c8 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Wed, 5 Aug 2020 17:09:02 +0000 Subject: [PATCH 09/40] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6ec9cf57..13f1157a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Bug #5499: Faction advance is available when requirements not met Bug #5502: Dead zone for analogue stick movement is too small Bug #5507: Sound volume is not clamped on ingame settings update + Bug #5539: Window resize breaks when going from a lower resolution to full screen resolution Feature #390: 3rd person look "over the shoulder" Feature #2386: Distant Statics in the form of Object Paging Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher From 8c213cbfb164497bd3ec29b656faa2f225442660 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 5 Aug 2020 22:39:48 +0300 Subject: [PATCH 10/40] Avoid optimizing animated shapes once again (regression #5565) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f88800e36..21ae49975 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -625,8 +625,8 @@ namespace NifOsg bool isAnimated = false; handleNodeControllers(nifNode, node, animflags, isAnimated); hasAnimatedParents |= isAnimated; - // Make sure empty nodes are not optimized away so the physics system can find them. - if (isAnimated || (hasAnimatedParents && (skipMeshes || hasMarkers))) + // Make sure empty nodes and animated shapes are not optimized away so the physics system can find them. + if (isAnimated || (hasAnimatedParents && ((skipMeshes || hasMarkers) || isGeometry))) node->setDataVariance(osg::Object::DYNAMIC); // LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations properly From ed3426cf2f69e1e57eef52ab07ecfec040d298de Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 25 Jul 2020 21:12:50 +0200 Subject: [PATCH 11/40] Move third person camera collision check from World::updatePlayer() to Camera::updatePosition() --- apps/openmw/mwbase/world.hpp | 7 ++++ apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwrender/camera.cpp | 51 +++++++++++++++++++------ apps/openmw/mwrender/camera.hpp | 5 +-- apps/openmw/mwworld/worldimp.cpp | 31 --------------- apps/openmw/mwworld/worldimp.hpp | 2 + 7 files changed, 52 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9709df362..f5a8ae5b5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -51,6 +51,11 @@ namespace ESM struct TimeStamp; } +namespace MWPhysics +{ + class PhysicsSystem; +} + namespace MWRender { class Animation; @@ -115,6 +120,8 @@ namespace MWBase virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) = 0; + virtual const MWPhysics::PhysicsSystem* getPhysics() const = 0; + virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d423830b1..133e0aeb0 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -311,7 +311,7 @@ namespace MWPhysics return result; } - PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) + PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) const { btCollisionWorld::ClosestConvexResultCallback callback(Misc::Convert::toBullet(from), Misc::Convert::toBullet(to)); callback.m_collisionFilterGroup = 0xff; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 32d460b1d..c2a74cbd8 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -123,7 +123,7 @@ namespace MWPhysics std::vector targets = std::vector(), int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const; - RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); + RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const; /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 328e53a79..47ef1f299 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -7,6 +7,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" @@ -16,6 +17,8 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "npcanimation.hpp" namespace @@ -195,6 +198,7 @@ namespace MWRender rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true); updateFocalPointOffset(duration); + updatePosition(); float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr); speed /= (1.f + speed / 500.f); @@ -205,6 +209,42 @@ namespace MWRender updateStandingPreviewMode(); } + void Camera::updatePosition() + { + mFocalPointAdjustment = osg::Vec3d(); + if (isFirstPerson()) + return; + + const float cameraObstacleLimit = 5.0f; + const float focalObstacleLimit = 10.f; + + const MWPhysics::PhysicsSystem* physics = MWBase::Environment::get().getWorld()->getPhysics(); + + // Adjust focal point to prevent clipping. + osg::Vec3d focal = getFocalPoint(); + osg::Vec3d focalOffset = getFocalPointOffset(); + float offsetLen = focalOffset.length(); + if (offsetLen > 0) + { + MWPhysics::PhysicsSystem::RayResult result = physics->castSphere(focal - focalOffset, focal, focalObstacleLimit); + if (result.mHit) + { + double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen; + mFocalPointAdjustment = focalOffset * std::max(-1.0, adjustmentCoef); + } + } + + // Calculate camera distance. + mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); + if (mDynamicCameraDistanceEnabled) + mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); + osg::Vec3d cameraPos; + getPosition(focal, cameraPos); + MWPhysics::PhysicsSystem::RayResult result = physics->castSphere(focal, cameraPos, cameraObstacleLimit); + if (result.mHit) + mCameraDistance = (result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length(); + } + void Camera::updateStandingPreviewMode() { if (!mStandingPreviewAllowed) @@ -389,7 +429,6 @@ namespace MWRender mIsNearest = dist <= mNearest; mBaseCameraDistance = osg::clampBetween(dist, mNearest, mFurthest); Settings::Manager::setFloat("third person camera distance", "Camera", mBaseCameraDistance); - setCameraDistance(); } void Camera::setCameraDistance(float dist, bool adjust) @@ -414,16 +453,6 @@ namespace MWRender return pitchCorrection + speedCorrection; } - void Camera::setCameraDistance() - { - mFocalPointAdjustment = osg::Vec3d(); - if (isFirstPerson()) - return; - mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); - if (mDynamicCameraDistanceEnabled) - mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); - } - void Camera::setAnimation(NpcAnimation *anim) { mAnimation = anim; diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index f2e5c390d..bf54be715 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -73,6 +73,7 @@ namespace MWRender bool mShowCrosshairInThirdPersonMode; void updateFocalPointOffset(float duration); + void updatePosition(); float getCameraDistanceCorrection() const; osg::ref_ptr mUpdateCallback; @@ -144,16 +145,12 @@ namespace MWRender /// Default distance can be restored with setCameraDistance(). void setCameraDistance(float dist, bool adjust = false); - /// Restore default camera distance and offset for current mode. - void setCameraDistance(); - float getCameraDistance() const; void setAnimation(NpcAnimation *anim); osg::Vec3d getFocalPoint() const; osg::Vec3d getFocalPointOffset() const; - void adjustFocalPoint(osg::Vec3d adjustment) { mFocalPointAdjustment = adjustment; } /// Stores focal and camera world positions in passed arguments void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2eec9bf0e..c111abc43 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1863,37 +1863,6 @@ namespace MWWorld int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); mRendering->setNightEyeFactor(std::min(1.f, (nightEye/100.f))); - - auto* camera = mRendering->getCamera(); - camera->setCameraDistance(); - if(!mRendering->getCamera()->isFirstPerson()) - { - float cameraObstacleLimit = mRendering->getNearClipDistance() * 2.5f; - float focalObstacleLimit = std::max(cameraObstacleLimit, 10.0f); - - // Adjust focal point. - osg::Vec3d focal = camera->getFocalPoint(); - osg::Vec3d focalOffset = camera->getFocalPointOffset(); - float offsetLen = focalOffset.length(); - if (offsetLen > 0) - { - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal - focalOffset, focal, focalObstacleLimit); - if (result.mHit) - { - double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen; - if (adjustmentCoef < -1) - adjustmentCoef = -1; - camera->adjustFocalPoint(focalOffset * adjustmentCoef); - } - } - - // Adjust camera position. - osg::Vec3d cameraPos; - camera->getPosition(focal, cameraPos); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal, cameraPos, cameraObstacleLimit); - if (result.mHit) - mRendering->getCamera()->setCameraDistance((result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length(), false); - } } void World::preloadSpells() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5eae9608e..ade6c4a62 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -214,6 +214,8 @@ namespace MWWorld void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) override; + const MWPhysics::PhysicsSystem* getPhysics() const override { return mPhysics.get(); } + CellStore *getExterior (int x, int y) override; CellStore *getInterior (const std::string& name) override; From 694e0b5906dde97ea624cfc6e0397a4e1ec801bd Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 25 Jul 2020 22:42:58 +0200 Subject: [PATCH 12/40] Refactoring. Simplification of camera interface. --- apps/openmw/mwbase/world.hpp | 3 +-- apps/openmw/mwinput/actionmanager.cpp | 26 +++++++++--------- apps/openmw/mwinput/controllermanager.cpp | 9 +++---- apps/openmw/mwinput/mousemanager.cpp | 12 +++------ apps/openmw/mwrender/camera.cpp | 32 +++++++++++------------ apps/openmw/mwrender/camera.hpp | 10 ++----- apps/openmw/mwrender/renderingmanager.cpp | 27 ------------------- apps/openmw/mwrender/renderingmanager.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 9 ++----- apps/openmw/mwworld/worldimp.hpp | 5 +--- 10 files changed, 42 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f5a8ae5b5..1c63d982f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -427,9 +427,8 @@ namespace MWBase virtual void togglePreviewMode(bool enable) = 0; virtual bool toggleVanityMode(bool enable) = 0; virtual void allowVanityMode(bool allow) = 0; - virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 0; - virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0; + virtual void adjustCameraDistance(float dist) = 0; virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0; virtual void disableDeferredPreviewRotation() = 0; diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index adb5a1c8a..d2430a612 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -26,7 +26,7 @@ namespace MWInput { - const float ZOOM_SCALE = 120.f; /// Used for scrolling camera in and out + const float ZOOM_SCALE = 10.f; /// Used for scrolling camera in and out ActionManager::ActionManager(BindingsManager* bindingsManager, osgViewer::ScreenCaptureHandler::CaptureOperation* screenCaptureOperation, @@ -195,6 +195,8 @@ namespace MWInput void ActionManager::executeAction(int action) { + auto* inputManager = MWBase::Environment::get().getInputManager(); + auto* windowManager = MWBase::Environment::get().getWindowManager(); // trigger action activated switch (action) { @@ -211,7 +213,7 @@ namespace MWInput toggleConsole (); break; case A_Activate: - MWBase::Environment::get().getInputManager()->resetIdleTime(); + inputManager->resetIdleTime(); activate(); break; case A_MoveLeft: @@ -272,18 +274,18 @@ namespace MWInput showQuickKeysMenu(); break; case A_ToggleHUD: - MWBase::Environment::get().getWindowManager()->toggleHud(); + windowManager->toggleHud(); break; case A_ToggleDebug: - MWBase::Environment::get().getWindowManager()->toggleDebugWindow(); + windowManager->toggleDebugWindow(); break; case A_ZoomIn: - if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch") && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") && !MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->setCameraDistance(ZOOM_SCALE, true, true); + if (inputManager->getControlSwitch("playerviewswitch") && inputManager->getControlSwitch("playercontrols") && !windowManager->isGuiMode()) + MWBase::Environment::get().getWorld()->adjustCameraDistance(-ZOOM_SCALE); break; case A_ZoomOut: - if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch") && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") && !MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->setCameraDistance(-ZOOM_SCALE, true, true); + if (inputManager->getControlSwitch("playerviewswitch") && inputManager->getControlSwitch("playercontrols") && !windowManager->isGuiMode()) + MWBase::Environment::get().getWorld()->adjustCameraDistance(ZOOM_SCALE); break; case A_QuickSave: quickSave(); @@ -292,19 +294,19 @@ namespace MWInput quickLoad(); break; case A_CycleSpellLeft: - if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic)) + if (checkAllowedToUseItems() && windowManager->isAllowed(MWGui::GW_Magic)) MWBase::Environment::get().getWindowManager()->cycleSpell(false); break; case A_CycleSpellRight: - if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic)) + if (checkAllowedToUseItems() && windowManager->isAllowed(MWGui::GW_Magic)) MWBase::Environment::get().getWindowManager()->cycleSpell(true); break; case A_CycleWeaponLeft: - if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + if (checkAllowedToUseItems() && windowManager->isAllowed(MWGui::GW_Inventory)) MWBase::Environment::get().getWindowManager()->cycleWeapon(false); break; case A_CycleWeaponRight: - if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + if (checkAllowedToUseItems() && windowManager->isAllowed(MWGui::GW_Inventory)) MWBase::Environment::get().getWindowManager()->cycleWeapon(true); break; case A_Sneak: diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index c9941c836..48091541c 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -190,10 +190,7 @@ namespace MWInput mGamepadZoom = 0; if (mGamepadZoom) - { - MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom); - MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true); - } + MWBase::Environment::get().getWorld()->adjustCameraDistance(-mGamepadZoom); } return triedToMove; @@ -291,12 +288,12 @@ namespace MWInput { if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { - mGamepadZoom = arg.value * 0.85f / 1000.f; + mGamepadZoom = arg.value * 0.85f / 1000.f / 12.f; return; // Do not propagate event. } else if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) { - mGamepadZoom = -arg.value * 0.85f / 1000.f; + mGamepadZoom = -arg.value * 0.85f / 1000.f / 12.f; return; // Do not propagate event. } } diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 84ab091c5..a3f436bfe 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -70,6 +70,7 @@ namespace MWInput mBindingsManager->mouseMoved(arg); MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + MWBase::World* world = MWBase::Environment::get().getWorld(); input->setJoystickLastUsed(false); input->resetIdleTime(); @@ -102,19 +103,14 @@ namespace MWInput rot[2] = -x; // Only actually turn player when we're not in vanity mode - if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && input->getControlSwitch("playerlooking")) + if (!world->vanityRotateCamera(rot) && input->getControlSwitch("playerlooking")) { - MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + MWWorld::Player& player = world->getPlayer(); player.yaw(x); player.pitch(y); } else if (!input->getControlSwitch("playerlooking")) - MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); - - if (arg.zrel && input->getControlSwitch("playerviewswitch") && input->getControlSwitch("playercontrols")) //Check to make sure you are allowed to zoomout and there is a change - { - MWBase::Environment::get().getWorld()->changeVanityModeScale(static_cast(arg.zrel)); - } + world->disableDeferredPreviewRotation(); } } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 47ef1f299..3b0ceb148 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -418,28 +418,26 @@ namespace MWRender return mCameraDistance; } - void Camera::updateBaseCameraDistance(float dist, bool adjust) + void Camera::adjustCameraDistance(float delta) { - if (isFirstPerson()) - return; + if (!isFirstPerson()) + { + if(isNearest() && delta < 0.f && getMode() != Mode::Preview && getMode() != Mode::Vanity) + toggleViewMode(); + else + mBaseCameraDistance = std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance) + delta; + } + else if (delta > 0.f) + { + toggleViewMode(); + mBaseCameraDistance = 0; + } - if (adjust) - dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance); - - mIsNearest = dist <= mNearest; - mBaseCameraDistance = osg::clampBetween(dist, mNearest, mFurthest); + mIsNearest = mBaseCameraDistance <= mNearest; + mBaseCameraDistance = osg::clampBetween(mBaseCameraDistance, mNearest, mFurthest); Settings::Manager::setFloat("third person camera distance", "Camera", mBaseCameraDistance); } - void Camera::setCameraDistance(float dist, bool adjust) - { - if (isFirstPerson()) - return; - if (adjust) - dist += mCameraDistance; - mCameraDistance = osg::clampBetween(dist, 10.f, mFurthest); - } - float Camera::getCameraDistanceCorrection() const { if (!mDynamicCameraDistanceEnabled) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index bf54be715..b3f6026eb 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -136,14 +136,8 @@ namespace MWRender void update(float duration, bool paused=false); - /// Set base camera distance for current mode. Don't work on 1st person view. - /// \param adjust Indicates should distance be adjusted or set. - void updateBaseCameraDistance(float dist, bool adjust = false); - - /// Set camera distance for current mode. Don't work on 1st person view. - /// \param adjust Indicates should distance be adjusted or set. - /// Default distance can be restored with setCameraDistance(). - void setCameraDistance(float dist, bool adjust = false); + /// Adds distDelta to the camera distance. Switches 3rd/1st person view if distance is less than limit. + void adjustCameraDistance(float distDelta); float getCameraDistance() const; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c6ac632e1..0d75325d8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1325,27 +1325,6 @@ namespace MWRender return true; } - void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) - { - if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) - { - if(mCamera->isNearest() && dist > 0.f) - mCamera->toggleViewMode(); - else if (override) - mCamera->updateBaseCameraDistance(-dist / 120.f * 10, adjust); - else - mCamera->setCameraDistance(-dist / 120.f * 10, adjust); - } - else if(mCamera->isFirstPerson() && dist < 0.f) - { - mCamera->toggleViewMode(); - if (override) - mCamera->updateBaseCameraDistance(0.f, false); - else - mCamera->setCameraDistance(0.f, false); - } - } - void RenderingManager::resetCamera() { mCamera->reset(); @@ -1386,12 +1365,6 @@ namespace MWRender mCamera->allowVanityMode(allow); } - void RenderingManager::changeVanityModeScale(float factor) - { - if(mCamera->isVanityOrPreviewModeEnabled()) - mCamera->updateBaseCameraDistance(-factor/120.f*10, true); - } - void RenderingManager::overrideFieldOfView(float val) { if (mFieldOfViewOverridden != true || mFieldOfViewOverride != val) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d6a0f89c3..c0b8f4293 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -210,7 +210,6 @@ namespace MWRender // camera stuff bool vanityRotateCamera(const float *rot); - void setCameraDistance(float dist, bool adjust, bool override); void resetCamera(); float getCameraDistance() const; Camera* getCamera(); @@ -219,7 +218,6 @@ namespace MWRender void togglePreviewMode(bool enable); bool toggleVanityMode(bool enable); void allowVanityMode(bool allow); - void changeVanityModeScale(float factor); /// temporarily override the field of view with given value. void overrideFieldOfView(float val); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c111abc43..b617183b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2394,19 +2394,14 @@ namespace MWWorld mRendering->allowVanityMode(allow); } - void World::changeVanityModeScale(float factor) - { - mRendering->changeVanityModeScale(factor); - } - bool World::vanityRotateCamera(float * rot) { return mRendering->vanityRotateCamera(rot); } - void World::setCameraDistance(float dist, bool adjust, bool override_) + void World::adjustCameraDistance(float dist) { - mRendering->setCameraDistance(dist, adjust, override_); + mRendering->getCamera()->adjustCameraDistance(dist); } void World::setupPlayer() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ade6c4a62..512c6ede3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -533,11 +533,8 @@ namespace MWWorld bool toggleVanityMode(bool enable) override; void allowVanityMode(bool allow) override; - - void changeVanityModeScale(float factor) override; - bool vanityRotateCamera(float * rot) override; - void setCameraDistance(float dist, bool adjust = false, bool override = true) override; + void adjustCameraDistance(float dist) override; void applyDeferredPreviewRotationToPlayer(float dt) override; void disableDeferredPreviewRotation() override; From e9b2e9b4740de737b26a8d1be26c35c1b8dde3e3 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 25 Jul 2020 23:33:50 +0200 Subject: [PATCH 13/40] Remove camera stuff from RenderingManager --- apps/openmw/mwrender/renderingmanager.cpp | 49 ----------------------- apps/openmw/mwrender/renderingmanager.hpp | 11 +---- apps/openmw/mwworld/worldimp.cpp | 18 +++++---- 3 files changed, 13 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 0d75325d8..5c79a4d26 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1316,55 +1316,6 @@ namespace MWRender return mTerrain->getHeightAt(pos); } - bool RenderingManager::vanityRotateCamera(const float *rot) - { - if(!mCamera->isVanityOrPreviewModeEnabled()) - return false; - - mCamera->rotateCamera(rot[0], rot[2], true); - return true; - } - - void RenderingManager::resetCamera() - { - mCamera->reset(); - } - - float RenderingManager::getCameraDistance() const - { - return mCamera->getCameraDistance(); - } - - Camera* RenderingManager::getCamera() - { - return mCamera.get(); - } - - const osg::Vec3f &RenderingManager::getCameraPosition() const - { - return mCurrentCameraPos; - } - - void RenderingManager::togglePOV(bool force) - { - mCamera->toggleViewMode(force); - } - - void RenderingManager::togglePreviewMode(bool enable) - { - mCamera->togglePreviewMode(enable); - } - - bool RenderingManager::toggleVanityMode(bool enable) - { - return mCamera->toggleVanityMode(enable); - } - - void RenderingManager::allowVanityMode(bool allow) - { - mCamera->allowVanityMode(allow); - } - void RenderingManager::overrideFieldOfView(float val) { if (mFieldOfViewOverridden != true || mFieldOfViewOverride != val) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c0b8f4293..1f6f25ace 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -209,15 +209,8 @@ namespace MWRender float getTerrainHeightAt(const osg::Vec3f& pos); // camera stuff - bool vanityRotateCamera(const float *rot); - void resetCamera(); - float getCameraDistance() const; - Camera* getCamera(); - const osg::Vec3f& getCameraPosition() const; - void togglePOV(bool force = false); - void togglePreviewMode(bool enable); - bool toggleVanityMode(bool enable); - void allowVanityMode(bool allow); + Camera* getCamera() { return mCamera.get(); } + const osg::Vec3f& getCameraPosition() const { return mCurrentCameraPos; } /// temporarily override the field of view with given value. void overrideFieldOfView(float val); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b617183b9..50242d7bd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -225,7 +225,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); - mRendering->resetCamera(); + mRendering->getCamera()->reset(); // we don't want old weather to persist on a new game // Note that if reset later, the initial ChangeWeather that the chargen script calls will be lost. @@ -1953,7 +1953,7 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) { - const float camDist = mRendering->getCameraDistance(); + const float camDist = mRendering->getCamera()->getCameraDistance(); maxDistance += camDist; MWWorld::Ptr facedObject; MWRender::RenderingManager::RayResult rayToObject; @@ -2356,7 +2356,7 @@ namespace MWWorld void World::togglePOV(bool force) { - mRendering->togglePOV(force); + mRendering->getCamera()->toggleViewMode(force); } bool World::isFirstPerson() const @@ -2371,12 +2371,12 @@ namespace MWWorld void World::togglePreviewMode(bool enable) { - mRendering->togglePreviewMode(enable); + mRendering->getCamera()->togglePreviewMode(enable); } bool World::toggleVanityMode(bool enable) { - return mRendering->toggleVanityMode(enable); + return mRendering->getCamera()->toggleVanityMode(enable); } void World::disableDeferredPreviewRotation() @@ -2391,12 +2391,16 @@ namespace MWWorld void World::allowVanityMode(bool allow) { - mRendering->allowVanityMode(allow); + mRendering->getCamera()->allowVanityMode(allow); } bool World::vanityRotateCamera(float * rot) { - return mRendering->vanityRotateCamera(rot); + if(!mRendering->getCamera()->isVanityOrPreviewModeEnabled()) + return false; + + mRendering->getCamera()->rotateCamera(rot[0], rot[2], true); + return true; } void World::adjustCameraDistance(float dist) From 0de6650add395b08d6958c2173607ce0e889895d Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Mon, 3 Aug 2020 22:44:16 +0200 Subject: [PATCH 14/40] Add RayCastingInterface --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 6 ++-- apps/openmw/mwphysics/physicssystem.cpp | 12 +++---- apps/openmw/mwphysics/physicssystem.hpp | 21 ++++-------- apps/openmw/mwphysics/raycasting.hpp | 41 +++++++++++++++++++++++ apps/openmw/mwrender/camera.cpp | 8 ++--- apps/openmw/mwworld/projectilemanager.cpp | 4 +-- apps/openmw/mwworld/worldimp.cpp | 11 ++++-- apps/openmw/mwworld/worldimp.hpp | 4 +-- 9 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 apps/openmw/mwphysics/raycasting.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d8fdf7e33..b718322ac 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -73,7 +73,7 @@ add_openmw_dir (mwworld add_openmw_dir (mwphysics physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback contacttestresultcallback deepestnotmecontacttestresultcallback stepper movementsolver - closestnotmeconvexresultcallback + closestnotmeconvexresultcallback raycasting ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1c63d982f..70e65e0ea 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -53,7 +53,7 @@ namespace ESM namespace MWPhysics { - class PhysicsSystem; + class RayCastingInterface; } namespace MWRender @@ -120,8 +120,6 @@ namespace MWBase virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) = 0; - virtual const MWPhysics::PhysicsSystem* getPhysics() const = 0; - virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; @@ -310,6 +308,8 @@ namespace MWBase virtual void updateAnimatedCollisionShape(const MWWorld::Ptr &ptr) = 0; + virtual const MWPhysics::RayCastingInterface* getRayCasting() const = 0; + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2, int mask) = 0; ///< cast a Ray and return true if there is an object in the ray path. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 133e0aeb0..91e7a9de0 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -179,7 +179,7 @@ namespace MWPhysics { // First of all, try to hit where you aim to int hitmask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; - RayResult result = castRay(origin, origin + (orient * osg::Vec3f(0.0f, queryDistance, 0.0f)), actor, targets, hitmask, CollisionType_Actor); + RayCastingResult result = castRay(origin, origin + (orient * osg::Vec3f(0.0f, queryDistance, 0.0f)), actor, targets, hitmask, CollisionType_Actor); if (result.mHit) { @@ -262,7 +262,7 @@ namespace MWPhysics return (point - Misc::Convert::toOsg(cb.m_hitPointWorld)).length(); } - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore, std::vector targets, int mask, int group) const + RayCastingResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore, std::vector targets, int mask, int group) const { btVector3 btFrom = Misc::Convert::toBullet(from); btVector3 btTo = Misc::Convert::toBullet(to); @@ -299,7 +299,7 @@ namespace MWPhysics mCollisionWorld->rayTest(btFrom, btTo, resultCallback); - RayResult result; + RayCastingResult result; result.mHit = resultCallback.hasHit(); if (resultCallback.hasHit()) { @@ -311,7 +311,7 @@ namespace MWPhysics return result; } - PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) const + RayCastingResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) const { btCollisionWorld::ClosestConvexResultCallback callback(Misc::Convert::toBullet(from), Misc::Convert::toBullet(to)); callback.m_collisionFilterGroup = 0xff; @@ -325,7 +325,7 @@ namespace MWPhysics mCollisionWorld->convexSweepTest(&shape, from_, to_, callback); - RayResult result; + RayCastingResult result; result.mHit = callback.hasHit(); if (result.mHit) { @@ -346,7 +346,7 @@ namespace MWPhysics osg::Vec3f pos1 (physactor1->getCollisionObjectPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.9)); // eye level osg::Vec3f pos2 (physactor2->getCollisionObjectPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.9)); - RayResult result = castRay(pos1, pos2, MWWorld::ConstPtr(), std::vector(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); + RayCastingResult result = castRay(pos1, pos2, MWWorld::ConstPtr(), std::vector(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); return !result.mHit; } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index c2a74cbd8..ade8775e6 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -13,6 +13,7 @@ #include "../mwworld/ptr.hpp" #include "collisiontype.hpp" +#include "raycasting.hpp" namespace osg { @@ -52,7 +53,7 @@ namespace MWPhysics class Object; class Actor; - class PhysicsSystem + class PhysicsSystem : public RayCastingInterface { public: PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); @@ -108,25 +109,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; - - struct RayResult - { - bool mHit; - osg::Vec3f mHitPos; - osg::Vec3f mHitNormal; - MWWorld::Ptr mHitObject; - }; + float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const final; /// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all other actors. - RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), + RayCastingResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), std::vector targets = std::vector(), - int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const; + int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const final; - RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const; + RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const final; /// Return true if actor1 can see actor2. - bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; + bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const final; bool isOnGround (const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwphysics/raycasting.hpp b/apps/openmw/mwphysics/raycasting.hpp new file mode 100644 index 000000000..7afbe9321 --- /dev/null +++ b/apps/openmw/mwphysics/raycasting.hpp @@ -0,0 +1,41 @@ +#ifndef OPENMW_MWPHYSICS_RAYCASTING_H +#define OPENMW_MWPHYSICS_RAYCASTING_H + +#include + +#include "../mwworld/ptr.hpp" + +#include "collisiontype.hpp" + +namespace MWPhysics +{ + struct RayCastingResult + { + bool mHit; + osg::Vec3f mHitPos; + osg::Vec3f mHitNormal; + MWWorld::Ptr mHitObject; + }; + + class RayCastingInterface + { + public: + /// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the + /// 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. + virtual float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const = 0; + + /// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all other actors. + virtual RayCastingResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), + std::vector targets = std::vector(), + int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const = 0; + + virtual RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const = 0; + + /// Return true if actor1 can see actor2. + virtual bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const = 0; + }; +} + +#endif diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 3b0ceb148..40cc9895d 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -17,7 +17,7 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwphysics/physicssystem.hpp" +#include "../mwphysics/raycasting.hpp" #include "npcanimation.hpp" @@ -218,7 +218,7 @@ namespace MWRender const float cameraObstacleLimit = 5.0f; const float focalObstacleLimit = 10.f; - const MWPhysics::PhysicsSystem* physics = MWBase::Environment::get().getWorld()->getPhysics(); + const auto* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting(); // Adjust focal point to prevent clipping. osg::Vec3d focal = getFocalPoint(); @@ -226,7 +226,7 @@ namespace MWRender float offsetLen = focalOffset.length(); if (offsetLen > 0) { - MWPhysics::PhysicsSystem::RayResult result = physics->castSphere(focal - focalOffset, focal, focalObstacleLimit); + MWPhysics::RayCastingResult result = rayCasting->castSphere(focal - focalOffset, focal, focalObstacleLimit); if (result.mHit) { double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen; @@ -240,7 +240,7 @@ namespace MWRender mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); osg::Vec3d cameraPos; getPosition(focal, cameraPos); - MWPhysics::PhysicsSystem::RayResult result = physics->castSphere(focal, cameraPos, cameraObstacleLimit); + MWPhysics::RayCastingResult result = rayCasting->castSphere(focal, cameraPos, cameraObstacleLimit); if (result.mHit) mCameraDistance = (result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length(); } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6ace82ea1..cc906e932 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -424,7 +424,7 @@ namespace MWWorld // Check for impact // TODO: use a proper btRigidBody / btGhostObject? - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, targetActors, 0xff, MWPhysics::CollisionType_Projectile); + MWPhysics::RayCastingResult result = mPhysics->castRay(pos, newPos, caster, targetActors, 0xff, MWPhysics::CollisionType_Projectile); bool hit = false; if (result.mHit) @@ -500,7 +500,7 @@ namespace MWWorld // Check for impact // TODO: use a proper btRigidBody / btGhostObject? - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, targetActors, 0xff, MWPhysics::CollisionType_Projectile); + MWPhysics::RayCastingResult result = mPhysics->castRay(pos, newPos, caster, targetActors, 0xff, MWPhysics::CollisionType_Projectile); bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 50242d7bd..8bf97769f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1542,6 +1542,11 @@ namespace MWWorld return mNavigator->updateObject(DetourNavigator::ObjectId(object), shapes, object->getCollisionObject()->getWorldTransform()); } + const MWPhysics::RayCastingInterface* World::getRayCasting() const + { + return mPhysics.get(); + } + bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) { int mask = MWPhysics::CollisionType_World | MWPhysics::CollisionType_Door; @@ -1554,7 +1559,7 @@ namespace MWWorld osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), mask); + MWPhysics::RayCastingResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), mask); return result.mHit; } @@ -2728,7 +2733,7 @@ namespace MWWorld if (includeWater) { collisionTypes |= MWPhysics::CollisionType_Water; } - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector(), collisionTypes); + MWPhysics::RayCastingResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector(), collisionTypes); if (!result.mHit) return maxDist; @@ -3091,7 +3096,7 @@ namespace MWWorld actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors); // Check for impact, if yes, handle hit, if not, launch projectile - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(sourcePos, worldPos, actor, targetActors, 0xff, MWPhysics::CollisionType_Projectile); + MWPhysics::RayCastingResult result = mPhysics->castRay(sourcePos, worldPos, actor, targetActors, 0xff, MWPhysics::CollisionType_Projectile); if (result.mHit) MWMechanics::projectileHit(actor, result.mHitObject, bow, projectile, result.mHitPos, attackStrength); else diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 512c6ede3..f1c8ed73a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -214,8 +214,6 @@ namespace MWWorld void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) override; - const MWPhysics::PhysicsSystem* getPhysics() const override { return mPhysics.get(); } - CellStore *getExterior (int x, int y) override; CellStore *getInterior (const std::string& name) override; @@ -412,6 +410,8 @@ namespace MWWorld void updateAnimatedCollisionShape(const Ptr &ptr) override; + const MWPhysics::RayCastingInterface* getRayCasting() const override; + bool castRay (float x1, float y1, float z1, float x2, float y2, float z2, int mask) override; ///< cast a Ray and return true if there is an object in the ray path. From a211527b4b247863042d1beec7fb4367a748b7c6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 7 Aug 2020 09:58:36 +0300 Subject: [PATCH 15/40] Fix AppVeyor warnings --- apps/openmw/mwmechanics/aiavoiddoor.cpp | 8 ++++---- apps/openmw/mwscript/miscextensions.cpp | 4 ++-- apps/openmw/mwscript/scriptmanagerimp.cpp | 2 -- components/sdlutil/sdlvideowrapper.cpp | 1 - 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index ce2553756..73a638563 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -60,14 +60,14 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont // Make all nearby actors also avoid the door std::vector actors; MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors); - for(auto& actor : actors) + for(auto& neighbor : actors) { - if (actor == getPlayer()) + if (neighbor == getPlayer()) continue; - MWMechanics::AiSequence& seq = actor.getClass().getCreatureStats(actor).getAiSequence(); + MWMechanics::AiSequence& seq = neighbor.getClass().getCreatureStats(neighbor).getAiSequence(); if (seq.getTypeId() != MWMechanics::AiPackageTypeId::AvoidDoor) - seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr), actor); + seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr), neighbor); } return false; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index cbacd62df..8ce891741 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -563,9 +563,9 @@ namespace MWScript effects += store.getMagicEffects(); } - for (const auto& effect : effects) + for (const auto& activeEffect : effects) { - if (effect.first.mId == key && effect.second.getModifier() > 0) + if (activeEffect.first.mId == key && activeEffect.second.getModifier() > 0) { runtime.push(1); return; diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 8ff768c2d..e1652b311 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -149,8 +149,6 @@ namespace MWScript int count = 0; int success = 0; - const MWWorld::Store& scripts = mStore.get(); - for (auto& script : mStore.get()) { if (!std::binary_search (mScriptBlacklist.begin(), mScriptBlacklist.end(), diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index 57d1e2985..b3ba98ee3 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -102,7 +102,6 @@ namespace SDLUtil int w = 0; int h = 0; auto index = SDL_GetWindowDisplayIndex(mWindow); - bool reposition = false; SDL_GetDisplayBounds(index, &rect); SDL_GetWindowSize(mWindow, &w, &h); From 35de34c01927dc74d13ea9e9bdcd34e6929677a9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 7 Aug 2020 10:07:19 +0300 Subject: [PATCH 16/40] Don't clamp GeomMorpherController recovered weight value Seems that Morrowind doesn't do it. --- components/nifosg/controller.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a4db2cba3..58f1c17a7 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -197,7 +197,6 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable float val = 0; if (!(*it).empty()) val = it->interpKey(input); - val = std::max(0.f, std::min(1.f, val)); SceneUtil::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); if (target.getWeight() != val) From aa131262ea7efadf0cde9258b913d4c2ae95bc20 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 7 Aug 2020 10:22:54 +0300 Subject: [PATCH 17/40] Implement quadratic interpolation for scalars and vectors --- components/nif/nifkey.hpp | 10 +++++----- components/nifosg/controller.hpp | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 333d8a7cf..4c10327e1 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -26,11 +26,11 @@ enum InterpolationType template struct KeyT { T mValue; + T mInTan; // Only for Quadratic interpolation, and never for QuaternionKeyList + T mOutTan; // Only for Quadratic interpolation, and never for QuaternionKeyList - // FIXME: Implement Quadratic and TBC interpolation + // FIXME: Implement TBC interpolation /* - T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList - T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList float mTension; // Only for TBC interpolation float mBias; // Only for TBC interpolation float mContinuity; // Only for TBC interpolation @@ -136,8 +136,8 @@ private: static void readQuadratic(NIFStream &nif, KeyT &key) { readValue(nif, key); - /*key.mForwardValue = */(nif.*getValue)(); - /*key.mBackwardValue = */(nif.*getValue)(); + key.mInTan = (nif.*getValue)(); + key.mOutTan = (nif.*getValue)(); } static void readQuadratic(NIFStream &nif, KeyT &key) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index df1086f56..be1292359 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -110,6 +110,24 @@ namespace NifOsg { case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; + case Nif::InterpolationType_Quadratic: + { + // Using a cubic Hermite spline. + // b1(t) = 2t^3 - 3t^2 + 1 + // b2(t) = -2t^3 + 3t^2 + // b3(t) = t^3 - 2t^2 + t + // b4(t) = t^3 - t^2 + // f(t) = a.mValue * b1(t) + b.mValue * b2(t) + a.mOutTan * b3(t) + b.mInTan * b4(t) + const float t = fraction; + const float t2 = t * t; + const float t3 = t2 * t; + const float b1 = 2.f * t3 - 3.f * t2 + 1; + const float b2 = -2.f * t3 + 3.f * t2; + const float b3 = t3 - 2.f * t2 + t; + const float b4 = t3 - t2; + return a.mValue * b1 + b.mValue * b2 + a.mOutTan * b3 + b.mInTan * b4; + } + // TODO: Implement TBC interpolation default: return a.mValue + ((b.mValue - a.mValue) * fraction); } @@ -120,6 +138,7 @@ namespace NifOsg { case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; + // TODO: Implement Quadratic and TBC interpolation default: { osg::Quat result; From fb28d27d080c2c365be1d159d310a3f710289968 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Fri, 7 Aug 2020 16:36:59 +0200 Subject: [PATCH 18/40] don't discard purged effects --- apps/openmw/mwmechanics/spells.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 32cd19c5b..a66c267cc 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -434,8 +434,9 @@ namespace MWMechanics const auto& baseSpells = mSpellList->getSpells(); for (const auto& it : mSpells) { - //Don't save spells stored in the base record - if(std::find(baseSpells.begin(), baseSpells.end(), it.first->mId) == baseSpells.end()) + // Don't save spells and powers stored in the base record + if((it.first->mData.mType != ESM::Spell::ST_Spell && it.first->mData.mType != ESM::Spell::ST_Power) || + std::find(baseSpells.begin(), baseSpells.end(), it.first->mId) == baseSpells.end()) { ESM::SpellState::SpellParams params; params.mEffectRands = it.second.mEffectRands; From 6a4fa8a8b58e41fc4cf7e1a64a27d4e2ae838d27 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Fri, 7 Aug 2020 20:17:44 +0000 Subject: [PATCH 19/40] Add more settings to openmw-launcher --- apps/launcher/advancedpage.cpp | 51 ++++- apps/launcher/advancedpage.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 3 +- .../reference/modding/settings/camera.rst | 7 +- .../reference/modding/settings/game.rst | 18 +- files/settings-default.cfg | 7 +- files/ui/advancedpage.ui | 207 ++++++++++++++++-- 7 files changed, 270 insertions(+), 24 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 2dd7d07c1..e82afc303 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -119,15 +119,22 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game"); loadSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game"); + loadSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game"); int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game"); if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2) unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex); loadSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game"); + loadSettingBool(enableNavigatorCheckBox, "enable", "Navigator"); } // Visuals { + loadSettingBool(autoUseObjectNormalMapsCheckBox, "auto use object normal maps", "Shaders"); + loadSettingBool(autoUseObjectSpecularMapsCheckBox, "auto use object specular maps", "Shaders"); + loadSettingBool(autoUseTerrainNormalMapsCheckBox, "auto use terrain normal maps", "Shaders"); + loadSettingBool(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders"); loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders"); + loadSettingBool(radialFogCheckBox, "radial fog", "Shaders"); loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game"); connect(animSourcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAnimSourcesToggled(bool))); loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game"); @@ -136,7 +143,6 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game"); loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game"); } - loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera"); loadSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game"); const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain"); @@ -149,6 +155,18 @@ bool Launcher::AdvancedPage::loadSettings() viewingDistanceComboBox->setValue(convertToCells(mEngineSettings.getInt("viewing distance", "Camera"))); } + // Camera + { + loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera"); + connect(viewOverShoulderCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotViewOverShoulderToggled(bool))); + viewOverShoulderGroup->setEnabled(viewOverShoulderCheckBox->checkState()); + loadSettingBool(autoSwitchShoulderCheckBox, "auto switch shoulder", "Camera"); + loadSettingBool(previewIfStandStillCheckBox, "preview if stand still", "Camera"); + loadSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera"); + defaultShoulderComboBox->setCurrentIndex( + mEngineSettings.getVector2("view over shoulder offset", "Camera").x() >= 0 ? 0 : 1); + } + // Interface Changes { loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game"); @@ -213,20 +231,26 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game"); saveSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game"); + saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game"); int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex(); if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game")) mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex); saveSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game"); + saveSettingBool(enableNavigatorCheckBox, "enable", "Navigator"); } // Visuals { + saveSettingBool(autoUseObjectNormalMapsCheckBox, "auto use object normal maps", "Shaders"); + saveSettingBool(autoUseObjectSpecularMapsCheckBox, "auto use object specular maps", "Shaders"); + saveSettingBool(autoUseTerrainNormalMapsCheckBox, "auto use terrain normal maps", "Shaders"); + saveSettingBool(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders"); saveSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders"); + saveSettingBool(radialFogCheckBox, "radial fog", "Shaders"); saveSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game"); saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game"); saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game"); saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game"); - saveSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera"); saveSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game"); const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain"); @@ -245,6 +269,24 @@ void Launcher::AdvancedPage::saveSettings() } } + // Camera + { + saveSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera"); + saveSettingBool(autoSwitchShoulderCheckBox, "auto switch shoulder", "Camera"); + saveSettingBool(previewIfStandStillCheckBox, "preview if stand still", "Camera"); + saveSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera"); + + osg::Vec2f shoulderOffset = mEngineSettings.getVector2("view over shoulder offset", "Camera"); + if (defaultShoulderComboBox->currentIndex() != (shoulderOffset.x() >= 0 ? 0 : 1)) + { + if (defaultShoulderComboBox->currentIndex() == 0) + shoulderOffset.x() = std::abs(shoulderOffset.x()); + else + shoulderOffset.x() = -std::abs(shoulderOffset.x()); + mEngineSettings.setVector2("view over shoulder offset", "Camera", shoulderOffset); + } + } + // Interface Changes { saveSettingBool(showEffectDurationCheckBox, "show effect duration", "Game"); @@ -326,3 +368,8 @@ void Launcher::AdvancedPage::slotAnimSourcesToggled(bool checked) shieldSheathingCheckBox->setCheckState(Qt::Unchecked); } } + +void Launcher::AdvancedPage::slotViewOverShoulderToggled(bool checked) +{ + viewOverShoulderGroup->setEnabled(viewOverShoulderCheckBox->checkState()); +} diff --git a/apps/launcher/advancedpage.hpp b/apps/launcher/advancedpage.hpp index 25cb66d9d..bdf5af0c8 100644 --- a/apps/launcher/advancedpage.hpp +++ b/apps/launcher/advancedpage.hpp @@ -32,6 +32,7 @@ namespace Launcher void on_skipMenuCheckBox_stateChanged(int state); void on_runScriptAfterStartupBrowseButton_clicked(); void slotAnimSourcesToggled(bool checked); + void slotViewOverShoulderToggled(bool checked); private: Files::ConfigurationManager &mCfgMgr; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c8e81aa49..2ff8241f4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2243,7 +2243,8 @@ void CharacterController::update(float duration, bool animationOnly) swimmingPitch += osg::clampBetween(targetSwimmingPitch - swimmingPitch, -maxSwimPitchDelta, maxSwimPitchDelta); mAnimation->setBodyPitchRadians(swimmingPitch); } - if (inwater && isPlayer && !isFirstPersonPlayer) + static const bool swimUpwardCorrection = Settings::Manager::getBool("swim upward correction", "Game"); + if (inwater && isPlayer && !isFirstPersonPlayer && swimUpwardCorrection) { static const float swimUpwardCoef = Settings::Manager::getFloat("swim upward coef", "Game"); static const float swimForwardCoef = sqrtf(1.0f - swimUpwardCoef * swimUpwardCoef); diff --git a/docs/source/reference/modding/settings/camera.rst b/docs/source/reference/modding/settings/camera.rst index 8d7078905..1025a2fbd 100644 --- a/docs/source/reference/modding/settings/camera.rst +++ b/docs/source/reference/modding/settings/camera.rst @@ -160,7 +160,7 @@ auto switch shoulder This setting makes difference only in third person mode if 'view over shoulder' is enabled. When player is close to an obstacle, automatically switches camera to the shoulder that is farther away from the obstacle. -This setting can only be configured by editing the settings configuration file. +This setting can be controlled in Advanced tab of the launcher. zoom out when move coef ----------------------- @@ -181,9 +181,10 @@ preview if stand still :Range: True/False :Default: False +Makes difference only in third person mode. If enabled then the character rotation is not synchonized with the camera rotation while the character doesn't move and not in combat mode. -This setting can only be configured by editing the settings configuration file. +This setting can be controlled in Advanced tab of the launcher. deferred preview rotation ------------------------- @@ -196,5 +197,5 @@ Makes difference only in third person mode. If enabled then the character smoothly rotates to the view direction after exiting preview or vanity mode. If disabled then the camera rotates rather than the character. -This setting can only be configured by editing the settings configuration file. +This setting can be controlled in Advanced tab of the launcher. diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 5291fb0ed..46bd22e50 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -327,7 +327,18 @@ Affects side and diagonal movement. Enabling this setting makes movement more re If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding. -If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it also changes straight right and straight left movement. +If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction. + +This setting can be controlled in Advanced tab of the launcher. + +swim upward correction +---------------- + +:Type: boolean +:Range: True/False +:Default: False + +Makes player swim a bit upward from the line of sight. Applies only in third person mode. Intended to make simpler swimming without diving. This setting can be controlled in Advanced tab of the launcher. @@ -336,9 +347,10 @@ swim upward coef :Type: floating point :Range: -1.0 to 1.0 -:Default: 0.0 +:Default: 0.2 -Makes player swim a bit upward (or downward in case of negative value) from the line of sight. Intended to make simpler swimming without diving. Recommened range of values is from 0.0 to 0.2. +Regulates strength of the "swim upward correction" effect (if enabled). +Makes player swim a bit upward (or downward in case of negative value) from the line of sight. Recommened range of values is from 0.0 to 0.25. This setting can only be configured by editing the settings configuration file. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 65e72c177..ac5433f30 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -325,8 +325,11 @@ uncapped damage fatigue = false # Turn lower body to movement direction. 'true' makes diagonal movement more realistic. turn to movement direction = false -# Makes player swim a bit upward (or downward in case of negative value) from the line of sight. -swim upward coef = 0.0 +# Makes player swim a bit upward from the line of sight. +swim upward correction = false + +# Strength of the 'swim upward correction' effect (if enabled). +swim upward coef = 0.2 # Make the training skills proposed by a trainer based on its base attribute instead of its modified ones trainers training skills based on base skill = false diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 08ffe10ce..ca57e5dc8 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -116,6 +116,16 @@ + + + + <html><head/><body><p>Makes player swim a bit upward from the line of sight. Applies only in third person mode. Intended to make simpler swimming without diving.</p></body></html> + + + Swim upward correction + + + @@ -164,6 +174,16 @@ + + + + <html><head/><body><p>Enable navigator. When enabled background threads are started to build nav mesh for world geometry. Pathfinding system uses nav mesh to build paths. When disabled only pathgrid is used to build paths. Single-core CPU systems may have big performance impact on exiting interior location and moving across exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn’t know where to go when you stand behind that stone and casting a firebolt.</p></body></html> + + + Build nav mesh for world geometry + + + @@ -178,6 +198,52 @@ Visuals + + + + <html><head/><body><p>If this option is enabled, normal maps are automatically recognized and used if they are named appropriately +(see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds). +If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). Affects objects.</p></body></html> + + + Auto use object normal maps + + + + + + + <html><head/><body><p>If this option is enabled, specular maps are automatically recognized and used if they are named appropriately +(see 'specular map pattern', e.g. for a base texture foo.dds, +the specular map texture would have to be named foo_spec.dds). +If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file +(.osg file, not supported in .nif files). Affects objects.</p></body></html> + + + Auto use object specular maps + + + + + + + <html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html> + + + Auto use terrain normal maps + + + + + + + <html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html> + + + Auto use terrain specular maps + + + @@ -191,6 +257,17 @@ Affected objects will use shaders. + + + + <html><head/><body><p>By default, the fog becomes thicker proportionally to your distance from the clipping plane set at the clipping distance, which causes distortion at the edges of the screen. +This setting makes the fog use the actual eye point distance (or so called Euclidean distance) to calculate the fog, which makes the fog look less artificial, especially if you have a wide FOV.</p></body></html> + + + Radial fog + + + @@ -246,22 +323,10 @@ Affected objects will use shaders. - - - - <html><head/><body><p>This setting controls third person view mode.</p><p>False: View is centered on the character's head. Crosshair is hidden. -True: In non-combat mode camera is positioned behind the character's shoulder. Crosshair is visible in third person mode as well. -</p></body></html> - - - View over the shoulder - - - - <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it also changes straight right and straight left movement.</p></body></html> + <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html> Turn to movement direction @@ -328,6 +393,122 @@ but also increase the amount of rendered geometry and significantly reduce the f + + + Camera + + + + + + <html><head/><body><p>This setting controls third person view mode.</p><p>False: View is centered on the character's head. Crosshair is hidden. +True: In non-combat mode camera is positioned behind the character's shoulder. Crosshair is visible in third person mode as well. +</p></body></html> + + + View over the shoulder + + + + + + + + 20 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Default shoulder: + + + + + + + 0 + + + + Right + + + + + Left + + + + + + + + + + + <html><head/><body><p>When player is close to an obstacle, automatically switches camera to the shoulder that is farther away from the obstacle.</p></body></html> + + + Auto switch shoulder + + + + + + + + + + <html><head/><body><p>If enabled then the character rotation is not synchonized with the camera rotation while the character doesn't move and not in combat mode.</p></body></html> + + + Preview if stand still + + + + + + + <html><head/><body><p>If enabled then the character smoothly rotates to the view direction after exiting preview or vanity mode. If disabled then the camera rotates rather than the character.</p></body></html> + + + Deferred preview rotation + + + + + + + Qt::Vertical + + + + + Interface changes From a0ca7c4b4321fe3c1894553ec0c675b9e839be72 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 9 Aug 2020 12:48:59 +0300 Subject: [PATCH 20/40] AIPursue: don't do a LOS check Properly resolve #4774 --- apps/openmw/mwmechanics/aipursue.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 7aa2a9554..bfe860d6d 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -39,8 +39,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled()) return true; - if (!MWBase::Environment::get().getWorld()->getLOS(target, actor) - || !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor)) + if (isTargetMagicallyHidden(target) && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor)) return false; if (target.getClass().getCreatureStats(target).isDead()) From c436f29a1efc1dd2ec04239618252180d1c1b9dd Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 9 Aug 2020 20:07:31 +0300 Subject: [PATCH 21/40] Make Advanced tab of the launcher look okay for everyone again --- apps/launcher/advancedpage.cpp | 32 -------------------------------- files/ui/advancedpage.ui | 11 ++++------- 2 files changed, 4 insertions(+), 39 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index e82afc303..1cc77ec6d 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -10,37 +10,6 @@ #include - -class HorizontalTextWestTabStyle : public QProxyStyle -{ -public: - QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const - { - QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); - if (type == QStyle::CT_TabBarTab) - { - s.transpose(); - s.setHeight(s.height() + 20); - } - return s; - } - - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const - { - if (element == CE_TabBarTabLabel) - { - if (const QStyleOptionTab* tab = qstyleoption_cast(option)) - { - QStyleOptionTab opt(*tab); - opt.shape = QTabBar::RoundedNorth; - QProxyStyle::drawControl(element, &opt, painter, widget); - return; - } - } - QProxyStyle::drawControl(element, option, painter, widget); - } -}; - Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Settings::Manager &engineSettings, QWidget *parent) @@ -53,7 +22,6 @@ Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, setupUi(this); loadSettings(); - AdvancedTabWidget->tabBar()->setStyle(new HorizontalTextWestTabStyle); mCellNameCompleter.setModel(&mCellNameCompleterModel); startDefaultCharacterAtField->setCompleter(&mCellNameCompleter); } diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index ca57e5dc8..4f1a30d4c 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -5,15 +5,12 @@ - - QTabWidget::West - 0 - Game mechanics + Game Mechanics @@ -509,9 +506,9 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C - + - Interface changes + Interface @@ -618,7 +615,7 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C - Bug fixes + Bug Fixes From 3497dcce76ce016870b232f668628d661f30c81c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 10 Aug 2020 17:33:11 +0100 Subject: [PATCH 22/40] Add OpenMW Chocolatey proxy as source --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e9da9f00a..8b4319495 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,6 +57,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/" --priority=1 - choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install 7zip -y - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' --version=3.18.0 -y @@ -146,6 +147,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/" --priority=1 - choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install 7zip -y - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y From 35d9ef355afc7ae255287632a0572d2e3246ff4f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 10 Aug 2020 17:38:17 +0100 Subject: [PATCH 23/40] Specify full repository URL --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8b4319495..15aaa339b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,7 +57,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/" --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' --version=3.18.0 -y @@ -147,7 +147,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/" --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 From f7d28445f75021e9dd83f21ed92f427eaa1d31f0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 10 Aug 2020 17:51:05 +0100 Subject: [PATCH 24/40] Add l to match typo in real URL --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 15aaa339b..b89b99ac8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,7 +57,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/Chocolatey/" --priority=1 + - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolately/" --priority=1 - choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install 7zip -y - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' --version=3.18.0 -y @@ -147,7 +147,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/Chocolatey/" --priority=1 + - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolately/" --priority=1 - choco install git --force --params "/GitAndUnixToolsOnPath" -y - choco install 7zip -y - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y From 7f342374fccc4d77e545588694d61708f3b8e6ff Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 12 Aug 2020 11:16:10 +0400 Subject: [PATCH 25/40] Fix crash when using 'showscenegraph 1' console command --- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2eec9bf0e..54dbfa7b6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3633,8 +3633,11 @@ namespace MWWorld std::string World::exportSceneGraph(const Ptr &ptr) { std::string file = mUserDataPath + "/openmw.osgt"; - mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr); - mWorldScene->removeFromPagedRefs(ptr); + if (!ptr.isEmpty()) + { + mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr); + mWorldScene->removeFromPagedRefs(ptr); + } mRendering->exportSceneGraph(ptr, file, "Ascii"); return file; } From 215ddb910641f921dc3b8463d1590de4eafcd9d9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 12 Aug 2020 11:16:37 +0400 Subject: [PATCH 26/40] Do not print warnings for VisController --- components/sceneutil/serialize.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 62325186c..9e7aa83f6 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -143,6 +143,7 @@ void registerSerializers() "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry", "NifOsg::UVController", + "NifOsg::VisController", "NifOsg::NodeIndexHolder", "osgMyGUI::Drawable", "osg::DrawCallback", From 98b2d5d921a4f15f15921f4d6893b5d27685d642 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Aug 2020 19:29:19 +0100 Subject: [PATCH 27/40] Make shadow debug HUD thread-safe * Double buffer the frustum uniforms. * Don't mess with the debug geometry's StateSet. * Change two-element vectors to arrays so the size is explicit. --- components/sceneutil/mwshadowtechnique.cpp | 20 +++++++++++--------- components/sceneutil/mwshadowtechnique.hpp | 5 +++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index fa38da54e..24ec190ba 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -3104,12 +3104,12 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFrustumFragmentShaderSource); frustumProgram->addShader(fragmentShader); - for (int i = 0; i < 2; ++i) + for (auto& frustumGeometry : mFrustumGeometries) { - mFrustumGeometries.emplace_back(new osg::Geometry()); - mFrustumGeometries[i]->setCullingActive(false); + frustumGeometry = new osg::Geometry(); + frustumGeometry->setCullingActive(false); - mFrustumGeometries[i]->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); + frustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); } osg::ref_ptr frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP); @@ -3145,12 +3145,14 @@ void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr t // It might be possible to change shadow settings at runtime if (shadowMapNumber > mDebugCameras.size()) addAnotherShadowMap(); - - mFrustumUniforms[shadowMapNumber]->set(matrix); - osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); + osg::ref_ptr stateSet = new osg::StateSet(); stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); + auto frustumUniform = mFrustumUniforms[cv.getTraversalNumber() % 2][shadowMapNumber]; + frustumUniform->set(matrix); + stateSet->addUniform(frustumUniform); + // Some of these calls may be superfluous. unsigned int traversalMask = cv.getTraversalMask(); cv.setTraversalMask(mDebugGeometry[shadowMapNumber]->getNodeMask()); @@ -3205,6 +3207,6 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() mFrustumTransforms[shadowMapNumber]->setCullingActive(false); mDebugCameras[shadowMapNumber]->addChild(mFrustumTransforms[shadowMapNumber]); - mFrustumUniforms.push_back(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "transform")); - mFrustumTransforms[shadowMapNumber]->getOrCreateStateSet()->addUniform(mFrustumUniforms[shadowMapNumber]); + for(auto& uniformVector : mFrustumUniforms) + uniformVector.push_back(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "transform")); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 77d0bd2b2..2078fc2d6 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -19,6 +19,7 @@ #ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H #define COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H 1 +#include #include #include @@ -282,8 +283,8 @@ namespace SceneUtil { osg::ref_ptr mDebugProgram; std::vector> mDebugGeometry; std::vector> mFrustumTransforms; - std::vector> mFrustumUniforms; - std::vector> mFrustumGeometries; + std::array>, 2> mFrustumUniforms; + std::array, 2> mFrustumGeometries; }; osg::ref_ptr _debugHud; From ce98d7053bc28913551f9188f575c432cb12ece8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Aug 2020 22:55:41 +0100 Subject: [PATCH 28/40] Double buffer view-dependent data stateset --- components/sceneutil/mwshadowtechnique.cpp | 17 +++++++++-------- components/sceneutil/mwshadowtechnique.hpp | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 24ec190ba..ae3a29295 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -749,7 +749,8 @@ MWShadowTechnique::ViewDependentData::ViewDependentData(MWShadowTechnique* vdsm) _viewDependentShadowMap(vdsm) { OSG_INFO<<"ViewDependentData::ViewDependentData()"<0) { - decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); + decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber())); } // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< stateset = vdd.getStateSet(); + osg::ref_ptr stateset = vdd.getStateSet(traversalNumber); std::lock_guard lock(_accessUniformsAndProgramMutex); - vdd.getStateSet()->clear(); + stateset->clear(); - vdd.getStateSet()->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); for(Uniforms::const_iterator itr=_uniforms.begin(); itr!=_uniforms.end(); @@ -3047,7 +3048,7 @@ osg::StateSet* MWShadowTechnique::selectStateSetForRenderingShadow(ViewDependent stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); } - return vdd.getStateSet(); + return stateset; } void MWShadowTechnique::resizeGLObjectBuffers(unsigned int /*maxSize*/) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 2078fc2d6..95f1117c0 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -192,7 +192,7 @@ namespace SceneUtil { ShadowDataList& getShadowDataList() { return _shadowDataList; } - osg::StateSet* getStateSet() { return _stateset.get(); } + osg::StateSet* getStateSet(unsigned int traversalNumber) { return _stateset[traversalNumber % 2].get(); } virtual void releaseGLObjects(osg::State* = 0) const; @@ -201,7 +201,7 @@ namespace SceneUtil { MWShadowTechnique* _viewDependentShadowMap; - osg::ref_ptr _stateset; + std::array, 2> _stateset; LightDataList _lightDataList; ShadowDataList _shadowDataList; @@ -231,7 +231,7 @@ namespace SceneUtil { virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; - virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; + virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const; protected: virtual ~MWShadowTechnique(); From 707204133d1f7c0932734ef893f289b52aa07f5a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 20 Aug 2020 00:38:13 +0100 Subject: [PATCH 29/40] Double-buffer shadow uniforms that change each frame --- components/sceneutil/mwshadowtechnique.cpp | 41 +++++++++++----------- components/sceneutil/mwshadowtechnique.hpp | 3 +- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index ae3a29295..7a435fe90 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1344,9 +1344,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) std::string validRegionUniformName = "validRegionMatrix" + std::to_string(sm_i); osg::ref_ptr validRegionUniform; - std::lock_guard lock(_accessUniformsAndProgramMutex); - - for (auto uniform : _uniforms) + for (auto uniform : _uniforms[cv.getTraversalNumber() % 2]) { if (uniform->getName() == validRegionUniformName) validRegionUniform = uniform; @@ -1355,7 +1353,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (!validRegionUniform) { validRegionUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, validRegionUniformName); - _uniforms.push_back(validRegionUniform); + _uniforms[cv.getTraversalNumber() % 2].push_back(validRegionUniform); } validRegionUniform->set(validRegionMatrix); @@ -1468,8 +1466,6 @@ void MWShadowTechnique::createShaders() unsigned int _baseTextureUnit = 0; - std::lock_guard lock(_accessUniformsAndProgramMutex); - _shadowCastingStateSet = new osg::StateSet; ShadowSettings* settings = getShadowedScene()->getShadowSettings(); @@ -1502,15 +1498,20 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - _uniforms.clear(); osg::ref_ptr baseTextureSampler = new osg::Uniform("baseTexture",(int)_baseTextureUnit); - _uniforms.push_back(baseTextureSampler.get()); - osg::ref_ptr baseTextureUnit = new osg::Uniform("baseTextureUnit",(int)_baseTextureUnit); - _uniforms.push_back(baseTextureUnit.get()); - _uniforms.push_back(new osg::Uniform("maximumShadowMapDistance", (float)settings->getMaximumShadowMapDistance())); - _uniforms.push_back(new osg::Uniform("shadowFadeStart", (float)_shadowFadeStart)); + osg::ref_ptr maxDistance = new osg::Uniform("maximumShadowMapDistance", (float)settings->getMaximumShadowMapDistance()); + osg::ref_ptr fadeStart = new osg::Uniform("shadowFadeStart", (float)_shadowFadeStart); + + for (auto& perFrameUniformList : _uniforms) + { + perFrameUniformList.clear(); + perFrameUniformList.push_back(baseTextureSampler); + perFrameUniformList.push_back(baseTextureUnit.get()); + perFrameUniformList.push_back(maxDistance); + perFrameUniformList.push_back(fadeStart); + } for(unsigned int sm_i=0; sm_igetNumShadowMapsPerLight(); ++sm_i) { @@ -1518,14 +1519,16 @@ void MWShadowTechnique::createShaders() std::stringstream sstr; sstr<<"shadowTexture"< shadowTextureSampler = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); - _uniforms.push_back(shadowTextureSampler.get()); + for (auto& perFrameUniformList : _uniforms) + perFrameUniformList.push_back(shadowTextureSampler.get()); } { std::stringstream sstr; sstr<<"shadowTextureUnit"< shadowTextureUnit = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); - _uniforms.push_back(shadowTextureUnit.get()); + for (auto& perFrameUniformList : _uniforms) + perFrameUniformList.push_back(shadowTextureUnit.get()); } } @@ -2981,18 +2984,14 @@ osg::StateSet* MWShadowTechnique::selectStateSetForRenderingShadow(ViewDependent osg::ref_ptr stateset = vdd.getStateSet(traversalNumber); - std::lock_guard lock(_accessUniformsAndProgramMutex); - stateset->clear(); stateset->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); - for(Uniforms::const_iterator itr=_uniforms.begin(); - itr!=_uniforms.end(); - ++itr) + for(auto uniform : _uniforms[traversalNumber % 2]) { - OSG_INFO<<"addUniform("<<(*itr)->getName()<<")"<addUniform(itr->get()); + OSG_INFO<<"addUniform("<getName()<<")"<addUniform(uniform); } if (_program.valid()) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 95f1117c0..bdfb44e46 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -248,8 +248,7 @@ namespace SceneUtil { osg::ref_ptr _fallbackShadowMapTexture; typedef std::vector< osg::ref_ptr > Uniforms; - mutable std::mutex _accessUniformsAndProgramMutex; - Uniforms _uniforms; + std::array _uniforms; osg::ref_ptr _program; bool _enableShadows; From fd14dad7897e0c80836b33d2ed281bb4da0b551a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 20 Aug 2020 03:01:43 +0100 Subject: [PATCH 30/40] const osg::ref_ptf reference should be faster than value as constructor and destructor are non-trivial I played around in GodBolt and got into an argument to determine this. The difference will be immeasurably small, but my curiosity has been satisfied. --- components/sceneutil/mwshadowtechnique.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 7a435fe90..dc22d4d80 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2988,7 +2988,7 @@ osg::StateSet* MWShadowTechnique::selectStateSetForRenderingShadow(ViewDependent stateset->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); - for(auto uniform : _uniforms[traversalNumber % 2]) + for(const auto& uniform : _uniforms[traversalNumber % 2]) { OSG_INFO<<"addUniform("<getName()<<")"<addUniform(uniform); From 7c9497c4dec8063c34f8189ffe1169ed6bc0d619 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 21 Aug 2020 12:52:26 +0400 Subject: [PATCH 31/40] Use two columns when there is too many checkboxes in launcher's tab --- apps/launcher/advancedpage.cpp | 4 +- files/ui/advancedpage.ui | 1054 +++++++++++++++++--------------- 2 files changed, 564 insertions(+), 494 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 1cc77ec6d..bc14a9269 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -127,7 +127,7 @@ bool Launcher::AdvancedPage::loadSettings() { loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera"); connect(viewOverShoulderCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotViewOverShoulderToggled(bool))); - viewOverShoulderGroup->setEnabled(viewOverShoulderCheckBox->checkState()); + viewOverShoulderVerticalLayout->setEnabled(viewOverShoulderCheckBox->checkState()); loadSettingBool(autoSwitchShoulderCheckBox, "auto switch shoulder", "Camera"); loadSettingBool(previewIfStandStillCheckBox, "preview if stand still", "Camera"); loadSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera"); @@ -339,5 +339,5 @@ void Launcher::AdvancedPage::slotAnimSourcesToggled(bool checked) void Launcher::AdvancedPage::slotViewOverShoulderToggled(bool checked) { - viewOverShoulderGroup->setEnabled(viewOverShoulderCheckBox->checkState()); + viewOverShoulderVerticalLayout->setEnabled(viewOverShoulderCheckBox->checkState()); } diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 4f1a30d4c..9084a7aba 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -2,6 +2,14 @@ AdvancedPage + + + 0 + 0 + 617 + 487 + + @@ -14,74 +22,128 @@ - - - <html><head/><body><p>This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. </p></body></html> - - - Toggle sneak - - - - - - - <html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.</p><p>If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.</p></body></html> - - - Can loot during death animation - - - - - - - <html><head/><body><p>Make player followers and escorters start combat with enemies who have started combat with them or the player. Otherwise they wait for the enemies or the player to do an attack first.</p></body></html> - - - Followers defend immediately - - - - - - - <html><head/><body><p>Make the value of filled soul gems dependent only on soul magnitude.</p></body></html> - - - Soulgem values rebalance - - - - - - - <html><head/><body><p>Make enchanted weaponry without Magical flag bypass normal weapons resistance, like in Morrowind.</p></body></html> - - - Enchanted weapons are magical - - - - - - - <html><head/><body><p>Make disposition change of merchants caused by trading permanent.</p></body></html> - - - Permanent barter disposition changes - - - - - - - <html><head/><body><p>Effects of reflected Absorb spells are not mirrored -- like in Morrowind.</p></body></html> - - - Classic reflected Absorb spells behavior - - + + + + + <html><head/><body><p>Make enchanted weaponry without Magical flag bypass normal weapons resistance, like in Morrowind.</p></body></html> + + + Enchanted weapons are magical + + + + + + + <html><head/><body><p>Makes player swim a bit upward from the line of sight. Applies only in third person mode. Intended to make simpler swimming without diving.</p></body></html> + + + Swim upward correction + + + + + + + <html><head/><body><p>Enable navigator. When enabled background threads are started to build nav mesh for world geometry. Pathfinding system uses nav mesh to build paths. When disabled only pathgrid is used to build paths. Single-core CPU systems may have big performance impact on exiting interior location and moving across exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn’t know where to go when you stand behind that stone and casting a firebolt.</p></body></html> + + + Build nav mesh for world geometry + + + + + + + <html><head/><body><p>This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. </p></body></html> + + + Toggle sneak + + + + + + + <html><head/><body><p>Make disposition change of merchants caused by trading permanent.</p></body></html> + + + Permanent barter disposition changes + + + + + + + <html><head/><body><p>Don't use race weight in NPC movement speed calculations.</p></body></html> + + + Racial variation in speed fix + + + + + + + <html><head/><body><p>Make Damage Fatigue magic effect uncapped like Drain Fatigue effect.</p><p>This means that unlike Morrowind you will be able to knock down actors using this effect.</p></body></html> + + + Uncapped Damage Fatigue + + + + + + + <html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.</p><p>If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.</p></body></html> + + + Can loot during death animation + + + + + + + <html><head/><body><p>Make the value of filled soul gems dependent only on soul magnitude.</p></body></html> + + + Soulgem values rebalance + + + + + + + <html><head/><body><p>Make player followers and escorters start combat with enemies who have started combat with them or the player. Otherwise they wait for the enemies or the player to do an attack first.</p></body></html> + + + Followers defend immediately + + + + + + + <html><head/><body><p>Effects of reflected Absorb spells are not mirrored -- like in Morrowind.</p></body></html> + + + Classic reflected Absorb spells behavior + + + + + + + <html><head/><body><p>Make stealing items from NPCs that were knocked down possible during combat.</p></body></html> + + + Always allow stealing from knocked out actors + + + + @@ -94,98 +156,62 @@ - - - <html><head/><body><p>Make Damage Fatigue magic effect uncapped like Drain Fatigue effect.</p><p>This means that unlike Morrowind you will be able to knock down actors using this effect.</p></body></html> - - - Uncapped Damage Fatigue - - - - - - - <html><head/><body><p>Don't use race weight in NPC movement speed calculations.</p></body></html> - - - Racial variation in speed fix - - - - - - - <html><head/><body><p>Makes player swim a bit upward from the line of sight. Applies only in third person mode. Intended to make simpler swimming without diving.</p></body></html> - - - Swim upward correction - - - - - - - <html><head/><body><p>Factor strength into hand-to-hand damage calculations, as the MCP formula: damage * (strength / 40).</p><p>The default value is Off.</p></body></html> - - - - + + + + + Factor strength into hand-to-hand combat: + + + + + + + 0 + + - Factor strength into hand-to-hand combat: + Off - - - - - - 0 + + + + Affect werewolves - - - Off - - - - - Affect werewolves - - - - - Do not affect werewolves - - - - - - + + + + Do not affect werewolves + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - <html><head/><body><p>Make stealing items from NPCs that were knocked down possible during combat.</p></body></html> - - - Always allow stealing from knocked out actors - - - - - - - <html><head/><body><p>Enable navigator. When enabled background threads are started to build nav mesh for world geometry. Pathfinding system uses nav mesh to build paths. When disabled only pathgrid is used to build paths. Single-core CPU systems may have big performance impact on exiting interior location and moving across exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn’t know where to go when you stand behind that stone and casting a firebolt.</p></body></html> - - - Build nav mesh for world geometry - - - - - + Qt::Vertical + + + 20 + 40 + + @@ -196,196 +222,197 @@ - - - <html><head/><body><p>If this option is enabled, normal maps are automatically recognized and used if they are named appropriately + + + + + <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html> + + + Turn to movement direction + + + + + + + <html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html> + + + Distant land + + + + + + + <html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html> + + + Auto use terrain normal maps + + + + + + + <html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html> + + + Auto use terrain specular maps + + + + + + + <html><head/><body><p>Use object paging for active cells grid.</p></body></html> + + + Active grid object paging + + + + + + + <html><head/><body><p>Use casting animations for magic items, just as for spells.</p></body></html> + + + Use magic item animation + + + + + + + <html><head/><body><p>Load per-group KF-files and skeleton files from Animations folder</p></body></html> + + + Use additional animation sources + + + + + + + <html><head/><body><p>If this option is enabled, normal maps are automatically recognized and used if they are named appropriately (see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds). If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). Affects objects.</p></body></html> - - - Auto use object normal maps - - - - - - - <html><head/><body><p>If this option is enabled, specular maps are automatically recognized and used if they are named appropriately + + + Auto use object normal maps + + + + + + + <html><head/><body><p>Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark. +Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option. +Affected objects will use shaders. +</p></body></html> + + + Bump/reflect map local lighting + + + + + + + + + Viewing distance + + + + + + + Cells + + + 0.000000000000000 + + + 0.500000000000000 + + + + + + + + + <html><head/><body><p>If this option is enabled, specular maps are automatically recognized and used if they are named appropriately (see 'specular map pattern', e.g. for a base texture foo.dds, the specular map texture would have to be named foo_spec.dds). If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.osg file, not supported in .nif files). Affects objects.</p></body></html> - - - Auto use object specular maps - - - - - - - <html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html> - - - Auto use terrain normal maps - - - - - - - <html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html> - - - Auto use terrain specular maps - - - - - - - <html><head/><body><p>Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark. -Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option. -Affected objects will use shaders. -</p></body></html> - - - Bump/reflect map local lighting - - - - - - - <html><head/><body><p>By default, the fog becomes thicker proportionally to your distance from the clipping plane set at the clipping distance, which causes distortion at the edges of the screen. + + + Auto use object specular maps + + + + + + + <html><head/><body><p>By default, the fog becomes thicker proportionally to your distance from the clipping plane set at the clipping distance, which causes distortion at the edges of the screen. This setting makes the fog use the actual eye point distance (or so called Euclidean distance) to calculate the fog, which makes the fog look less artificial, especially if you have a wide FOV.</p></body></html> - - - Radial fog - - + + + Radial fog + + + + - - - <html><head/><body><p>Use casting animations for magic items, just as for spells.</p></body></html> + + + 20 - - Use magic item animation - - + + + + false + + + <html><head/><body><p>Render holstered weapons (with quivers and scabbards), requires modded assets.</p></body></html> + + + Weapon sheathing + + + + + + + false + + + <html><head/><body><p>Render holstered shield, requires modded assets.</p></body></html> + + + Shield sheathing + + + + - - - <html><head/><body><p>Load per-group KF-files and skeleton files from Animations folder</p></body></html> - - - Use additional animation sources - - - - - - - - 20 - - - - - false - - - <html><head/><body><p>Render holstered weapons (with quivers and scabbards), requires modded assets.</p></body></html> - - - Weapon sheathing - - - - - - - false - - - <html><head/><body><p>Render holstered shield, requires modded assets.</p></body></html> - - - Shield sheathing - - - - - - - - - - <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html> - - - Turn to movement direction - - - - - - - <html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html> - - - Distant land - - - - - - - <html><head/><body><p>Use object paging for active cells grid.</p></body></html> - - - Active grid object paging - - - - - - - <html><head/><body><p>This value controls the maximum visible distance (in cell units). -Larger values significantly improve rendering in exterior spaces, -but also increase the amount of rendered geometry and significantly reduce the frame rate.</p></body></html> - - - - - - Viewing distance - - - - - - - 0.0 - - - 0.5 - - - Cells - - - - - - - - + Qt::Vertical + + + 20 + 40 + + @@ -408,75 +435,84 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C - - - - 20 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Default shoulder: - - - - - - - 0 - - - - Right - - - - - Left - - - - - - - - - - - <html><head/><body><p>When player is close to an obstacle, automatically switches camera to the shoulder that is farther away from the obstacle.</p></body></html> - - - Auto switch shoulder - - - - + + + <html><head/><body><p>When player is close to an obstacle, automatically switches camera to the shoulder that is farther away from the obstacle.</p></body></html> + + + Auto switch shoulder + + + + + 20 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Default shoulder: + + + + + + + 0 + + + + Right + + + + + Left + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + @@ -502,6 +538,12 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C Qt::Vertical + + + 0 + 0 + + @@ -511,6 +553,57 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C Interface + + + + + + Show owned: + + + + + + + 1 + + + + Off + + + + + Tool Tip Only + + + + + Crosshair Only + + + + + Tool Tip and Crosshair + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -561,54 +654,17 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C - - - - <html><head/><body><p>Enable visual clues for items owned by NPCs when the crosshair is on the object.</p><p>The default value is Off.</p></body></html> - - - - - - Show owned: - - - - - - - 1 - - - - Off - - - - - Tool Tip Only - - - - - Crosshair Only - - - - - Tool Tip and Crosshair - - - - - - - - + Qt::Vertical + + + 20 + 40 + + @@ -643,6 +699,12 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C Qt::Vertical + + + 0 + 0 + + @@ -668,28 +730,23 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C - - - - <html><head/><body><p>This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave.</p></body></html> - - - - - - Maximum Quicksaves - - - - - - - 1 - - - - - + + + + + + Maximum Quicksaves + + + + + + + 1 + + + + @@ -700,40 +757,35 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C Other - - - - <html><head/><body><p>Specify the format for screen shots taken by pressing the screen shot key (bound to F12 by default). This setting should be the file extension commonly associated with the desired format. The formats supported will be determined at compilation, but “jpg”, “png”, and “tga” should be allowed.</p></body></html> - - - - + + + + + + Screenshot Format + + + + + + - Screenshot Format + JPG - - - - - - - JPG - - - - - PNG - - - - - TGA - - - - - - + + + + PNG + + + + + TGA + + + + + @@ -743,6 +795,12 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C Qt::Vertical + + + 0 + 0 + + @@ -796,6 +854,12 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C QSizePolicy::Fixed + + + 0 + 0 + + @@ -840,6 +904,12 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C Qt::Vertical + + + 0 + 0 + + From b60d5904e2f6ea6e55096d0405b3e5754d94f6db Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 26 Aug 2020 00:16:14 +0100 Subject: [PATCH 32/40] Correct SDL_GetNumVideoDisplays error message It logged the wrong function --- apps/launcher/graphicspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 45c093bee..01992dcce 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -65,7 +65,7 @@ bool Launcher::GraphicsPage::setupSDL() msgBox.setWindowTitle(tr("Error receiving number of screens")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumVideoDisplays failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return false; } From f9e667dd8c5e7311e05b3d3ed7d70011d91b0ad4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 26 Aug 2020 12:34:27 +0400 Subject: [PATCH 33/40] Fix MSVC warnings --- apps/openmw/mwphysics/physicssystem.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ade8775e6..26005b396 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -57,7 +57,7 @@ namespace MWPhysics { public: PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); - ~PhysicsSystem (); + virtual ~PhysicsSystem (); void setUnrefQueue(SceneUtil::UnrefQueue* unrefQueue); @@ -109,17 +109,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 final; /// @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 targets = std::vector(), - 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 final; - 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 final; /// 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 final; bool isOnGround (const MWWorld::Ptr& actor); From 5538fea1d17d11ca632a6a306951c2f07791db34 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 26 Aug 2020 16:58:12 +0100 Subject: [PATCH 34/40] Display standard resolutions on single-monitor machines --- apps/launcher/graphicspage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 01992dcce..c1a946145 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -75,6 +75,7 @@ bool Launcher::GraphicsPage::setupSDL() { screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1)); } + screenChanged(0); // Disconnect from SDL processes quitSDL(); From a495888d3d56042423c8bd6f5b39c1168ee5aba0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 26 Aug 2020 16:58:51 +0100 Subject: [PATCH 35/40] Get per-monitor resolution list while SDL is alive --- apps/launcher/graphicspage.cpp | 4 +++- apps/launcher/graphicspage.hpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index c1a946145..c745332dc 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -71,8 +71,10 @@ bool Launcher::GraphicsPage::setupSDL() } screenComboBox->clear(); + mResolutionsPerScreen.clear(); for (int i = 0; i < displays; i++) { + mResolutionsPerScreen.append(getAvailableResolutions(i)); screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1)); } screenChanged(0); @@ -332,7 +334,7 @@ void Launcher::GraphicsPage::screenChanged(int screen) { if (screen >= 0) { resolutionComboBox->clear(); - resolutionComboBox->addItems(getAvailableResolutions(screen)); + resolutionComboBox->addItems(mResolutionsPerScreen[screen]); } } diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 4ce5b584f..3b03a72bd 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -38,6 +38,8 @@ namespace Launcher Files::ConfigurationManager &mCfgMgr; Settings::Manager &mEngineSettings; + QVector mResolutionsPerScreen; + static QStringList getAvailableResolutions(int screen); static QRect getMaximumResolution(); From b71f13965a2773a8bad256cafed8b631d755ba91 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 27 Aug 2020 02:30:40 +0100 Subject: [PATCH 36/40] Don't set pipefail --- CI/activate_msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/activate_msvc.sh b/CI/activate_msvc.sh index 1641f6b3e..05925737a 100644 --- a/CI/activate_msvc.sh +++ b/CI/activate_msvc.sh @@ -1,6 +1,6 @@ #!/bin/bash -set -euo pipefail +set -eu if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then echo "Error: Script not sourced." From 70384d8a83bac54e14c3446a914e726061f37786 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 27 Aug 2020 03:03:03 +0100 Subject: [PATCH 37/40] Restore previous bash settings on exit --- CI/activate_msvc.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/CI/activate_msvc.sh b/CI/activate_msvc.sh index 05925737a..47f2c246f 100644 --- a/CI/activate_msvc.sh +++ b/CI/activate_msvc.sh @@ -1,13 +1,24 @@ #!/bin/bash +oldSettings=$- set -eu +function restoreOldSettings { + if [[ $oldSettings != *e* ]]; then + set +e + fi + if [[ $oldSettings != *u* ]]; then + set +u + fi +} + if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then echo "Error: Script not sourced." echo "You must source this script for it to work, i.e. " echo "source ./activate_msvc.sh" echo "or" echo ". ./activate_msvc.sh" + restoreOldSettings exit 1 fi @@ -78,7 +89,10 @@ command -v mt >/dev/null 2>&1 || { echo "Error: mt (MS Windows Manifest Tool) mi if [ $MISSINGTOOLS -ne 0 ]; then echo "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing." + restoreOldSettings return 1 fi -IFS="$originalIFS" \ No newline at end of file +IFS="$originalIFS" + +restoreOldSettings \ No newline at end of file From f90a049702d1439267a2c7b78a39bfc16a874470 Mon Sep 17 00:00:00 2001 From: psi29a Date: Thu, 27 Aug 2020 11:48:59 +0000 Subject: [PATCH 38/40] Merge branch 'movement_refactoring' into 'master' Refactoring related to "smooth movement" See merge request OpenMW/openmw!285 (cherry picked from commit 6eaf0a389d5aed3b74ab1a7cf89574612f964bdf) e847b4c8 Split getSpeed() to getMaxSpeed() and getCurrentSpeed() a96c46bc Refactor calculation of movement.mSpeedFactor 03ee9090 Use getMaxSpeed instead of getCurrentSpeed where it makes sense. a178af5c Create helper functions `normalizeAngle` and `rotateVec2f` --- apps/openmw/mwclass/actor.cpp | 9 ++++++ apps/openmw/mwclass/actor.hpp | 5 +++- apps/openmw/mwclass/creature.cpp | 7 +---- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 7 +---- apps/openmw/mwclass/npc.hpp | 4 +-- apps/openmw/mwmechanics/actors.cpp | 12 ++++---- apps/openmw/mwmechanics/aipackage.cpp | 6 ++-- apps/openmw/mwmechanics/character.cpp | 41 +++++++++------------------ apps/openmw/mwmechanics/movement.hpp | 6 ++++ apps/openmw/mwmechanics/obstacle.cpp | 2 +- apps/openmw/mwmechanics/steering.cpp | 2 +- apps/openmw/mwrender/camera.cpp | 24 ++++------------ apps/openmw/mwworld/class.cpp | 7 ++++- apps/openmw/mwworld/class.hpp | 19 +++++++------ components/misc/mathutil.hpp | 27 ++++++++++++++++++ 16 files changed, 97 insertions(+), 83 deletions(-) create mode 100644 components/misc/mathutil.hpp diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index 4eb9728a1..61d6e7347 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -91,4 +91,13 @@ namespace MWClass { return true; } + + float Actor::getCurrentSpeed(const MWWorld::Ptr& ptr) const + { + const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr); + float moveSpeed = this->getMaxSpeed(ptr) * movementSettings.mSpeedFactor; + if (movementSettings.mIsStrafing) + moveSpeed *= 0.75f; + return moveSpeed; + } } diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index 7cdee8061..6ccd552f9 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. + ///< Return desired rotations, as euler angles. Sets getMovementSettings(ptr).mRotation to zero. virtual float getEncumbrance(const MWWorld::Ptr& ptr) const; ///< Returns total weight of objects inside this object (including modifications from magic @@ -42,6 +42,9 @@ namespace MWClass virtual bool isActor() const; + /// Return current movement speed. + virtual float getCurrentSpeed(const MWWorld::Ptr& ptr) const; + // not implemented Actor(const Actor&); Actor& operator= (const Actor&); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 15e0fa6ab..5c5524a12 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -500,7 +500,7 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } - float Creature::getSpeed(const MWWorld::Ptr &ptr) const + float Creature::getMaxSpeed(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -532,11 +532,6 @@ namespace MWClass else moveSpeed = getWalkSpeed(ptr); - const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr); - if (movementSettings.mIsStrafing) - moveSpeed *= 0.75f; - moveSpeed *= movementSettings.mSpeedFactor; - return moveSpeed; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 2d7aa5a19..ca991052b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -94,7 +94,7 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - float getSpeed (const MWWorld::Ptr& ptr) const; + float getMaxSpeed (const MWWorld::Ptr& ptr) const; static void registerSelf(); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0c00d3bd1..b89d79fc9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -936,7 +936,7 @@ namespace MWClass return ref->mBase->mScript; } - float Npc::getSpeed(const MWWorld::Ptr& ptr) const + float Npc::getMaxSpeed(const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead()) @@ -979,11 +979,6 @@ namespace MWClass if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing) moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat(); - const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr); - if (movementSettings.mIsStrafing) - moveSpeed *= 0.75f; - moveSpeed *= movementSettings.mSpeedFactor; - return moveSpeed; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index d52afcd82..1ed4e8cae 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -84,8 +84,8 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual float getSpeed (const MWWorld::Ptr& ptr) const; - ///< Return movement speed. + virtual float getMaxSpeed (const MWWorld::Ptr& ptr) const; + ///< Return maximal movement speed. virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b91b01e4a..14a2e17c9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -472,9 +472,6 @@ namespace MWMechanics void Actors::updateMovementSpeed(const MWWorld::Ptr& actor) { - float previousSpeedFactor = actor.getClass().getMovementSettings(actor).mSpeedFactor; - float newSpeedFactor = 1.f; - CreatureStats &stats = actor.getClass().getCreatureStats(actor); MWMechanics::AiSequence& seq = stats.getAiSequence(); @@ -484,10 +481,13 @@ namespace MWMechanics osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3(); float distance = (targetPos - actorPos).length(); if (distance < DECELERATE_DISTANCE) - newSpeedFactor = std::max(0.7f, 0.1f * previousSpeedFactor * (distance/64.f + 2.f)); + { + float speedCoef = std::max(0.7f, 0.1f * (distance/64.f + 2.f)); + auto& movement = actor.getClass().getMovementSettings(actor); + movement.mPosition[0] *= speedCoef; + movement.mPosition[1] *= speedCoef; + } } - - actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor; } void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f7c07bde0..53e366579 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -144,7 +144,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& mTimer = 0; } - const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration + const float actorTolerance = 2 * actor.getClass().getMaxSpeed(actor) * duration + 1.2 * std::max(halfExtents.x(), halfExtents.y()); const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance); @@ -300,7 +300,7 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin if (canActorMoveByZAxis(actor)) return true; - const float actorSpeed = actor.getClass().getSpeed(actor); + const float actorSpeed = actor.getClass().getMaxSpeed(actor); const float maxAvoidDist = AI_REACTION_TIME * actorSpeed + actorSpeed / getAngularVelocity(actorSpeed) * 2; // *2 - for reliability const float distToTarget = osg::Vec2f(endPoint.x(), endPoint.y()).length(); @@ -360,7 +360,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& actor, const osg::Vec3f& dest) { // get actor's shortest radius for moving in circle - float speed = actor.getClass().getSpeed(actor); + float speed = actor.getClass().getMaxSpeed(actor); speed += speed * 0.1f; // 10% real speed inaccuracy float radius = speed / getAngularVelocity(speed); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2ff8241f4..5d102f69e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include +#include #include #include @@ -51,15 +52,6 @@ namespace { -// Wraps a value to (-PI, PI] -void wrap(float& rad) -{ - if (rad>0) - rad = std::fmod(rad+osg::PI, 2.0f*osg::PI)-osg::PI; - else - rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI; -} - std::string getBestAttack (const ESM::Weapon* weapon) { int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; @@ -1958,23 +1950,19 @@ void CharacterController::update(float duration, bool animationOnly) osg::Vec3f rot = cls.getRotationVector(mPtr); osg::Vec3f vec(movementSettings.asVec3()); - vec.normalize(); - float analogueMult = 1.0f; if (isPlayer) { // TODO: Move this code to mwinput. // Joystick analogue movement. - float xAxis = std::abs(movementSettings.mPosition[0]); - float yAxis = std::abs(movementSettings.mPosition[1]); - analogueMult = std::max(xAxis, yAxis); + movementSettings.mSpeedFactor = std::max(std::abs(vec.x()), std::abs(vec.y())); // Due to the half way split between walking/running, we multiply speed by 2 while walking, unless a keyboard was used. - if(!isrunning && !sneak && !flying && analogueMult <= 0.5f) - analogueMult *= 2.f; - - movementSettings.mSpeedFactor = analogueMult; - } + if(!isrunning && !sneak && !flying && movementSettings.mSpeedFactor <= 0.5f) + movementSettings.mSpeedFactor *= 2.f; + } else + movementSettings.mSpeedFactor = std::min(vec.length(), 1.f); + vec.normalize(); float effectiveRotation = rot.z(); static const bool turnToMovementDirection = Settings::Manager::getBool("turn to movement direction", "Game"); @@ -2007,7 +1995,7 @@ void CharacterController::update(float duration, bool animationOnly) else mAnimation->setUpperBodyYawRadians(stats.getSideMovementAngle() / 4); - speed = cls.getSpeed(mPtr); + speed = cls.getCurrentSpeed(mPtr); vec.x() *= speed; vec.y() *= speed; @@ -2077,7 +2065,7 @@ void CharacterController::update(float duration, bool animationOnly) } } fatigueLoss *= duration; - fatigueLoss *= analogueMult; + fatigueLoss *= movementSettings.mSpeedFactor; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); if (!godmode) @@ -2908,13 +2896,10 @@ void CharacterController::updateHeadTracking(float duration) zAngleRadians = std::atan2(direction.x(), direction.y()) - std::atan2(actorDirection.x(), actorDirection.y()); xAngleRadians = -std::asin(direction.z()); - wrap(zAngleRadians); - wrap(xAngleRadians); - - xAngleRadians = std::min(xAngleRadians, osg::DegreesToRadians(40.f)); - xAngleRadians = std::max(xAngleRadians, osg::DegreesToRadians(-40.f)); - zAngleRadians = std::min(zAngleRadians, osg::DegreesToRadians(30.f)); - zAngleRadians = std::max(zAngleRadians, osg::DegreesToRadians(-30.f)); + const double xLimit = osg::DegreesToRadians(40.0); + const double zLimit = osg::DegreesToRadians(30.0); + zAngleRadians = osg::clampBetween(Misc::normalizeAngle(zAngleRadians), -xLimit, xLimit); + xAngleRadians = osg::clampBetween(Misc::normalizeAngle(xAngleRadians), -zLimit, zLimit); } float factor = duration*5; diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index 86b970e60..57e106cde 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -8,8 +8,14 @@ namespace MWMechanics /// Desired movement for an actor struct Movement { + // Desired movement. Direction is relative to the current orientation. + // Length of the vector controls desired speed. 0 - stay, 0.5 - half-speed, 1.0 - max speed. float mPosition[3]; + // Desired rotation delta (euler angles). float mRotation[3]; + + // Controlled by CharacterController, should not be changed from other places. + // These fields can not be private fields in CharacterController, because Actor::getCurrentSpeed uses it. float mSpeedFactor; bool mIsStrafing; diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 715dfecd2..88325ee7c 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -122,7 +122,7 @@ namespace MWMechanics if (mWalkState != WalkState::Evade) { - const float distSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) * duration; + const float distSameSpot = DIST_SAME_SPOT * actor.getClass().getCurrentSpeed(actor) * duration; const float prevDistance = (destination - mPrev).length(); const float currentDistance = (destination - position).length(); const float movedDistance = prevDistance - currentDistance; diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index b08a90220..d442085ea 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -32,7 +32,7 @@ bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, f if (absDiff < epsilonRadians) return true; - float limit = getAngularVelocity(actor.getClass().getSpeed(actor)) * MWBase::Environment::get().getFrameDuration(); + float limit = getAngularVelocity(actor.getClass().getMaxSpeed(actor)) * MWBase::Environment::get().getFrameDuration(); if (absDiff > limit) diff = osg::sign(diff) * limit; diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 40cc9895d..0d6ed262b 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -200,7 +201,7 @@ namespace MWRender updateFocalPointOffset(duration); updatePosition(); - float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr); + float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr); speed /= (1.f + speed / 500.f); float maxDelta = 300.f * duration; mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta); @@ -249,7 +250,7 @@ namespace MWRender { if (!mStandingPreviewAllowed) return; - float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr); + float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr); bool combat = mTrackingPtr.getClass().isActor() && mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing; bool standingStill = speed == 0 && !combat && !mFirstPersonView; @@ -396,12 +397,7 @@ namespace MWRender void Camera::setYaw(float angle) { - if (angle > osg::PI) { - angle -= osg::PI*2; - } else if (angle < -osg::PI) { - angle += osg::PI*2; - } - mYaw = angle; + mYaw = Misc::normalizeAngle(angle); } void Camera::setPitch(float angle) @@ -538,16 +534,8 @@ namespace MWRender return; } - mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mPitch; - mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mYaw; - if (mDeferredRotation.x() > osg::PI) - mDeferredRotation.x() -= 2 * osg::PI; - if (mDeferredRotation.x() < -osg::PI) - mDeferredRotation.x() += 2 * osg::PI; - if (mDeferredRotation.z() > osg::PI) - mDeferredRotation.z() -= 2 * osg::PI; - if (mDeferredRotation.z() < -osg::PI) - mDeferredRotation.z() += 2 * osg::PI; + mDeferredRotation.x() = Misc::normalizeAngle(-ptr.getRefData().getPosition().rot[0] - mPitch); + mDeferredRotation.z() = Misc::normalizeAngle(-ptr.getRefData().getPosition().rot[2] - mYaw); } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index ad8766d06..950c8a6d4 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -159,7 +159,12 @@ namespace MWWorld return ""; } - float Class::getSpeed (const Ptr& ptr) const + float Class::getMaxSpeed (const Ptr& ptr) const + { + return 0; + } + + float Class::getCurrentSpeed (const Ptr& ptr) const { return 0; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e82712220..445f2e986 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -172,8 +172,15 @@ namespace MWWorld ///< Return name of the script attached to ptr (default implementation: return an empty /// string). - virtual float getSpeed (const Ptr& ptr) const; - ///< Return movement speed. + virtual float getWalkSpeed(const Ptr& ptr) const; + virtual float getRunSpeed(const Ptr& ptr) const; + virtual float getSwimSpeed(const Ptr& ptr) const; + + /// Return maximal movement speed for the current state. + virtual float getMaxSpeed(const Ptr& ptr) const; + + /// Return current movement speed. + virtual float getCurrentSpeed(const Ptr& ptr) const; virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) @@ -182,7 +189,7 @@ namespace MWWorld ///< Return desired movement. virtual osg::Vec3f getRotationVector (const Ptr& ptr) const; - ///< Return desired rotations, as euler angles. + ///< Return desired rotations, as euler angles. Sets getMovementSettings(ptr).mRotation to zero. virtual std::pair, bool> getEquipmentSlots (const ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object @@ -364,12 +371,6 @@ namespace MWWorld virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const; virtual void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const; - - virtual float getWalkSpeed(const Ptr& ptr) const; - - virtual float getRunSpeed(const Ptr& ptr) const; - - virtual float getSwimSpeed(const Ptr& ptr) const; }; } diff --git a/components/misc/mathutil.hpp b/components/misc/mathutil.hpp new file mode 100644 index 000000000..2f7f446b5 --- /dev/null +++ b/components/misc/mathutil.hpp @@ -0,0 +1,27 @@ +#ifndef MISC_MATHUTIL_H +#define MISC_MATHUTIL_H + +#include +#include + +namespace Misc +{ + + /// Normalizes given angle to the range [-PI, PI]. E.g. PI*3/2 -> -PI/2. + inline double normalizeAngle(double angle) + { + double fullTurns = angle / (2 * osg::PI) + 0.5; + return (fullTurns - floor(fullTurns) - 0.5) * (2 * osg::PI); + } + + /// Rotates given 2d vector counterclockwise. Angle is in radians. + inline osg::Vec2f rotateVec2f(osg::Vec2f vec, float angle) + { + float s = std::sin(angle); + float c = std::cos(angle); + return osg::Vec2f(vec.x() * c + vec.y() * -s, vec.x() * s + vec.y() * c); + } + +} + +#endif From c495c21923dcc08a8360555b274eebb1e93347ba Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Thu, 27 Aug 2020 11:48:59 +0000 Subject: [PATCH 39/40] Merge branch 'movement_refactoring' into 'master' Refactoring related to "smooth movement" See merge request OpenMW/openmw!285 (cherry picked from commit 6eaf0a389d5aed3b74ab1a7cf89574612f964bdf) e847b4c8 Split getSpeed() to getMaxSpeed() and getCurrentSpeed() a96c46bc Refactor calculation of movement.mSpeedFactor 03ee9090 Use getMaxSpeed instead of getCurrentSpeed where it makes sense. a178af5c Create helper functions `normalizeAngle` and `rotateVec2f` --- apps/openmw/mwclass/actor.cpp | 9 ++++++ apps/openmw/mwclass/actor.hpp | 5 +++- apps/openmw/mwclass/creature.cpp | 7 +---- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 7 +---- apps/openmw/mwclass/npc.hpp | 4 +-- apps/openmw/mwmechanics/actors.cpp | 12 ++++---- apps/openmw/mwmechanics/aipackage.cpp | 6 ++-- apps/openmw/mwmechanics/character.cpp | 41 +++++++++------------------ apps/openmw/mwmechanics/movement.hpp | 6 ++++ apps/openmw/mwmechanics/obstacle.cpp | 2 +- apps/openmw/mwmechanics/steering.cpp | 2 +- apps/openmw/mwrender/camera.cpp | 24 ++++------------ apps/openmw/mwworld/class.cpp | 7 ++++- apps/openmw/mwworld/class.hpp | 19 +++++++------ components/misc/mathutil.hpp | 27 ++++++++++++++++++ 16 files changed, 97 insertions(+), 83 deletions(-) create mode 100644 components/misc/mathutil.hpp diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index 4eb9728a1..61d6e7347 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -91,4 +91,13 @@ namespace MWClass { return true; } + + float Actor::getCurrentSpeed(const MWWorld::Ptr& ptr) const + { + const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr); + float moveSpeed = this->getMaxSpeed(ptr) * movementSettings.mSpeedFactor; + if (movementSettings.mIsStrafing) + moveSpeed *= 0.75f; + return moveSpeed; + } } diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index 7cdee8061..6ccd552f9 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. + ///< Return desired rotations, as euler angles. Sets getMovementSettings(ptr).mRotation to zero. virtual float getEncumbrance(const MWWorld::Ptr& ptr) const; ///< Returns total weight of objects inside this object (including modifications from magic @@ -42,6 +42,9 @@ namespace MWClass virtual bool isActor() const; + /// Return current movement speed. + virtual float getCurrentSpeed(const MWWorld::Ptr& ptr) const; + // not implemented Actor(const Actor&); Actor& operator= (const Actor&); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 15e0fa6ab..5c5524a12 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -500,7 +500,7 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } - float Creature::getSpeed(const MWWorld::Ptr &ptr) const + float Creature::getMaxSpeed(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -532,11 +532,6 @@ namespace MWClass else moveSpeed = getWalkSpeed(ptr); - const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr); - if (movementSettings.mIsStrafing) - moveSpeed *= 0.75f; - moveSpeed *= movementSettings.mSpeedFactor; - return moveSpeed; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 2d7aa5a19..ca991052b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -94,7 +94,7 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - float getSpeed (const MWWorld::Ptr& ptr) const; + float getMaxSpeed (const MWWorld::Ptr& ptr) const; static void registerSelf(); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0c00d3bd1..b89d79fc9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -936,7 +936,7 @@ namespace MWClass return ref->mBase->mScript; } - float Npc::getSpeed(const MWWorld::Ptr& ptr) const + float Npc::getMaxSpeed(const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead()) @@ -979,11 +979,6 @@ namespace MWClass if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing) moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat(); - const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr); - if (movementSettings.mIsStrafing) - moveSpeed *= 0.75f; - moveSpeed *= movementSettings.mSpeedFactor; - return moveSpeed; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index d52afcd82..1ed4e8cae 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -84,8 +84,8 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual float getSpeed (const MWWorld::Ptr& ptr) const; - ///< Return movement speed. + virtual float getMaxSpeed (const MWWorld::Ptr& ptr) const; + ///< Return maximal movement speed. virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b91b01e4a..14a2e17c9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -472,9 +472,6 @@ namespace MWMechanics void Actors::updateMovementSpeed(const MWWorld::Ptr& actor) { - float previousSpeedFactor = actor.getClass().getMovementSettings(actor).mSpeedFactor; - float newSpeedFactor = 1.f; - CreatureStats &stats = actor.getClass().getCreatureStats(actor); MWMechanics::AiSequence& seq = stats.getAiSequence(); @@ -484,10 +481,13 @@ namespace MWMechanics osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3(); float distance = (targetPos - actorPos).length(); if (distance < DECELERATE_DISTANCE) - newSpeedFactor = std::max(0.7f, 0.1f * previousSpeedFactor * (distance/64.f + 2.f)); + { + float speedCoef = std::max(0.7f, 0.1f * (distance/64.f + 2.f)); + auto& movement = actor.getClass().getMovementSettings(actor); + movement.mPosition[0] *= speedCoef; + movement.mPosition[1] *= speedCoef; + } } - - actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor; } void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f7c07bde0..53e366579 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -144,7 +144,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& mTimer = 0; } - const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration + const float actorTolerance = 2 * actor.getClass().getMaxSpeed(actor) * duration + 1.2 * std::max(halfExtents.x(), halfExtents.y()); const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance); @@ -300,7 +300,7 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin if (canActorMoveByZAxis(actor)) return true; - const float actorSpeed = actor.getClass().getSpeed(actor); + const float actorSpeed = actor.getClass().getMaxSpeed(actor); const float maxAvoidDist = AI_REACTION_TIME * actorSpeed + actorSpeed / getAngularVelocity(actorSpeed) * 2; // *2 - for reliability const float distToTarget = osg::Vec2f(endPoint.x(), endPoint.y()).length(); @@ -360,7 +360,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& actor, const osg::Vec3f& dest) { // get actor's shortest radius for moving in circle - float speed = actor.getClass().getSpeed(actor); + float speed = actor.getClass().getMaxSpeed(actor); speed += speed * 0.1f; // 10% real speed inaccuracy float radius = speed / getAngularVelocity(speed); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2ff8241f4..5d102f69e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include +#include #include #include @@ -51,15 +52,6 @@ namespace { -// Wraps a value to (-PI, PI] -void wrap(float& rad) -{ - if (rad>0) - rad = std::fmod(rad+osg::PI, 2.0f*osg::PI)-osg::PI; - else - rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI; -} - std::string getBestAttack (const ESM::Weapon* weapon) { int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; @@ -1958,23 +1950,19 @@ void CharacterController::update(float duration, bool animationOnly) osg::Vec3f rot = cls.getRotationVector(mPtr); osg::Vec3f vec(movementSettings.asVec3()); - vec.normalize(); - float analogueMult = 1.0f; if (isPlayer) { // TODO: Move this code to mwinput. // Joystick analogue movement. - float xAxis = std::abs(movementSettings.mPosition[0]); - float yAxis = std::abs(movementSettings.mPosition[1]); - analogueMult = std::max(xAxis, yAxis); + movementSettings.mSpeedFactor = std::max(std::abs(vec.x()), std::abs(vec.y())); // Due to the half way split between walking/running, we multiply speed by 2 while walking, unless a keyboard was used. - if(!isrunning && !sneak && !flying && analogueMult <= 0.5f) - analogueMult *= 2.f; - - movementSettings.mSpeedFactor = analogueMult; - } + if(!isrunning && !sneak && !flying && movementSettings.mSpeedFactor <= 0.5f) + movementSettings.mSpeedFactor *= 2.f; + } else + movementSettings.mSpeedFactor = std::min(vec.length(), 1.f); + vec.normalize(); float effectiveRotation = rot.z(); static const bool turnToMovementDirection = Settings::Manager::getBool("turn to movement direction", "Game"); @@ -2007,7 +1995,7 @@ void CharacterController::update(float duration, bool animationOnly) else mAnimation->setUpperBodyYawRadians(stats.getSideMovementAngle() / 4); - speed = cls.getSpeed(mPtr); + speed = cls.getCurrentSpeed(mPtr); vec.x() *= speed; vec.y() *= speed; @@ -2077,7 +2065,7 @@ void CharacterController::update(float duration, bool animationOnly) } } fatigueLoss *= duration; - fatigueLoss *= analogueMult; + fatigueLoss *= movementSettings.mSpeedFactor; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); if (!godmode) @@ -2908,13 +2896,10 @@ void CharacterController::updateHeadTracking(float duration) zAngleRadians = std::atan2(direction.x(), direction.y()) - std::atan2(actorDirection.x(), actorDirection.y()); xAngleRadians = -std::asin(direction.z()); - wrap(zAngleRadians); - wrap(xAngleRadians); - - xAngleRadians = std::min(xAngleRadians, osg::DegreesToRadians(40.f)); - xAngleRadians = std::max(xAngleRadians, osg::DegreesToRadians(-40.f)); - zAngleRadians = std::min(zAngleRadians, osg::DegreesToRadians(30.f)); - zAngleRadians = std::max(zAngleRadians, osg::DegreesToRadians(-30.f)); + const double xLimit = osg::DegreesToRadians(40.0); + const double zLimit = osg::DegreesToRadians(30.0); + zAngleRadians = osg::clampBetween(Misc::normalizeAngle(zAngleRadians), -xLimit, xLimit); + xAngleRadians = osg::clampBetween(Misc::normalizeAngle(xAngleRadians), -zLimit, zLimit); } float factor = duration*5; diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index 86b970e60..57e106cde 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -8,8 +8,14 @@ namespace MWMechanics /// Desired movement for an actor struct Movement { + // Desired movement. Direction is relative to the current orientation. + // Length of the vector controls desired speed. 0 - stay, 0.5 - half-speed, 1.0 - max speed. float mPosition[3]; + // Desired rotation delta (euler angles). float mRotation[3]; + + // Controlled by CharacterController, should not be changed from other places. + // These fields can not be private fields in CharacterController, because Actor::getCurrentSpeed uses it. float mSpeedFactor; bool mIsStrafing; diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 715dfecd2..88325ee7c 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -122,7 +122,7 @@ namespace MWMechanics if (mWalkState != WalkState::Evade) { - const float distSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) * duration; + const float distSameSpot = DIST_SAME_SPOT * actor.getClass().getCurrentSpeed(actor) * duration; const float prevDistance = (destination - mPrev).length(); const float currentDistance = (destination - position).length(); const float movedDistance = prevDistance - currentDistance; diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index b08a90220..d442085ea 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -32,7 +32,7 @@ bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, f if (absDiff < epsilonRadians) return true; - float limit = getAngularVelocity(actor.getClass().getSpeed(actor)) * MWBase::Environment::get().getFrameDuration(); + float limit = getAngularVelocity(actor.getClass().getMaxSpeed(actor)) * MWBase::Environment::get().getFrameDuration(); if (absDiff > limit) diff = osg::sign(diff) * limit; diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 40cc9895d..0d6ed262b 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -200,7 +201,7 @@ namespace MWRender updateFocalPointOffset(duration); updatePosition(); - float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr); + float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr); speed /= (1.f + speed / 500.f); float maxDelta = 300.f * duration; mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta); @@ -249,7 +250,7 @@ namespace MWRender { if (!mStandingPreviewAllowed) return; - float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr); + float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr); bool combat = mTrackingPtr.getClass().isActor() && mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing; bool standingStill = speed == 0 && !combat && !mFirstPersonView; @@ -396,12 +397,7 @@ namespace MWRender void Camera::setYaw(float angle) { - if (angle > osg::PI) { - angle -= osg::PI*2; - } else if (angle < -osg::PI) { - angle += osg::PI*2; - } - mYaw = angle; + mYaw = Misc::normalizeAngle(angle); } void Camera::setPitch(float angle) @@ -538,16 +534,8 @@ namespace MWRender return; } - mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mPitch; - mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mYaw; - if (mDeferredRotation.x() > osg::PI) - mDeferredRotation.x() -= 2 * osg::PI; - if (mDeferredRotation.x() < -osg::PI) - mDeferredRotation.x() += 2 * osg::PI; - if (mDeferredRotation.z() > osg::PI) - mDeferredRotation.z() -= 2 * osg::PI; - if (mDeferredRotation.z() < -osg::PI) - mDeferredRotation.z() += 2 * osg::PI; + mDeferredRotation.x() = Misc::normalizeAngle(-ptr.getRefData().getPosition().rot[0] - mPitch); + mDeferredRotation.z() = Misc::normalizeAngle(-ptr.getRefData().getPosition().rot[2] - mYaw); } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index ad8766d06..950c8a6d4 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -159,7 +159,12 @@ namespace MWWorld return ""; } - float Class::getSpeed (const Ptr& ptr) const + float Class::getMaxSpeed (const Ptr& ptr) const + { + return 0; + } + + float Class::getCurrentSpeed (const Ptr& ptr) const { return 0; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e82712220..445f2e986 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -172,8 +172,15 @@ namespace MWWorld ///< Return name of the script attached to ptr (default implementation: return an empty /// string). - virtual float getSpeed (const Ptr& ptr) const; - ///< Return movement speed. + virtual float getWalkSpeed(const Ptr& ptr) const; + virtual float getRunSpeed(const Ptr& ptr) const; + virtual float getSwimSpeed(const Ptr& ptr) const; + + /// Return maximal movement speed for the current state. + virtual float getMaxSpeed(const Ptr& ptr) const; + + /// Return current movement speed. + virtual float getCurrentSpeed(const Ptr& ptr) const; virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) @@ -182,7 +189,7 @@ namespace MWWorld ///< Return desired movement. virtual osg::Vec3f getRotationVector (const Ptr& ptr) const; - ///< Return desired rotations, as euler angles. + ///< Return desired rotations, as euler angles. Sets getMovementSettings(ptr).mRotation to zero. virtual std::pair, bool> getEquipmentSlots (const ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object @@ -364,12 +371,6 @@ namespace MWWorld virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const; virtual void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const; - - virtual float getWalkSpeed(const Ptr& ptr) const; - - virtual float getRunSpeed(const Ptr& ptr) const; - - virtual float getSwimSpeed(const Ptr& ptr) const; }; } diff --git a/components/misc/mathutil.hpp b/components/misc/mathutil.hpp new file mode 100644 index 000000000..2f7f446b5 --- /dev/null +++ b/components/misc/mathutil.hpp @@ -0,0 +1,27 @@ +#ifndef MISC_MATHUTIL_H +#define MISC_MATHUTIL_H + +#include +#include + +namespace Misc +{ + + /// Normalizes given angle to the range [-PI, PI]. E.g. PI*3/2 -> -PI/2. + inline double normalizeAngle(double angle) + { + double fullTurns = angle / (2 * osg::PI) + 0.5; + return (fullTurns - floor(fullTurns) - 0.5) * (2 * osg::PI); + } + + /// Rotates given 2d vector counterclockwise. Angle is in radians. + inline osg::Vec2f rotateVec2f(osg::Vec2f vec, float angle) + { + float s = std::sin(angle); + float c = std::cos(angle); + return osg::Vec2f(vec.x() * c + vec.y() * -s, vec.x() * s + vec.y() * c); + } + +} + +#endif From 9189a42c4c317b3db4a40a7486f61e45abbdc93a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 29 Aug 2020 12:07:13 +0400 Subject: [PATCH 40/40] Fix failed assertion --- apps/openmw/mwinput/mousemanager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index a3f436bfe..ac30d4487 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -70,7 +70,6 @@ namespace MWInput mBindingsManager->mouseMoved(arg); MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); - MWBase::World* world = MWBase::Environment::get().getWorld(); input->setJoystickLastUsed(false); input->resetIdleTime(); @@ -94,6 +93,8 @@ namespace MWInput if (mMouseLookEnabled && !input->controlsDisabled()) { + MWBase::World* world = MWBase::Environment::get().getWorld(); + float x = arg.xrel * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f; float y = arg.yrel * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f; @@ -110,7 +111,7 @@ namespace MWInput player.pitch(y); } else if (!input->getControlSwitch("playerlooking")) - world->disableDeferredPreviewRotation(); + MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); } }