From 532b26bf3cda07fc73f23bdf39f07678f2024389 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Apr 2017 15:32:18 +0200 Subject: [PATCH 001/410] osgShadow experiment --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderingmanager.cpp | 43 +++++++++++++++++++++-- apps/openmw/mwrender/vismask.hpp | 4 ++- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b4e9ad4b4..7c8e8cd16e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,8 +206,8 @@ if(NOT HAVE_STDINT_H) message(FATAL_ERROR "stdint.h was not found" ) endif() +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX osgShadow) -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a066784888..6e4a7baab6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -126,6 +126,7 @@ target_link_libraries(openmw ${OSGDB_LIBRARIES} ${OSGVIEWER_LIBRARIES} ${OSGGA_LIBRARIES} + ${OSGSHADOW_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6ee9b8ae87..87c13f9814 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,6 +13,13 @@ #include #include +#include +#include +#include +#include +#include +#include + #include #include @@ -183,6 +190,7 @@ namespace MWRender , mFieldOfViewOverridden(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); + resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders")); resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); @@ -198,7 +206,35 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - mRootNode->addChild(sceneRoot); + osg::ref_ptr shadowedScene (new osgShadow::ShadowedScene); + + osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings(); + settings->setLightNum(0); + settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player); + settings->setReceivesShadowTraversalMask(~0u); + + settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); + settings->setBaseShadowTextureUnit(1); + settings->setMinimumShadowMapNearFarRatio(0); + settings->setNumShadowMapsPerLight(1); + //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); + //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored + //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + //settings->setDebugDraw(true); + + settings->setPerspectiveShadowMapCutOffAngle(0); + settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); + + int mapres = 2048; + settings->setTextureSize(osg::Vec2s(mapres,mapres)); + + osgShadow::ShadowTechnique* tech = new osgShadow::ViewDependentShadowMap; + shadowedScene->setShadowTechnique(tech); + + //mRootNode->addChild(sceneRoot); + shadowedScene->addChild(sceneRoot); + mRootNode->addChild(shadowedScene); + mPathgrid.reset(new Pathgrid(mRootNode)); @@ -228,7 +264,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - source->setNodeMask(Mask_Lighting); + //source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -272,7 +308,8 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); - mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); + //mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); + mViewer->getCamera()->setCullMask(~(Mask_Lighting)); mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index d52c7c232e..1f620b7f71 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -51,7 +51,9 @@ namespace MWRender Mask_PreCompile = (1<<16), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<17) + Mask_Lighting = (1<<17), + + Mask_CastsShadows = (1<<18) }; } From 76e8a0b768bc38c56f1711a1aa1051ac7c0a92ec Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Sep 2017 22:32:45 +0100 Subject: [PATCH 002/410] Add changes I missed in a merge. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0050104cf3..5f0c539a58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX osgShadow) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS From 99f6a1b8e15b86aa7860b3e3c2890533bb4b8bea Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 19 Sep 2017 23:44:37 +0100 Subject: [PATCH 003/410] Switch to LispSM --- apps/openmw/mwrender/renderingmanager.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 820fdab49b..1b78bef807 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -213,24 +213,31 @@ namespace MWRender settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player); settings->setReceivesShadowTraversalMask(~0u); - settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(1); - settings->setMinimumShadowMapNearFarRatio(0); - settings->setNumShadowMapsPerLight(1); + //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); + //settings->setBaseShadowTextureUnit(1); + //settings->setMinimumShadowMapNearFarRatio(0); + //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); //settings->setDebugDraw(true); - settings->setPerspectiveShadowMapCutOffAngle(0); - settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); + //settings->setPerspectiveShadowMapCutOffAngle(0); + //settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); int mapres = 2048; settings->setTextureSize(osg::Vec2s(mapres,mapres)); - osgShadow::ShadowTechnique* tech = new osgShadow::ViewDependentShadowMap; + osgShadow::MinimalShadowMap* tech = new osgShadow::LightSpacePerspectiveShadowMapDB(); shadowedScene->setShadowTechnique(tech); + tech->setMaxFarPlane(0); + tech->setTextureSize(osg::Vec2s(mapres, mapres)); + tech->setShadowTextureCoordIndex(1); + tech->setShadowTextureUnit(1); + tech->setBaseTextureCoordIndex(0); + tech->setBaseTextureUnit(0); + //mRootNode->addChild(sceneRoot); shadowedScene->addChild(sceneRoot); mRootNode->addChild(shadowedScene); From f50063402dea5ab8a2e1badd2e7566d1ca100cbf Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 21 Sep 2017 00:25:48 +0100 Subject: [PATCH 004/410] Adjust shaders to support shadows --- CI/before_script.msvc.sh | 2 +- files/shaders/lighting.glsl | 28 +++++++++++++++++++++------- files/shaders/objects_fragment.glsl | 13 ++++++++++--- files/shaders/objects_vertex.glsl | 6 ++++++ files/shaders/terrain_fragment.glsl | 13 ++++++++++--- files/shaders/terrain_vertex.glsl | 6 ++++++ 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 14998a3c61..11317a33fe 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -761,7 +761,7 @@ if [ -z $CI ]; then echo " settings-default.cfg" cp settings-default.cfg $BUILD_CONFIG/settings-default.cfg echo " resources/" - cp -r resources $BUILD_CONFIG/resources + cp -r resources $BUILD_CONFIG echo fi diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 7b8486fbec..892ae485ac 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,10 +1,23 @@ #define MAX_LIGHTS 8 -vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) +vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; float d; + lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); + d = length(lightDir); + lightDir = normalize(lightDir); + + return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0); +} + +#ifdef FRAGMENT +vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) +#else +vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) +#endif +{ #if @colorMode == 3 vec4 diffuse = gl_FrontMaterial.diffuse; vec3 ambient = vertexColor.xyz; @@ -17,13 +30,14 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) #endif vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); - for (int i=0; i Date: Thu, 21 Sep 2017 00:49:34 +0100 Subject: [PATCH 005/410] Stop shadowing ambient lighting from the light casting a shadow when using per-pixel lighting. --- files/shaders/lighting.glsl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 892ae485ac..e50e2f9c23 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,6 +1,6 @@ #define MAX_LIGHTS 8 -vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) +vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient, float shadowing) { vec3 lightDir; float d; @@ -9,7 +9,7 @@ vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 d = length(lightDir); lightDir = normalize(lightDir); - return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0); + return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0) * shadowing; } #ifdef FRAGMENT @@ -31,13 +31,13 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); #ifdef FRAGMENT - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient) * shadowing; + lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, shadowing); #else - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient); + lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, 1.0); #endif for (int i=1; i Date: Thu, 21 Sep 2017 01:59:02 +0100 Subject: [PATCH 006/410] Make shadows play nicely with per-vertex lighting --- files/shaders/lighting.glsl | 34 +++++++++++++++++++++-------- files/shaders/objects_fragment.glsl | 3 ++- files/shaders/objects_vertex.glsl | 3 ++- files/shaders/terrain_fragment.glsl | 3 ++- files/shaders/terrain_vertex.glsl | 3 ++- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index e50e2f9c23..fe298e1600 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,21 +1,33 @@ #define MAX_LIGHTS 8 -vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient, float shadowing) +vec3 lightAmbient(int lightIndex, vec3 ambient) +{ + return ambient * gl_LightSource[lightIndex].ambient.xyz; +} + +vec3 lightDiffuse(int lightIndex, vec4 diffuse, vec3 viewNormal, vec3 lightDir) +{ + return diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0); +} + +void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; - float d; + float lightDistance; - lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); - d = length(lightDir); + lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); + lightDistance = length(lightDir); lightDir = normalize(lightDir); + float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); - return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0) * shadowing; + ambientOut = lightAmbient(lightIndex, ambient) * illumination; + diffuseOut = lightDiffuse(lightIndex, diffuse, viewNormal, lightDir) * illumination; } #ifdef FRAGMENT vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) #else -vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) +vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) #endif { #if @colorMode == 3 @@ -30,14 +42,18 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) #endif vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); + vec3 diffuseLight, ambientLight; + perLight(ambientLight, diffuseLight, 0, viewPos, viewNormal, diffuse, ambient); #ifdef FRAGMENT - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, shadowing); + lightResult.xyz += ambientLight + diffuseLight * shadowing; #else - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, 1.0); + shadowDiffuse = diffuseLight; + lightResult.xyz += ambientLight; #endif for (int i=1; i Date: Thu, 21 Sep 2017 02:03:53 +0100 Subject: [PATCH 007/410] Tidy up the mess I made of lighting.glsl a bit by removing two single-line functions that are only ever called in one location. --- files/shaders/lighting.glsl | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index fe298e1600..afa636e3c3 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,15 +1,5 @@ #define MAX_LIGHTS 8 -vec3 lightAmbient(int lightIndex, vec3 ambient) -{ - return ambient * gl_LightSource[lightIndex].ambient.xyz; -} - -vec3 lightDiffuse(int lightIndex, vec4 diffuse, vec3 viewNormal, vec3 lightDir) -{ - return diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0); -} - void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; @@ -20,8 +10,8 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie lightDir = normalize(lightDir); float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); - ambientOut = lightAmbient(lightIndex, ambient) * illumination; - diffuseOut = lightDiffuse(lightIndex, diffuse, viewNormal, lightDir) * illumination; + ambientOut = ambient * gl_LightSource[lightIndex].ambient.xyz * illumination; + diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; } #ifdef FRAGMENT From ebd3dcf2b34e7626550bd608830fa831b78e5e14 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 3 Oct 2017 02:58:25 +0100 Subject: [PATCH 008/410] Remove unnecessary preprocessor variable in shaders --- files/shaders/lighting.glsl | 2 +- files/shaders/objects_fragment.glsl | 2 -- files/shaders/terrain_fragment.glsl | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index afa636e3c3..8678d18dd9 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -14,7 +14,7 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; } -#ifdef FRAGMENT +#ifdef PER_PIXEL_LIGHTING vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) #else vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index f90e5f8bab..b3bfa600b5 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define FRAGMENT - #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 2e61caeb0f..9da9dfad5d 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define FRAGMENT - varying vec2 uv; uniform sampler2D diffuseMap; From 0568c93b39d2b08713caa327021938994213a016 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 3 Oct 2017 03:40:23 +0100 Subject: [PATCH 009/410] Add specific shadow source files to MWRender --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++----- apps/openmw/mwrender/shadow.cpp | 11 +++++++++ apps/openmw/mwrender/shadow.hpp | 27 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 apps/openmw/mwrender/shadow.cpp create mode 100644 apps/openmw/mwrender/shadow.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 47a30f9a01..97744d4dd0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,6 +24,7 @@ add_openmw_dir (mwrender creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation renderbin actoranimation landmanager + shadow ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 04c3355cab..e670eaebc0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -14,11 +14,6 @@ #include #include -#include -#include -#include -#include -#include #include #include @@ -57,6 +52,7 @@ #include "water.hpp" #include "terrainstorage.hpp" #include "util.hpp" +#include "shadow.hpp" namespace MWRender { @@ -228,7 +224,7 @@ namespace MWRender int mapres = 2048; settings->setTextureSize(osg::Vec2s(mapres,mapres)); - osgShadow::MinimalShadowMap* tech = new osgShadow::LightSpacePerspectiveShadowMapDB(); + MWShadow* tech = new MWShadow(); shadowedScene->setShadowTechnique(tech); tech->setMaxFarPlane(0); diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp new file mode 100644 index 0000000000..17cc5156bb --- /dev/null +++ b/apps/openmw/mwrender/shadow.cpp @@ -0,0 +1,11 @@ +#include "shadow.hpp" + +namespace MWRender +{ + void MWShadow::ViewData::init(MWShadow * st, osgUtil::CullVisitor * cv) + { + LightSpacePerspectiveShadowMapDB::ViewData::init(st, cv); + osg::StateSet * stateset = _camera->getOrCreateStateSet(); + stateset->removeAttribute(osg::StateAttribute::CULLFACE); + } +} diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp new file mode 100644 index 0000000000..51338c5bf8 --- /dev/null +++ b/apps/openmw/mwrender/shadow.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_MWRENDER_SHADOW_H +#define OPENMW_MWRENDER_SHADOW_H + +#include + +namespace MWRender +{ + class MWShadow : public osgShadow::LightSpacePerspectiveShadowMapDB + { + protected: + struct ViewData : public LightSpacePerspectiveShadowMapDB::ViewData + { + virtual void init(MWShadow * st, osgUtil::CullVisitor * cv); + }; + + virtual ViewDependentShadowTechnique::ViewData * initViewDependentData(osgUtil::CullVisitor *cv, ViewDependentShadowTechnique::ViewData * vd) + { + MWShadow::ViewData* td = dynamic_cast(vd); + if (!td) + td = new MWShadow::ViewData; + td->init(this, cv); + return td; + } + }; +} + +#endif //OPENMW_MWRENDER_SHADOW_H From 2b78fb436d3f5c47c961c9a46780464219cf7f6b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 8 Oct 2017 00:44:35 +0100 Subject: [PATCH 010/410] Fix issue with shader preprocessor variables --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 8678d18dd9..5d59754ec6 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -14,7 +14,7 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; } -#ifdef PER_PIXEL_LIGHTING +#if PER_PIXEL_LIGHTING vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) #else vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) From e0ce28427213177c87b092646592ffc32dbef578 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 8 Oct 2017 01:34:54 +0100 Subject: [PATCH 011/410] Fix the same shader preprocessor variable issue for the third time now --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 5d59754ec6..09b78b5962 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -34,7 +34,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow vec3 diffuseLight, ambientLight; perLight(ambientLight, diffuseLight, 0, viewPos, viewNormal, diffuse, ambient); -#ifdef FRAGMENT +#if PER_PIXEL_LIGHTING lightResult.xyz += ambientLight + diffuseLight * shadowing; #else shadowDiffuse = diffuseLight; From c2cd3380862bb3819e288c94d0e1ae6ca96762a9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 13 Oct 2017 18:05:25 +0100 Subject: [PATCH 012/410] Add shadow DLL under Windows automatically --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 11317a33fe..8c73bf78d8 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -557,7 +557,7 @@ printf "OSG 3.4.0-scrawl... " "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll echo Done. } From 20607bdcd98f7fff60a93084a6d90ab83c884595 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 13 Oct 2017 18:17:49 +0100 Subject: [PATCH 013/410] Actually add shadow DLL under Windows automatically for real this time --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 8c73bf78d8..3895a0a96d 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -554,7 +554,7 @@ printf "OSG 3.4.0-scrawl... " fi add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ - "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll + "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer,Shadow}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll From 26a7b48d692c27baf353bd748fb6db40348184cb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 20:47:19 +0100 Subject: [PATCH 014/410] Attempt to make a VDSM work, and also to set up a debug HUD, but without success. --- apps/openmw/mwrender/renderingmanager.cpp | 6 +- apps/openmw/mwrender/shadow.cpp | 698 +++++++++++++++++++++- apps/openmw/mwrender/shadow.hpp | 28 +- files/shaders/objects_fragment.glsl | 4 +- files/shaders/terrain_fragment.glsl | 4 +- 5 files changed, 714 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e670eaebc0..172ff34a85 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,7 +210,7 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - //settings->setBaseShadowTextureUnit(1); + settings->setBaseShadowTextureUnit(1); //settings->setMinimumShadowMapNearFarRatio(0); //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); @@ -227,12 +227,12 @@ namespace MWRender MWShadow* tech = new MWShadow(); shadowedScene->setShadowTechnique(tech); - tech->setMaxFarPlane(0); + /*tech->setMaxFarPlane(0); tech->setTextureSize(osg::Vec2s(mapres, mapres)); tech->setShadowTextureCoordIndex(1); tech->setShadowTextureUnit(1); tech->setBaseTextureCoordIndex(0); - tech->setBaseTextureUnit(0); + tech->setBaseTextureUnit(0);*/ //mRootNode->addChild(sceneRoot); shadowedScene->addChild(sceneRoot); diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 17cc5156bb..c58334a51a 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -1,11 +1,701 @@ #include "shadow.hpp" +#include +#include +#include +#include +#include +#include + namespace MWRender { - void MWShadow::ViewData::init(MWShadow * st, osgUtil::CullVisitor * cv) + using namespace osgShadow; + + std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; + std::string debugFragmentShaderSource = + "uniform sampler2D texture; \n" + " \n" + "void main(void) \n" + "{ \n" +#if 0 + " float f = texture2D( texture, gl_TexCoord[0] ).r; \n" + " \n" + " f = 256.0 * f; \n" + " float fC = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fS = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fH = floor( f ) / 256.0; \n" + " \n" + " fS *= 0.5; \n" + " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" + " \n" + " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" + " abs( fC - 0.333333 ), \n" + " abs( fC - 0.666667 ) ); \n" + " \n" + " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" + " \n" + " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" + " fMax = 1.0 / fMax; \n" + " \n" + " vec3 color = fMax * rgb; \n" + " \n" + " gl_FragColor = vec4( fS + fH * color, 1 ); \n" +#else + " gl_FragColor = texture2D(texture, gl_TexCoord[0]); \n" + " //gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0); \n" +#endif + "} \n"; + + + MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), testTex(new osg::Texture2D) { - LightSpacePerspectiveShadowMapDB::ViewData::init(st, cv); - osg::StateSet * stateset = _camera->getOrCreateStateSet(); - stateset->removeAttribute(osg::StateAttribute::CULLFACE); + debugCamera->setViewport(0, 0, 200, 200); + debugCamera->setRenderOrder(osg::Camera::POST_RENDER); + debugCamera->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); + debugProgram->addShader(vertexShader); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); + debugProgram->addShader(fragmentShader); + + debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0));- + debugCamera->addChild(debugGeometry); + osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); + stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", 0); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + + testTex->setDataVariance(osg::Object::DYNAMIC); + osg::ref_ptr testImage = osgDB::readRefImageFile("path/to/an/image/file.png"); + testTex->setImage(testImage); + } + + class VDSMCameraCullCallback : public osg::NodeCallback + { + public: + + VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); + + virtual void operator()(osg::Node*, osg::NodeVisitor* nv); + + osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); } + osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); } + + protected: + + ViewDependentShadowMap* _vdsm; + osg::ref_ptr _projectionMatrix; + osg::ref_ptr _renderStage; + osg::Polytope _polytope; + }; + + VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope) : + _vdsm(vdsm), + _polytope(polytope) + { + } + + void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = dynamic_cast(nv); + osg::Camera* camera = dynamic_cast(node); + OSG_INFO << "VDSMCameraCullCallback::operator()(osg::Node* " << camera << ", osg::NodeVisitor* " << cv << ")" << std::endl; + +#if 1 + if (!_polytope.empty()) + { + OSG_INFO << "Pushing custom Polytope" << std::endl; + + osg::CullingSet& cs = cv->getProjectionCullingStack().back(); + + cs.setFrustum(_polytope); + + cv->pushCullingSet(); + } +#endif + if (_vdsm->getShadowedScene()) + { + _vdsm->getShadowedScene()->osg::Group::traverse(*nv); + } +#if 1 + if (!_polytope.empty()) + { + OSG_INFO << "Popping custom Polytope" << std::endl; + cv->popCullingSet(); + } +#endif + + _renderStage = cv->getCurrentRenderBin()->getStage(); + + OSG_INFO << "VDSM second : _renderStage = " << _renderStage << std::endl; + + if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + // make sure that the near plane is computed correctly. + cv->computeNearPlane(); + + osg::Matrixd projection = *(cv->getProjectionMatrix()); + + OSG_INFO << "RTT Projection matrix " << projection << std::endl; + + osg::Matrix::value_type left, right, bottom, top, zNear, zFar; + osg::Matrix::value_type epsilon = 1e-6; + if (fabs(projection(0, 3))setProjectionMatrix(projection); + + _projectionMatrix = cv->getProjectionMatrix(); + } + } + + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + { + public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + { + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + } + + void apply(osg::Node& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Geode& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + for (unsigned int i = 0; igetBoundingBox()); + } + } + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Billboard&) + { + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; + } + + void apply(osg::Projection&) + { + // projection nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void apply(osg::Transform& transform) + { + if (isCulled(transform)) return; + + // push the culling mode. + pushCurrentMask(); + + // absolute transforms won't affect a shadow map so their subgraphs should be ignored. + if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) + { + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); + + traverse(transform); + + popModelViewMatrix(); + } + + // pop the culling mode. + popCurrentMask(); + + } + + void apply(osg::Camera&) + { + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void updateBound(const osg::BoundingBox& bb) + { + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); + } + + void update(const osg::Vec3& v) + { + if (v.z()<-1.0f) + { + //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; + float y = v.y(); + if (y<-1.0f) y = -1.0f; + if (y>1.0f) y = 1.0f; + _bb.expandBy(osg::Vec3(x, y, v.z())); + } + + osg::BoundingBox _bb; + }; + + void MWShadow::cull(osgUtil::CullVisitor& cv) + { + OSG_INFO << std::endl << std::endl << "ViewDependentShadowMap::cull(osg::CullVisitor&" << &cv << ")" << std::endl; + + if (!_shadowCastingStateSet) + { + OSG_INFO << "Warning, init() has not yet been called so ShadowCastingStateSet has not been setup yet, unable to create shadows." << std::endl; + _shadowedScene->osg::Group::traverse(cv); + return; + } + + ViewDependentData* vdd = getViewDependentData(&cv); + + if (!vdd) + { + OSG_INFO << "Warning, now ViewDependentData created, unable to create shadows." << std::endl; + _shadowedScene->osg::Group::traverse(cv); + return; + } + + ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + OSG_INFO << "cv->getProjectionMatrix()=" << *cv.getProjectionMatrix() << std::endl; + + osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode(); + + osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix(); + + // check whether this main views projection is perspective or orthographic + bool orthographicViewFrustum = viewProjectionMatrix(0, 3) == 0.0 && + viewProjectionMatrix(1, 3) == 0.0 && + viewProjectionMatrix(2, 3) == 0.0; + + double minZNear = 0.0; + double maxZFar = DBL_MAX; + + if (cachedNearFarMode == osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + double left, right, top, bottom; + if (orthographicViewFrustum) + { + viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar); + } + else + { + viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar); + } + OSG_INFO << "minZNear=" << minZNear << ", maxZFar=" << maxZFar << std::endl; + } + + // set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible + if (settings->getComputeNearFarModeOverride() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride()); + } + + // 1. Traverse main scene graph + cv.pushStateSet(_shadowRecievingPlaceholderStateSet.get()); + + osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); + + cullShadowReceivingScene(&cv); + + cv.popStateSet(); + + if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + OSG_INFO << "Just done main subgraph traversak" << std::endl; + // make sure that the near plane is computed correctly so that any projection matrix computations + // are all done correctly. + cv.computeNearPlane(); + } + + // clamp the minZNear and maxZFar to those provided by ShadowSettings + maxZFar = osg::minimum(settings->getMaximumShadowMapDistance(), maxZFar); + if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); + + //OSG_NOTICE<<"maxZFar "<getLightDataList(); + for (LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = **itr; + + // 3.1 compute light space polytope + // + osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); + + // if polytope is empty then no rendering. + if (polytope.empty()) + { + OSG_NOTICE << "Polytope empty no shadow to render" << std::endl; + continue; + } + + // 3.2 compute RTT camera view+projection matrix settings + // + osg::Matrixd projectionMatrix; + osg::Matrixd viewMatrix; + if (!computeShadowCameraSettings(frustum, pl, projectionMatrix, viewMatrix)) + { + OSG_NOTICE << "No valid Camera settings, no shadow to render" << std::endl; + continue; + } + + // if we are using multiple shadow maps and CastShadowTraversalMask is being used + // traverse the scene to compute the extents of the objects + if (/*numShadowMapsPerLight>1 &&*/ _shadowedScene->getCastsShadowTraversalMask() != 0xffffffff) + { + // osg::ElapsedTime timer; + + osg::ref_ptr viewport = new osg::Viewport(0, 0, 2048, 2048); + ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); + clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); + + osg::Matrixd invertModelView; + invertModelView.invert(viewMatrix); + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); + cs.setFrustum(local_polytope); + clsb.pushCullingSet(); + + _shadowedScene->accept(clsb); + + // OSG_NOTICE<<"Extents of LightSpace "< texture = sd->_texture; + osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); + if (false) + stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + else + stateSet->setTextureAttributeAndModes(0, testTex, osg::StateAttribute::ON); + + unsigned int traversalMask = cv.getTraversalMask(); + cv.setTraversalMask(debugGeometry->getNodeMask()); + cv.pushStateSet(stateSet); + debugCamera->accept(cv); + cv.popStateSet(); + cv.setTraversalMask(traversalMask); + + cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); + } + + osg::ref_ptr camera = sd->_camera; + + camera->setProjectionMatrix(projectionMatrix); + camera->setViewMatrix(viewMatrix); + + if (settings->getDebugDraw()) + { + camera->getViewport()->x() = pos_x; + pos_x += static_cast(camera->getViewport()->width()) + 40; + } + + // transform polytope in model coords into light spaces eye coords. + osg::Matrixd invertModelView; + invertModelView.invert(camera->getViewMatrix()); + + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + + if (numShadowMapsPerLight>1) + { + // compute the start and end range in non-dimensional coords +#if 0 + double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); + double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); +#endif + + // hardwired for 2 splits + double r_start = (sm_i == 0) ? -1.0 : splitPoint; + double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; + + // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap + // to prevent a seam showing through between the shadowmaps + if (sm_i + 10) + { + // not the first shadowmap so insert a polytope to clip the scene from before r_start + + // plane in clip space coords + osg::Plane plane(0.0, 1.0, 0.0, -r_start); + + // transform into eye coords + plane.transformProvidingInverse(projectionMatrix); + local_polytope.getPlaneList().push_back(plane); + + //OSG_NOTICE<<"Adding r_start plane "<0) + { + decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); + } + + // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< +#include namespace MWRender { - class MWShadow : public osgShadow::LightSpacePerspectiveShadowMapDB + class MWShadow : public osgShadow::ViewDependentShadowMap { - protected: - struct ViewData : public LightSpacePerspectiveShadowMapDB::ViewData - { - virtual void init(MWShadow * st, osgUtil::CullVisitor * cv); - }; + public: + MWShadow(); - virtual ViewDependentShadowTechnique::ViewData * initViewDependentData(osgUtil::CullVisitor *cv, ViewDependentShadowTechnique::ViewData * vd) - { - MWShadow::ViewData* td = dynamic_cast(vd); - if (!td) - td = new MWShadow::ViewData; - td->init(this, cv); - return td; - } + virtual void cull(osgUtil::CullVisitor& cv); + protected: + osg::ref_ptr debugCamera; + + osg::ref_ptr debugProgram; + + osg::ref_ptr debugGeometry; + + osg::ref_ptr testTex; }; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index b3bfa600b5..4dd282dc43 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -55,7 +55,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture; +uniform sampler2DShadow shadowTexture0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -116,7 +116,7 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = shadow2DProj(shadowTexture, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 9da9dfad5d..e27dd384ea 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -25,7 +25,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture; +uniform sampler2DShadow shadowTexture0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -68,7 +68,7 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = shadow2DProj(shadowTexture, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); From be50ed738728d6e884013be19f35039cf9036e29 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 13 Oct 2017 18:27:32 +0100 Subject: [PATCH 015/410] Use a test image guaranteed to exist. --- apps/openmw/mwrender/shadow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index c58334a51a..65ce8d5bde 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -71,7 +71,7 @@ namespace MWRender stateSet->addUniform(textureUniform.get()); testTex->setDataVariance(osg::Object::DYNAMIC); - osg::ref_ptr testImage = osgDB::readRefImageFile("path/to/an/image/file.png"); + osg::ref_ptr testImage = osgDB::readRefImageFile("resources/mygui/openmw.png"); testTex->setImage(testImage); } From 737563875ab4929c902327310e04ad77b9e056f0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 14 Oct 2017 01:13:45 +0100 Subject: [PATCH 016/410] Remove superfluous - sign and switch to other debug shader --- apps/openmw/mwrender/shadow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 65ce8d5bde..2f57f6e066 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -17,7 +17,7 @@ namespace MWRender " \n" "void main(void) \n" "{ \n" -#if 0 +#if 1 " float f = texture2D( texture, gl_TexCoord[0] ).r; \n" " \n" " f = 256.0 * f; \n" @@ -62,7 +62,7 @@ namespace MWRender osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); debugProgram->addShader(fragmentShader); - debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0));- + debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0)); debugCamera->addChild(debugGeometry); osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); From cf54b4a13044a397098ae0382b29589870f07bad Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 26 Oct 2017 20:38:36 +0100 Subject: [PATCH 017/410] Prevent debug HUD geometry from being culled erroneously. --- apps/openmw/mwrender/shadow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 2f57f6e066..b8600e2116 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -63,6 +63,7 @@ namespace MWRender debugProgram->addShader(fragmentShader); debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0)); + debugGeometry->setCullingActive(false); debugCamera->addChild(debugGeometry); osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); From ab669a434efb3f9c42667f60bcdac68ccb151a49 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 30 Oct 2017 19:54:54 +0000 Subject: [PATCH 018/410] Update the shadow frustrum bounds properly --- apps/openmw/mwrender/shadow.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index b8600e2116..089a4da3d3 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -227,6 +227,19 @@ namespace MWRender popCurrentMask(); } + void apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); + } + void apply(osg::Billboard&) { OSG_INFO << "Warning Billboards not yet supported" << std::endl; @@ -547,7 +560,7 @@ namespace MWRender { osg::ref_ptr texture = sd->_texture; osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); - if (false) + if (true) stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); else stateSet->setTextureAttributeAndModes(0, testTex, osg::StateAttribute::ON); From e15d4619210478e8331472cfa784923476d200be Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 30 Oct 2017 20:06:52 +0000 Subject: [PATCH 019/410] Add (potentially physically-flawed) shadow support to the water shader --- files/shaders/water_fragment.glsl | 5 ++++- files/shaders/water_vertex.glsl | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 931422d5e6..f04a9d8a87 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -142,6 +142,9 @@ uniform vec3 nodePosition; uniform float rainIntensity; +uniform sampler2DShadow shadowTexture0; +varying vec4 shadowSpaceCoords; + float frustumDepth; float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value @@ -158,7 +161,7 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - float shadow = 1.0; + float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 7d7b7b18aa..513edc730c 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,6 +4,8 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +varying vec4 shadowSpaceCoords; + void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; @@ -19,4 +21,8 @@ void main(void) position = gl_Vertex; depthPassthrough = gl_Position.z; + + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + shadowSpaceCoords = (gl_ModelViewMatrix * gl_Vertex) * eyePlaneMat; } From d0866d1b3ce7604a7b6590dbc3d198430d867bfa Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 31 Oct 2017 20:21:54 +0100 Subject: [PATCH 020/410] Revert change to node mask that appears to not serve any purpose --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e871e1cfcf..3c4c1101ff 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -268,7 +268,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - //source->setNodeMask(Mask_Lighting); + source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -315,8 +315,7 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); - //mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); - mViewer->getCamera()->setCullMask(~(Mask_Lighting)); + mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); From 8141ee47d59a9c951851586b3e6d73d56d3e6359 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 31 Oct 2017 20:22:14 +0100 Subject: [PATCH 021/410] Fix shader compile error --- apps/openmw/mwrender/shadow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 089a4da3d3..915979bac3 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -18,7 +18,7 @@ namespace MWRender "void main(void) \n" "{ \n" #if 1 - " float f = texture2D( texture, gl_TexCoord[0] ).r; \n" + " float f = texture2D( texture, gl_TexCoord[0].xy ).r; \n" " \n" " f = 256.0 * f; \n" " float fC = floor( f ) / 256.0; \n" @@ -45,7 +45,7 @@ namespace MWRender " \n" " gl_FragColor = vec4( fS + fH * color, 1 ); \n" #else - " gl_FragColor = texture2D(texture, gl_TexCoord[0]); \n" + " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" " //gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0); \n" #endif "} \n"; From ceaf0ee4092982075ea035238e46fc8d573bc64a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 31 Oct 2017 21:21:05 +0100 Subject: [PATCH 022/410] Enable shadow casting for terrain Add a check to TerrainDrawable to make sure shadows are only drawn once, not once per blending pass --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/terrain/terraindrawable.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3c4c1101ff..cdf4ed16a4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -206,7 +206,7 @@ namespace MWRender osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings(); settings->setLightNum(0); - settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player); + settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player|Mask_Terrain); settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); diff --git a/components/terrain/terraindrawable.cpp b/components/terrain/terraindrawable.cpp index f3080e31cd..60d5917070 100644 --- a/components/terrain/terraindrawable.cpp +++ b/components/terrain/terraindrawable.cpp @@ -51,6 +51,12 @@ void TerrainDrawable::cull(osgUtil::CullVisitor *cv) if (osg::isNaN(depth)) return; + if (cv->getCurrentCamera()->getName() == "ShadowCamera") + { + cv->addDrawableAndDepth(this, &matrix, depth); + return; + } + bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv); for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it) From ce0e937e8d2c654ad3280604024d619e443785a1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 1 Nov 2017 18:22:59 +0000 Subject: [PATCH 023/410] Attempt to force the sky to not accept the default shadow shader or shadow texture. --- apps/openmw/mwrender/sky.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6c599fc3fa..4256f6987b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1122,7 +1122,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana skyroot->setName("Sky Root"); // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need - skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE); + skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); + skyroot->getOrCreateStateSet()->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); From d0587a3ad5c922d97cea5544c710181d662802c8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 3 Nov 2017 14:33:06 +0000 Subject: [PATCH 024/410] Clean up the debug hud now it's working. --- apps/openmw/mwrender/shadow.cpp | 13 +++---------- apps/openmw/mwrender/shadow.hpp | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 915979bac3..347952b4cb 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -51,7 +51,7 @@ namespace MWRender "} \n"; - MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), testTex(new osg::Texture2D) + MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), debugTextureUnit(0) { debugCamera->setViewport(0, 0, 200, 200); debugCamera->setRenderOrder(osg::Camera::POST_RENDER); @@ -67,13 +67,9 @@ namespace MWRender debugCamera->addChild(debugGeometry); osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", 0); + osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); //textureUniform->setType(osg::Uniform::SAMPLER_2D); stateSet->addUniform(textureUniform.get()); - - testTex->setDataVariance(osg::Object::DYNAMIC); - osg::ref_ptr testImage = osgDB::readRefImageFile("resources/mygui/openmw.png"); - testTex->setImage(testImage); } class VDSMCameraCullCallback : public osg::NodeCallback @@ -560,10 +556,7 @@ namespace MWRender { osg::ref_ptr texture = sd->_texture; osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); - if (true) - stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - else - stateSet->setTextureAttributeAndModes(0, testTex, osg::StateAttribute::ON); + stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); unsigned int traversalMask = cv.getTraversalMask(); cv.setTraversalMask(debugGeometry->getNodeMask()); diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index 4a4e8b8a5b..a941f9c2e6 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -12,13 +12,13 @@ namespace MWRender virtual void cull(osgUtil::CullVisitor& cv); protected: + const int debugTextureUnit; + osg::ref_ptr debugCamera; osg::ref_ptr debugProgram; osg::ref_ptr debugGeometry; - - osg::ref_ptr testTex; }; } From 3f63ebce77c3c300d725b0954a4e137147365c2b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 5 Nov 2017 14:37:36 +0000 Subject: [PATCH 025/410] Theoretically, at least, fix everything (except hte sky issue which is resolved in another branch) --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- files/shaders/objects_vertex.glsl | 3 ++- files/shaders/terrain_vertex.glsl | 3 ++- files/shaders/water_vertex.glsl | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cdf4ed16a4..aa5240618a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,7 +210,7 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(1); + settings->setBaseShadowTextureUnit(7); //settings->setMinimumShadowMapNearFarRatio(0); //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 42949dccbb..4046386dd6 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -46,6 +46,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; +uniform int shadowTextureUnit0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -104,6 +105,6 @@ void main(void) passNormal = gl_Normal.xyz; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); shadowSpaceCoords = viewPos * eyePlaneMat; } diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 89a2307a1e..17a9c436ea 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -14,6 +14,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; +uniform int shadowTextureUnit0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -38,6 +39,6 @@ void main(void) uv = gl_MultiTexCoord0.xy; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); shadowSpaceCoords = viewPos * eyePlaneMat; } diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 513edc730c..6aaa0537c9 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,6 +4,7 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +uniform int shadowTextureUnit0; varying vec4 shadowSpaceCoords; void main(void) @@ -23,6 +24,6 @@ void main(void) depthPassthrough = gl_Position.z; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); shadowSpaceCoords = (gl_ModelViewMatrix * gl_Vertex) * eyePlaneMat; } From 7a03ad65584451a63b5db47885d4265bebd6ae89 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 5 Nov 2017 14:46:03 +0000 Subject: [PATCH 026/410] Switch to a tidier way of disabling the correct texture unit --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/shadow.hpp | 2 ++ apps/openmw/mwrender/sky.cpp | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa5240618a..bdabdaeabb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,7 +210,7 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(7); + settings->setBaseShadowTextureUnit(MWShadow::baseShadowTextureUnit); //settings->setMinimumShadowMapNearFarRatio(0); //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index a941f9c2e6..4e1725c7fe 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -10,6 +10,8 @@ namespace MWRender public: MWShadow(); + const static int baseShadowTextureUnit = 7; + virtual void cull(osgUtil::CullVisitor& cv); protected: const int debugTextureUnit; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4256f6987b..9f4542ae9c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -48,6 +48,7 @@ #include "vismask.hpp" #include "renderbin.hpp" +#include "shadow.hpp" namespace { @@ -1123,7 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - skyroot->getOrCreateStateSet()->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); + skyroot->getOrCreateStateSet()->setTextureMode(MWShadow::baseShadowTextureUnit, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); From 56fa33af66183d79275cea742b0e6dcf743981ae Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 00:32:04 +0000 Subject: [PATCH 027/410] Enable parallel split shadow maps --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++-- apps/openmw/mwrender/shadow.cpp | 40 +++++++++++++---------- apps/openmw/mwrender/shadow.hpp | 7 ++-- files/shaders/objects_fragment.glsl | 7 ++-- files/shaders/objects_vertex.glsl | 8 +++-- files/shaders/terrain_fragment.glsl | 7 ++-- files/shaders/terrain_vertex.glsl | 8 +++-- files/shaders/water_fragment.glsl | 7 ++-- files/shaders/water_vertex.glsl | 9 +++-- 9 files changed, 65 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa5240618a..645c106679 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,13 +210,13 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(7); + settings->setBaseShadowTextureUnit(8 - MWShadow::numberOfShadowMapsPerLight); //settings->setMinimumShadowMapNearFarRatio(0); - //settings->setNumShadowMapsPerLight(1); + settings->setNumShadowMapsPerLight(MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); - //settings->setDebugDraw(true); + //settings->setDebugDraw(true); // don't turn this on because it makes everything break //settings->setPerspectiveShadowMapCutOffAngle(0); //settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 347952b4cb..40b2ff311b 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -51,25 +51,31 @@ namespace MWRender "} \n"; - MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), debugTextureUnit(0) + MWShadow::MWShadow() : debugProgram(new osg::Program), debugTextureUnit(0) { - debugCamera->setViewport(0, 0, 200, 200); - debugCamera->setRenderOrder(osg::Camera::POST_RENDER); - debugCamera->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); debugProgram->addShader(vertexShader); osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); debugProgram->addShader(fragmentShader); - debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0)); - debugGeometry->setCullingActive(false); - debugCamera->addChild(debugGeometry); - osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); - stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + { + std::cout << i << std::endl; + + debugCameras.push_back(new osg::Camera); + debugCameras[i]->setViewport(200 * i, 0, 200, 200); + debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); + debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + debugGeometry[i]->setCullingActive(false); + debugCameras[i]->addChild(debugGeometry[i]); + osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + } } class VDSMCameraCullCallback : public osg::NodeCallback @@ -552,16 +558,16 @@ namespace MWRender previous_sdl.erase(previous_sdl.begin()); } - if (true) + if (debugHud) { osg::ref_ptr texture = sd->_texture; - osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); + osg::ref_ptr stateSet = debugGeometry[sm_i]->getOrCreateStateSet(); stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); unsigned int traversalMask = cv.getTraversalMask(); - cv.setTraversalMask(debugGeometry->getNodeMask()); + cv.setTraversalMask(debugGeometry[sm_i]->getNodeMask()); cv.pushStateSet(stateSet); - debugCamera->accept(cv); + debugCameras[sm_i]->accept(cv); cv.popStateSet(); cv.setTraversalMask(traversalMask); diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index a941f9c2e6..e7663c55ac 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -8,17 +8,20 @@ namespace MWRender class MWShadow : public osgShadow::ViewDependentShadowMap { public: + static const int numberOfShadowMapsPerLight = 2; + static const bool debugHud = true; + MWShadow(); virtual void cull(osgUtil::CullVisitor& cv); protected: const int debugTextureUnit; - osg::ref_ptr debugCamera; + std::vector> debugCameras; osg::ref_ptr debugProgram; - osg::ref_ptr debugGeometry; + std::vector> debugGeometry; }; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 4dd282dc43..f6355aaa69 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -56,7 +56,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform sampler2DShadow shadowTexture0; -varying vec4 shadowSpaceCoords; +uniform sampler2DShadow shadowTexture1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" #include "parallax.glsl" @@ -116,7 +118,8 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; + shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 4046386dd6..b90a8722b8 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -47,7 +47,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform int shadowTextureUnit0; -varying vec4 shadowSpaceCoords; +uniform int shadowTextureUnit1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" @@ -106,5 +108,7 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords = viewPos * eyePlaneMat; + shadowSpaceCoords0 = viewPos * eyePlaneMat; + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); + shadowSpaceCoords1 = viewPos * eyePlaneMat; } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e27dd384ea..e79adaafba 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -26,7 +26,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform sampler2DShadow shadowTexture0; -varying vec4 shadowSpaceCoords; +uniform sampler2DShadow shadowTexture1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" #include "parallax.glsl" @@ -68,7 +70,8 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; + shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 17a9c436ea..015039252e 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -15,7 +15,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform int shadowTextureUnit0; -varying vec4 shadowSpaceCoords; +uniform int shadowTextureUnit1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" @@ -40,5 +42,7 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords = viewPos * eyePlaneMat; + shadowSpaceCoords0 = viewPos * eyePlaneMat; + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); + shadowSpaceCoords1 = viewPos * eyePlaneMat; } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index f04a9d8a87..3529b7347f 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -143,7 +143,9 @@ uniform vec3 nodePosition; uniform float rainIntensity; uniform sampler2DShadow shadowTexture0; -varying vec4 shadowSpaceCoords; +uniform sampler2DShadow shadowTexture1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; float frustumDepth; @@ -161,7 +163,8 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; + float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; + shadow *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 6aaa0537c9..0c280fb7e0 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -5,7 +5,9 @@ varying vec4 position; varying float depthPassthrough; uniform int shadowTextureUnit0; -varying vec4 shadowSpaceCoords; +uniform int shadowTextureUnit1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; void main(void) { @@ -23,7 +25,10 @@ void main(void) depthPassthrough = gl_Position.z; + vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords = (gl_ModelViewMatrix * gl_Vertex) * eyePlaneMat; + shadowSpaceCoords0 = viewPos * eyePlaneMat; + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); + shadowSpaceCoords1 = viewPos * eyePlaneMat; } From 3106159721239e59cf9d2229dd62bd792554c33f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 16:40:32 +0000 Subject: [PATCH 028/410] Turn off all shadow texture units for the sky now it is possible for there to be more than one --- apps/openmw/mwrender/sky.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 9f4542ae9c..8eec3f30b2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1124,7 +1124,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - skyroot->getOrCreateStateSet()->setTextureMode(MWShadow::baseShadowTextureUnit, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); + for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + skyroot->getOrCreateStateSet()->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); From 715f29165ba385a62177ae92fbe4f5cf526bfae1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 20:22:45 +0000 Subject: [PATCH 029/410] Dynamically adjust shaders to have the required number of shadow maps. --- components/shader/shadermanager.cpp | 37 +++++++++++++++++++++++++---- components/shader/shadermanager.hpp | 3 ++- files/shaders/objects_fragment.glsl | 16 ++++++++----- files/shaders/objects_vertex.glsl | 18 +++++++------- files/shaders/terrain_fragment.glsl | 16 ++++++++----- files/shaders/terrain_vertex.glsl | 20 +++++++++------- files/shaders/water_fragment.glsl | 21 +++++++++++----- files/shaders/water_vertex.glsl | 24 +++++++++++-------- 8 files changed, 105 insertions(+), 50 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 7cb49c6cb5..02488dd42b 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -99,10 +99,39 @@ namespace Shader return true; } - osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType) + osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType, bool disableShadows) { OpenThreads::ScopedLock lock(mMutex); + // set up shadows in the shader + // get these values from settings manager + bool shadows = true & !disableShadows; + int numShadowMaps = 2; + DefineMap definesWithShadows; + if (shadows) + { + definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); + + /*definesWithShadows.insert(std::string("shadow_texture_unit_declarations"), std::string("")); + definesWithShadows.insert(std::string("shadow_space_coordinate_declarations"), std::string("")); + definesWithShadows.insert(std::string("shadow_space_coordinate_calculations"), std::string("")); + definesWithShadows.insert(std::string("shadow_texture_sampler_declarations"), std::string("")); + definesWithShadows.insert(std::string("shadow_texture_lookup_calculations"), std::string(""));*/ + for (int i = 0; i < numShadowMaps; ++i) + { + definesWithShadows["shadow_texture_unit_declarations"] += "uniform int shadowTextureUnit" + std::to_string(i) + ";\n"; + definesWithShadows["shadow_space_coordinate_declarations"] += "varying vec4 shadowSpaceCoords" + std::to_string(i) + ";\n"; + + definesWithShadows["shadow_space_coordinate_calculations"] += "eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneT[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneR[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneQ[shadowTextureUnit" + std::to_string(i) + "]);\n" + + "shadowSpaceCoords" + std::to_string(i) + " = viewPos * eyePlaneMat;\n"; + + definesWithShadows["shadow_texture_sampler_declarations"] += "uniform sampler2DShadow shadowTexture" + std::to_string(i) + ";\n"; + definesWithShadows["shadow_texture_lookup_calculations"] += "shadowing *= shadow2DProj(shadowTexture" + std::to_string(i) + ", shadowSpaceCoords" + std::to_string(i) + ").r;\n"; + } + } + + definesWithShadows.insert(defines.begin(), defines.end()); + // read the template if we haven't already TemplateMap::iterator templateIt = mShaderTemplates.find(shaderTemplate); if (templateIt == mShaderTemplates.end()) @@ -126,11 +155,11 @@ namespace Shader templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; } - ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, defines)); + ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, definesWithShadows)); if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, defines)) + if (!parseDefines(shaderSource, definesWithShadows)) return NULL; osg::ref_ptr shader (new osg::Shader(shaderType)); @@ -139,7 +168,7 @@ namespace Shader static unsigned int counter = 0; shader->setName(std::to_string(counter++)); - shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), shader)).first; + shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, definesWithShadows), shader)).first; } return shaderIt->second; } diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index bd820a725c..17c46f58c0 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -26,9 +26,10 @@ namespace Shader /// @param shaderTemplate The filename of the shader template. /// @param defines Define values that can be retrieved by the shader template. /// @param shaderType The type of shader (usually vertex or fragment shader). + /// @param disableShadows Whether to disable shadows in the shader regardless of the overall setting. False by default. /// @note May return NULL on failure. /// @note Thread safe. - osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType); + osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType, bool disableShadows = false); osg::ref_ptr getProgram(osg::ref_ptr vertexShader, osg::ref_ptr fragmentShader); diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index f6355aaa69..7d9372c718 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; @@ -55,10 +57,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture0; -uniform sampler2DShadow shadowTexture1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_sampler_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" #include "parallax.glsl" @@ -118,8 +120,10 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; - shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; + float shadowing = 1.0; +#if SHADOWS + @shadow_texture_lookup_calculations +#endif // SHADOWS #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index b90a8722b8..fb612afc82 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -46,10 +48,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform int shadowTextureUnit0; -uniform int shadowTextureUnit1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_unit_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" @@ -106,9 +108,9 @@ void main(void) passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; +#if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords0 = viewPos * eyePlaneMat; - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); - shadowSpaceCoords1 = viewPos * eyePlaneMat; + mat4 eyePlaneMat; + @shadow_space_coordinate_calculations +#endif // SHADOWS } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e79adaafba..e512d74756 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + varying vec2 uv; uniform sampler2D diffuseMap; @@ -25,10 +27,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture0; -uniform sampler2DShadow shadowTexture1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_sampler_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" #include "parallax.glsl" @@ -70,8 +72,10 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; - shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; + float shadowing = 1.0; +#if SHADOWS + @shadow_texture_lookup_calculations +#endif // SHADOWS #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 015039252e..692e76cce7 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + varying vec2 uv; varying float depth; @@ -14,10 +16,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform int shadowTextureUnit0; -uniform int shadowTextureUnit1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_unit_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" @@ -40,9 +42,9 @@ void main(void) uv = gl_MultiTexCoord0.xy; - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords0 = viewPos * eyePlaneMat; - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); - shadowSpaceCoords1 = viewPos * eyePlaneMat; + #if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @shadow_space_coordinate_calculations + #endif // SHADOWS } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 3529b7347f..586a247a4b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,6 +1,7 @@ #version 120 #define REFRACTION @refraction_enabled +#define SHADOWS @shadows_enabled // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) @@ -142,10 +143,11 @@ uniform vec3 nodePosition; uniform float rainIntensity; -uniform sampler2DShadow shadowTexture0; -uniform sampler2DShadow shadowTexture1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_sampler_declarations + + @shadow_space_coordinate_declarations +#endif // SHADOWS float frustumDepth; @@ -163,8 +165,15 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; - shadow *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; + #if SHADOWS + float shadowing = 1.0; + + @shadow_texture_lookup_calculations + + float shadow = shadowing; + #else // NOT SHADOWS + float shadow = 1.0; + #endif // SHADOWS vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 0c280fb7e0..6381155d0b 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,10 +4,13 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; -uniform int shadowTextureUnit0; -uniform int shadowTextureUnit1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#define SHADOWS @shadows_enabled + +#if SHADOWS + @shadow_texture_unit_declarations + + @shadow_space_coordinate_declarations +#endif // SHADOWS void main(void) { @@ -25,10 +28,11 @@ void main(void) depthPassthrough = gl_Position.z; - vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords0 = viewPos * eyePlaneMat; - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); - shadowSpaceCoords1 = viewPos * eyePlaneMat; + #if SHADOWS + vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + + @shadow_space_coordinate_calculations + #endif // SHADOWS } From 34032052319b621c776a0427f5348e2b0f51109c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 20:34:48 +0000 Subject: [PATCH 030/410] Use three shadow maps per light --- apps/openmw/mwrender/shadow.cpp | 9 +++++---- apps/openmw/mwrender/shadow.hpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 40b2ff311b..9a4e2688af 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -420,11 +420,11 @@ namespace MWRender previous_sdl.swap(sdl); unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight(); - if (numShadowMapsPerLight>2) + /*if (numShadowMapsPerLight>2) { OSG_NOTICE << "numShadowMapsPerLight of " << numShadowMapsPerLight << " is greater than maximum supported, falling back to 2." << std::endl; numShadowMapsPerLight = 2; - } + }*/ LightDataList& pll = vdd->getLightDataList(); for (LightDataList::iterator itr = pll.begin(); @@ -596,14 +596,15 @@ namespace MWRender if (numShadowMapsPerLight>1) { // compute the start and end range in non-dimensional coords -#if 0 +#if 1 double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); -#endif +#else // hardwired for 2 splits double r_start = (sm_i == 0) ? -1.0 : splitPoint; double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; +#endif // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap // to prevent a seam showing through between the shadowmaps diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index e7663c55ac..e8d5b1b51d 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -8,7 +8,7 @@ namespace MWRender class MWShadow : public osgShadow::ViewDependentShadowMap { public: - static const int numberOfShadowMapsPerLight = 2; + static const int numberOfShadowMapsPerLight = 3; static const bool debugHud = true; MWShadow(); From aa31cbba4ffba8630ce80f8ec25333c81984aa48 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 01:20:52 +0000 Subject: [PATCH 031/410] Attempt (and fail) to make the local map show without unwanted shadow --- apps/openmw/mwrender/localmap.cpp | 8 ++++++++ components/shader/shadermanager.cpp | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b78c4dcd2c..4b60a7cf22 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -23,6 +23,7 @@ #include "../mwworld/cellstore.hpp" #include "vismask.hpp" +#include "shadow.hpp" namespace { @@ -201,6 +202,13 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + osg::ref_ptr fakeShadowMapImage = new osg::Image(); + fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); + *(float*)fakeShadowMapImage->data() = -std::numeric_limits::infinity(); // this has been tried both positive and negative + osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + camera->addChild(lightSource); camera->setStateSet(stateset); camera->setViewport(0, 0, mMapResolution, mMapResolution); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 02488dd42b..93b0168ae7 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -11,6 +11,8 @@ #include #include +#include "apps/openmw/mwrender/shadow.hpp" + namespace Shader { @@ -106,7 +108,7 @@ namespace Shader // set up shadows in the shader // get these values from settings manager bool shadows = true & !disableShadows; - int numShadowMaps = 2; + int numShadowMaps = MWRender::MWShadow::numberOfShadowMapsPerLight; DefineMap definesWithShadows; if (shadows) { From 2e7951c83f552b82d5054b1ce2f5072a2577186d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 01:28:10 +0000 Subject: [PATCH 032/410] Remove unused mask --- apps/openmw/mwrender/vismask.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 1f620b7f71..d52c7c232e 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -51,9 +51,7 @@ namespace MWRender Mask_PreCompile = (1<<16), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<17), - - Mask_CastsShadows = (1<<18) + Mask_Lighting = (1<<17) }; } From e201e359a91369b084d67ad9485ec2ad4457c8fe Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 01:44:49 +0000 Subject: [PATCH 033/410] Move Shadow to Components --- apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwrender/localmap.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- apps/openmw/mwrender/sky.cpp | 4 ++-- components/CMakeLists.txt | 2 +- {apps/openmw/mwrender => components/sceneutil}/shadow.cpp | 2 +- {apps/openmw/mwrender => components/sceneutil}/shadow.hpp | 8 ++++---- components/shader/shadermanager.cpp | 4 ++-- 8 files changed, 16 insertions(+), 17 deletions(-) rename {apps/openmw/mwrender => components/sceneutil}/shadow.cpp (99%) rename {apps/openmw/mwrender => components/sceneutil}/shadow.hpp (82%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 97744d4dd0..47a30f9a01 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,7 +24,6 @@ add_openmw_dir (mwrender creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation renderbin actoranimation landmanager - shadow ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 4b60a7cf22..c7f90bc5f3 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "../mwbase/environment.hpp" @@ -23,7 +24,6 @@ #include "../mwworld/cellstore.hpp" #include "vismask.hpp" -#include "shadow.hpp" namespace { @@ -206,7 +206,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); *(float*)fakeShadowMapImage->data() = -std::numeric_limits::infinity(); // this has been tried both positive and negative osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); - for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); camera->addChild(lightSource); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 176d179f47..1b34e433dd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,6 @@ #include "water.hpp" #include "terrainstorage.hpp" #include "util.hpp" -#include "shadow.hpp" namespace MWRender { @@ -210,9 +210,9 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(MWShadow::baseShadowTextureUnit); + settings->setBaseShadowTextureUnit(SceneUtil::MWShadow::baseShadowTextureUnit); //settings->setMinimumShadowMapNearFarRatio(0); - settings->setNumShadowMapsPerLight(MWShadow::numberOfShadowMapsPerLight); + settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); @@ -224,7 +224,7 @@ namespace MWRender int mapres = 2048; settings->setTextureSize(osg::Vec2s(mapres,mapres)); - MWShadow* tech = new MWShadow(); + SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); shadowedScene->setShadowTechnique(tech); /*tech->setMaxFarPlane(0); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8eec3f30b2..331782c7bd 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -42,13 +42,13 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "vismask.hpp" #include "renderbin.hpp" -#include "shadow.hpp" namespace { @@ -1124,7 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) skyroot->getOrCreateStateSet()->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a0b426a163..f6af33b25f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -56,7 +56,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer shadow ) add_component_dir (nif diff --git a/apps/openmw/mwrender/shadow.cpp b/components/sceneutil/shadow.cpp similarity index 99% rename from apps/openmw/mwrender/shadow.cpp rename to components/sceneutil/shadow.cpp index 9a4e2688af..e8b267dadb 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -7,7 +7,7 @@ #include #include -namespace MWRender +namespace SceneUtil { using namespace osgShadow; diff --git a/apps/openmw/mwrender/shadow.hpp b/components/sceneutil/shadow.hpp similarity index 82% rename from apps/openmw/mwrender/shadow.hpp rename to components/sceneutil/shadow.hpp index 445a7b0f55..8d8278deb2 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -1,9 +1,9 @@ -#ifndef OPENMW_MWRENDER_SHADOW_H -#define OPENMW_MWRENDER_SHADOW_H +#ifndef COMPONENTS_SCENEUTIL_SHADOW_H +#define COMPONENTS_SCENEUTIL_SHADOW_H #include -namespace MWRender +namespace SceneUtil { class MWShadow : public osgShadow::ViewDependentShadowMap { @@ -27,4 +27,4 @@ namespace MWRender }; } -#endif //OPENMW_MWRENDER_SHADOW_H +#endif //COMPONENTS_SCENEUTIL_SHADOW_H diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 3b4373387c..a0b1aca83c 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -11,7 +11,7 @@ #include #include -#include "apps/openmw/mwrender/shadow.hpp" +#include "components/sceneutil/shadow.hpp" namespace Shader { @@ -108,7 +108,7 @@ namespace Shader // set up shadows in the shader // get these values from settings manager bool shadows = true & !disableShadows; - int numShadowMaps = MWRender::MWShadow::numberOfShadowMapsPerLight; + int numShadowMaps = SceneUtil::MWShadow::numberOfShadowMapsPerLight; DefineMap definesWithShadows; if (shadows) { From 6e0b61d084c5a98ecbfd43b3e6d733db28805ca2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 04:09:14 +0000 Subject: [PATCH 034/410] Add missing libraries to components target --- components/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f6af33b25f..1e3a68ac89 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -210,6 +210,7 @@ target_link_libraries(components ${OSGVIEWER_LIBRARIES} ${OSGTEXT_LIBRARIES} ${OSGGA_LIBRARIES} + ${OSGSHADOW_LIBRARIES} ${OSGANIMATION_LIBRARIES} ${Bullet_LIBRARIES} ${SDL2_LIBRARIES} From 64d5d0fd667eec0e0b074898453483068564b73c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 13:30:13 +0000 Subject: [PATCH 035/410] Prevent the local map from being considered to be shadowed. --- apps/openmw/mwrender/localmap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index c7f90bc5f3..7f3132a9e9 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -204,8 +204,10 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f osg::ref_ptr fakeShadowMapImage = new osg::Image(); fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - *(float*)fakeShadowMapImage->data() = -std::numeric_limits::infinity(); // this has been tried both positive and negative + *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + fakeShadowMapTexture->setShadowComparison(true); + fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); From 548c42b5fd204dcb596462ada9a626cde97ac803 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 13:38:30 +0000 Subject: [PATCH 036/410] Disable over-zealous shadows in the character preview. --- apps/openmw/mwrender/characterpreview.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index f7219959af..15cc638936 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -150,6 +151,15 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); + osg::ref_ptr fakeShadowMapImage = new osg::Image(); + fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); + *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); + osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + fakeShadowMapTexture->setShadowComparison(true); + fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); + for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) + stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) osg::ref_ptr fog (new osg::Fog); From 590531595b9033641be6d7661cd6757d5bdca96f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 Nov 2017 02:02:27 +0000 Subject: [PATCH 037/410] Create @foreach shader preprocessor macro in preparation for moving shadow setup out of shadermanager.cpp --- components/shader/shadermanager.cpp | 121 +++++++++++++++++++++++----- files/shaders/objects_fragment.glsl | 10 ++- files/shaders/objects_vertex.glsl | 11 ++- files/shaders/terrain_fragment.glsl | 10 ++- files/shaders/terrain_vertex.glsl | 19 +++-- files/shaders/water_fragment.glsl | 25 +++--- files/shaders/water_vertex.glsl | 12 ++- 7 files changed, 159 insertions(+), 49 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a0b1aca83c..ea971586ab 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -74,13 +74,82 @@ namespace Shader return true; } + bool parseFors(std::string& source) + { + const char escapeCharacter = '$'; + size_t foundPos = 0; + while ((foundPos = source.find(escapeCharacter)) != std::string::npos) + { + size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); + if (endPos == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string command = source.substr(foundPos + 1, endPos - (foundPos + 1)); + if (command != "foreach") + { + std::cerr << "Unknown shader directive: $" << command << std::endl; + return false; + } + + size_t iterNameStart = endPos + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string iteratorName = "$" + source.substr(iterNameStart, iterNameEnd - iterNameStart); + + size_t listStart = iterNameEnd + 1; + size_t listEnd = source.find_first_of("\n\r", listStart); + if (listEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string list = source.substr(listStart, listEnd - listStart); + std::vector listElements; + boost::split(listElements, list, boost::is_any_of(",")); + + size_t contentStart = source.find_first_not_of("\n\r", listEnd); + size_t contentEnd = source.find("$endforeach", contentStart); + if (contentEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string content = source.substr(contentStart, contentEnd - contentStart); + + size_t overallEnd = contentEnd + std::string("$endforeach").length(); + // This will be wrong if there are other #line directives, so that needs fixing + int lineNumber = std::count(source.begin(), source.begin() + overallEnd, '\n') + 2; + + std::string replacement = ""; + for (std::vector::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++) + { + std::string contentInstance = content; + size_t foundIterator; + while ((foundIterator = contentInstance.find(iteratorName)) != std::string::npos) + contentInstance.replace(foundIterator, iteratorName.length(), *element); + replacement += contentInstance; + } + replacement += "\n#line " + std::to_string(lineNumber); + source.replace(foundPos, overallEnd - foundPos, replacement); + } + + return true; + } + bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines) { const char escapeCharacter = '@'; size_t foundPos = 0; + std::vector forIterators; while ((foundPos = source.find(escapeCharacter)) != std::string::npos) { - size_t endPos = source.find_first_of(" \n\r()[].;", foundPos); + size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); if (endPos == std::string::npos) { std::cerr << "Unexpected EOF" << std::endl; @@ -88,7 +157,34 @@ namespace Shader } std::string define = source.substr(foundPos+1, endPos - (foundPos+1)); ShaderManager::DefineMap::const_iterator defineFound = defines.find(define); - if (defineFound == defines.end()) + if (define == "foreach") + { + source.replace(foundPos, 1, "$"); + size_t iterNameStart = endPos + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + forIterators.push_back(source.substr(iterNameStart, iterNameEnd - iterNameStart)); + } + else if (define == "endforeach") + { + source.replace(foundPos, 1, "$"); + if (forIterators.empty()) + { + std::cerr << "endforeach without foreach" << std::endl; + return false; + } + else + forIterators.pop_back(); + } + else if (std::find(forIterators.begin(), forIterators.end(), define) != forIterators.end()) + { + source.replace(foundPos, 1, "$"); + } + else if (defineFound == defines.end()) { std::cerr << "Undefined " << define << std::endl; return false; @@ -113,23 +209,10 @@ namespace Shader if (shadows) { definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - - /*definesWithShadows.insert(std::string("shadow_texture_unit_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_space_coordinate_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_space_coordinate_calculations"), std::string("")); - definesWithShadows.insert(std::string("shadow_texture_sampler_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_texture_lookup_calculations"), std::string(""));*/ for (int i = 0; i < numShadowMaps; ++i) - { - definesWithShadows["shadow_texture_unit_declarations"] += "uniform int shadowTextureUnit" + std::to_string(i) + ";\n"; - definesWithShadows["shadow_space_coordinate_declarations"] += "varying vec4 shadowSpaceCoords" + std::to_string(i) + ";\n"; - - definesWithShadows["shadow_space_coordinate_calculations"] += "eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneT[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneR[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneQ[shadowTextureUnit" + std::to_string(i) + "]);\n" - + "shadowSpaceCoords" + std::to_string(i) + " = viewPos * eyePlaneMat;\n"; - - definesWithShadows["shadow_texture_sampler_declarations"] += "uniform sampler2DShadow shadowTexture" + std::to_string(i) + ";\n"; - definesWithShadows["shadow_texture_lookup_calculations"] += "shadowing *= shadow2DProj(shadowTexture" + std::to_string(i) + ", shadowSpaceCoords" + std::to_string(i) + ").r;\n"; - } + definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; + // remove extra comma + definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); } definesWithShadows.insert(defines.begin(), defines.end()); @@ -161,7 +244,7 @@ namespace Shader if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, definesWithShadows)) + if (!parseDefines(shaderSource, definesWithShadows) || !parseFors(shaderSource)) { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 7d9372c718..9196c14902 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -58,8 +58,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_sampler_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -122,7 +124,9 @@ void main() float shadowing = 1.0; #if SHADOWS - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index fb612afc82..f84971c972 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -49,8 +49,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_unit_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -111,6 +113,9 @@ void main(void) #if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; - @shadow_space_coordinate_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach #endif // SHADOWS } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e512d74756..1b985e14b4 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -28,8 +28,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_sampler_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -74,7 +76,9 @@ void main() float shadowing = 1.0; #if SHADOWS - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 692e76cce7..7cb959d3ef 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -17,8 +17,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_unit_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -42,9 +44,12 @@ void main(void) uv = gl_MultiTexCoord0.xy; - #if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @shadow_space_coordinate_calculations - #endif // SHADOWS +#if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach +#endif // SHADOWS } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 586a247a4b..ca09aa94be 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +//DUMPME + #define REFRACTION @refraction_enabled #define SHADOWS @shadows_enabled @@ -144,9 +146,10 @@ uniform vec3 nodePosition; uniform float rainIntensity; #if SHADOWS - @shadow_texture_sampler_declarations - - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS float frustumDepth; @@ -165,15 +168,17 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - #if SHADOWS - float shadowing = 1.0; +#if SHADOWS + float shadowing = 1.0; - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach - float shadow = shadowing; - #else // NOT SHADOWS - float shadow = 1.0; - #endif // SHADOWS + float shadow = shadowing; +#else // NOT SHADOWS + float shadow = 1.0; +#endif // SHADOWS vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 6381155d0b..1a14bcaa66 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -7,9 +7,10 @@ varying float depthPassthrough; #define SHADOWS @shadows_enabled #if SHADOWS - @shadow_texture_unit_declarations - - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS void main(void) @@ -33,6 +34,9 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; - @shadow_space_coordinate_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach #endif // SHADOWS } From 3d18ddc8e4b607cadf9caecb37fb94872ae3b0f8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 17 Nov 2017 17:18:33 +0000 Subject: [PATCH 038/410] Take into account previous #line directives when expanding @foreach shader macros --- components/shader/shadermanager.cpp | 18 ++++++++++++++++-- files/shaders/water_fragment.glsl | 2 -- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index ea971586ab..59c81f40a6 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -123,8 +123,22 @@ namespace Shader std::string content = source.substr(contentStart, contentEnd - contentStart); size_t overallEnd = contentEnd + std::string("$endforeach").length(); - // This will be wrong if there are other #line directives, so that needs fixing - int lineNumber = std::count(source.begin(), source.begin() + overallEnd, '\n') + 2; + + size_t lineDirectivePosition = source.rfind("#line", overallEnd); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString); + } + else + { + lineDirectivePosition = 0; + lineNumber = 2; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n'); std::string replacement = ""; for (std::vector::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ca09aa94be..fddd81eff2 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -//DUMPME - #define REFRACTION @refraction_enabled #define SHADOWS @shadows_enabled From 166ba220720b8f65b4f8de7b2349a65ac0eb5f8a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 21 Nov 2017 16:53:12 +0000 Subject: [PATCH 039/410] Prevent line count changes within conditional blocks (because of conditional includes or @foreach expansion) ruining line numbering. --- components/shader/shadermanager.cpp | 60 +++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 59c81f40a6..b5c292ad77 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -21,6 +21,44 @@ namespace Shader mPath = path; } + bool addLineDirectivesAfterConditionalBlocks(std::string& source) + { + for (size_t position = 0; position < source.length(); ) + { + size_t foundPos = source.find("#endif", position); + foundPos = std::min(foundPos, source.find("#elif", position)); + foundPos = std::min(foundPos, source.find("#else", position)); + + if (foundPos == std::string::npos) + break; + + foundPos = source.find_first_of("\n\r", foundPos); + foundPos = source.find_first_not_of("\n\r", foundPos); + + size_t lineDirectivePosition = source.rfind("#line", foundPos); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString) - 1; + } + else + { + lineDirectivePosition = 0; + lineNumber = 1; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); + + source.replace(foundPos, 0, "#line " + std::to_string(lineNumber) + "\n"); + + position = foundPos; + } + + return true; + } + bool parseIncludes(boost::filesystem::path shaderPath, std::string& source) { boost::replace_all(source, "\r\n", "\n"); @@ -54,14 +92,30 @@ namespace Shader std::stringstream buffer; buffer << includeFstream.rdbuf(); + std::string stringRepresentation = buffer.str(); + addLineDirectivesAfterConditionalBlocks(stringRepresentation); // insert #line directives so we get correct line numbers in compiler errors int includedFileNumber = fileNumber++; - int lineNumber = std::count(source.begin(), source.begin() + foundPos, '\n'); + size_t lineDirectivePosition = source.rfind("#line", foundPos); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString) - 1; + } + else + { + lineDirectivePosition = 0; + lineNumber = 1; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); std::stringstream toInsert; - toInsert << "#line 0 " << includedFileNumber << "\n" << buffer.str() << "\n#line " << lineNumber << " 0\n"; + toInsert << "#line 0 " << includedFileNumber << "\n" << stringRepresentation << "\n#line " << lineNumber << " 0\n"; source.replace(foundPos, (end-foundPos+1), toInsert.str()); @@ -248,7 +302,7 @@ namespace Shader // parse includes std::string source = buffer.str(); - if (!parseIncludes(boost::filesystem::path(mPath), source)) + if (!addLineDirectivesAfterConditionalBlocks(source) || !parseIncludes(boost::filesystem::path(mPath), source)) return NULL; templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; From 7a9df977c7b0a6ac689964550aa04889bf56a7fb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 21 Nov 2017 17:20:57 +0000 Subject: [PATCH 040/410] Add some prerequisits for making shadows disableable --- components/shader/shadermanager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index b5c292ad77..a7a5e99a07 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -165,7 +165,8 @@ namespace Shader } std::string list = source.substr(listStart, listEnd - listStart); std::vector listElements; - boost::split(listElements, list, boost::is_any_of(",")); + if (list != "") + boost::split(listElements, list, boost::is_any_of(",")); size_t contentStart = source.find_first_not_of("\n\r", listEnd); size_t contentEnd = source.find("$endforeach", contentStart); @@ -282,6 +283,11 @@ namespace Shader // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); } + else + { + definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); + definesWithShadows["shadow_texture_unit_list"] = ""; + } definesWithShadows.insert(defines.begin(), defines.end()); From 98cd9fc144fef83724d7c16a12c41d66ba972240 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 22 Nov 2017 20:07:07 +0000 Subject: [PATCH 041/410] Add preliminary support for global shader defines. --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++ components/sceneutil/shadow.cpp | 24 ++++++++++ components/sceneutil/shadow.hpp | 7 +++ components/shader/shadermanager.cpp | 57 ++++++++++------------- components/shader/shadermanager.hpp | 12 ++++- 5 files changed, 70 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1b34e433dd..c2ade69d9f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -238,6 +238,10 @@ namespace MWRender shadowedScene->addChild(sceneRoot); mRootNode->addChild(shadowedScene); + Shader::ShaderManager::DefineMap shadowDefines = tech->getShadowDefines(); + Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); + globalDefines.insert(shadowDefines.begin(), shadowDefines.end()); + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mPathgrid.reset(new Pathgrid(mRootNode)); diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e8b267dadb..87aeb051e6 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -712,4 +712,28 @@ namespace SceneUtil // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< +#include + namespace SceneUtil { class MWShadow : public osgShadow::ViewDependentShadowMap { public: static const int numberOfShadowMapsPerLight = 3; + static const int enableShadows = true; static const bool debugHud = true; MWShadow(); @@ -16,6 +19,10 @@ namespace SceneUtil const static int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; virtual void cull(osgUtil::CullVisitor& cv); + + virtual Shader::ShaderManager::DefineMap getShadowDefines(); + + virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); protected: const int debugTextureUnit; diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a7a5e99a07..b8beffa2e1 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -11,8 +11,6 @@ #include #include -#include "components/sceneutil/shadow.hpp" - namespace Shader { @@ -211,7 +209,7 @@ namespace Shader return true; } - bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines) + bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines) { const char escapeCharacter = '@'; size_t foundPos = 0; @@ -226,6 +224,7 @@ namespace Shader } std::string define = source.substr(foundPos+1, endPos - (foundPos+1)); ShaderManager::DefineMap::const_iterator defineFound = defines.find(define); + ShaderManager::DefineMap::const_iterator globalDefineFound = globalDefines.find(define); if (define == "foreach") { source.replace(foundPos, 1, "$"); @@ -253,44 +252,27 @@ namespace Shader { source.replace(foundPos, 1, "$"); } - else if (defineFound == defines.end()) + else if (defineFound != defines.end()) { - std::cerr << "Undefined " << define << std::endl; - return false; + source.replace(foundPos, endPos - foundPos, defineFound->second); + } + else if (globalDefineFound != globalDefines.end()) + { + source.replace(foundPos, endPos - foundPos, globalDefineFound->second); } else { - source.replace(foundPos, endPos-foundPos, defineFound->second); + std::cerr << "Undefined " << define << std::endl; + return false; } } return true; } - osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType, bool disableShadows) + osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType) { OpenThreads::ScopedLock lock(mMutex); - // set up shadows in the shader - // get these values from settings manager - bool shadows = true & !disableShadows; - int numShadowMaps = SceneUtil::MWShadow::numberOfShadowMapsPerLight; - DefineMap definesWithShadows; - if (shadows) - { - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - for (int i = 0; i < numShadowMaps; ++i) - definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; - // remove extra comma - definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); - } - else - { - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); - definesWithShadows["shadow_texture_unit_list"] = ""; - } - - definesWithShadows.insert(defines.begin(), defines.end()); - // read the template if we haven't already TemplateMap::iterator templateIt = mShaderTemplates.find(shaderTemplate); if (templateIt == mShaderTemplates.end()) @@ -314,11 +296,11 @@ namespace Shader templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; } - ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, definesWithShadows)); + ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, defines)); if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, definesWithShadows) || !parseFors(shaderSource)) + if (!parseDefines(shaderSource, defines, mGlobalDefines) || !parseFors(shaderSource)) { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); @@ -331,7 +313,7 @@ namespace Shader static unsigned int counter = 0; shader->setName(std::to_string(counter++)); - shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, definesWithShadows), shader)).first; + shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), shader)).first; } return shaderIt->second; } @@ -350,6 +332,17 @@ namespace Shader return found->second; } + ShaderManager::DefineMap ShaderManager::getGlobalDefines() + { + return DefineMap(mGlobalDefines); + } + + void ShaderManager::setGlobalDefines(DefineMap & defines) + { + mGlobalDefines = defines; + // TODO: We need to trigger the regeneration of all shaders. + } + void ShaderManager::releaseGLObjects(osg::State *state) { OpenThreads::ScopedLock lock(mMutex); diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 17c46f58c0..baaa738659 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -26,18 +26,26 @@ namespace Shader /// @param shaderTemplate The filename of the shader template. /// @param defines Define values that can be retrieved by the shader template. /// @param shaderType The type of shader (usually vertex or fragment shader). - /// @param disableShadows Whether to disable shadows in the shader regardless of the overall setting. False by default. /// @note May return NULL on failure. /// @note Thread safe. - osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType, bool disableShadows = false); + osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType); osg::ref_ptr getProgram(osg::ref_ptr vertexShader, osg::ref_ptr fragmentShader); + /// Get (a copy of) the DefineMap used to construct all shaders + DefineMap getGlobalDefines(); + + /// Set the DefineMap used to construct all shaders + /// @param defines The DefineMap to use + void setGlobalDefines(DefineMap& defines); + void releaseGLObjects(osg::State* state); private: std::string mPath; + DefineMap mGlobalDefines; + // typedef std::map TemplateMap; TemplateMap mShaderTemplates; From 4612597877e7817febe67b24dbd3e35900ce8b43 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 22 Nov 2017 20:54:39 +0000 Subject: [PATCH 042/410] Switch to insert_or_assign semantics when adding shadow defines to the global shader defines. --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c2ade69d9f..52bc8de3c3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -240,7 +240,10 @@ namespace MWRender Shader::ShaderManager::DefineMap shadowDefines = tech->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); - globalDefines.insert(shadowDefines.begin(), shadowDefines.end()); + + for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) + globalDefines[itr->first] = itr->second; + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mPathgrid.reset(new Pathgrid(mRootNode)); From 974e4d5299515a0b754215b06fbd5c6ee72dded5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 24 Nov 2017 22:43:40 +0000 Subject: [PATCH 043/410] Add check for null shaders when releasing OpenGL objects --- components/shader/shadermanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index b8beffa2e1..3b18d0b756 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -347,7 +347,10 @@ namespace Shader { OpenThreads::ScopedLock lock(mMutex); for (auto shader : mShaders) - shader.second->releaseGLObjects(state); + { + if (shader.second != nullptr) + shader.second->releaseGLObjects(state); + } for (auto program : mPrograms) program.second->releaseGLObjects(state); } From 617473c7dadeb18a60bfcde70ffd350ab5654f3c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Dec 2017 18:06:20 +0000 Subject: [PATCH 044/410] Force near plane out further for LiSpSM projection --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 52bc8de3c3..9258b754f7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -211,7 +211,7 @@ namespace MWRender //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); settings->setBaseShadowTextureUnit(SceneUtil::MWShadow::baseShadowTextureUnit); - //settings->setMinimumShadowMapNearFarRatio(0); + settings->setMinimumShadowMapNearFarRatio(0.25); settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored From 7cce2d6f87113aabfb6ab2587ca45b799f38e5b9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Dec 2017 22:37:40 +0000 Subject: [PATCH 045/410] Implement a more sensible shadow map cascading system --- components/sceneutil/shadow.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 87aeb051e6..dfcd5c1e80 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -596,14 +596,34 @@ namespace SceneUtil if (numShadowMapsPerLight>1) { // compute the start and end range in non-dimensional coords -#if 1 +#if 0 double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); -#else +#elif 0 // hardwired for 2 splits double r_start = (sm_i == 0) ? -1.0 : splitPoint; double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; +#else + double r_start, r_end; + // Split such that each shadow map covers a quarter of the area of the one after it + if (sm_i == 0) + r_start = -1.0; + else + { + r_start = (1 - pow(4.0, sm_i)) / (1 - pow(4.0, numShadowMapsPerLight)); + r_start *= 2.0; + r_start -= 1.0; + } + + if (sm_i + 1 == numShadowMapsPerLight) + r_end = 1.0; + else + { + r_end = (1 - pow(4.0, sm_i + 1)) / (1 - pow(4.0, numShadowMapsPerLight)); + r_end *= 2.0; + r_end -= 1.0; + } #endif // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap From 8957c92a36ae55cd77537a8ba48ba1838938f035 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Dec 2017 00:52:10 +0000 Subject: [PATCH 046/410] Switch to a more industry-standard shadow map splitting scheme --- components/sceneutil/shadow.cpp | 42 ++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index dfcd5c1e80..a4079d1a00 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -604,7 +604,7 @@ namespace SceneUtil // hardwired for 2 splits double r_start = (sm_i == 0) ? -1.0 : splitPoint; double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; -#else +#elif 0 double r_start, r_end; // Split such that each shadow map covers a quarter of the area of the one after it if (sm_i == 0) @@ -613,6 +613,7 @@ namespace SceneUtil { r_start = (1 - pow(4.0, sm_i)) / (1 - pow(4.0, numShadowMapsPerLight)); r_start *= 2.0; + //r_start += double(sm_i) / double(numShadowMapsPerLight); r_start -= 1.0; } @@ -622,8 +623,47 @@ namespace SceneUtil { r_end = (1 - pow(4.0, sm_i + 1)) / (1 - pow(4.0, numShadowMapsPerLight)); r_end *= 2.0; + //r_end += double(sm_i + 1) / double(numShadowMapsPerLight); r_end -= 1.0; } +#else + double r_start, r_end; + + // split system based on the original Parallel Split Shadow Maps paper. + double n = (frustum.eye - frustum.centerNearPlane).length(); + double f = (frustum.eye - frustum.centerFarPlane).length(); + double i = double(sm_i); + double m = double(numShadowMapsPerLight); + double deltaBias = 0; + if (sm_i == 0) + r_start = -1.0; + else + { + // compute the split point in main camera view + double ciLog = n * pow(f / n, i / m); + double ciUniform = n + (f - n) * i / m; + double ci = (ciLog + ciUniform) / 2 + deltaBias; + + // work out where this is in light space + osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; + osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; + r_start = lightSpacePos.y(); + } + + if (sm_i + 1 == numShadowMapsPerLight) + r_end = 1.0; + else + { + // compute the split point in main camera view + double ciLog = n * pow(f / n, (i + 1) / m); + double ciUniform = n + (f - n) * (i + 1) / m; + double ci = (ciLog + ciUniform) / 2 + deltaBias; + + // work out where this is in light space + osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; + osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; + r_end = lightSpacePos.y(); + } #endif // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap From 229cc9696f904b4235dffdf0394b1d6b43759a5d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Dec 2017 01:57:53 +0000 Subject: [PATCH 047/410] Make updating global shader defines update shaders. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/shader/shadermanager.cpp | 23 +++++++++++++++++++++-- components/shader/shadermanager.hpp | 4 +++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9258b754f7..5449fd4608 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,7 +244,7 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; - mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines, mViewer); mPathgrid.reset(new Pathgrid(mRootNode)); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 3b18d0b756..533b3ae561 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -337,10 +337,29 @@ namespace Shader return DefineMap(mGlobalDefines); } - void ShaderManager::setGlobalDefines(DefineMap & defines) + void ShaderManager::setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer) { mGlobalDefines = defines; - // TODO: We need to trigger the regeneration of all shaders. + bool threadsStarted = viewer->areThreadsRunning(); + if (threadsStarted) + viewer->stopThreading(); + for (auto shaderMapElement: mShaders) + { + std::string templateId = shaderMapElement.first.first; + ShaderManager::DefineMap defines = shaderMapElement.first.second; + osg::ref_ptr shader = shaderMapElement.second; + if (shader == nullptr) + // I'm not sure how to handle a shader that was already broken as there's no way to get a potential replacement to the nodes that need it. + continue; + std::string shaderSource = mShaderTemplates[templateId]; + if (!parseDefines(shaderSource, defines, mGlobalDefines) || !parseFors(shaderSource)) + // We just broke the shader and there's no way to force existing objects back to fixed-function mode as we would when creating the shader. + // If we put a nullptr in the shader map, we just lose the ability to put a working one in later. + continue; + shader->setShaderSource(shaderSource); + } + if (threadsStarted) + viewer->startThreading(); } void ShaderManager::releaseGLObjects(osg::State *state) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index baaa738659..16b4d639bb 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -8,6 +8,8 @@ #include +#include + #include namespace Shader @@ -37,7 +39,7 @@ namespace Shader /// Set the DefineMap used to construct all shaders /// @param defines The DefineMap to use - void setGlobalDefines(DefineMap& defines); + void setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer); void releaseGLObjects(osg::State* state); From b08938485f362f081cb9880bc8dad8c88964c15a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Dec 2017 23:55:19 +0000 Subject: [PATCH 048/410] Make suspending viewer threads the responsibility of the caller, not the shader manager. --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- components/shader/shadermanager.cpp | 9 ++------- components/shader/shadermanager.hpp | 3 ++- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5449fd4608..41d9969d41 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,7 +244,8 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; - mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines, mViewer); + // It is unnecessary to stop/start the viewer as no frames are being rendered yet. + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mPathgrid.reset(new Pathgrid(mRootNode)); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 533b3ae561..eb3a88eb45 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -337,12 +337,9 @@ namespace Shader return DefineMap(mGlobalDefines); } - void ShaderManager::setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer) + void ShaderManager::setGlobalDefines(DefineMap & globalDefines) { - mGlobalDefines = defines; - bool threadsStarted = viewer->areThreadsRunning(); - if (threadsStarted) - viewer->stopThreading(); + mGlobalDefines = globalDefines; for (auto shaderMapElement: mShaders) { std::string templateId = shaderMapElement.first.first; @@ -358,8 +355,6 @@ namespace Shader continue; shader->setShaderSource(shaderSource); } - if (threadsStarted) - viewer->startThreading(); } void ShaderManager::releaseGLObjects(osg::State *state) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 16b4d639bb..02f35975d5 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -39,7 +39,8 @@ namespace Shader /// Set the DefineMap used to construct all shaders /// @param defines The DefineMap to use - void setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer); + /// @note This will change the source code for any shaders already created, potentially causing problems if they're being used to render a frame. It is recommended that any associated Viewers have their threading stopped while this function is running if any shaders are in use. + void setGlobalDefines(DefineMap & globalDefines); void releaseGLObjects(osg::State* state); From 4de3a361fb790162ea991a1e2190963f024ee717 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 26 Dec 2017 23:18:50 +0000 Subject: [PATCH 049/410] Make shadow maps only cover regions where shadow receivers might be. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 41d9969d41..caa8089097 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -215,7 +215,7 @@ namespace MWRender settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored - //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); //settings->setDebugDraw(true); // don't turn this on because it makes everything break //settings->setPerspectiveShadowMapCutOffAngle(0); From c192c851dbf05e00101deaba539247216791573e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 26 Dec 2017 23:51:50 +0000 Subject: [PATCH 050/410] Make disabling shadows disable their performance impact, too. --- components/sceneutil/shadow.cpp | 6 ++++++ components/sceneutil/shadow.hpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index a4079d1a00..21a0de89a3 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -321,6 +321,12 @@ namespace SceneUtil void MWShadow::cull(osgUtil::CullVisitor& cv) { + if (!enableShadows) + { + _shadowedScene->osg::Group::traverse(cv); + return; + } + OSG_INFO << std::endl << std::endl << "ViewDependentShadowMap::cull(osg::CullVisitor&" << &cv << ")" << std::endl; if (!_shadowCastingStateSet) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index aa8085f0df..3c665bac79 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -11,7 +11,7 @@ namespace SceneUtil { public: static const int numberOfShadowMapsPerLight = 3; - static const int enableShadows = true; + static const bool enableShadows = true; static const bool debugHud = true; MWShadow(); From c3e0398d1c93962ed2f4b5a79afb37032de50fb3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Dec 2017 02:32:17 +0000 Subject: [PATCH 051/410] Add settings --- apps/openmw/mwrender/characterpreview.cpp | 9 +-- apps/openmw/mwrender/localmap.cpp | 9 +-- apps/openmw/mwrender/renderingmanager.cpp | 29 +++----- apps/openmw/mwrender/sky.cpp | 3 +- components/sceneutil/shadow.cpp | 89 +++++++++++++++++------ components/sceneutil/shadow.hpp | 15 ++-- files/settings-default.cfg | 19 +++++ 7 files changed, 107 insertions(+), 66 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 15cc638936..e329d9ebc7 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -151,14 +151,7 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); - osg::ref_ptr fakeShadowMapImage = new osg::Image(); - fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); - osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); - fakeShadowMapTexture->setShadowComparison(true); - fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); - for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) - stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + SceneUtil::MWShadow::disableShadowsForStateSet(stateset); // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 7f3132a9e9..d4f55f18b0 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -202,14 +202,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - osg::ref_ptr fakeShadowMapImage = new osg::Image(); - fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); - osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); - fakeShadowMapTexture->setShadowComparison(true); - fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); - for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) - stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + SceneUtil::MWShadow::disableShadowsForStateSet(stateset); camera->addChild(lightSource); camera->setStateSet(stateset); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index caa8089097..e72149b76b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -204,26 +204,15 @@ namespace MWRender osg::ref_ptr shadowedScene (new osgShadow::ShadowedScene); - osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings(); - settings->setLightNum(0); - settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player|Mask_Terrain); - settings->setReceivesShadowTraversalMask(~0u); - - //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(SceneUtil::MWShadow::baseShadowTextureUnit); - settings->setMinimumShadowMapNearFarRatio(0.25); - settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); - //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); - //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored - settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); - //settings->setDebugDraw(true); // don't turn this on because it makes everything break - - //settings->setPerspectiveShadowMapCutOffAngle(0); - //settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); - - int mapres = 2048; - settings->setTextureSize(osg::Vec2s(mapres,mapres)); - + int shadowCastingTraversalMask = Mask_Scene; + if (Settings::Manager::getBool("actor shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Actor; + if (Settings::Manager::getBool("player shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Player; + if (Settings::Manager::getBool("terrain shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Terrain; + SceneUtil::MWShadow::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); + SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); shadowedScene->setShadowTechnique(tech); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 331782c7bd..79f5f00bb7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1124,8 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) - skyroot->getOrCreateStateSet()->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); + SceneUtil::MWShadow::disableShadowsForStateSet(skyroot->getOrCreateStateSet()); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 21a0de89a3..0d654a817a 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace SceneUtil { using namespace osgShadow; @@ -46,35 +48,76 @@ namespace SceneUtil " gl_FragColor = vec4( fS + fH * color, 1 ); \n" #else " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" - " //gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0); \n" #endif "} \n"; - - MWShadow::MWShadow() : debugProgram(new osg::Program), debugTextureUnit(0) + void MWShadow::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) { - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); - debugProgram->addShader(vertexShader); - osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); - debugProgram->addShader(fragmentShader); + if (!Settings::Manager::getBool("enable shadows", "Shadows")) + return; - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + settings->setLightNum(0); + settings->setCastsShadowTraversalMask(castsShadowMask); + settings->setReceivesShadowTraversalMask(~0u); + + int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); + settings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); + settings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); + + settings->setMinimumShadowMapNearFarRatio(0.25); + if (Settings::Manager::getBool("compute tight scene bounds", "Shadows")) + settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + + int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); + settings->setTextureSize(osg::Vec2s(mapres, mapres)); + } + + void MWShadow::disableShadowsForStateSet(osg::ref_ptr stateset) + { + int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); + int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; + + osg::ref_ptr fakeShadowMapImage = new osg::Image(); + fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); + *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); + osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + fakeShadowMapTexture->setShadowComparison(true); + fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); + for (int i = baseShadowTextureUnit; i < baseShadowTextureUnit + numberOfShadowMapsPerLight; ++i) + stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + } + + MWShadow::MWShadow() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), + numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), + baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), + debugHud(Settings::Manager::getBool("enable debug hud", "Shadows")), + debugProgram(new osg::Program), debugTextureUnit(0) + { + if (debugHud) { - std::cout << i << std::endl; - - debugCameras.push_back(new osg::Camera); - debugCameras[i]->setViewport(200 * i, 0, 200, 200); - debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); - debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - - debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); - debugGeometry[i]->setCullingActive(false); - debugCameras[i]->addChild(debugGeometry[i]); - osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); - stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); + debugProgram->addShader(vertexShader); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); + debugProgram->addShader(fragmentShader); + + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + { + std::cout << i << std::endl; + + debugCameras.push_back(new osg::Camera); + debugCameras[i]->setViewport(200 * i, 0, 200, 200); + debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); + debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + debugGeometry[i]->setCullingActive(false); + debugCameras[i]->addChild(debugGeometry[i]); + osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + } } } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 3c665bac79..ec7bbb8d27 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -1,6 +1,7 @@ #ifndef COMPONENTS_SCENEUTIL_SHADOW_H #define COMPONENTS_SCENEUTIL_SHADOW_H +#include #include #include @@ -10,14 +11,12 @@ namespace SceneUtil class MWShadow : public osgShadow::ViewDependentShadowMap { public: - static const int numberOfShadowMapsPerLight = 3; - static const bool enableShadows = true; - static const bool debugHud = true; + static void setupShadowSettings(osg::ref_ptr settings, int castsShadowMask); + + static void disableShadowsForStateSet(osg::ref_ptr stateSet); MWShadow(); - const static int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; - virtual void cull(osgUtil::CullVisitor& cv); virtual Shader::ShaderManager::DefineMap getShadowDefines(); @@ -31,6 +30,12 @@ namespace SceneUtil osg::ref_ptr debugProgram; std::vector> debugGeometry; + + const int numberOfShadowMapsPerLight; + const bool enableShadows; + const bool debugHud; + + const int baseShadowTextureUnit; }; } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 2538834024..bd63f2bc66 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -466,3 +466,22 @@ companion x = 0.25 companion y = 0.0 companion w = 0.75 companion h = 0.375 + +[Shadows] +# Enable or disable shadows. +enable shadows = false +# How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. +number of shadow maps = 1 +# Enable the debug hud to see what the shadow map(s) contain. +enable debug hud = false +# Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. +compute tight scene bounds = false +# How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. +shadow map resolution = 1024 +# Allow actors to cast shadows. Potentially decreases performance. +actor shadows = false +# Allow the player to cast shadows. Potentially decreases performance. +player shadows = false +# Allow terrain to cast shadows. Potentially decreases performance. +terrain shadows = false +# Note: Right now, there is no setting allowing toggling of shadows for statics \ No newline at end of file From 8d4b32166c5d6980aebefc5b268460190a74785d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Dec 2017 02:35:25 +0000 Subject: [PATCH 052/410] Remove outdated comments --- apps/openmw/mwrender/renderingmanager.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e72149b76b..c8b3812b1a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -216,14 +216,6 @@ namespace MWRender SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); shadowedScene->setShadowTechnique(tech); - /*tech->setMaxFarPlane(0); - tech->setTextureSize(osg::Vec2s(mapres, mapres)); - tech->setShadowTextureCoordIndex(1); - tech->setShadowTextureUnit(1); - tech->setBaseTextureCoordIndex(0); - tech->setBaseTextureUnit(0);*/ - - //mRootNode->addChild(sceneRoot); shadowedScene->addChild(sceneRoot); mRootNode->addChild(shadowedScene); From d63fa5c0b5acec9f7566e965d1fcbdb97df73478 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Dec 2017 04:01:10 +0000 Subject: [PATCH 053/410] Add rst documentation for the shadow settings. --- .../reference/modding/settings/index.rst | 1 + .../reference/modding/settings/shadows.rst | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 docs/source/reference/modding/settings/shadows.rst diff --git a/docs/source/reference/modding/settings/index.rst b/docs/source/reference/modding/settings/index.rst index 56d76a8d10..a11df35a3d 100644 --- a/docs/source/reference/modding/settings/index.rst +++ b/docs/source/reference/modding/settings/index.rst @@ -31,6 +31,7 @@ The ranges I have included with each setting are the physically possible ranges, game general shaders + shadows input saves sound diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst new file mode 100644 index 0000000000..d8e8624795 --- /dev/null +++ b/docs/source/reference/modding/settings/shadows.rst @@ -0,0 +1,89 @@ +Shadow Settings +############### + +enable shadows +-------------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable or disable the rendering of shadows. +Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. + +number of shadow maps +--------------------- + +:Type: integer +:Range: 1 to 8, but higher values may conflict with other texture effects +:Default: 1 + +Control how many shadow maps to use - more of these means each shadow map texel covers less area, producing better-looking shadows, but may decrease performance. +Using too many shadow maps will lead to them overriding texture slots used for other effects, producing unpleasant artefacts. +A value of three is recommended in most cases, but other values may produce better results or performance. + +enable debug hud +---------------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable or disable the debug hud to see what the shadow map(s) contain. +This setting is only recommended for developers, bug reporting and advanced users performing fine-tuning of shadow settings. + +compute tight scene bounds +-------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +With this setting enabled, attempt to better use the shadow map(s) by making them cover a smaller area. +This can be especially helpful when looking downwards with a high viewing distance but will be less useful with the default value. +The performance impact of this may be very large. + +shadow map resolution +--------------------- + +:Type: integer +:Range: Dependent on GPU/driver combination +:Default: 1024 + +Control How large to make the shadow map(s). +Higher values increase GPU load but can produce better-looking results. +Power-of-two values may turn out to be faster than smaller values which are not powers of two on some GPU/driver combinations. + +actor shadows +------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow actors to cast shadows. +Potentially decreases performance. + +player shadows +-------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow the player to cast shadows. +Potentially decreases performance. + +terrain shadows +--------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow terrain to cast shadows. +Potentially decreases performance. + + + +Note: Right now, there is no setting allowing toggling of shadows for statics \ No newline at end of file From bf9a1ded63b3c5997409cacc2fb2916bb52e191e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 2 Jan 2018 16:39:05 +0000 Subject: [PATCH 054/410] Mark a function as override --- components/sceneutil/shadow.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index ec7bbb8d27..e5c3db327c 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -17,7 +17,7 @@ namespace SceneUtil MWShadow(); - virtual void cull(osgUtil::CullVisitor& cv); + virtual void cull(osgUtil::CullVisitor& cv) override; virtual Shader::ShaderManager::DefineMap getShadowDefines(); From 112ade2a3ff217da958a5b81ff8e2a30ae106929 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 22 Jan 2018 15:52:37 +0000 Subject: [PATCH 055/410] Ensure TerrainDrawables affect the computed near/far planes. --- components/terrain/terraindrawable.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/terrain/terraindrawable.cpp b/components/terrain/terraindrawable.cpp index 60d5917070..f216bb33bb 100644 --- a/components/terrain/terraindrawable.cpp +++ b/components/terrain/terraindrawable.cpp @@ -47,6 +47,12 @@ void TerrainDrawable::cull(osgUtil::CullVisitor *cv) osg::RefMatrix& matrix = *cv->getModelViewMatrix(); + if (cv->getComputeNearFarMode() && bb.valid()) + { + if (!cv->updateCalculatedNearFar(matrix, *this, false)) + return; + } + float depth = bb.valid() ? distance(bb.center(),matrix) : 0.0f; if (osg::isNaN(depth)) return; From c3d7c7de214d757edbc32e073a157ea6e8a4eab4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 23 Jan 2018 20:13:37 +0000 Subject: [PATCH 056/410] Prevent first-person meshes disappearing. --- apps/openmw/mwrender/npcanimation.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 08e376f083..eca9bb3e65 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -350,11 +350,16 @@ public: if (cv->getProjectionMatrix()->getPerspective(fov, aspect, zNear, zFar)) { fov = mFov; - osg::RefMatrix* newProjectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); + osg::ref_ptr newProjectionMatrix = new osg::RefMatrix(); newProjectionMatrix->makePerspective(fov, aspect, zNear, zFar); - cv->pushProjectionMatrix(newProjectionMatrix); + osg::ref_ptr invertedOldMatrix = cv->getProjectionMatrix(); + invertedOldMatrix = new osg::RefMatrix(osg::RefMatrix::inverse(*invertedOldMatrix)); + osg::ref_ptr viewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + viewMatrix->postMult(*newProjectionMatrix); + viewMatrix->postMult(*invertedOldMatrix); + cv->pushModelViewMatrix(viewMatrix, osg::Transform::ReferenceFrame::ABSOLUTE_RF); traverse(node, nv); - cv->popProjectionMatrix(); + cv->popModelViewMatrix(); } else traverse(node, nv); From 9f20aaccfb944580655ef1e41df0e0dce0f1638c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 25 Jan 2018 16:08:34 +0000 Subject: [PATCH 057/410] Add some more advanced settings to control shadows. --- components/sceneutil/shadow.cpp | 9 +++-- .../reference/modding/settings/shadows.rst | 37 ++++++++++++++++++- files/settings-default.cfg | 6 +++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 0d654a817a..f1943f08d5 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -64,7 +64,7 @@ namespace SceneUtil settings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); settings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); - settings->setMinimumShadowMapNearFarRatio(0.25); + settings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows")); if (Settings::Manager::getBool("compute tight scene bounds", "Shadows")) settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); @@ -683,7 +683,8 @@ namespace SceneUtil double f = (frustum.eye - frustum.centerFarPlane).length(); double i = double(sm_i); double m = double(numShadowMapsPerLight); - double deltaBias = 0; + double ratio = Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"); + double deltaBias = Settings::Manager::getFloat("split point bias", "Shadows"); if (sm_i == 0) r_start = -1.0; else @@ -691,7 +692,7 @@ namespace SceneUtil // compute the split point in main camera view double ciLog = n * pow(f / n, i / m); double ciUniform = n + (f - n) * i / m; - double ci = (ciLog + ciUniform) / 2 + deltaBias; + double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; @@ -706,7 +707,7 @@ namespace SceneUtil // compute the split point in main camera view double ciLog = n * pow(f / n, (i + 1) / m); double ciUniform = n + (f - n) * (i + 1) / m; - double ci = (ciLog + ciUniform) / 2 + deltaBias; + double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index d8e8624795..334663fe8f 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -86,4 +86,39 @@ Potentially decreases performance. -Note: Right now, there is no setting allowing toggling of shadows for statics \ No newline at end of file +Note: Right now, there is no setting allowing toggling of shadows for statics + +Expert settings +*************** + +You probably shouldn't be changing these if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. +If you have, then you may get better results tuning these for your specific view distance. + +split point uniform logarithmic ratio +------------------------------------- + +:Type: float +:Range: 0.0-1.0 for sensible results. Other values may 'work' but could behave bizarrely. +:Default: 0.5 + +Controls the ratio of :math:`C_i^{log}` versus :math:`C_i^{uniform}` used to form the Practical Split Scheme as described in the linked paper. + +split point bias +---------------- + +:Type: float +:Range: Any value supported by C++ floats on your platform, although undesirable behaviour is more likely to appear the further the value is from zero. +:Default: 0.0 + +The :math:`\delta_{bias}` parameter used to form the Practical Split Scheme as described in the linked paper. + +minimum lispsm near far ratio +----------------------------- + +:Type: float +:Range: Must be greater than zero. +:Default: 0.25 + +Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. +Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. +Increasing this pushes detail further away by moving the frustum apex further from the near plane. \ No newline at end of file diff --git a/files/settings-default.cfg b/files/settings-default.cfg index bc18302424..49615dc68e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -475,12 +475,18 @@ companion h = 0.375 enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 +# Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. +split point uniform logarithmic ratio = 0.5 +# Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. +split point bias = 0.0 # Enable the debug hud to see what the shadow map(s) contain. enable debug hud = false # Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. compute tight scene bounds = false # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. shadow map resolution = 1024 +# Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. Increasing this pushes detail further away. +minimum lispsm near far ratio = 0.25 # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false # Allow the player to cast shadows. Potentially decreases performance. From 0cb9903c88f36c597d4b144dfeed5d5147ea26d1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 25 Jan 2018 21:30:11 +0000 Subject: [PATCH 058/410] Tweak headings in settings documentation --- docs/source/reference/modding/settings/shadows.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 334663fe8f..a0e902d7b2 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -1,6 +1,9 @@ Shadow Settings ############### +Main settings +************* + enable shadows -------------- From 6251e0519e00fa81f6c4a46257b1bdaa0c1a8a30 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 23 Feb 2018 23:31:53 +0000 Subject: [PATCH 059/410] Use CLSB results to reduce maximum shadow map distance when sensible. --- components/sceneutil/shadow.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index f1943f08d5..e8c7e19472 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -449,6 +449,18 @@ namespace SceneUtil Frustum frustum(&cv, minZNear, maxZFar); + double reducedNear, reducedFar; + if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + reducedNear = osg::maximum(cv.getCalculatedNearPlane(), minZNear); + reducedFar = osg::minimum(cv.getCalculatedFarPlane(), maxZFar); + } + else + { + reducedNear = minZNear; + reducedFar = maxZFar; + } + // return compute near far mode back to it's original settings cv.setComputeNearFarMode(cachedNearFarMode); @@ -544,6 +556,20 @@ namespace SceneUtil double yMid = (clsb._bb.yMin() + clsb._bb.yMax())*0.5f; double yRange = (clsb._bb.yMax() - clsb._bb.yMin()); + osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); + double minZ = DBL_MAX; + double maxZ = -DBL_MAX; + for (unsigned int i = 0; i < 8; i++) + { + osg::Vec3 corner = clsb._bb.corner(i); + corner = corner * cornerConverter; + + maxZ = osg::maximum(maxZ, -corner.z()); + minZ = osg::minimum(minZ, -corner.z()); + } + reducedNear = osg::maximum(reducedNear, minZ); + reducedFar = osg::minimum(reducedFar, maxZ); + // OSG_NOTICE<<" xMid="< Date: Sun, 4 Feb 2018 23:27:45 +0000 Subject: [PATCH 060/410] Move the declaration of ComputeLightSpaceBounds to the header so that it can be accessed from other compilation units. (cherry picked from commit 8ac4fb208897a18da4934dd6f2fe84560b44ba9d) --- components/sceneutil/shadow.cpp | 234 ++++++++++++++++---------------- components/sceneutil/shadow.hpp | 26 ++++ 2 files changed, 140 insertions(+), 120 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e8c7e19472..1e4112971f 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -227,140 +227,134 @@ namespace SceneUtil } } - class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + MWShadow::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { - public: - ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Node& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Geode& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + for (unsigned int i = 0; igetBoundingBox()); - } + updateBound(node.getDrawable(i)->getBoundingBox()); } - - // pop the culling mode. - popCurrentMask(); } - void apply(osg::Drawable& drawable) + // pop the culling mode. + popCurrentMask(); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) + { + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Projection&) + { + // projection nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Transform& transform) + { + if (isCulled(transform)) return; + + // push the culling mode. + pushCurrentMask(); + + // absolute transforms won't affect a shadow map so their subgraphs should be ignored. + if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) { - if (isCulled(drawable)) return; + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - // push the culling mode. - pushCurrentMask(); + traverse(transform); - updateBound(drawable.getBoundingBox()); - - // pop the culling mode. - popCurrentMask(); + popModelViewMatrix(); } - void apply(osg::Billboard&) + // pop the culling mode. + popCurrentMask(); + + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Camera&) + { + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void MWShadow::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) + { + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); + } + + void MWShadow::ComputeLightSpaceBounds::update(const osg::Vec3& v) + { + if (v.z()<-1.0f) { - OSG_INFO << "Warning Billboards not yet supported" << std::endl; + //OSG_NOTICE<<"discarding("< matrix = new osg::RefMatrix(*getModelViewMatrix()); - transform.computeLocalToWorldMatrix(*matrix, this); - pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - - traverse(transform); - - popModelViewMatrix(); - } - - // pop the culling mode. - popCurrentMask(); - - } - - void apply(osg::Camera&) - { - // camera nodes won't affect a shadow map so their subgraphs should be ignored - return; - } - - void updateBound(const osg::BoundingBox& bb) - { - if (!bb.valid()) return; - - const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); - - update(bb.corner(0) * matrix); - update(bb.corner(1) * matrix); - update(bb.corner(2) * matrix); - update(bb.corner(3) * matrix); - update(bb.corner(4) * matrix); - update(bb.corner(5) * matrix); - update(bb.corner(6) * matrix); - update(bb.corner(7) * matrix); - } - - void update(const osg::Vec3& v) - { - if (v.z()<-1.0f) - { - //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; - float y = v.y(); - if (y<-1.0f) y = -1.0f; - if (y>1.0f) y = 1.0f; - _bb.expandBy(osg::Vec3(x, y, v.z())); - } - - osg::BoundingBox _bb; - }; + float x = v.x(); + if (x<-1.0f) x = -1.0f; + if (x>1.0f) x = 1.0f; + float y = v.y(); + if (y<-1.0f) y = -1.0f; + if (y>1.0f) y = 1.0f; + _bb.expandBy(osg::Vec3(x, y, v.z())); + } void MWShadow::cull(osgUtil::CullVisitor& cv) { diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index e5c3db327c..b92e8658b2 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -22,6 +22,32 @@ namespace SceneUtil virtual Shader::ShaderManager::DefineMap getShadowDefines(); virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); + + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + { + public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + void apply(osg::Node& node); + + void apply(osg::Geode& node); + + void apply(osg::Drawable& drawable); + + void apply(osg::Billboard&); + + void apply(osg::Projection&); + + void apply(osg::Transform& transform); + + void apply(osg::Camera&); + + void updateBound(const osg::BoundingBox& bb); + + void update(const osg::Vec3& v); + + osg::BoundingBox _bb; + }; protected: const int debugTextureUnit; From 9ec59783bac3dd69f0e0754591842bd733d5fef5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 5 Feb 2018 23:03:18 +0000 Subject: [PATCH 061/410] Add basic support for distant terrain CLSB (cherry picked from commit 0f9dc3e65b72e6fff762f7a0933bae6f861e5fd4) --- components/sceneutil/shadow.cpp | 8 ++++++++ components/sceneutil/shadow.hpp | 3 +++ components/terrain/quadtreeworld.cpp | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 1e4112971f..cc3eb0be6c 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -282,6 +282,14 @@ namespace SceneUtil popCurrentMask(); } + void MWShadow::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) + { + // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. + + update(osg::Vec3(-1.0, -1.0, 0.0)); + update(osg::Vec3(1.0, 1.0, 0.0)); + } + void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) { OSG_INFO << "Warning Billboards not yet supported" << std::endl; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index b92e8658b2..897b8759da 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace SceneUtil @@ -34,6 +35,8 @@ namespace SceneUtil void apply(osg::Drawable& drawable); + void apply(Terrain::QuadTreeWorld& quadTreeWorld); + void apply(osg::Billboard&); void apply(osg::Projection&); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f310648050..76baa2f45b 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -4,6 +4,8 @@ #include +#include + #include "quadtreenode.hpp" #include "storage.hpp" #include "viewdata.hpp" @@ -344,7 +346,12 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) + { + SceneUtil::MWShadow::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); + if (shadowBoundsVisitor) + shadowBoundsVisitor->apply(*this); return; + } ViewData* vd = mRootNode->getView(nv); From 273914aba871eb81ff08d3a0b16c35e3c9e590cc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:13:05 +0000 Subject: [PATCH 062/410] Add osgShadow ViewDependentShadowMaps as they can be found in OSG's GitHub Repository --- components/CMakeLists.txt | 2 +- components/sceneutil/mwshadowtechnique | 196 ++ components/sceneutil/mwshadowtechnique.cpp | 2430 ++++++++++++++++++++ 3 files changed, 2627 insertions(+), 1 deletion(-) create mode 100644 components/sceneutil/mwshadowtechnique create mode 100644 components/sceneutil/mwshadowtechnique.cpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1e3a68ac89..e68e7ed077 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -56,7 +56,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer shadow + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer shadow mwshadowtechnique ) add_component_dir (nif diff --git a/components/sceneutil/mwshadowtechnique b/components/sceneutil/mwshadowtechnique new file mode 100644 index 0000000000..63b80fed18 --- /dev/null +++ b/components/sceneutil/mwshadowtechnique @@ -0,0 +1,196 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP +#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 + +#include +#include +#include +#include +#include + +#include + +namespace osgShadow { + +/** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ +class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique +{ + public : + ViewDependentShadowMap(); + + ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_Object(osgShadow, ViewDependentShadowMap); + + /** initialize the ShadowedScene and local cached data structures.*/ + virtual void init(); + + /** run the update traversal of the ShadowedScene and update any loca chached data structures.*/ + virtual void update(osg::NodeVisitor& nv); + + /** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/ + virtual void cull(osgUtil::CullVisitor& cv); + + /** Resize any per context GLObject buffers to specified size. */ + virtual void resizeGLObjectBuffers(unsigned int maxSize); + + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objects + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + + /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ + virtual void cleanSceneGraph(); + + + struct OSGSHADOW_EXPORT Frustum + { + Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); + + osg::Matrixd projectionMatrix; + osg::Matrixd modelViewMatrix; + + typedef std::vector Vertices; + Vertices corners; + + typedef std::vector Indices; + typedef std::vector Faces; + Faces faces; + + typedef std::vector Edges; + Edges edges; + + osg::Vec3d eye; + osg::Vec3d centerNearPlane; + osg::Vec3d centerFarPlane; + osg::Vec3d center; + osg::Vec3d frustumCenterLine; + }; + + // forward declare + class ViewDependentData; + + struct OSGSHADOW_EXPORT LightData : public osg::Referenced + { + LightData(ViewDependentData* vdd); + + virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); + + ViewDependentData* _viewDependentData; + + osg::ref_ptr lightMatrix; + osg::ref_ptr light; + + osg::Vec4d lightPos; + osg::Vec3d lightPos3; + osg::Vec3d lightDir; + bool directionalLight; + + typedef std::vector ActiveTextureUnits; + ActiveTextureUnits textureUnits; + }; + + typedef std::list< osg::ref_ptr > LightDataList; + + struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + { + ShadowData(ViewDependentData* vdd); + + virtual void releaseGLObjects(osg::State* = 0) const; + + ViewDependentData* _viewDependentData; + + unsigned int _textureUnit; + osg::ref_ptr _texture; + osg::ref_ptr _texgen; + osg::ref_ptr _camera; + }; + + typedef std::list< osg::ref_ptr > ShadowDataList; + + + class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + { + public: + ViewDependentData(ViewDependentShadowMap* vdsm); + + const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } + + LightDataList& getLightDataList() { return _lightDataList; } + + ShadowDataList& getShadowDataList() { return _shadowDataList; } + + osg::StateSet* getStateSet() { return _stateset.get(); } + + virtual void releaseGLObjects(osg::State* = 0) const; + + protected: + virtual ~ViewDependentData() {} + + ViewDependentShadowMap* _viewDependentShadowMap; + + osg::ref_ptr _stateset; + + LightDataList _lightDataList; + ShadowDataList _shadowDataList; + }; + + virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); + + ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); + + + + virtual void createShaders(); + + virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; + + virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); + + virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera); + + virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); + + virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; + + virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; + + virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; + +protected: + virtual ~ViewDependentShadowMap(); + + typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; + mutable OpenThreads::Mutex _viewDependentDataMapMutex; + ViewDependentDataMap _viewDependentDataMap; + + osg::ref_ptr _shadowRecievingPlaceholderStateSet; + + osg::ref_ptr _shadowCastingStateSet; + osg::ref_ptr _polygonOffset; + osg::ref_ptr _fallbackBaseTexture; + osg::ref_ptr _fallbackShadowMapTexture; + + typedef std::vector< osg::ref_ptr > Uniforms; + mutable OpenThreads::Mutex _accessUniformsAndProgramMutex; + Uniforms _uniforms; + osg::ref_ptr _program; +}; + +} + +#endif diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp new file mode 100644 index 0000000000..f72f2ce159 --- /dev/null +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -0,0 +1,2430 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include +#include +#include +#include +#include + +#include + +using namespace osgShadow; + +////////////////////////////////////////////////////////////////// +// fragment shader +// +#if 0 +static const char fragmentShaderSource_withBaseTexture[] = + "uniform sampler2D baseTexture; \n" + "uniform sampler2DShadow shadowTexture; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" + " vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy ); \n" + " color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture, gl_TexCoord[1] ).r ); \n" + " gl_FragColor = color; \n" + "} \n"; +#else +static const char fragmentShaderSource_withBaseTexture[] = + "uniform sampler2D baseTexture; \n" + "uniform int baseTextureUnit; \n" + "uniform sampler2DShadow shadowTexture0; \n" + "uniform int shadowTextureUnit0; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" + " vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n" + " color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r ); \n" + " gl_FragColor = color; \n" + "} \n"; + +static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] = + "uniform sampler2D baseTexture; \n" + "uniform int baseTextureUnit; \n" + "uniform sampler2DShadow shadowTexture0; \n" + "uniform int shadowTextureUnit0; \n" + "uniform sampler2DShadow shadowTexture1; \n" + "uniform int shadowTextureUnit1; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" + " vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n" + " float shadow0 = shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r; \n" + " float shadow1 = shadow2DProj( shadowTexture1, gl_TexCoord[shadowTextureUnit1] ).r; \n" + " color *= mix( colorAmbientEmissive, gl_Color, shadow0*shadow1 ); \n" + " gl_FragColor = color; \n" + "} \n"; +#endif + +template +class RenderLeafTraverser : public T +{ +public: + + RenderLeafTraverser() + { + } + + void traverse(const osgUtil::RenderStage* rs) + { + traverse(static_cast(rs)); + } + + void traverse(const osgUtil::RenderBin* renderBin) + { + const osgUtil::RenderBin::RenderBinList& rbl = renderBin->getRenderBinList(); + for(osgUtil::RenderBin::RenderBinList::const_iterator itr = rbl.begin(); + itr != rbl.end(); + ++itr) + { + traverse(itr->second.get()); + } + + const osgUtil::RenderBin::RenderLeafList& rll = renderBin->getRenderLeafList(); + for(osgUtil::RenderBin::RenderLeafList::const_iterator itr = rll.begin(); + itr != rll.end(); + ++itr) + { + handle(*itr); + } + + const osgUtil::RenderBin::StateGraphList& rgl = renderBin->getStateGraphList(); + for(osgUtil::RenderBin::StateGraphList::const_iterator itr = rgl.begin(); + itr != rgl.end(); + ++itr) + { + traverse(*itr); + } + + } + + void traverse(const osgUtil::StateGraph* stateGraph) + { + const osgUtil::StateGraph::ChildList& cl = stateGraph->_children; + for(osgUtil::StateGraph::ChildList::const_iterator itr = cl.begin(); + itr != cl.end(); + ++itr) + { + traverse(itr->second.get()); + } + + const osgUtil::StateGraph::LeafList& ll = stateGraph->_leaves; + for(osgUtil::StateGraph::LeafList::const_iterator itr = ll.begin(); + itr != ll.end(); + ++itr) + { + handle(itr->get()); + } + } + + inline void handle(const osgUtil::RenderLeaf* renderLeaf) + { + this->operator()(renderLeaf); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// VDSMCameraCullCallback +// +class VDSMCameraCullCallback : public osg::NodeCallback +{ + public: + + VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); + + virtual void operator()(osg::Node*, osg::NodeVisitor* nv); + + osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); } + osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); } + + protected: + + ViewDependentShadowMap* _vdsm; + osg::ref_ptr _projectionMatrix; + osg::ref_ptr _renderStage; + osg::Polytope _polytope; +}; + +VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope): + _vdsm(vdsm), + _polytope(polytope) +{ +} + +void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + osgUtil::CullVisitor* cv = nv->asCullVisitor(); + osg::Camera* camera = node->asCamera(); + OSG_INFO<<"VDSMCameraCullCallback::operator()(osg::Node* "<getProjectionCullingStack().back(); + + cs.setFrustum(_polytope); + + cv->pushCullingSet(); + } +#endif + if (_vdsm->getShadowedScene()) + { + _vdsm->getShadowedScene()->osg::Group::traverse(*nv); + } +#if 1 + if (!_polytope.empty()) + { + OSG_INFO<<"Popping custom Polytope"<popCullingSet(); + } +#endif + + _renderStage = cv->getCurrentRenderBin()->getStage(); + + OSG_INFO<<"VDSM second : _renderStage = "<<_renderStage<getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + // make sure that the near plane is computed correctly. + cv->computeNearPlane(); + + osg::Matrixd projection = *(cv->getProjectionMatrix()); + + OSG_INFO<<"RTT Projection matrix "<setProjectionMatrix(projection); + + _projectionMatrix = cv->getProjectionMatrix(); + } +} + + +class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack +{ +public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + { + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix),osg::Transform::ABSOLUTE_RF); + } + + void apply(osg::Node& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Billboard&) + { + OSG_INFO<<"Warning Billboards not yet supported"< matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix,this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); + + traverse(transform); + + popModelViewMatrix(); + } + + // pop the culling mode. + popCurrentMask(); + + } + + void apply(osg::Camera&) + { + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void updateBound(const osg::BoundingBox& bb) + { + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); + } + + void update(const osg::Vec3& v) + { + if (v.z()<-1.0f) + { + //OSG_NOTICE<<"discarding("<1.0f) x=1.0f; + float y = v.y(); + if (y<-1.0f) y=-1.0f; + if (y>1.0f) y=1.0f; + _bb.expandBy(osg::Vec3(x,y,v.z())); + } + + osg::BoundingBox _bb; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// LightData +// +ViewDependentShadowMap::LightData::LightData(ViewDependentShadowMap::ViewDependentData* vdd): + _viewDependentData(vdd), + directionalLight(false) +{ +} + +void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) +{ + lightMatrix = lm; + light = l; + + lightPos = light->getPosition(); + directionalLight = (light->getPosition().w()== 0.0); + if (directionalLight) + { + lightPos3.set(0.0, 0.0, 0.0); // directional light has no destinct position + lightDir.set(-lightPos.x(), -lightPos.y(), -lightPos.z()); + lightDir.normalize(); + OSG_INFO<<" Directional light, lightPos="<setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT); + + //_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + _camera->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f)); + + _camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + + // switch off small feature culling as this can cull out geometry that will still be large enough once perspective correction takes effect. + _camera->setCullingMode(_camera->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING); + + // set viewport + _camera->setViewport(0,0,textureSize.x(),textureSize.y()); + + + if (debug) + { + // clear just the depth buffer + _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // render after the main camera + _camera->setRenderOrder(osg::Camera::POST_RENDER); + + // attach the texture and use it as the color buffer. + //_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); + _camera->attach(osg::Camera::COLOR_BUFFER, _texture.get()); + } + else + { + // clear the depth and colour bufferson each clear. + _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // set the camera to render before the main camera. + _camera->setRenderOrder(osg::Camera::PRE_RENDER); + + // tell the camera to use OpenGL frame buffer object where supported. + _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + + // attach the texture and use it as the color buffer. + _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); + //_camera->attach(osg::Camera::COLOR_BUFFER, _texture.get()); + } +} + +void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) const +{ + OSG_INFO<<"ViewDependentShadowMap::ShadowData::releaseGLObjects"<releaseGLObjects(state); + _camera->releaseGLObjects(state); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// Frustum +// +ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar): + corners(8), + faces(6), + edges(12) +{ + projectionMatrix = *(cv->getProjectionMatrix()); + modelViewMatrix = *(cv->getModelViewMatrix()); + + OSG_INFO<<"Projection matrix "<getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + osg::Matrix::value_type zNear = osg::maximum(cv->getCalculatedNearPlane(),minZNear); + osg::Matrix::value_type zFar = osg::minimum(cv->getCalculatedFarPlane(),maxZFar); + + cv->clampProjectionMatrix(projectionMatrix, zNear, zFar); + + OSG_INFO<<"zNear = "<releaseGLObjects(state); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// ViewDependentShadowMap +// +ViewDependentShadowMap::ViewDependentShadowMap(): + ShadowTechnique() +{ + _shadowRecievingPlaceholderStateSet = new osg::StateSet; +} + +ViewDependentShadowMap::ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop): + ShadowTechnique(vdsm,copyop) +{ + _shadowRecievingPlaceholderStateSet = new osg::StateSet; +} + +ViewDependentShadowMap::~ViewDependentShadowMap() +{ +} + + +void ViewDependentShadowMap::init() +{ + if (!_shadowedScene) return; + + OSG_INFO<<"ViewDependentShadowMap::init()"< lock(_viewDependentDataMapMutex); + ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv); + if (itr!=_viewDependentDataMap.end()) return itr->second.get(); + + osg::ref_ptr vdd = createViewDependentData(cv); + _viewDependentDataMap[cv] = vdd; + return vdd.release(); +} + +void ViewDependentShadowMap::update(osg::NodeVisitor& nv) +{ + OSG_INFO<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<osg::Group::traverse(nv); +} + +void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv) +{ + OSG_INFO<osg::Group::traverse(cv); + return; + } + + ViewDependentData* vdd = getViewDependentData(&cv); + + if (!vdd) + { + OSG_INFO<<"Warning, now ViewDependentData created, unable to create shadows."<osg::Group::traverse(cv); + return; + } + + ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + OSG_INFO<<"cv->getProjectionMatrix()="<<*cv.getProjectionMatrix()<getMaximumShadowMapDistance(),maxZFar); + if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); + + //OSG_NOTICE<<"maxZFar "<getLightDataList(); + for(LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = **itr; + + // 3.1 compute light space polytope + // + osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); + + // if polytope is empty then no rendering. + if (polytope.empty()) + { + OSG_NOTICE<<"Polytope empty no shadow to render"<1 &&*/ _shadowedScene->getCastsShadowTraversalMask()!=0xffffffff) + { + // osg::ElapsedTime timer; + + osg::ref_ptr viewport = new osg::Viewport(0,0,2048,2048); + ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); + clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); + + osg::Matrixd invertModelView; + invertModelView.invert(viewMatrix); + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); + cs.setFrustum(local_polytope); + clsb.pushCullingSet(); + + _shadowedScene->accept(clsb); + + // OSG_NOTICE<<"Extents of LightSpace "< camera = sd->_camera; + + camera->setProjectionMatrix(projectionMatrix); + camera->setViewMatrix(viewMatrix); + + if (settings->getDebugDraw()) + { + camera->getViewport()->x() = pos_x; + pos_x += static_cast(camera->getViewport()->width()) + 40; + } + + // transform polytope in model coords into light spaces eye coords. + osg::Matrixd invertModelView; + invertModelView.invert(camera->getViewMatrix()); + + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + + if (numShadowMapsPerLight>1) + { + // compute the start and end range in non-dimensional coords +#if 0 + double r_start = (sm_i==0) ? -1.0 : (double(sm_i)/double(numShadowMapsPerLight)*2.0-1.0); + double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : (double(sm_i+1)/double(numShadowMapsPerLight)*2.0-1.0); +#endif + + // hardwired for 2 splits + double r_start = (sm_i==0) ? -1.0 : splitPoint; + double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : splitPoint; + + // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap + // to prevent a seam showing through between the shadowmaps + if (sm_i+10) + { + // not the first shadowmap so insert a polytope to clip the scene from before r_start + + // plane in clip space coords + osg::Plane plane(0.0,1.0,0.0,-r_start); + + // transform into eye coords + plane.transformProvidingInverse(projectionMatrix); + local_polytope.getPlaneList().push_back(plane); + + //OSG_NOTICE<<"Adding r_start plane "<0) + { + decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); + } + + // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<getLightDataList(); + + LightDataList previous_ldl; + previous_ldl.swap(pll); + + //MR testing giving a specific light + osgUtil::RenderStage * rs = cv->getCurrentRenderBin()->getStage(); + + OSG_INFO<<"selectActiveLights osgUtil::RenderStage="<getModelViewMatrix()); + + osgUtil::PositionalStateContainer::AttrMatrixList& aml = + rs->getPositionalStateContainer()->getAttrMatrixList(); + + + const ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + for(osgUtil::PositionalStateContainer::AttrMatrixList::reverse_iterator itr = aml.rbegin(); + itr != aml.rend(); + ++itr) + { + const osg::Light* light = dynamic_cast(itr->first.get()); + if (light && light->getLightNum() >= 0) + { + // is LightNum matched to that defined in settings + if (settings && settings->getLightNum()>=0 && light->getLightNum()!=settings->getLightNum()) continue; + + LightDataList::iterator pll_itr = pll.begin(); + for(; pll_itr != pll.end(); ++pll_itr) + { + if ((*pll_itr)->light->getLightNum()==light->getLightNum()) break; + } + + if (pll_itr==pll.end()) + { + OSG_INFO<<"Light num "<getLightNum()<setLightData(itr->second.get(), light, modelViewMatrix); + pll.push_back(ld); + } + else + { + OSG_INFO<<"Light num "<getLightNum()<<" already used, ignore light"< lock(_accessUniformsAndProgramMutex); + + _shadowCastingStateSet = new osg::StateSet; + + ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + if (!settings->getDebugDraw()) + { + // note soft (attribute only no mode override) setting. When this works ? + // 1. for objects prepared for backface culling + // because they usually also set CullFace and CullMode on in their state + // For them we override CullFace but CullMode remains set by them + // 2. For one faced, trees, and similar objects which cannot use + // backface nor front face so they usually use CullMode off set here. + // In this case we will draw them in their entirety. + + _shadowCastingStateSet->setAttribute( new osg::CullFace( osg::CullFace::FRONT ), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); + + // make sure GL_CULL_FACE is off by default + // we assume that if object has cull face attribute set to back + // it will also set cull face mode ON so no need for override + _shadowCastingStateSet->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); + } + +#if 1 + float factor = 1.1; + float units = 4.0; +#else + float factor = -1.1; + float units = -4.0; +#endif + _polygonOffset = new osg::PolygonOffset(factor, units); + _shadowCastingStateSet->setAttribute(_polygonOffset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + _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()); + + for(unsigned int sm_i=0; sm_igetNumShadowMapsPerLight(); ++sm_i) + { + { + std::stringstream sstr; + sstr<<"shadowTexture"< shadowTextureSampler = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); + _uniforms.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()); + } + } + + switch(settings->getShaderHint()) + { + case(ShadowSettings::NO_SHADERS): + { + OSG_INFO<<"No shaders provided by, user must supply own shaders"< fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); + if (settings->getNumShadowMapsPerLight()==2) + { + _program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture_twoShadowMaps)); + } + else + { + _program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture)); + } + + break; + } + } + + { + osg::ref_ptr image = new osg::Image; + image->allocateImage( 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE ); + *(osg::Vec4ub*)image->data() = osg::Vec4ub( 0xFF, 0xFF, 0xFF, 0xFF ); + + _fallbackBaseTexture = new osg::Texture2D(image.get()); + _fallbackBaseTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT); + _fallbackBaseTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT); + _fallbackBaseTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); + _fallbackBaseTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); + + _fallbackShadowMapTexture = new osg::Texture2D(image.get()); + _fallbackShadowMapTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT); + _fallbackShadowMapTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT); + _fallbackShadowMapTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); + _fallbackShadowMapTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); + + } +} + +osg::Polytope ViewDependentShadowMap::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) +{ + OSG_INFO<<"computeLightViewFrustumPolytope()"<getShadowSettings(); + + double dotProduct_v = positionedLight.lightDir * frustum.frustumCenterLine; + double gamma_v = acos(dotProduct_v); + if (gamma_vgetPerspectiveShadowMapCutOffAngle()) || gamma_v>osg::DegreesToRadians(180.0-settings->getPerspectiveShadowMapCutOffAngle())) + { + OSG_INFO<<"View direction and Light direction below tolerance"<=0.0 && d1>=0.0) + { + // OSG_NOTICE<<" Edge completely inside"<first; + osg::Vec3d& v1 = itr->second; + osg::Vec3d intersection = v0 - (v1-v0)*(d0/(d1-d0)); + intersections.push_back(intersection); + // OSG_NOTICE<<" Edge across clip plane, v0="<=side_y.length2()) ? side_x : side_y; + side.normalize(); + + osg::Vec3d up = side ^ normal; + up.normalize(); + + osg::Vec3d center; + for(Vertices::iterator itr = intersections.begin(); + itr != intersections.end(); + ++itr) + { + center += *itr; + } + + center /= double(intersections.size()); + + typedef std::map VertexMap; + VertexMap vertexMap; + for(Vertices::iterator itr = intersections.begin(); + itr != intersections.end(); + ++itr) + { + osg::Vec3d dv = (*itr-center); + double h = dv * side; + double v = dv * up; + double angle = atan2(h,v); + // OSG_NOTICE<<"angle = "<_modelview.get()!=previous_modelview) + { + previous_modelview = renderLeaf->_modelview.get(); + if (previous_modelview) + { + light_mvp.mult(*renderLeaf->_modelview, light_p); + } + else + { + // no modelview matrix (such as when LightPointNode is in the scene graph) so assume + // that modelview matrix is indentity. + light_mvp = light_p; + } + // OSG_INFO<<"Computing new light_mvp "<_drawable->getBoundingBox(); + if (bb.valid()) + { + // OSG_NOTICE<<"checked extents of "<_drawable->getName()<max_z) { max_z=ls.z(); /* OSG_NOTICE<<" + ";*/ } + + // OSG_NOTICE<<" bb.z() in ls = "<getShadowSettings(); + + //frustum.projectionMatrix; + //frustum.modelViewMatrix; + + osg::Matrixd light_p = camera->getProjectionMatrix(); + osg::Matrixd light_v = camera->getViewMatrix(); + osg::Matrixd light_vp = light_v * light_p; + osg::Vec3d lightdir(0.0,0.0,-1.0); + + // check whether this light space projection is perspective or orthographic. + bool orthographicLightSpaceProjection = light_p(0,3)==0.0 && light_p(1,3)==0.0 && light_p(2,3)==0.0; + + if (!orthographicLightSpaceProjection) + { + OSG_INFO<<"perspective light space projection not yet supported."<setProjectionMatrix(light_p); + } + +#endif + + osg::Vec3d eye_v = frustum.eye * light_v; + //osg::Vec3d centerNearPlane_v = frustum.centerNearPlane * light_v; + osg::Vec3d center_v = frustum.center * light_v; + osg::Vec3d viewdir_v = center_v-eye_v; viewdir_v.normalize(); + + double dotProduct_v = lightdir * viewdir_v; + double gamma_v = acos(dotProduct_v); + if (gamma_vgetPerspectiveShadowMapCutOffAngle()) || gamma_v>osg::DegreesToRadians(180-settings->getPerspectiveShadowMapCutOffAngle())) + { + // OSG_NOTICE<<"Light and view vectors near parallel - use standard shadow map."<getTraversalMask(); + + cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getReceivesShadowTraversalMask() ); + + _shadowedScene->osg::Group::traverse(*cv); + + cv->setTraversalMask( traversalMask ); + + return; +} + +void ViewDependentShadowMap::cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const +{ + OSG_INFO<<"cullShadowCastingScene()"<getTraversalMask(); + + cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getCastsShadowTraversalMask() ); + + if (camera) camera->accept(*cv); + + cv->setTraversalMask( traversalMask ); + + return; +} + +osg::StateSet* ViewDependentShadowMap::selectStateSetForRenderingShadow(ViewDependentData& vdd) const +{ + OSG_INFO<<" selectStateSetForRenderingShadow() "< stateset = vdd.getStateSet(); + + OpenThreads::ScopedLock lock(_accessUniformsAndProgramMutex); + + vdd.getStateSet()->clear(); + + vdd.getStateSet()->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); + + for(Uniforms::const_iterator itr=_uniforms.begin(); + itr!=_uniforms.end(); + ++itr) + { + OSG_INFO<<"addUniform("<<(*itr)->getName()<<")"<addUniform(itr->get()); + } + + if (_program.valid()) + { + stateset->setAttribute(_program.get()); + } + + LightDataList& pll = vdd.getLightDataList(); + for(LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = (**itr); + + // if no texture units have been activated for this light then no shadow state required. + if (pl.textureUnits.empty()) continue; + + for(LightData::ActiveTextureUnits::iterator atu_itr = pl.textureUnits.begin(); + atu_itr != pl.textureUnits.end(); + ++atu_itr) + { + OSG_INFO<<" Need to assign state for "<<*atu_itr<getShadowSettings(); + unsigned int shadowMapModeValue = settings->getUseOverrideForShadowMapTexture() ? + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE : + osg::StateAttribute::ON; + + + ShadowDataList& sdl = vdd.getShadowDataList(); + for(ShadowDataList::iterator itr = sdl.begin(); + itr != sdl.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + ShadowData& sd = (**itr); + + OSG_INFO<<" ShadowData for "<setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), shadowMapModeValue); + + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); + } + + return vdd.getStateSet(); +} + +void ViewDependentShadowMap::resizeGLObjectBuffers(unsigned int /*maxSize*/) +{ + // the way that ViewDependentData is mapped shouldn't +} + +void ViewDependentShadowMap::releaseGLObjects(osg::State* state) const +{ + OpenThreads::ScopedLock lock(_viewDependentDataMapMutex); + for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin(); + itr != _viewDependentDataMap.end(); + ++itr) + { + ViewDependentData* vdd = itr->second.get(); + if (vdd) + { + vdd->releaseGLObjects(state); + } + } +} From 74672485556ef5760a4c271b2f663b6a5679bc5a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:14:29 +0000 Subject: [PATCH 063/410] Undo a modification from the upstream shadow technique which breaks compatibiltiy with OSG 3.4 --- 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 f72f2ce159..876943c884 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -168,7 +168,7 @@ VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) { - osgUtil::CullVisitor* cv = nv->asCullVisitor(); + osgUtil::CullVisitor* cv = dynamic_cast(nv); osg::Camera* camera = node->asCamera(); OSG_INFO<<"VDSMCameraCullCallback::operator()(osg::Node* "< Date: Sat, 24 Feb 2018 00:15:54 +0000 Subject: [PATCH 064/410] Add a notice clarifying the source of the shadow technique files. --- components/sceneutil/mwshadowtechnique.cpp | 5 + components/sceneutil/mwshadowtechnique.hpp | 201 +++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 components/sceneutil/mwshadowtechnique.hpp diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 876943c884..e68e234840 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1,3 +1,8 @@ +/* This file is based on OpenSceneGraph's src/osgShadow/ViewDependentShadowMap.cpp. + * Where applicable, any changes made are covered by OpenMW's GPL 3 license, not the OSGPL. + * The original copyright notice is listed below. + */ + /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield * * This library is open source and may be redistributed and/or modified under diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp new file mode 100644 index 0000000000..4352d811a7 --- /dev/null +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -0,0 +1,201 @@ +/* This file is based on OpenSceneGraph's include/osgShadow/ViewDependentShadowMap. + * Where applicable, any changes made are covered by OpenMW's GPL 3 license, not the OSGPL. + * The original copyright notice is listed below. + */ + +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield +* +* This library is open source and may be redistributed and/or modified under +* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or +* (at your option) any later version. The full license is in LICENSE file +* included with this distribution, and on the openscenegraph.org website. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP +#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 + +#include +#include +#include +#include +#include + +#include + +namespace osgShadow { + + /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ + class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique + { + public: + ViewDependentShadowMap(); + + ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(osgShadow, ViewDependentShadowMap); + + /** initialize the ShadowedScene and local cached data structures.*/ + virtual void init(); + + /** run the update traversal of the ShadowedScene and update any loca chached data structures.*/ + virtual void update(osg::NodeVisitor& nv); + + /** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/ + virtual void cull(osgUtil::CullVisitor& cv); + + /** Resize any per context GLObject buffers to specified size. */ + virtual void resizeGLObjectBuffers(unsigned int maxSize); + + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objects + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + + /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ + virtual void cleanSceneGraph(); + + + struct OSGSHADOW_EXPORT Frustum + { + Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); + + osg::Matrixd projectionMatrix; + osg::Matrixd modelViewMatrix; + + typedef std::vector Vertices; + Vertices corners; + + typedef std::vector Indices; + typedef std::vector Faces; + Faces faces; + + typedef std::vector Edges; + Edges edges; + + osg::Vec3d eye; + osg::Vec3d centerNearPlane; + osg::Vec3d centerFarPlane; + osg::Vec3d center; + osg::Vec3d frustumCenterLine; + }; + + // forward declare + class ViewDependentData; + + struct OSGSHADOW_EXPORT LightData : public osg::Referenced + { + LightData(ViewDependentData* vdd); + + virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); + + ViewDependentData* _viewDependentData; + + osg::ref_ptr lightMatrix; + osg::ref_ptr light; + + osg::Vec4d lightPos; + osg::Vec3d lightPos3; + osg::Vec3d lightDir; + bool directionalLight; + + typedef std::vector ActiveTextureUnits; + ActiveTextureUnits textureUnits; + }; + + typedef std::list< osg::ref_ptr > LightDataList; + + struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + { + ShadowData(ViewDependentData* vdd); + + virtual void releaseGLObjects(osg::State* = 0) const; + + ViewDependentData* _viewDependentData; + + unsigned int _textureUnit; + osg::ref_ptr _texture; + osg::ref_ptr _texgen; + osg::ref_ptr _camera; + }; + + typedef std::list< osg::ref_ptr > ShadowDataList; + + + class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + { + public: + ViewDependentData(ViewDependentShadowMap* vdsm); + + const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } + + LightDataList& getLightDataList() { return _lightDataList; } + + ShadowDataList& getShadowDataList() { return _shadowDataList; } + + osg::StateSet* getStateSet() { return _stateset.get(); } + + virtual void releaseGLObjects(osg::State* = 0) const; + + protected: + virtual ~ViewDependentData() {} + + ViewDependentShadowMap* _viewDependentShadowMap; + + osg::ref_ptr _stateset; + + LightDataList _lightDataList; + ShadowDataList _shadowDataList; + }; + + virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); + + ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); + + + + virtual void createShaders(); + + virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; + + virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); + + virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera); + + virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); + + virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; + + virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; + + virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; + + protected: + virtual ~ViewDependentShadowMap(); + + typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; + mutable OpenThreads::Mutex _viewDependentDataMapMutex; + ViewDependentDataMap _viewDependentDataMap; + + osg::ref_ptr _shadowRecievingPlaceholderStateSet; + + osg::ref_ptr _shadowCastingStateSet; + osg::ref_ptr _polygonOffset; + osg::ref_ptr _fallbackBaseTexture; + osg::ref_ptr _fallbackShadowMapTexture; + + typedef std::vector< osg::ref_ptr > Uniforms; + mutable OpenThreads::Mutex _accessUniformsAndProgramMutex; + Uniforms _uniforms; + osg::ref_ptr _program; + }; + +} + +#endif From 11e59d3c11183e997afc8dcd641c77f7d46666ce Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:52:46 +0000 Subject: [PATCH 065/410] Move to the correct namespace. --- components/sceneutil/mwshadowtechnique.cpp | 4 +++- components/sceneutil/mwshadowtechnique.hpp | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e68e234840..a7ec6a2d75 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -16,7 +16,8 @@ * OpenSceneGraph Public License for more details. */ -#include +#include "mwshadowtechnique.hpp" + #include #include #include @@ -25,6 +26,7 @@ #include using namespace osgShadow; +using namespace SceneUtil; ////////////////////////////////////////////////////////////////// // fragment shader diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 4352d811a7..d9df993719 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -16,8 +16,8 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP -#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 +#ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H +#define COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H 1 #include #include @@ -27,10 +27,10 @@ #include -namespace osgShadow { +namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ - class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique + class OSGSHADOW_EXPORT ViewDependentShadowMap : public osgShadow::ShadowTechnique { public: ViewDependentShadowMap(); From c815366044eb21078f2a810de06ea761d1d96d23 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:55:24 +0000 Subject: [PATCH 066/410] Move to the correct namespace part 2 --- components/sceneutil/mwshadowtechnique.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index d9df993719..1d213bc0f8 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -37,7 +37,7 @@ namespace SceneUtil { ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); - META_Object(osgShadow, ViewDependentShadowMap); + META_Object(SceneUtil, ViewDependentShadowMap); /** initialize the ShadowedScene and local cached data structures.*/ virtual void init(); From 7bd4c5e4b32f426d16758da2a0340b594b97f502 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:57:58 +0000 Subject: [PATCH 067/410] Change class name --- components/sceneutil/mwshadowtechnique.cpp | 76 +++++++++++----------- components/sceneutil/mwshadowtechnique.hpp | 16 ++--- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index a7ec6a2d75..71cfef2556 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -152,7 +152,7 @@ class VDSMCameraCullCallback : public osg::NodeCallback { public: - VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); + VDSMCameraCullCallback(MWShadowTechnique* vdsm, osg::Polytope& polytope); virtual void operator()(osg::Node*, osg::NodeVisitor* nv); @@ -161,13 +161,13 @@ class VDSMCameraCullCallback : public osg::NodeCallback protected: - ViewDependentShadowMap* _vdsm; + MWShadowTechnique* _vdsm; osg::ref_ptr _projectionMatrix; osg::ref_ptr _renderStage; osg::Polytope _polytope; }; -VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope): +VDSMCameraCullCallback::VDSMCameraCullCallback(MWShadowTechnique* vdsm, osg::Polytope& polytope): _vdsm(vdsm), _polytope(polytope) { @@ -375,13 +375,13 @@ public: // // LightData // -ViewDependentShadowMap::LightData::LightData(ViewDependentShadowMap::ViewDependentData* vdd): +MWShadowTechnique::LightData::LightData(MWShadowTechnique::ViewDependentData* vdd): _viewDependentData(vdd), directionalLight(false) { } -void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) +void MWShadowTechnique::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) { lightMatrix = lm; light = l; @@ -426,7 +426,7 @@ void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const o // // ShadowData // -ViewDependentShadowMap::ShadowData::ShadowData(ViewDependentShadowMap::ViewDependentData* vdd): +MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData* vdd): _viewDependentData(vdd), _textureUnit(0) { @@ -511,9 +511,9 @@ ViewDependentShadowMap::ShadowData::ShadowData(ViewDependentShadowMap::ViewDepen } } -void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) const +void MWShadowTechnique::ShadowData::releaseGLObjects(osg::State* state) const { - OSG_INFO<<"ViewDependentShadowMap::ShadowData::releaseGLObjects"<releaseGLObjects(state); _camera->releaseGLObjects(state); } @@ -522,7 +522,7 @@ void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) con // // Frustum // -ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar): +MWShadowTechnique::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar): corners(8), faces(6), edges(12) @@ -651,14 +651,14 @@ ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNe // // ViewDependentData // -ViewDependentShadowMap::ViewDependentData::ViewDependentData(ViewDependentShadowMap* vdsm): +MWShadowTechnique::ViewDependentData::ViewDependentData(MWShadowTechnique* vdsm): _viewDependentShadowMap(vdsm) { OSG_INFO<<"ViewDependentData::ViewDependentData()"< lock(_viewDependentDataMapMutex); ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv); @@ -721,15 +721,15 @@ ViewDependentShadowMap::ViewDependentData* ViewDependentShadowMap::getViewDepend return vdd.release(); } -void ViewDependentShadowMap::update(osg::NodeVisitor& nv) +void MWShadowTechnique::update(osg::NodeVisitor& nv) { - OSG_INFO<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<osg::Group::traverse(nv); } -void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv) +void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) { - OSG_INFO<getShadowSettings(); @@ -2286,7 +2286,7 @@ bool ViewDependentShadowMap::adjustPerspectiveShadowMapCameraSettings(osgUtil::R return true; } -bool ViewDependentShadowMap::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen) +bool MWShadowTechnique::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen) { OSG_INFO<<"assignTexGenSettings() textureUnit="< lock(_viewDependentDataMapMutex); for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin(); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 1d213bc0f8..efbf2ed5cd 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -30,14 +30,14 @@ namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ - class OSGSHADOW_EXPORT ViewDependentShadowMap : public osgShadow::ShadowTechnique + class OSGSHADOW_EXPORT MWShadowTechnique : public osgShadow::ShadowTechnique { public: - ViewDependentShadowMap(); + MWShadowTechnique(); - ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + MWShadowTechnique(const MWShadowTechnique& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); - META_Object(SceneUtil, ViewDependentShadowMap); + META_Object(SceneUtil, MWShadowTechnique); /** initialize the ShadowedScene and local cached data structures.*/ virtual void init(); @@ -129,9 +129,9 @@ namespace SceneUtil { class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced { public: - ViewDependentData(ViewDependentShadowMap* vdsm); + ViewDependentData(MWShadowTechnique* vdsm); - const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } + const MWShadowTechnique* getViewDependentShadowMap() const { return _viewDependentShadowMap; } LightDataList& getLightDataList() { return _lightDataList; } @@ -144,7 +144,7 @@ namespace SceneUtil { protected: virtual ~ViewDependentData() {} - ViewDependentShadowMap* _viewDependentShadowMap; + MWShadowTechnique* _viewDependentShadowMap; osg::ref_ptr _stateset; @@ -177,7 +177,7 @@ namespace SceneUtil { virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; protected: - virtual ~ViewDependentShadowMap(); + virtual ~MWShadowTechnique(); typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; mutable OpenThreads::Mutex _viewDependentDataMapMutex; From ce02c83089990a1bf826c1ef3233667df970530f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:27:47 +0000 Subject: [PATCH 068/410] Copy debug shader source into new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 71cfef2556..5217b48327 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -77,6 +77,45 @@ static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] = "} \n"; #endif +std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; +std::string debugFragmentShaderSource = + "uniform sampler2D texture; \n" + " \n" + "void main(void) \n" + "{ \n" +#if 1 + " float f = texture2D(texture, gl_TexCoord[0].xy).r; \n" + " \n" + " f = 256.0 * f; \n" + " float fC = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fS = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fH = floor( f ) / 256.0; \n" + " \n" + " fS *= 0.5; \n" + " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" + " \n" + " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" + " abs( fC - 0.333333 ), \n" + " abs( fC - 0.666667 ) ); \n" + " \n" + " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" + " \n" + " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" + " fMax = 1.0 / fMax; \n" + " \n" + " vec3 color = fMax * rgb; \n" + " \n" + " gl_FragColor = vec4( fS + fH * color, 1 ); \n" +#else + " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" +#endif + "} \n"; + + template class RenderLeafTraverser : public T { From 02d0ee3485dc35590099bfd76ec57a74c12ece24 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:29:31 +0000 Subject: [PATCH 069/410] Rename old shadow class to shadow manager --- apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +-- apps/openmw/mwrender/sky.cpp | 2 +- components/sceneutil/shadow.cpp | 34 +++++++++++------------ components/sceneutil/shadow.hpp | 4 +-- components/terrain/quadtreeworld.cpp | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index e329d9ebc7..63fe32dfec 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -151,7 +151,7 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); - SceneUtil::MWShadow::disableShadowsForStateSet(stateset); + SceneUtil::ShadowManager::disableShadowsForStateSet(stateset); // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d4f55f18b0..97e9c817a9 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -202,7 +202,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - SceneUtil::MWShadow::disableShadowsForStateSet(stateset); + SceneUtil::ShadowManager::disableShadowsForStateSet(stateset); camera->addChild(lightSource); camera->setStateSet(stateset); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8b3812b1a..a59ba8c1aa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -211,9 +211,9 @@ namespace MWRender shadowCastingTraversalMask |= Mask_Player; if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - SceneUtil::MWShadow::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); + SceneUtil::ShadowManager::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); - SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); + SceneUtil::ShadowManager* tech = new SceneUtil::ShadowManager(); shadowedScene->setShadowTechnique(tech); shadowedScene->addChild(sceneRoot); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 79f5f00bb7..3e81a7610f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1124,7 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - SceneUtil::MWShadow::disableShadowsForStateSet(skyroot->getOrCreateStateSet()); + SceneUtil::ShadowManager::disableShadowsForStateSet(skyroot->getOrCreateStateSet()); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index cc3eb0be6c..8c729e3cc1 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -51,7 +51,7 @@ namespace SceneUtil #endif "} \n"; - void MWShadow::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) + void ShadowManager::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) { if (!Settings::Manager::getBool("enable shadows", "Shadows")) return; @@ -72,7 +72,7 @@ namespace SceneUtil settings->setTextureSize(osg::Vec2s(mapres, mapres)); } - void MWShadow::disableShadowsForStateSet(osg::ref_ptr stateset) + void ShadowManager::disableShadowsForStateSet(osg::ref_ptr stateset) { int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; @@ -87,7 +87,7 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - MWShadow::MWShadow() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), + ShadowManager::ShadowManager() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), debugHud(Settings::Manager::getBool("enable debug hud", "Shadows")), @@ -227,7 +227,7 @@ namespace SceneUtil } } - MWShadow::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + ShadowManager::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); @@ -237,7 +237,7 @@ namespace SceneUtil pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Node& node) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Node& node) { if (isCulled(node)) return; @@ -250,7 +250,7 @@ namespace SceneUtil popCurrentMask(); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Geode& node) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Geode& node) { if (isCulled(node)) return; @@ -269,7 +269,7 @@ namespace SceneUtil popCurrentMask(); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) { if (isCulled(drawable)) return; @@ -282,7 +282,7 @@ namespace SceneUtil popCurrentMask(); } - void MWShadow::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) + void ShadowManager::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) { // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. @@ -290,19 +290,19 @@ namespace SceneUtil update(osg::Vec3(1.0, 1.0, 0.0)); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Billboard&) { OSG_INFO << "Warning Billboards not yet supported" << std::endl; return; } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Projection&) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Projection&) { // projection nodes won't affect a shadow map so their subgraphs should be ignored return; } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Transform& transform) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Transform& transform) { if (isCulled(transform)) return; @@ -326,13 +326,13 @@ namespace SceneUtil } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Camera&) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Camera&) { // camera nodes won't affect a shadow map so their subgraphs should be ignored return; } - void MWShadow::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) + void ShadowManager::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) { if (!bb.valid()) return; @@ -348,7 +348,7 @@ namespace SceneUtil update(bb.corner(7) * matrix); } - void MWShadow::ComputeLightSpaceBounds::update(const osg::Vec3& v) + void ShadowManager::ComputeLightSpaceBounds::update(const osg::Vec3& v) { if (v.z()<-1.0f) { @@ -364,7 +364,7 @@ namespace SceneUtil _bb.expandBy(osg::Vec3(x, y, v.z())); } - void MWShadow::cull(osgUtil::CullVisitor& cv) + void ShadowManager::cull(osgUtil::CullVisitor& cv) { if (!enableShadows) { @@ -851,7 +851,7 @@ namespace SceneUtil // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< settings, int castsShadowMask); static void disableShadowsForStateSet(osg::ref_ptr stateSet); - MWShadow(); + ShadowManager(); virtual void cull(osgUtil::CullVisitor& cv) override; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 76baa2f45b..85c43ce1d0 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -347,7 +347,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) { - SceneUtil::MWShadow::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); + SceneUtil::ShadowManager::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); if (shadowBoundsVisitor) shadowBoundsVisitor->apply(*this); return; From 06b2ce6646df4d7c6a22fe691f2ca06deb5643a8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:34:14 +0000 Subject: [PATCH 070/410] Fix alignment issues caused by renaming classes --- components/sceneutil/mwshadowtechnique.cpp | 2 +- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 5217b48327..e8543c8b4a 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -200,7 +200,7 @@ class VDSMCameraCullCallback : public osg::NodeCallback protected: - MWShadowTechnique* _vdsm; + MWShadowTechnique* _vdsm; osg::ref_ptr _projectionMatrix; osg::ref_ptr _renderStage; osg::Polytope _polytope; diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index efbf2ed5cd..e7465ff39f 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -144,7 +144,7 @@ namespace SceneUtil { protected: virtual ~ViewDependentData() {} - MWShadowTechnique* _viewDependentShadowMap; + MWShadowTechnique* _viewDependentShadowMap; osg::ref_ptr _stateset; From 4c31b38f773b8252262f29961d51c1d856eadad7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:58:12 +0000 Subject: [PATCH 071/410] Move CLSB changes to new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 219 +++++++++++---------- components/sceneutil/mwshadowtechnique.hpp | 27 +++ 2 files changed, 137 insertions(+), 109 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e8543c8b4a..522172f42c 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -293,122 +293,123 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) } } - -class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack +MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { -public: - ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix): - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) - { - setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); - pushViewport(viewport); - pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); - pushModelViewMatrix(new osg::RefMatrix(viewMatrix),osg::Transform::ABSOLUTE_RF); + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Node& node) +{ + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) +{ + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) +{ + // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. + + update(osg::Vec3(-1.0, -1.0, 0.0)); + update(osg::Vec3(1.0, 1.0, 0.0)); +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Billboard&) +{ + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Projection&) +{ + // projection nodes won't affect a shadow map so their subgraphs should be ignored + return; +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Transform& transform) +{ + if (isCulled(transform)) return; + + // push the culling mode. + pushCurrentMask(); + + // absolute transforms won't affect a shadow map so their subgraphs should be ignored. + if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) + { + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); + + traverse(transform); + + popModelViewMatrix(); } - void apply(osg::Node& node) + // pop the culling mode. + popCurrentMask(); + +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Camera&) +{ + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; +} + +void MWShadowTechnique::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) +{ + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); +} + +void MWShadowTechnique::ComputeLightSpaceBounds::update(const osg::Vec3& v) +{ + if (v.z()<-1.0f) { - if (isCulled(node)) return; - - // push the culling mode. - pushCurrentMask(); - - traverse(node); - - // pop the culling mode. - popCurrentMask(); - } - - void apply(osg::Drawable& drawable) - { - if (isCulled(drawable)) return; - - // push the culling mode. - pushCurrentMask(); - - updateBound(drawable.getBoundingBox()); - - // pop the culling mode. - popCurrentMask(); - } - - void apply(osg::Billboard&) - { - OSG_INFO<<"Warning Billboards not yet supported"< matrix = new osg::RefMatrix(*getModelViewMatrix()); - transform.computeLocalToWorldMatrix(*matrix,this); - pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - - traverse(transform); - - popModelViewMatrix(); - } - - // pop the culling mode. - popCurrentMask(); - - } - - void apply(osg::Camera&) - { - // camera nodes won't affect a shadow map so their subgraphs should be ignored - return; - } - - void updateBound(const osg::BoundingBox& bb) - { - if (!bb.valid()) return; - - const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); - - update(bb.corner(0) * matrix); - update(bb.corner(1) * matrix); - update(bb.corner(2) * matrix); - update(bb.corner(3) * matrix); - update(bb.corner(4) * matrix); - update(bb.corner(5) * matrix); - update(bb.corner(6) * matrix); - update(bb.corner(7) * matrix); - } - - void update(const osg::Vec3& v) - { - if (v.z()<-1.0f) - { - //OSG_NOTICE<<"discarding("<1.0f) x=1.0f; - float y = v.y(); - if (y<-1.0f) y=-1.0f; - if (y>1.0f) y=1.0f; - _bb.expandBy(osg::Vec3(x,y,v.z())); - } - - osg::BoundingBox _bb; -}; + float x = v.x(); + if (x<-1.0f) x = -1.0f; + if (x>1.0f) x = 1.0f; + float y = v.y(); + if (y<-1.0f) y = -1.0f; + if (y>1.0f) y = 1.0f; + _bb.expandBy(osg::Vec3(x, y, v.z())); +} /////////////////////////////////////////////////////////////////////////////////////////////// // diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index e7465ff39f..7cf7db1551 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -27,6 +27,8 @@ #include +#include + namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ @@ -59,6 +61,31 @@ namespace SceneUtil { /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ virtual void cleanSceneGraph(); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + { + public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + void apply(osg::Node& node); + + void apply(osg::Drawable& drawable); + + void apply(Terrain::QuadTreeWorld& quadTreeWorld); + + void apply(osg::Billboard&); + + void apply(osg::Projection&); + + void apply(osg::Transform& transform); + + void apply(osg::Camera&); + + void updateBound(const osg::BoundingBox& bb); + + void update(const osg::Vec3& v); + + osg::BoundingBox _bb; + }; struct OSGSHADOW_EXPORT Frustum { From 0f1e770c53d3216bfa7a562852263fb14155713e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 15:51:22 +0000 Subject: [PATCH 072/410] Transfer changes to cull to new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 94 ++++++++++++++++++++-- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 522172f42c..1b390e33b3 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -769,6 +769,12 @@ void MWShadowTechnique::update(osg::NodeVisitor& nv) void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) { + /* TODO: if (!enableShadows) + { + _shadowedScene->osg::Group::traverse(cv); + return; + }*/ + OSG_INFO<(cv.getCalculatedNearPlane(), minZNear); + reducedFar = osg::minimum(cv.getCalculatedFarPlane(), maxZFar); + } + else + { + reducedNear = minZNear; + reducedFar = maxZFar; + } + // return compute near far mode back to it's original settings cv.setComputeNearFarMode(cachedNearFarMode); @@ -868,11 +886,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) previous_sdl.swap(sdl); unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight(); - if (numShadowMapsPerLight>2) - { - OSG_NOTICE<<"numShadowMapsPerLight of "<getLightDataList(); for(LightDataList::iterator itr = pll.begin(); @@ -943,6 +956,20 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double yMid = (clsb._bb.yMin()+clsb._bb.yMax())*0.5f; double yRange = (clsb._bb.yMax()-clsb._bb.yMin()); + osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); + double minZ = DBL_MAX; + double maxZ = -DBL_MAX; + for (unsigned int i = 0; i < 8; i++) + { + osg::Vec3 corner = clsb._bb.corner(i); + corner = corner * cornerConverter; + + maxZ = osg::maximum(maxZ, -corner.z()); + minZ = osg::minimum(minZ, -corner.z()); + } + reducedNear = osg::maximum(reducedNear, minZ); + reducedFar = osg::minimum(reducedFar, maxZ); + // OSG_NOTICE<<" xMid="< Date: Mon, 26 Feb 2018 16:25:44 +0000 Subject: [PATCH 073/410] Make shadows disableable. --- components/sceneutil/mwshadowtechnique.cpp | 14 ++++++++++++-- components/sceneutil/mwshadowtechnique.hpp | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 1b390e33b3..23ff2e7a98 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -745,6 +745,16 @@ void MWShadowTechnique::cleanSceneGraph() OSG_INFO<<"MWShadowTechnique::cleanSceneGraph()"<osg::Group::traverse(cv); return; - }*/ + } OSG_INFO< _program; + + bool _enableShadows; }; } From 5d719e9d5fa721847b227ad75685f173490319cc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:20:01 +0000 Subject: [PATCH 074/410] Add the debug HUD to the new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 71 +++++++++++++++++----- components/sceneutil/mwshadowtechnique.hpp | 21 +++++++ 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 23ff2e7a98..e99d9d6927 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -1043,21 +1043,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) previous_sdl.erase(previous_sdl.begin()); } - /* TODO: if (debugHud) - { - osg::ref_ptr texture = sd->_texture; - osg::ref_ptr stateSet = debugGeometry[sm_i]->getOrCreateStateSet(); - stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); - - unsigned int traversalMask = cv.getTraversalMask(); - cv.setTraversalMask(debugGeometry[sm_i]->getNodeMask()); - cv.pushStateSet(stateSet); - debugCameras[sm_i]->accept(cv); - cv.popStateSet(); - cv.setTraversalMask(traversalMask); - - cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); - }*/ + if (_debugHud) + _debugHud->draw(sd->_texture, sm_i, cv); osg::ref_ptr camera = sd->_camera; @@ -2566,4 +2553,56 @@ void MWShadowTechnique::releaseGLObjects(osg::State* state) const vdd->releaseGLObjects(state); } } + if (_debugHud) + _debugHud->releaseGLObjects(state); +} + +SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) +{ + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); + mDebugProgram->addShader(vertexShader); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); + mDebugProgram->addShader(fragmentShader); + + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + { + mDebugCameras.push_back(new osg::Camera); + mDebugCameras[i]->setViewport(200 * i, 0, 200, 200); + mDebugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); + mDebugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + mDebugGeometry[i]->setCullingActive(false); + mDebugCameras[i]->addChild(mDebugGeometry[i]); + osg::ref_ptr stateSet = mDebugGeometry[i]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(mDebugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + } +} + +void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv) +{ + osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); + stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); + + // Some of these calls may be superfluous. + unsigned int traversalMask = cv.getTraversalMask(); + cv.setTraversalMask(mDebugGeometry[shadowMapNumber]->getNodeMask()); + cv.pushStateSet(stateSet); + mDebugCameras[shadowMapNumber]->accept(cv); + cv.popStateSet(); + cv.setTraversalMask(traversalMask); + + // cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); +} + +void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) const +{ + for (auto const& camera : mDebugCameras) + camera->releaseGLObjects(state); + mDebugProgram->releaseGLObjects(state); + for (auto const& node : mDebugGeometry) + node->releaseGLObjects(state); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 4b83e6bb71..7494b02bef 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -227,6 +227,27 @@ namespace SceneUtil { osg::ref_ptr _program; bool _enableShadows; + + // TODO: actually construct this + class DebugHUD : public osg::Referenced + { + public: + DebugHUD(int numberOfShadowMapsPerLight); + + void draw(); + + virtual void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv); + + virtual void releaseGLObjects(osg::State* state = 0) const; + protected: + static const int sDebugTextureUnit; + + std::vector> mDebugCameras; + osg::ref_ptr mDebugProgram; + std::vector> mDebugGeometry; + }; + + osg::ref_ptr _debugHud; }; } From 7b52091a82ab8d23d3673c305344c2351f8bdae9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:36:43 +0000 Subject: [PATCH 075/410] Make the debug hud enableable --- components/sceneutil/mwshadowtechnique.cpp | 10 ++++++++++ components/sceneutil/mwshadowtechnique.hpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e99d9d6927..dc64204a30 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -755,6 +755,16 @@ void MWShadowTechnique::enableShadows() _enableShadows = false; } +void SceneUtil::MWShadowTechnique::enableDebugHUD() +{ + _debugHud = new DebugHUD(getShadowedScene()->getShadowSettings()->getNumShadowMapsPerLight()); +} + +void SceneUtil::MWShadowTechnique::disableDebugHUD() +{ + _debugHud = nullptr; +} + MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) { return new ViewDependentData(this); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 7494b02bef..cd5a71f922 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -65,6 +65,10 @@ namespace SceneUtil { virtual void disableShadows(); + virtual void enableDebugHUD(); + + virtual void disableDebugHUD(); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: From 478367bef328109e57f4fa169673488a8f18a79c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:50:54 +0000 Subject: [PATCH 076/410] Ensure the debug HUD won't crash if settings are changed at runtime. --- components/sceneutil/mwshadowtechnique.cpp | 39 +++++++++++++--------- components/sceneutil/mwshadowtechnique.hpp | 2 ++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index dc64204a30..01e65bc36d 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2575,25 +2575,15 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) mDebugProgram->addShader(fragmentShader); for (int i = 0; i < numberOfShadowMapsPerLight; ++i) - { - mDebugCameras.push_back(new osg::Camera); - mDebugCameras[i]->setViewport(200 * i, 0, 200, 200); - mDebugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); - mDebugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - - mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); - mDebugGeometry[i]->setCullingActive(false); - mDebugCameras[i]->addChild(mDebugGeometry[i]); - osg::ref_ptr stateSet = mDebugGeometry[i]->getOrCreateStateSet(); - stateSet->setAttributeAndModes(mDebugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); - } + addAnotherShadowMap(); } void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv) { + // It might be possible to change shadow settings at runtime + if (shadowMapNumber > mDebugCameras.size()) + addAnotherShadowMap(); + osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); @@ -2616,3 +2606,22 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) for (auto const& node : mDebugGeometry) node->releaseGLObjects(state); } + +void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() +{ + unsigned int shadowMapNumber = mDebugCameras.size(); + + mDebugCameras.push_back(new osg::Camera); + mDebugCameras[shadowMapNumber]->setViewport(200 * shadowMapNumber, 0, 200, 200); + mDebugCameras[shadowMapNumber]->setRenderOrder(osg::Camera::POST_RENDER); + mDebugCameras[shadowMapNumber]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + mDebugGeometry[shadowMapNumber]->setCullingActive(false); + mDebugCameras[shadowMapNumber]->addChild(mDebugGeometry[shadowMapNumber]); + osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(mDebugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); +} diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index cd5a71f922..199babf6f6 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -244,6 +244,8 @@ namespace SceneUtil { virtual void releaseGLObjects(osg::State* state = 0) const; protected: + virtual void addAnotherShadowMap(); + static const int sDebugTextureUnit; std::vector> mDebugCameras; From 639a4f5e8c87fd08ffb397f66cdb57f4ecce8abd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:52:19 +0000 Subject: [PATCH 077/410] Remove TODO left in by accident. Also, become 100 commits ahead of upstream. --- components/sceneutil/mwshadowtechnique.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 199babf6f6..b1dcbfd311 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -232,7 +232,6 @@ namespace SceneUtil { bool _enableShadows; - // TODO: actually construct this class DebugHUD : public osg::Referenced { public: From 99db93510ce3e185cb43bc6bd86a79c63bc7de7b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 21:09:29 +0000 Subject: [PATCH 078/410] Undo minor cockup where the same file appeared twice --- components/sceneutil/mwshadowtechnique | 196 ------------------------- 1 file changed, 196 deletions(-) delete mode 100644 components/sceneutil/mwshadowtechnique diff --git a/components/sceneutil/mwshadowtechnique b/components/sceneutil/mwshadowtechnique deleted file mode 100644 index 63b80fed18..0000000000 --- a/components/sceneutil/mwshadowtechnique +++ /dev/null @@ -1,196 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * OpenSceneGraph Public License for more details. -*/ - -#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP -#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 - -#include -#include -#include -#include -#include - -#include - -namespace osgShadow { - -/** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ -class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique -{ - public : - ViewDependentShadowMap(); - - ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); - - META_Object(osgShadow, ViewDependentShadowMap); - - /** initialize the ShadowedScene and local cached data structures.*/ - virtual void init(); - - /** run the update traversal of the ShadowedScene and update any loca chached data structures.*/ - virtual void update(osg::NodeVisitor& nv); - - /** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/ - virtual void cull(osgUtil::CullVisitor& cv); - - /** Resize any per context GLObject buffers to specified size. */ - virtual void resizeGLObjectBuffers(unsigned int maxSize); - - /** If State is non-zero, this function releases any associated OpenGL objects for - * the specified graphics context. Otherwise, releases OpenGL objects - * for all graphics contexts. */ - virtual void releaseGLObjects(osg::State* = 0) const; - - /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ - virtual void cleanSceneGraph(); - - - struct OSGSHADOW_EXPORT Frustum - { - Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); - - osg::Matrixd projectionMatrix; - osg::Matrixd modelViewMatrix; - - typedef std::vector Vertices; - Vertices corners; - - typedef std::vector Indices; - typedef std::vector Faces; - Faces faces; - - typedef std::vector Edges; - Edges edges; - - osg::Vec3d eye; - osg::Vec3d centerNearPlane; - osg::Vec3d centerFarPlane; - osg::Vec3d center; - osg::Vec3d frustumCenterLine; - }; - - // forward declare - class ViewDependentData; - - struct OSGSHADOW_EXPORT LightData : public osg::Referenced - { - LightData(ViewDependentData* vdd); - - virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); - - ViewDependentData* _viewDependentData; - - osg::ref_ptr lightMatrix; - osg::ref_ptr light; - - osg::Vec4d lightPos; - osg::Vec3d lightPos3; - osg::Vec3d lightDir; - bool directionalLight; - - typedef std::vector ActiveTextureUnits; - ActiveTextureUnits textureUnits; - }; - - typedef std::list< osg::ref_ptr > LightDataList; - - struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced - { - ShadowData(ViewDependentData* vdd); - - virtual void releaseGLObjects(osg::State* = 0) const; - - ViewDependentData* _viewDependentData; - - unsigned int _textureUnit; - osg::ref_ptr _texture; - osg::ref_ptr _texgen; - osg::ref_ptr _camera; - }; - - typedef std::list< osg::ref_ptr > ShadowDataList; - - - class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced - { - public: - ViewDependentData(ViewDependentShadowMap* vdsm); - - const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } - - LightDataList& getLightDataList() { return _lightDataList; } - - ShadowDataList& getShadowDataList() { return _shadowDataList; } - - osg::StateSet* getStateSet() { return _stateset.get(); } - - virtual void releaseGLObjects(osg::State* = 0) const; - - protected: - virtual ~ViewDependentData() {} - - ViewDependentShadowMap* _viewDependentShadowMap; - - osg::ref_ptr _stateset; - - LightDataList _lightDataList; - ShadowDataList _shadowDataList; - }; - - virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); - - ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); - - - - virtual void createShaders(); - - virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; - - virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); - - virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); - - virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera); - - virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); - - virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; - - virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; - - virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; - -protected: - virtual ~ViewDependentShadowMap(); - - typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; - mutable OpenThreads::Mutex _viewDependentDataMapMutex; - ViewDependentDataMap _viewDependentDataMap; - - osg::ref_ptr _shadowRecievingPlaceholderStateSet; - - osg::ref_ptr _shadowCastingStateSet; - osg::ref_ptr _polygonOffset; - osg::ref_ptr _fallbackBaseTexture; - osg::ref_ptr _fallbackShadowMapTexture; - - typedef std::vector< osg::ref_ptr > Uniforms; - mutable OpenThreads::Mutex _accessUniformsAndProgramMutex; - Uniforms _uniforms; - osg::ref_ptr _program; -}; - -} - -#endif From 97b607fc663afc964db8b6e69cd74516a495636c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 21:10:06 +0000 Subject: [PATCH 079/410] Make whitespace match upstream OSG --- components/sceneutil/mwshadowtechnique.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index b1dcbfd311..797266287b 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -4,16 +4,16 @@ */ /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield -* -* This library is open source and may be redistributed and/or modified under -* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or -* (at your option) any later version. The full license is in LICENSE file -* included with this distribution, and on the openscenegraph.org website. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* OpenSceneGraph Public License for more details. + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. */ #ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H From e233dae1cd2cf87e03ac219c4c9572b5453580e7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 22:27:09 +0000 Subject: [PATCH 080/410] Hook up the new shadow technique --- apps/openmw/mwrender/renderingmanager.cpp | 12 +- apps/openmw/mwrender/renderingmanager.hpp | 2 + components/sceneutil/mwshadowtechnique.cpp | 8 +- components/sceneutil/mwshadowtechnique.hpp | 12 +- components/sceneutil/shadow.cpp | 817 +-------------------- components/sceneutil/shadow.hpp | 52 +- components/terrain/quadtreeworld.cpp | 4 +- 7 files changed, 46 insertions(+), 861 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a59ba8c1aa..920c7278ce 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -202,8 +202,6 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - osg::ref_ptr shadowedScene (new osgShadow::ShadowedScene); - int shadowCastingTraversalMask = Mask_Scene; if (Settings::Manager::getBool("actor shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Actor; @@ -211,15 +209,11 @@ namespace MWRender shadowCastingTraversalMask |= Mask_Player; if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - SceneUtil::ShadowManager::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); - SceneUtil::ShadowManager* tech = new SceneUtil::ShadowManager(); - shadowedScene->setShadowTechnique(tech); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode)); + mShadowManager->setupShadowSettings(shadowCastingTraversalMask); - shadowedScene->addChild(sceneRoot); - mRootNode->addChild(shadowedScene); - - Shader::ShaderManager::DefineMap shadowDefines = tech->getShadowDefines(); + Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0087e43d2..d322bfaf4f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -50,6 +50,7 @@ namespace Fallback namespace SceneUtil { + class ShadowManager; class WorkQueue; class UnrefQueue; } @@ -234,6 +235,7 @@ namespace MWRender TerrainStorage* mTerrainStorage; std::unique_ptr mSky; std::unique_ptr mEffectManager; + std::unique_ptr mShadowManager; osg::ref_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; std::unique_ptr mCamera; diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 01e65bc36d..123030b258 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -713,7 +713,9 @@ void MWShadowTechnique::ViewDependentData::releaseGLObjects(osg::State* state) c // MWShadowTechnique // MWShadowTechnique::MWShadowTechnique(): - ShadowTechnique() + ShadowTechnique(), + _enableShadows(false), + _debugHud(nullptr) { _shadowRecievingPlaceholderStateSet = new osg::StateSet; } @@ -750,7 +752,7 @@ void MWShadowTechnique::enableShadows() _enableShadows = true; } -void MWShadowTechnique::enableShadows() +void MWShadowTechnique::disableShadows() { _enableShadows = false; } @@ -2567,7 +2569,7 @@ void MWShadowTechnique::releaseGLObjects(osg::State* state) const _debugHud->releaseGLObjects(state); } -SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) +SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) : mDebugProgram(new osg::Program) { osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); mDebugProgram->addShader(vertexShader); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 797266287b..41f1d7c32d 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -32,7 +32,7 @@ namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ - class OSGSHADOW_EXPORT MWShadowTechnique : public osgShadow::ShadowTechnique + class MWShadowTechnique : public osgShadow::ShadowTechnique { public: MWShadowTechnique(); @@ -95,7 +95,7 @@ namespace SceneUtil { osg::BoundingBox _bb; }; - struct OSGSHADOW_EXPORT Frustum + struct Frustum { Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); @@ -122,7 +122,7 @@ namespace SceneUtil { // forward declare class ViewDependentData; - struct OSGSHADOW_EXPORT LightData : public osg::Referenced + struct LightData : public osg::Referenced { LightData(ViewDependentData* vdd); @@ -144,7 +144,7 @@ namespace SceneUtil { typedef std::list< osg::ref_ptr > LightDataList; - struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + struct ShadowData : public osg::Referenced { ShadowData(ViewDependentData* vdd); @@ -161,7 +161,7 @@ namespace SceneUtil { typedef std::list< osg::ref_ptr > ShadowDataList; - class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + class ViewDependentData : public osg::Referenced { public: ViewDependentData(MWShadowTechnique* vdsm); @@ -245,7 +245,7 @@ namespace SceneUtil { protected: virtual void addAnotherShadowMap(); - static const int sDebugTextureUnit; + static const int sDebugTextureUnit = 0; std::vector> mDebugCameras; osg::ref_ptr mDebugProgram; diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 8c729e3cc1..8c58cb6033 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -13,48 +13,17 @@ namespace SceneUtil { using namespace osgShadow; - std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; - std::string debugFragmentShaderSource = - "uniform sampler2D texture; \n" - " \n" - "void main(void) \n" - "{ \n" -#if 1 - " float f = texture2D( texture, gl_TexCoord[0].xy ).r; \n" - " \n" - " f = 256.0 * f; \n" - " float fC = floor( f ) / 256.0; \n" - " \n" - " f = 256.0 * fract( f ); \n" - " float fS = floor( f ) / 256.0; \n" - " \n" - " f = 256.0 * fract( f ); \n" - " float fH = floor( f ) / 256.0; \n" - " \n" - " fS *= 0.5; \n" - " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" - " \n" - " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" - " abs( fC - 0.333333 ), \n" - " abs( fC - 0.666667 ) ); \n" - " \n" - " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" - " \n" - " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" - " fMax = 1.0 / fMax; \n" - " \n" - " vec3 color = fMax * rgb; \n" - " \n" - " gl_FragColor = vec4( fS + fH * color, 1 ); \n" -#else - " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" -#endif - "} \n"; - - void ShadowManager::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) + void ShadowManager::setupShadowSettings(int castsShadowMask) { if (!Settings::Manager::getBool("enable shadows", "Shadows")) + { + mShadowTechnique->disableShadows(); return; + } + else + mShadowTechnique->enableShadows(); + + osg::ref_ptr settings = mShadowedScene->getShadowSettings(); settings->setLightNum(0); settings->setCastsShadowTraversalMask(castsShadowMask); @@ -70,6 +39,11 @@ namespace SceneUtil int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); settings->setTextureSize(osg::Vec2s(mapres, mapres)); + + if (Settings::Manager::getBool("enable debug hud", "Shadows")) + mShadowTechnique->enableDebugHUD(); + else + mShadowTechnique->disableDebugHUD(); } void ShadowManager::disableShadowsForStateSet(osg::ref_ptr stateset) @@ -87,768 +61,15 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), - debugHud(Settings::Manager::getBool("enable debug hud", "Shadows")), - debugProgram(new osg::Program), debugTextureUnit(0) + mShadowedScene(new osgShadow::ShadowedScene), + mShadowTechnique(new MWShadowTechnique) { - if (debugHud) - { - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); - debugProgram->addShader(vertexShader); - osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); - debugProgram->addShader(fragmentShader); - - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) - { - std::cout << i << std::endl; - - debugCameras.push_back(new osg::Camera); - debugCameras[i]->setViewport(200 * i, 0, 200, 200); - debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); - debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - - debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); - debugGeometry[i]->setCullingActive(false); - debugCameras[i]->addChild(debugGeometry[i]); - osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); - stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); - } - } - } - - class VDSMCameraCullCallback : public osg::NodeCallback - { - public: - - VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); - - virtual void operator()(osg::Node*, osg::NodeVisitor* nv); - - osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); } - osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); } - - protected: - - ViewDependentShadowMap* _vdsm; - osg::ref_ptr _projectionMatrix; - osg::ref_ptr _renderStage; - osg::Polytope _polytope; - }; - - VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope) : - _vdsm(vdsm), - _polytope(polytope) - { - } - - void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = dynamic_cast(nv); - osg::Camera* camera = dynamic_cast(node); - OSG_INFO << "VDSMCameraCullCallback::operator()(osg::Node* " << camera << ", osg::NodeVisitor* " << cv << ")" << std::endl; - -#if 1 - if (!_polytope.empty()) - { - OSG_INFO << "Pushing custom Polytope" << std::endl; - - osg::CullingSet& cs = cv->getProjectionCullingStack().back(); - - cs.setFrustum(_polytope); - - cv->pushCullingSet(); - } -#endif - if (_vdsm->getShadowedScene()) - { - _vdsm->getShadowedScene()->osg::Group::traverse(*nv); - } -#if 1 - if (!_polytope.empty()) - { - OSG_INFO << "Popping custom Polytope" << std::endl; - cv->popCullingSet(); - } -#endif - - _renderStage = cv->getCurrentRenderBin()->getStage(); - - OSG_INFO << "VDSM second : _renderStage = " << _renderStage << std::endl; - - if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - // make sure that the near plane is computed correctly. - cv->computeNearPlane(); - - osg::Matrixd projection = *(cv->getProjectionMatrix()); - - OSG_INFO << "RTT Projection matrix " << projection << std::endl; - - osg::Matrix::value_type left, right, bottom, top, zNear, zFar; - osg::Matrix::value_type epsilon = 1e-6; - if (fabs(projection(0, 3))setProjectionMatrix(projection); - - _projectionMatrix = cv->getProjectionMatrix(); - } - } - - ShadowManager::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) - { - setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); - - pushViewport(viewport); - pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); - pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Node& node) - { - if (isCulled(node)) return; - - // push the culling mode. - pushCurrentMask(); - - traverse(node); - - // pop the culling mode. - popCurrentMask(); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Geode& node) - { - if (isCulled(node)) return; - - // push the culling mode. - pushCurrentMask(); - - for (unsigned int i = 0; igetBoundingBox()); - } - } - - // pop the culling mode. - popCurrentMask(); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) - { - if (isCulled(drawable)) return; - - // push the culling mode. - pushCurrentMask(); - - updateBound(drawable.getBoundingBox()); - - // pop the culling mode. - popCurrentMask(); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) - { - // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. - - update(osg::Vec3(-1.0, -1.0, 0.0)); - update(osg::Vec3(1.0, 1.0, 0.0)); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Billboard&) - { - OSG_INFO << "Warning Billboards not yet supported" << std::endl; - return; - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Projection&) - { - // projection nodes won't affect a shadow map so their subgraphs should be ignored - return; - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Transform& transform) - { - if (isCulled(transform)) return; - - // push the culling mode. - pushCurrentMask(); - - // absolute transforms won't affect a shadow map so their subgraphs should be ignored. - if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) - { - osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); - transform.computeLocalToWorldMatrix(*matrix, this); - pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - - traverse(transform); - - popModelViewMatrix(); - } - - // pop the culling mode. - popCurrentMask(); - - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Camera&) - { - // camera nodes won't affect a shadow map so their subgraphs should be ignored - return; - } - - void ShadowManager::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) - { - if (!bb.valid()) return; - - const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); - - update(bb.corner(0) * matrix); - update(bb.corner(1) * matrix); - update(bb.corner(2) * matrix); - update(bb.corner(3) * matrix); - update(bb.corner(4) * matrix); - update(bb.corner(5) * matrix); - update(bb.corner(6) * matrix); - update(bb.corner(7) * matrix); - } - - void ShadowManager::ComputeLightSpaceBounds::update(const osg::Vec3& v) - { - if (v.z()<-1.0f) - { - //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; - float y = v.y(); - if (y<-1.0f) y = -1.0f; - if (y>1.0f) y = 1.0f; - _bb.expandBy(osg::Vec3(x, y, v.z())); - } - - void ShadowManager::cull(osgUtil::CullVisitor& cv) - { - if (!enableShadows) - { - _shadowedScene->osg::Group::traverse(cv); - return; - } - - OSG_INFO << std::endl << std::endl << "ViewDependentShadowMap::cull(osg::CullVisitor&" << &cv << ")" << std::endl; - - if (!_shadowCastingStateSet) - { - OSG_INFO << "Warning, init() has not yet been called so ShadowCastingStateSet has not been setup yet, unable to create shadows." << std::endl; - _shadowedScene->osg::Group::traverse(cv); - return; - } - - ViewDependentData* vdd = getViewDependentData(&cv); - - if (!vdd) - { - OSG_INFO << "Warning, now ViewDependentData created, unable to create shadows." << std::endl; - _shadowedScene->osg::Group::traverse(cv); - return; - } - - ShadowSettings* settings = getShadowedScene()->getShadowSettings(); - - OSG_INFO << "cv->getProjectionMatrix()=" << *cv.getProjectionMatrix() << std::endl; - - osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode(); - - osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix(); - - // check whether this main views projection is perspective or orthographic - bool orthographicViewFrustum = viewProjectionMatrix(0, 3) == 0.0 && - viewProjectionMatrix(1, 3) == 0.0 && - viewProjectionMatrix(2, 3) == 0.0; - - double minZNear = 0.0; - double maxZFar = DBL_MAX; - - if (cachedNearFarMode == osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - double left, right, top, bottom; - if (orthographicViewFrustum) - { - viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar); - } - else - { - viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar); - } - OSG_INFO << "minZNear=" << minZNear << ", maxZFar=" << maxZFar << std::endl; - } - - // set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible - if (settings->getComputeNearFarModeOverride() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride()); - } - - // 1. Traverse main scene graph - cv.pushStateSet(_shadowRecievingPlaceholderStateSet.get()); - - osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); - - cullShadowReceivingScene(&cv); - - cv.popStateSet(); - - if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - OSG_INFO << "Just done main subgraph traversak" << std::endl; - // make sure that the near plane is computed correctly so that any projection matrix computations - // are all done correctly. - cv.computeNearPlane(); - } - - // clamp the minZNear and maxZFar to those provided by ShadowSettings - maxZFar = osg::minimum(settings->getMaximumShadowMapDistance(), maxZFar); - if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); - - //OSG_NOTICE<<"maxZFar "<(cv.getCalculatedNearPlane(), minZNear); - reducedFar = osg::minimum(cv.getCalculatedFarPlane(), maxZFar); - } - else - { - reducedNear = minZNear; - reducedFar = maxZFar; - } - - // return compute near far mode back to it's original settings - cv.setComputeNearFarMode(cachedNearFarMode); - - OSG_INFO << "frustum.eye=" << frustum.eye << ", frustum.centerNearPlane, " << frustum.centerNearPlane << " distance = " << (frustum.eye - frustum.centerNearPlane).length() << std::endl; - - - // 2. select active light sources - // create a list of light sources + their matrices to place them - selectActiveLights(&cv, vdd); - - - unsigned int pos_x = 0; - unsigned int textureUnit = settings->getBaseShadowTextureUnit(); - unsigned int numValidShadows = 0; - - ShadowDataList& sdl = vdd->getShadowDataList(); - ShadowDataList previous_sdl; - previous_sdl.swap(sdl); - - unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight(); - /*if (numShadowMapsPerLight>2) - { - OSG_NOTICE << "numShadowMapsPerLight of " << numShadowMapsPerLight << " is greater than maximum supported, falling back to 2." << std::endl; - numShadowMapsPerLight = 2; - }*/ - - LightDataList& pll = vdd->getLightDataList(); - for (LightDataList::iterator itr = pll.begin(); - itr != pll.end(); - ++itr) - { - // 3. create per light/per shadow map division of lightspace/frustum - // create a list of light/shadow map data structures - - LightData& pl = **itr; - - // 3.1 compute light space polytope - // - osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); - - // if polytope is empty then no rendering. - if (polytope.empty()) - { - OSG_NOTICE << "Polytope empty no shadow to render" << std::endl; - continue; - } - - // 3.2 compute RTT camera view+projection matrix settings - // - osg::Matrixd projectionMatrix; - osg::Matrixd viewMatrix; - if (!computeShadowCameraSettings(frustum, pl, projectionMatrix, viewMatrix)) - { - OSG_NOTICE << "No valid Camera settings, no shadow to render" << std::endl; - continue; - } - - // if we are using multiple shadow maps and CastShadowTraversalMask is being used - // traverse the scene to compute the extents of the objects - if (/*numShadowMapsPerLight>1 &&*/ _shadowedScene->getCastsShadowTraversalMask() != 0xffffffff) - { - // osg::ElapsedTime timer; - - osg::ref_ptr viewport = new osg::Viewport(0, 0, 2048, 2048); - ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); - clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); - - osg::Matrixd invertModelView; - invertModelView.invert(viewMatrix); - osg::Polytope local_polytope(polytope); - local_polytope.transformProvidingInverse(invertModelView); - - osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); - cs.setFrustum(local_polytope); - clsb.pushCullingSet(); - - _shadowedScene->accept(clsb); - - // OSG_NOTICE<<"Extents of LightSpace "<(maxZ, -corner.z()); - minZ = osg::minimum(minZ, -corner.z()); - } - reducedNear = osg::maximum(reducedNear, minZ); - reducedFar = osg::minimum(reducedFar, maxZ); - - // OSG_NOTICE<<" xMid="< texture = sd->_texture; - osg::ref_ptr stateSet = debugGeometry[sm_i]->getOrCreateStateSet(); - stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); - - unsigned int traversalMask = cv.getTraversalMask(); - cv.setTraversalMask(debugGeometry[sm_i]->getNodeMask()); - cv.pushStateSet(stateSet); - debugCameras[sm_i]->accept(cv); - cv.popStateSet(); - cv.setTraversalMask(traversalMask); - - cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); - } - - osg::ref_ptr camera = sd->_camera; - - camera->setProjectionMatrix(projectionMatrix); - camera->setViewMatrix(viewMatrix); - - if (settings->getDebugDraw()) - { - camera->getViewport()->x() = pos_x; - pos_x += static_cast(camera->getViewport()->width()) + 40; - } - - // transform polytope in model coords into light spaces eye coords. - osg::Matrixd invertModelView; - invertModelView.invert(camera->getViewMatrix()); - - osg::Polytope local_polytope(polytope); - local_polytope.transformProvidingInverse(invertModelView); - - - if (numShadowMapsPerLight>1) - { - // compute the start and end range in non-dimensional coords -#if 0 - double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); - double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); -#elif 0 - - // hardwired for 2 splits - double r_start = (sm_i == 0) ? -1.0 : splitPoint; - double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; -#elif 0 - double r_start, r_end; - // Split such that each shadow map covers a quarter of the area of the one after it - if (sm_i == 0) - r_start = -1.0; - else - { - r_start = (1 - pow(4.0, sm_i)) / (1 - pow(4.0, numShadowMapsPerLight)); - r_start *= 2.0; - //r_start += double(sm_i) / double(numShadowMapsPerLight); - r_start -= 1.0; - } - - if (sm_i + 1 == numShadowMapsPerLight) - r_end = 1.0; - else - { - r_end = (1 - pow(4.0, sm_i + 1)) / (1 - pow(4.0, numShadowMapsPerLight)); - r_end *= 2.0; - //r_end += double(sm_i + 1) / double(numShadowMapsPerLight); - r_end -= 1.0; - } -#else - double r_start, r_end; - - // split system based on the original Parallel Split Shadow Maps paper. - double n = reducedNear; - double f = reducedFar; - double i = double(sm_i); - double m = double(numShadowMapsPerLight); - double ratio = Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"); - double deltaBias = Settings::Manager::getFloat("split point bias", "Shadows"); - if (sm_i == 0) - r_start = -1.0; - else - { - // compute the split point in main camera view - double ciLog = n * pow(f / n, i / m); - double ciUniform = n + (f - n) * i / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; - - // work out where this is in light space - osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; - osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; - r_start = lightSpacePos.y(); - } - - if (sm_i + 1 == numShadowMapsPerLight) - r_end = 1.0; - else - { - // compute the split point in main camera view - double ciLog = n * pow(f / n, (i + 1) / m); - double ciUniform = n + (f - n) * (i + 1) / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; - - // work out where this is in light space - osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; - osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; - r_end = lightSpacePos.y(); - } -#endif - - // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap - // to prevent a seam showing through between the shadowmaps - if (sm_i + 10) - { - // not the first shadowmap so insert a polytope to clip the scene from before r_start - - // plane in clip space coords - osg::Plane plane(0.0, 1.0, 0.0, -r_start); - - // transform into eye coords - plane.transformProvidingInverse(projectionMatrix); - local_polytope.getPlaneList().push_back(plane); - - //OSG_NOTICE<<"Adding r_start plane "<0) - { - decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); - } - - // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<setShadowTechnique(mShadowTechnique); + mShadowedScene->addChild(sceneRoot); + rootNode->addChild(mShadowedScene); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index cfe1a4f3f4..5ac2711852 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -2,69 +2,35 @@ #define COMPONENTS_SCENEUTIL_SHADOW_H #include -#include #include #include +#include "mwshadowtechnique.hpp" + namespace SceneUtil { - class ShadowManager : public osgShadow::ViewDependentShadowMap + class ShadowManager { public: - static void setupShadowSettings(osg::ref_ptr settings, int castsShadowMask); - static void disableShadowsForStateSet(osg::ref_ptr stateSet); - ShadowManager(); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode); - virtual void cull(osgUtil::CullVisitor& cv) override; + virtual void setupShadowSettings(int castsShadowMask); virtual Shader::ShaderManager::DefineMap getShadowDefines(); virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); - - class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack - { - public: - ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); - - void apply(osg::Node& node); - - void apply(osg::Geode& node); - - void apply(osg::Drawable& drawable); - - void apply(Terrain::QuadTreeWorld& quadTreeWorld); - - void apply(osg::Billboard&); - - void apply(osg::Projection&); - - void apply(osg::Transform& transform); - - void apply(osg::Camera&); - - void updateBound(const osg::BoundingBox& bb); - - void update(const osg::Vec3& v); - - osg::BoundingBox _bb; - }; protected: - const int debugTextureUnit; - - std::vector> debugCameras; - - osg::ref_ptr debugProgram; - - std::vector> debugGeometry; - const int numberOfShadowMapsPerLight; const bool enableShadows; - const bool debugHud; const int baseShadowTextureUnit; + + osg::ref_ptr mShadowedScene; + + osg::ref_ptr mShadowTechnique; }; } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 85c43ce1d0..651b2cd24d 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include "quadtreenode.hpp" #include "storage.hpp" @@ -347,7 +347,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) { - SceneUtil::ShadowManager::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); + SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); if (shadowBoundsVisitor) shadowBoundsVisitor->apply(*this); return; From 882b63cba97913f1b3f1897d4f3da8e485c65ca3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 23:00:46 +0000 Subject: [PATCH 081/410] Make split point control parameters configurable with the new shadow technique. --- components/sceneutil/mwshadowtechnique.cpp | 16 ++++++++++++---- components/sceneutil/mwshadowtechnique.hpp | 7 +++++++ components/sceneutil/shadow.cpp | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 123030b258..fbf0fc9d24 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -767,6 +767,16 @@ void SceneUtil::MWShadowTechnique::disableDebugHUD() _debugHud = nullptr; } +void SceneUtil::MWShadowTechnique::setSplitPointUniformLogarithmicRatio(double ratio) +{ + _splitPointUniformLogRatio = ratio; +} + +void SceneUtil::MWShadowTechnique::setSplitPointDeltaBias(double bias) +{ + _splitPointDeltaBias = bias; +} + MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) { return new ViewDependentData(this); @@ -1096,8 +1106,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double f = reducedFar; double i = double(sm_i); double m = double(numShadowMapsPerLight); - double ratio = 0.5; // TODO: Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"); - double deltaBias = 0.0; // TODO: Settings::Manager::getFloat("split point bias", "Shadows"); if (sm_i == 0) r_start = -1.0; else @@ -1105,7 +1113,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // compute the split point in main camera view double ciLog = n * pow(f / n, i / m); double ciUniform = n + (f - n) * i / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; + double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; @@ -1120,7 +1128,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // compute the split point in main camera view double ciLog = n * pow(f / n, (i + 1) / m); double ciUniform = n + (f - n) * (i + 1) / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; + double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 41f1d7c32d..1fad0eee52 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -69,6 +69,10 @@ namespace SceneUtil { virtual void disableDebugHUD(); + virtual void setSplitPointUniformLogarithmicRatio(double ratio); + + virtual void setSplitPointDeltaBias(double bias); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: @@ -232,6 +236,9 @@ namespace SceneUtil { bool _enableShadows; + double _splitPointUniformLogRatio = 0.5; + double _splitPointDeltaBias = 0.0; + class DebugHUD : public osg::Referenced { public: diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 8c58cb6033..99cb71beb1 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -40,6 +40,9 @@ namespace SceneUtil int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); settings->setTextureSize(osg::Vec2s(mapres, mapres)); + mShadowTechnique->setSplitPointUniformLogarithmicRatio(Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows")); + mShadowTechnique->setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); + if (Settings::Manager::getBool("enable debug hud", "Shadows")) mShadowTechnique->enableDebugHUD(); else From 35eb71052e8d6cb530f4380a2e57711369a328b8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 23:52:46 +0000 Subject: [PATCH 082/410] Tidy up the shadow manager --- components/sceneutil/shadow.cpp | 38 ++++++++++++++++----------------- components/sceneutil/shadow.hpp | 7 ++---- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 99cb71beb1..9d25b57646 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -15,30 +15,30 @@ namespace SceneUtil void ShadowManager::setupShadowSettings(int castsShadowMask) { - if (!Settings::Manager::getBool("enable shadows", "Shadows")) + mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows"); + + if (!mEnableShadows) { mShadowTechnique->disableShadows(); return; } - else - mShadowTechnique->enableShadows(); + + mShadowTechnique->enableShadows(); - osg::ref_ptr settings = mShadowedScene->getShadowSettings(); - - settings->setLightNum(0); - settings->setCastsShadowTraversalMask(castsShadowMask); - settings->setReceivesShadowTraversalMask(~0u); + mShadowSettings->setLightNum(0); + mShadowSettings->setCastsShadowTraversalMask(castsShadowMask); + mShadowSettings->setReceivesShadowTraversalMask(~0u); int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); - settings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); - settings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); + mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); + mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); - settings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows")); + mShadowSettings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows")); if (Settings::Manager::getBool("compute tight scene bounds", "Shadows")) - settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); - settings->setTextureSize(osg::Vec2s(mapres, mapres)); + mShadowSettings->setTextureSize(osg::Vec2s(mapres, mapres)); mShadowTechnique->setSplitPointUniformLogarithmicRatio(Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows")); mShadowTechnique->setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); @@ -64,25 +64,25 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), - numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), - baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), - mShadowedScene(new osgShadow::ShadowedScene), + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : mShadowedScene(new osgShadow::ShadowedScene), mShadowTechnique(new MWShadowTechnique) { mShadowedScene->setShadowTechnique(mShadowTechnique); + mShadowedScene->addChild(sceneRoot); rootNode->addChild(mShadowedScene); + + mShadowSettings = mShadowedScene->getShadowSettings(); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() { - if (!enableShadows) + if (!mEnableShadows) return getShadowsDisabledDefines(); Shader::ShaderManager::DefineMap definesWithShadows; definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + for (int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 5ac2711852..2936941ff3 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -23,13 +23,10 @@ namespace SceneUtil virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); protected: - const int numberOfShadowMapsPerLight; - const bool enableShadows; - - const int baseShadowTextureUnit; + bool mEnableShadows; osg::ref_ptr mShadowedScene; - + osg::ref_ptr mShadowSettings; osg::ref_ptr mShadowTechnique; }; } From f9cf1ac94b7f436aaedf77f0898b8fdba4ca3e5b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 00:13:51 +0000 Subject: [PATCH 083/410] Separate indoor and outdoor shadow casting masks. --- apps/openmw/mwrender/renderingmanager.cpp | 9 ++++++--- components/sceneutil/shadow.cpp | 20 ++++++++++++++++---- components/sceneutil/shadow.hpp | 11 +++++++++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 920c7278ce..5971de9662 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -202,7 +202,7 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - int shadowCastingTraversalMask = Mask_Scene; + int shadowCastingTraversalMask = 0; if (Settings::Manager::getBool("actor shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Actor; if (Settings::Manager::getBool("player shadows", "Shadows")) @@ -210,8 +210,7 @@ namespace MWRender if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode)); - mShadowManager->setupShadowSettings(shadowCastingTraversalMask); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Scene | shadowCastingTraversalMask, shadowCastingTraversalMask)); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); @@ -462,6 +461,10 @@ namespace MWRender void RenderingManager::setSkyEnabled(bool enabled) { mSky->setEnabled(enabled); + if (enabled) + mShadowManager->enableOutdoorMode(); + else + mShadowManager->enableIndoorMode(); } bool RenderingManager::toggleRenderMode(RenderMode mode) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 9d25b57646..00e6b93a99 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -13,7 +13,7 @@ namespace SceneUtil { using namespace osgShadow; - void ShadowManager::setupShadowSettings(int castsShadowMask) + void ShadowManager::setupShadowSettings() { mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows"); @@ -26,7 +26,6 @@ namespace SceneUtil mShadowTechnique->enableShadows(); mShadowSettings->setLightNum(0); - mShadowSettings->setCastsShadowTraversalMask(castsShadowMask); mShadowSettings->setReceivesShadowTraversalMask(~0u); int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); @@ -64,8 +63,10 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : mShadowedScene(new osgShadow::ShadowedScene), - mShadowTechnique(new MWShadowTechnique) + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask) : mShadowedScene(new osgShadow::ShadowedScene), + mShadowTechnique(new MWShadowTechnique), + mOutdoorShadowCastingMask(outdoorShadowCastingMask), + mIndoorShadowCastingMask(indoorShadowCastingMask) { mShadowedScene->setShadowTechnique(mShadowTechnique); @@ -73,6 +74,9 @@ namespace SceneUtil rootNode->addChild(mShadowedScene); mShadowSettings = mShadowedScene->getShadowSettings(); + setupShadowSettings(); + + enableOutdoorMode(); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() @@ -98,4 +102,12 @@ namespace SceneUtil return definesWithShadows; } + void ShadowManager::enableIndoorMode() + { + mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); + } + void ShadowManager::enableOutdoorMode() + { + mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); + } } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 2936941ff3..61a564a2a8 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -15,16 +15,23 @@ namespace SceneUtil public: static void disableShadowsForStateSet(osg::ref_ptr stateSet); - ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask); - virtual void setupShadowSettings(int castsShadowMask); + virtual void setupShadowSettings(); virtual Shader::ShaderManager::DefineMap getShadowDefines(); virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); + + virtual void enableIndoorMode(); + + virtual void enableOutdoorMode(); protected: bool mEnableShadows; + unsigned int mOutdoorShadowCastingMask; + unsigned int mIndoorShadowCastingMask; + osg::ref_ptr mShadowedScene; osg::ref_ptr mShadowSettings; osg::ref_ptr mShadowTechnique; From 66a114d6ecb32a5112c3a3a2f1516954e41b3f4b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 14:15:06 +0000 Subject: [PATCH 084/410] Fix a couple of warnings --- components/sceneutil/shadow.cpp | 2 +- components/sceneutil/shadow.hpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 00e6b93a99..9b20544790 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -86,7 +86,7 @@ namespace SceneUtil Shader::ShaderManager::DefineMap definesWithShadows; definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - for (int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) + for (unsigned int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 61a564a2a8..6a3fccea64 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -17,6 +17,8 @@ namespace SceneUtil ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask); + virtual ~ShadowManager() = default; + virtual void setupShadowSettings(); virtual Shader::ShaderManager::DefineMap getShadowDefines(); From 3fe8dc63090c6d5ea8f4ef435495cc90d014010b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 16:05:11 +0000 Subject: [PATCH 085/410] Remove leftover import --- apps/openmw/mwrender/renderingmanager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5aa9da425e..773363051b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,8 +13,6 @@ #include #include -#include - #include #include From 451d0de4631029fd53733ef0f2412ad0f35f959a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 16:18:42 +0000 Subject: [PATCH 086/410] Remove dependency on osgAnimation that somehow snuck in --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4513d6996a..c2d4304e45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX osgShadow) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS From bc4b4c66e432914ffa8cbf8ce78b0952f1c2717e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 16:54:48 +0000 Subject: [PATCH 087/410] (Hopefully) add include which G++ requires even though VC++ doesn't. --- components/sceneutil/shadow.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 6a3fccea64..9444591c96 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -2,6 +2,7 @@ #define COMPONENTS_SCENEUTIL_SHADOW_H #include +#include #include #include From fc4190279820e0bbd4c7d075eefab7acab8862e3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 14:37:11 +0000 Subject: [PATCH 088/410] Replace a dynamic cast with string comarison --- components/sceneutil/mwshadowtechnique.cpp | 2 ++ components/terrain/quadtreeworld.cpp | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index fbf0fc9d24..80e2c1d387 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -301,6 +301,8 @@ MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewpor pushViewport(viewport); pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + + setName("SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds,AcceptedByComponentsTerrainQuadTreeWorld"); } void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Node& node) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 651b2cd24d..e1beaee026 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -347,9 +347,16 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) { - SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); - if (shadowBoundsVisitor) - shadowBoundsVisitor->apply(*this); + if (nv.getName().find("AcceptedByComponentsTerrainQuadTreeWorld") != std::string::npos) + { + if (nv.getName().find("SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds") != std::string::npos) + { + SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds* clsb = static_cast(&nv); + clsb->apply(*this); + } + else + nv.apply(*mRootNode); + } return; } From 6f582f5411abb761d89a7a946fd76bd625800f9d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 17:30:53 +0000 Subject: [PATCH 089/410] Make indoor shadows do something meaningful. --- apps/openmw/mwrender/objects.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwrender/vismask.hpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f0a3d2e381..28b7732c36 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -73,6 +73,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight) { insertBegin(ptr); + ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object); osg::ref_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 773363051b..aabfa91a7b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -200,7 +200,7 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - int shadowCastingTraversalMask = 0; + int shadowCastingTraversalMask = Mask_Scene; if (Settings::Manager::getBool("actor shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Actor; if (Settings::Manager::getBool("player shadows", "Shadows")) @@ -208,7 +208,7 @@ namespace MWRender if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Scene | shadowCastingTraversalMask, shadowCastingTraversalMask)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Object | shadowCastingTraversalMask, shadowCastingTraversalMask)); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index d52c7c232e..53026150b5 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -33,6 +33,7 @@ namespace MWRender Mask_SimpleWater = (1<<7), Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), + Mask_Object = (1<<18), // TODO: get Scrawl or Zini to decide if we want this to be (1<<10) and to shift all of the other masks by one. // child of Sky Mask_Sun = (1<<10), From cfad38b8690adc68a587ad8888b55b42bda039c6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 17:32:45 +0000 Subject: [PATCH 090/410] Make masks consecutive and ordered. --- apps/openmw/mwrender/vismask.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 53026150b5..1d94b4bf9d 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -33,26 +33,26 @@ namespace MWRender Mask_SimpleWater = (1<<7), Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), - Mask_Object = (1<<18), // TODO: get Scrawl or Zini to decide if we want this to be (1<<10) and to shift all of the other masks by one. + Mask_Object = (1<<10), // child of Sky - Mask_Sun = (1<<10), - Mask_WeatherParticles = (1<<11), + Mask_Sun = (1<<11), + Mask_WeatherParticles = (1<<12), // top level masks - Mask_Scene = (1<<12), - Mask_GUI = (1<<13), + Mask_Scene = (1<<13), + Mask_GUI = (1<<14), // Set on a ParticleSystem Drawable - Mask_ParticleSystem = (1<<14), + Mask_ParticleSystem = (1<<15), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<15), + Mask_RenderToTexture = (1<<16), - Mask_PreCompile = (1<<16), + Mask_PreCompile = (1<<17), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<17) + Mask_Lighting = (1<<18) }; } From 94c7cf414f858f5818f97dbf681f7d540adee5ff Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 18:28:32 +0000 Subject: [PATCH 091/410] Update documentation to clarify the effects of using shadows without shaders. --- docs/source/reference/modding/settings/shaders.rst | 1 + docs/source/reference/modding/settings/shadows.rst | 4 ++++ files/settings-default.cfg | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/shaders.rst b/docs/source/reference/modding/settings/shaders.rst index 17d0929174..dbce11464c 100644 --- a/docs/source/reference/modding/settings/shaders.rst +++ b/docs/source/reference/modding/settings/shaders.rst @@ -1,6 +1,7 @@ Shader Settings ############### +.. _force-shaders-label: force shaders ------------- diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index a0e902d7b2..fe471df1e4 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -13,6 +13,10 @@ enable shadows Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. +When used in fixed-function mode, shadowed regions will appear completely black. +To prevent this, enable :ref:`force-shaders-label`. +A keen developer may be able to implement something better using the advice of `this post`_, but it may be more difficult than it seems. + number of shadow maps --------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e2632f9e59..ae3d6eefcd 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -474,7 +474,7 @@ companion w = 0.38 companion h = 0.63 [Shadows] -# Enable or disable shadows. +# Enable or disable shadows. Bear in mind that when used without "[Shaders]/force shaders" set to true (i.e. objects and terrain are rendered in fixed-function mode) shadowed areas will be completely black. As such, it is recommended to use this feature in conjunction with shaders. enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 From 4acd9228ee2a86bacf2f22e09d4a2e5dc1709301 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 18:30:17 +0000 Subject: [PATCH 092/410] fix RST error --- docs/source/reference/modding/settings/shadows.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index fe471df1e4..8e3b79c003 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -15,7 +15,7 @@ Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. When used in fixed-function mode, shadowed regions will appear completely black. To prevent this, enable :ref:`force-shaders-label`. -A keen developer may be able to implement something better using the advice of `this post`_, but it may be more difficult than it seems. +A keen developer may be able to implement something better using the advice of `this post `_, but it may be more difficult than it seems. number of shadow maps From d6a7aec971c2ba0b041c58cc6e0497180b5e84d6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 01:54:21 +0000 Subject: [PATCH 093/410] Make RenderingManager::configureAmbient do what it was intended to. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aabfa91a7b..680f4ebd02 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -416,7 +416,7 @@ namespace MWRender osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); mSunLight->setDiffuse(diffuse); mSunLight->setSpecular(diffuse); - mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); + mSunLight->setPosition(osg::Vec4f(-1.f, 1.f, 1.f, 0.f)); } void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular) From 3bed2a7b010bee4f53d81ae733a8f2b2492be8a7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 02:01:03 +0000 Subject: [PATCH 094/410] Fix some copiler warnings (hopefully) --- components/sceneutil/shadow.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 9444591c96..6829046506 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -32,12 +32,12 @@ namespace SceneUtil protected: bool mEnableShadows; - unsigned int mOutdoorShadowCastingMask; - unsigned int mIndoorShadowCastingMask; - osg::ref_ptr mShadowedScene; osg::ref_ptr mShadowSettings; osg::ref_ptr mShadowTechnique; + + unsigned int mOutdoorShadowCastingMask; + unsigned int mIndoorShadowCastingMask; }; } From b553b58de5d5b1bb0c5cdffc35dac2b1e3fe2cd9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 02:03:16 +0000 Subject: [PATCH 095/410] Fix another compiler warning --- components/sceneutil/mwshadowtechnique.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 80e2c1d387..11089a49c2 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1015,6 +1015,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } +#if 0 double splitPoint = 0.0; if (numShadowMapsPerLight>1) @@ -1049,6 +1050,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) OSG_INFO<<" n="< Date: Sat, 3 Mar 2018 15:06:05 +0000 Subject: [PATCH 097/410] Apply Scrawl's fix for the local map --- apps/openmw/mwrender/localmap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 97e9c817a9..70d7a1dbe6 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -171,7 +171,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene|Mask_SimpleWater|Mask_Terrain); + camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -372,7 +372,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain); + computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); From e46bf28e5fc028d6268c0fa255ab5a0e36adc5f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 15:13:36 +0000 Subject: [PATCH 098/410] Add object shadows setting --- apps/openmw/mwrender/renderingmanager.cpp | 6 +++++- files/settings-default.cfg | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 680f4ebd02..33ce9346bf 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -207,8 +207,12 @@ namespace MWRender shadowCastingTraversalMask |= Mask_Player; if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; + + int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; + if (Settings::Manager::getBool("object shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Object; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Object | shadowCastingTraversalMask, shadowCastingTraversalMask)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask)); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ae3d6eefcd..ee102af520 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -496,4 +496,5 @@ actor shadows = false player shadows = false # Allow terrain to cast shadows. Potentially decreases performance. terrain shadows = false -# Note: Right now, there is no setting allowing toggling of shadows for statics +# Allow world objects to cast shadows. Potentially decreases performance. +object shadows = false From 6d29375d5e23e0ba1ea6dc3569d4ccd1919f908c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 15:50:36 +0000 Subject: [PATCH 099/410] Turning on shadows will now force shaders on --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- docs/source/reference/modding/settings/shadows.rst | 5 ++--- files/settings-default.cfg | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 33ce9346bf..bc414401f0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -186,7 +186,7 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); - resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders")); + resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows")); // Shadows have problems with fixed-function mode resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 8e3b79c003..4dac6a88b1 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -13,9 +13,8 @@ enable shadows Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. -When used in fixed-function mode, shadowed regions will appear completely black. -To prevent this, enable :ref:`force-shaders-label`. -A keen developer may be able to implement something better using the advice of `this post `_, but it may be more difficult than it seems. +Bear in mind that this will force OpenMW to use shaders as if :ref:`force-shaders-label` was enabled. +A keen developer may be able to implement compatibility with fixed-function mode using the advice of `this post `_, but it may be more difficult than it seems. number of shadow maps diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ee102af520..c0283b3785 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -474,7 +474,7 @@ companion w = 0.38 companion h = 0.63 [Shadows] -# Enable or disable shadows. Bear in mind that when used without "[Shaders]/force shaders" set to true (i.e. objects and terrain are rendered in fixed-function mode) shadowed areas will be completely black. As such, it is recommended to use this feature in conjunction with shaders. +# Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 From 4547151863db04c1a6b1d795fbffc577516c3b56 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 5 May 2018 00:08:00 +0100 Subject: [PATCH 100/410] Add the view frustum to the debug HUD (in the most annoying way possible) --- components/sceneutil/mwshadowtechnique.cpp | 37 ++++++++++++++++++++++ components/sceneutil/mwshadowtechnique.hpp | 2 ++ 2 files changed, 39 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 904c51669d..b84e797c1b 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -762,11 +762,43 @@ void MWShadowTechnique::disableShadows() void SceneUtil::MWShadowTechnique::enableDebugHUD() { _debugHud = new DebugHUD(getShadowedScene()->getShadowSettings()->getNumShadowMapsPerLight()); + _frustumGeometry = new osg::Geometry(); + _frustumGeometry->setCullingActive(false); + + osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); + _frustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(4); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(7); + frustumDrawElements->push_back(4); + + frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); + _frustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(7); + + // Ensure this doesn't contribute to bounds calculation. + _frustumGeometry->setComputeBoundingBoxCallback(new osg::Drawable::ComputeBoundingBoxCallback()); + _frustumGeometry->setComputeBoundingSphereCallback(new osg::Node::ComputeBoundingSphereCallback()); + + getShadowedScene()->addChild(_frustumGeometry); } void SceneUtil::MWShadowTechnique::disableDebugHUD() { _debugHud = nullptr; + getShadowedScene()->removeChild(_frustumGeometry); + _frustumGeometry = nullptr; } void SceneUtil::MWShadowTechnique::setSplitPointUniformLogarithmicRatio(double ratio) @@ -887,6 +919,11 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) //OSG_NOTICE<<"maxZFar "< frustumCorners = new osg::Vec3dArray(8, &frustum.corners[0]); + _frustumGeometry->setVertexArray(frustumCorners); + } double reducedNear, reducedFar; if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 1fad0eee52..7f5aeb85d4 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -260,6 +260,8 @@ namespace SceneUtil { }; osg::ref_ptr _debugHud; + + osg::ref_ptr _frustumGeometry; }; } From 166e7df7781826e72c4e110df7a84fa07d7c0567 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 11 May 2018 19:08:42 +0100 Subject: [PATCH 101/410] Improve debug HUD frustum --- components/sceneutil/mwshadowtechnique.cpp | 139 +++++++++++++++------ components/sceneutil/mwshadowtechnique.hpp | 9 +- 2 files changed, 105 insertions(+), 43 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index b84e797c1b..db0788318a 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -115,6 +115,44 @@ std::string debugFragmentShaderSource = #endif "} \n"; +std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z;}"; +std::string debugFrustumFragmentShaderSource = + "varying float depth; \n" + " \n" + "void main(void) \n" + "{ \n" +#if 1 + " float f = depth; \n" + " \n" + " f = 256.0 * f; \n" + " float fC = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fS = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fH = floor( f ) / 256.0; \n" + " \n" + " fS *= 0.5; \n" + " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" + " \n" + " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" + " abs( fC - 0.333333 ), \n" + " abs( fC - 0.666667 ) ); \n" + " \n" + " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" + " \n" + " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" + " fMax = 1.0 / fMax; \n" + " \n" + " vec3 color = fMax * rgb; \n" + " \n" + " gl_FragColor = vec4( fS + fH * color, 1 ); \n" +#else + " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" +#endif + "} \n"; + template class RenderLeafTraverser : public T @@ -762,43 +800,14 @@ void MWShadowTechnique::disableShadows() void SceneUtil::MWShadowTechnique::enableDebugHUD() { _debugHud = new DebugHUD(getShadowedScene()->getShadowSettings()->getNumShadowMapsPerLight()); - _frustumGeometry = new osg::Geometry(); - _frustumGeometry->setCullingActive(false); + - osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); - _frustumGeometry->addPrimitiveSet(frustumDrawElements); - frustumDrawElements->push_back(0); - frustumDrawElements->push_back(1); - frustumDrawElements->push_back(2); - frustumDrawElements->push_back(3); - frustumDrawElements->push_back(0); - frustumDrawElements->push_back(4); - frustumDrawElements->push_back(5); - frustumDrawElements->push_back(6); - frustumDrawElements->push_back(7); - frustumDrawElements->push_back(4); - - frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); - _frustumGeometry->addPrimitiveSet(frustumDrawElements); - frustumDrawElements->push_back(1); - frustumDrawElements->push_back(5); - frustumDrawElements->push_back(2); - frustumDrawElements->push_back(6); - frustumDrawElements->push_back(3); - frustumDrawElements->push_back(7); - - // Ensure this doesn't contribute to bounds calculation. - _frustumGeometry->setComputeBoundingBoxCallback(new osg::Drawable::ComputeBoundingBoxCallback()); - _frustumGeometry->setComputeBoundingSphereCallback(new osg::Node::ComputeBoundingSphereCallback()); - - getShadowedScene()->addChild(_frustumGeometry); + } void SceneUtil::MWShadowTechnique::disableDebugHUD() { _debugHud = nullptr; - getShadowedScene()->removeChild(_frustumGeometry); - _frustumGeometry = nullptr; } void SceneUtil::MWShadowTechnique::setSplitPointUniformLogarithmicRatio(double ratio) @@ -919,11 +928,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) //OSG_NOTICE<<"maxZFar "< frustumCorners = new osg::Vec3dArray(8, &frustum.corners[0]); - _frustumGeometry->setVertexArray(frustumCorners); - } + if (_debugHud) + _debugHud->setFrustumVertices(new osg::Vec3dArray(8, &frustum.corners[0])); double reducedNear, reducedFar; if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) @@ -1106,9 +1112,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) previous_sdl.erase(previous_sdl.begin()); } - if (_debugHud) - _debugHud->draw(sd->_texture, sm_i, cv); - osg::ref_ptr camera = sd->_camera; camera->setProjectionMatrix(projectionMatrix); @@ -1273,6 +1276,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // increment counters. ++textureUnit; ++numValidShadows ; + + if (_debugHud) + _debugHud->draw(sd->_texture, sm_i, camera->getViewMatrix() * camera->getProjectionMatrix(), cv); } } @@ -2625,15 +2631,51 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); mDebugProgram->addShader(fragmentShader); + mFrustumGeometry = new osg::Geometry(); + mFrustumGeometry->setCullingActive(false); + + osg::ref_ptr frustumProgram = new osg::Program; + vertexShader = new osg::Shader(osg::Shader::VERTEX, debugFrustumVertexShaderSource); + frustumProgram->addShader(vertexShader); + fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFrustumFragmentShaderSource); + frustumProgram->addShader(fragmentShader); + + mFrustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); + //mFrustumGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); + mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(4); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(7); + frustumDrawElements->push_back(4); + + frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); + mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(7); + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) addAnotherShadowMap(); } -void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv) +void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, const osg::Matrixd &matrix, osgUtil::CullVisitor& cv) { // 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(); stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); @@ -2656,6 +2698,14 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) mDebugProgram->releaseGLObjects(state); for (auto const& node : mDebugGeometry) node->releaseGLObjects(state); + for (auto const& node : mFrustumTransforms) + node->releaseGLObjects(state); + mFrustumGeometry->releaseGLObjects(state); +} + +void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) +{ + mFrustumGeometry->setVertexArray(vertices); } void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() @@ -2666,6 +2716,7 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() mDebugCameras[shadowMapNumber]->setViewport(200 * shadowMapNumber, 0, 200, 200); mDebugCameras[shadowMapNumber]->setRenderOrder(osg::Camera::POST_RENDER); mDebugCameras[shadowMapNumber]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + mDebugCameras[shadowMapNumber]->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); mDebugGeometry[shadowMapNumber]->setCullingActive(false); @@ -2675,4 +2726,12 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); //textureUniform->setType(osg::Uniform::SAMPLER_2D); stateSet->addUniform(textureUniform.get()); + + mFrustumTransforms.push_back(new osg::Group); + mFrustumTransforms[shadowMapNumber]->addChild(mFrustumGeometry); + 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]); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 7f5aeb85d4..eb5b650a00 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -246,9 +246,11 @@ namespace SceneUtil { void draw(); - virtual void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv); + virtual void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, const osg::Matrixd &matrix, osgUtil::CullVisitor& cv); virtual void releaseGLObjects(osg::State* state = 0) const; + + virtual void setFrustumVertices(osg::ref_ptr vertices); protected: virtual void addAnotherShadowMap(); @@ -257,11 +259,12 @@ namespace SceneUtil { std::vector> mDebugCameras; osg::ref_ptr mDebugProgram; std::vector> mDebugGeometry; + std::vector> mFrustumTransforms; + std::vector> mFrustumUniforms; + osg::ref_ptr mFrustumGeometry; }; osg::ref_ptr _debugHud; - - osg::ref_ptr _frustumGeometry; }; } From 1b30d47d7f79fdcba463241df0c683f7b44fad69 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 13 May 2018 12:56:40 +0100 Subject: [PATCH 102/410] Add a hacky temporary version of cascading shadow maps --- components/sceneutil/mwshadowtechnique.cpp | 29 +++++++++++++++------- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index db0788318a..d2c4c3a8f4 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -149,7 +149,7 @@ std::string debugFrustumFragmentShaderSource = " \n" " gl_FragColor = vec4( fS + fH * color, 1 ); \n" #else - " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" + " gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0); \n" #endif "} \n"; @@ -1130,7 +1130,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) osg::Polytope local_polytope(polytope); local_polytope.transformProvidingInverse(invertModelView); - + double cascaseNear = reducedNear; + double cascadeFar = reducedFar; if (numShadowMapsPerLight>1) { // compute the start and end range in non-dimensional coords @@ -1158,6 +1159,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double ciLog = n * pow(f / n, i / m); double ciUniform = n + (f - n) * i / m; double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; + cascaseNear = ci; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; @@ -1173,7 +1175,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double ciLog = n * pow(f / n, (i + 1) / m); double ciUniform = n + (f - n) * (i + 1) / m; double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; - + cascadeFar = ci; + // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; @@ -1185,7 +1188,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (sm_i+10) + if (false)//(sm_i>0) { // not the first shadowmap so insert a polytope to clip the scene from before r_start @@ -1200,7 +1203,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } - if (sm_i+1setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) + mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED); + else + mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); + if (Settings::Manager::getBool("enable debug hud", "Shadows")) mShadowTechnique->enableDebugHUD(); else diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3cc2b138ee..1ffc745e83 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -512,6 +512,8 @@ companion h = 0.63 enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 +# If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. +allow shadow map overlap = true # Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. split point uniform logarithmic ratio = 0.5 # Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. From 84284a60a74de83e15e00af8a9d64f3ba12f65af Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 17 May 2018 17:35:55 +0100 Subject: [PATCH 106/410] Make CSM shader changes controllable by the setting. --- components/sceneutil/shadow.cpp | 7 +++++++ files/shaders/objects_fragment.glsl | 28 +++++++++++++++++----------- files/shaders/terrain_fragment.glsl | 28 +++++++++++++++++----------- files/shaders/water_fragment.glsl | 28 +++++++++++++++++----------- 4 files changed, 58 insertions(+), 33 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 363e0ac3fd..374faee8ce 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -96,6 +96,11 @@ namespace SceneUtil // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) + definesWithShadows["shadowMapsOverlap"] = "1"; + else + definesWithShadows["shadowMapsOverlap"] = "0"; + return definesWithShadows; } @@ -105,6 +110,8 @@ namespace SceneUtil definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); definesWithShadows["shadow_texture_unit_list"] = ""; + definesWithShadows["shadowMapsOverlap"] = "0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 7ba3d1de0d..5eb98899ad 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -124,20 +124,26 @@ void main() float shadowing = 1.0; #if SHADOWS - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } } - } - @endforeach + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach + #endif #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 68ab1bbdd0..ae9f5a7bab 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -76,20 +76,26 @@ void main() float shadowing = 1.0; #if SHADOWS - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } } - } - @endforeach + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach + #endif #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index e953b2611e..7aa7ca0b0d 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -168,20 +168,26 @@ void main(void) #if SHADOWS float shadowing = 1.0; - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } } - } - @endforeach + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach + #endif float shadow = shadowing; #else // NOT SHADOWS From 9f0a49c303c32bca1cde7c60a1f4f13b229239a6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 17 May 2018 20:27:10 +0100 Subject: [PATCH 107/410] Disable CSM when disabled in the settings. --- components/sceneutil/mwshadowtechnique.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 2cf10f4d78..7630675927 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1254,7 +1254,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (!orthographicViewFrustum && settings->getShadowMapProjectionHint()==ShadowSettings::PERSPECTIVE_SHADOW_MAP) { - adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), cascaseNear, cascadeFar); + if (settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED) + adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), cascaseNear, cascadeFar); + else + adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), reducedNear, reducedFar); if (vdsmCallback->getProjectionMatrix()) { vdsmCallback->getProjectionMatrix()->set(camera->getProjectionMatrix()); From 2c30bc1b4f612a979f9ba164b78d67a971d61898 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 18 May 2018 22:39:57 +0100 Subject: [PATCH 108/410] Accidentally fix the one remaing case where shadows look awful while refactoring some stuff. --- components/sceneutil/mwshadowtechnique.cpp | 59 ++++++++++++++++++++++ components/sceneutil/mwshadowtechnique.hpp | 2 + 2 files changed, 61 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 7630675927..70352541fd 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1239,6 +1239,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } } + if (settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED) + cropShadowCameraToMainFrustum(frustum, camera, cascaseNear, cascadeFar); + else + cropShadowCameraToMainFrustum(frustum, camera, reducedNear, reducedFar); osg::ref_ptr vdsmCallback = new VDSMCameraCullCallback(this, local_polytope); camera->setCullCallback(vdsmCallback.get()); @@ -2159,6 +2163,61 @@ struct RenderLeafBounds double min_z, max_z; }; +bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Camera* camera, double viewNear, double viewFar) +{ + osg::Matrixd light_p = camera->getProjectionMatrix(); + osg::Matrixd light_v = camera->getViewMatrix(); + osg::Matrixd light_vp = light_v * light_p; + + ConvexHull convexHull; + convexHull.setToFrustum(frustum); + + osg::Vec3d nearPoint = frustum.eye + frustum.frustumCenterLine * viewNear; + osg::Vec3d farPoint = frustum.eye + frustum.frustumCenterLine * viewFar; + + double nearDist = -frustum.frustumCenterLine * nearPoint; + double farDist = frustum.frustumCenterLine * farPoint; + + convexHull.clip(osg::Plane(frustum.frustumCenterLine, nearDist)); + convexHull.clip(osg::Plane(-frustum.frustumCenterLine, farDist)); + + convexHull.transform(light_vp); + + double xMin = -1.0, xMax = 1.0; + double yMin = -1.0, yMax = 1.0; + double zMin = -1.0, zMax = 1.0; + + if (convexHull.valid()) + { + xMin = osg::maximum(-1.0, convexHull.min(0)); + xMax = osg::minimum(1.0, convexHull.max(0)); + yMin = osg::maximum(-1.0, convexHull.min(1)); + yMax = osg::minimum(1.0, convexHull.max(1)); + } + else + return false; + + // we always want the lightspace to include the computed near plane. + zMin = -1.0; + if (xMin != -1.0 || yMin != -1.0 || zMin != -1.0 || + xMax != 1.0 || yMax != 1.0 || zMax != 1.0) + { + osg::Matrix m; + m.makeTranslate(osg::Vec3d(-0.5*(xMax + xMin), + -0.5*(yMax + yMin), + -0.5*(zMax + zMin))); + + m.postMultScale(osg::Vec3d(2.0 / (xMax - xMin), + 2.0 / (yMax - yMin), + 2.0 / (zMax - zMin))); + + light_p.postMult(m); + camera->setProjectionMatrix(light_p); + } + + return true; +} + bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& /*positionedLight*/, osg::Camera* camera, double viewNear, double viewFar) { const ShadowSettings* settings = getShadowedScene()->getShadowSettings(); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index f11aec0bbe..ce5c0b6742 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -205,6 +205,8 @@ namespace SceneUtil { virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + virtual bool cropShadowCameraToMainFrustum(Frustum& frustum, osg::Camera* camera, double viewNear, double viewFar); + virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera, double viewNear, double viewFar); virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); From feac7bd88e8086f20a4dc1f67dd273d0bd6e2eb9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 20 May 2018 00:17:06 +0100 Subject: [PATCH 109/410] Use 3 shadow maps by default as 1 sucks. --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 1ffc745e83..5c404a78f2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -511,7 +511,7 @@ companion h = 0.63 # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. -number of shadow maps = 1 +number of shadow maps = 3 # If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. allow shadow map overlap = true # Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. From 86ce33f437717449f03636953cccfb98a78e1e99 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 21 May 2018 16:00:51 +0100 Subject: [PATCH 110/410] Update documentation --- .../reference/modding/settings/shadows.rst | 18 ++++++++++++++++-- files/settings-default.cfg | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 4dac6a88b1..f9ebd1f63e 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -22,12 +22,23 @@ number of shadow maps :Type: integer :Range: 1 to 8, but higher values may conflict with other texture effects -:Default: 1 +:Default: 3 Control how many shadow maps to use - more of these means each shadow map texel covers less area, producing better-looking shadows, but may decrease performance. Using too many shadow maps will lead to them overriding texture slots used for other effects, producing unpleasant artefacts. A value of three is recommended in most cases, but other values may produce better results or performance. +allow shadow map overlap +------------------------ + +:Type: boolean +:Range: True/False +:Default: True + +If true, allow shadow maps to overlap. +Counter-intuitively, will produce much better results when the light is behind the camera. +When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. + enable debug hud ---------------- @@ -97,8 +108,9 @@ Note: Right now, there is no setting allowing toggling of shadows for statics Expert settings *************** -You probably shouldn't be changing these if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. +You probably shouldn't be changing these yourself if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. If you have, then you may get better results tuning these for your specific view distance. +Copying values from another user who's done careful tuning is the recommended way of arriving at an optimal value for these settings. split point uniform logarithmic ratio ------------------------------------- @@ -108,6 +120,8 @@ split point uniform logarithmic ratio :Default: 0.5 Controls the ratio of :math:`C_i^{log}` versus :math:`C_i^{uniform}` used to form the Practical Split Scheme as described in the linked paper. +When using a larger-than-default viewing distance and distant terrain, and you have `allow shadow map overlap`_ enabled, larger values will prevent nearby shadows losing quality. +It is therefore recommended that this isn't left at the default when the viewing distance is changed. split point bias ---------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 5c404a78f2..c8d68c14c9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -514,7 +514,7 @@ enable shadows = false number of shadow maps = 3 # If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. allow shadow map overlap = true -# Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. +# Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you might not want to change this, especially not without reading the associated papers first. When "allow shadow map overlap" is combined with a higher-than-default viewing distance, values closer to 1.0 will prevent nearby shadows losing a lot of quality. split point uniform logarithmic ratio = 0.5 # Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. split point bias = 0.0 From 9093ab59f63b27fefda32c785c00bf3b46654791 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 21 May 2018 23:57:38 +0100 Subject: [PATCH 111/410] Restore water object refractions and reflections. --- apps/openmw/mwrender/water.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 6e1fef716f..0b4a8e062a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -221,7 +221,7 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("RefractionCamera"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -312,7 +312,7 @@ public: bool reflectActors = Settings::Manager::getBool("reflect actors", "Water"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); From 50fdd0be994f09cd8a696f44651aeba775031a64 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 29 May 2018 00:52:43 +0100 Subject: [PATCH 112/410] Resolve computed near plane issues with extremely high viewing distances. --- components/sceneutil/mwshadowtechnique.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 70352541fd..378881d8dc 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -927,6 +927,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) //OSG_NOTICE<<"maxZFar "<setFrustumVertices(new osg::Vec3dArray(8, &frustum.corners[0])); @@ -2252,7 +2255,7 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render double nearDist = frustum.frustumCenterLine.x() * nearPoint.x() + frustum.frustumCenterLine.y() * nearPoint.y() + frustum.frustumCenterLine.z() * nearPoint.z(); double farDist = -frustum.frustumCenterLine.x() * farPoint.x() - frustum.frustumCenterLine.y() * farPoint.y() - frustum.frustumCenterLine.z() * farPoint.z(); - + convexHull.clip(osg::Plane(frustum.frustumCenterLine, -nearDist)); convexHull.clip(osg::Plane(-frustum.frustumCenterLine, -farDist)); From f5b144ef774364d0571d5d58c4ca65b0eaa475bb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jun 2018 17:04:56 +0100 Subject: [PATCH 113/410] Improve bounds calculation for shadow casters outside of the viewing frustum --- components/sceneutil/mwshadowtechnique.cpp | 166 +++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 378881d8dc..0bb8a26c98 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1787,6 +1787,168 @@ struct ConvexHull _edges.push_back( Edge(frustum.corners[3],frustum.corners[7]) ); } + struct ConvexHull2D + { + // Implementation based on https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#C++ + typedef osg::Vec3d Point; + + static double cross(const Point &O, const Point &A, const Point &B) + { + return (A.x() - O.x())*(B.y() - O.y()) - (A.y() - O.y())*(B.x() - O.x()); + } + + // Calculates the 2D convex hull and returns it as a vector containing the points in CCW order with the first and last point being the same. + static std::vector convexHull(std::set &P) + { + size_t n = P.size(), k = 0; + if (n <= 3) + return std::vector(P.cbegin(), P.cend()); + + std::vector H(2 * n); + + // Points are already sorted in a std::set + + // Build lower hull + for (auto pItr = P.cbegin(); pItr != P.cend(); ++pItr) + { + while (k >= 2 && cross(H[k - 2], H[k - 1], *pItr) <= 0) + k--; + H[k++] = *pItr; + } + + // Build upper hull + size_t t = k + 1; + for (auto pItr = std::next(P.crbegin()); pItr != P.crend(); ++pItr) + { + while (k >= t && cross(H[k - 2], H[k - 1], *pItr) <= 0) + k--; + H[k++] = *pItr; + } + + H.resize(k - 1); + return H; + } + }; + + bool shouldBeDeleted(osg::Vec3d vertex, std::set &extremeVertices) + { + // A vertex should be deleted if there is no route -Z-wards to an extreme vertex + // equivalent to all -Z-wards vertices being deletable. + if (extremeVertices.find(vertex) != extremeVertices.end()) + return false; + for (Edge edge : _edges) + { + osg::Vec3d otherEnd; + if (edge.first == vertex) + otherEnd = edge.second; + else if (edge.second == vertex) + otherEnd = edge.first; + else + continue; + + if (otherEnd.z() >= vertex.z()) + continue; + + if (!shouldBeDeleted(otherEnd, extremeVertices)) + return false; + } + + return true; + } + + void extendTowardsNegativeZ() + { + typedef std::set VertexSet; + + // Collect the set of vertices + VertexSet vertices; + for (Edge edge : _edges) + { + vertices.insert(edge.first); + vertices.insert(edge.second); + } + + if (vertices.size() == 0) + return; + + // Get the vertices contributing to the 2D convex hull + Vertices extremeVertices = ConvexHull2D::convexHull(vertices); + VertexSet extremeVerticesSet(extremeVertices.cbegin(), extremeVertices.cend()); + + // Add their extrusions to the final edge collection + Edges finalEdges; + // Add edges towards -Z + for (auto vertex : extremeVertices) + finalEdges.push_back(Edge(vertex, osg::Vec3d(vertex.x(), vertex.y(), -DBL_MAX))); + // Add edge loop to 'seal' the hull + for (auto itr = extremeVertices.cbegin(); itr != extremeVertices.cend() - 1; ++itr) + finalEdges.push_back(Edge(osg::Vec3d(itr->x(), itr->y(), -DBL_MAX), osg::Vec3d((itr + 1)->x(), (itr + 1)->y(), -DBL_MAX))); + // The convex hull algorithm we are using places a point at both ends of the vector, so we don't need to add the last edge separately. + // finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX))); + + // Collect the first layer of unneeded vertices and remove the edges connecting them to the rest of the mesh + VertexSet deletedVertices; + for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */ ) + { + if (extremeVerticesSet.find(edgeItr->first) != extremeVerticesSet.end()) + { + if (extremeVerticesSet.find(edgeItr->second) == extremeVerticesSet.end()) + { + if (edgeItr->first.z() >= edgeItr->second.z()) + { + // If we can travel along edges towards -Z and reach an extreme vertex, the current edge must be kept + if (shouldBeDeleted(edgeItr->second, extremeVerticesSet)) + { + deletedVertices.insert(edgeItr->second); + edgeItr = _edges.erase(edgeItr); + continue; + } + } + } + } + else if (extremeVerticesSet.find(edgeItr->second) != extremeVerticesSet.end()) + { + if (edgeItr->second.z() >= edgeItr->first.z()) + { + if (shouldBeDeleted(edgeItr->first, extremeVerticesSet)) + { + deletedVertices.insert(edgeItr->first); + edgeItr = _edges.erase(edgeItr); + continue; + } + } + } + ++edgeItr; + } + + // Remove all edges connected to removed vertices + bool modifiedSomething = true; + while (modifiedSomething) + { + modifiedSomething = false; + for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */) + { + if (deletedVertices.find(edgeItr->first) != deletedVertices.end()) + { + deletedVertices.insert(edgeItr->second); + edgeItr = _edges.erase(edgeItr); + modifiedSomething = true; + continue; + } + else if (deletedVertices.find(edgeItr->second) != deletedVertices.end()) + { + deletedVertices.insert(edgeItr->first); + edgeItr = _edges.erase(edgeItr); + modifiedSomething = true; + continue; + } + ++edgeItr; + } + } + + _edges.splice(_edges.end(), finalEdges); + } + void transform(const osg::Matrixd& m) { for(Edges::iterator itr = _edges.begin(); @@ -2186,6 +2348,8 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam convexHull.transform(light_vp); + convexHull.extendTowardsNegativeZ(); + double xMin = -1.0, xMax = 1.0; double yMin = -1.0, yMax = 1.0; double zMin = -1.0, zMax = 1.0; @@ -2269,6 +2433,8 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render convexHull.transform(light_vp); + convexHull.extendTowardsNegativeZ(); + #if 0 convexHull.output(osg::notify(osg::NOTICE)); From ed68db5ef9edba4417a9db79f598c3bf0474b9dc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 19 Jun 2018 23:48:59 +0100 Subject: [PATCH 114/410] Fix issue where the camera frustum cropping wouldn't consider where casters might cast shadows, just where they actually were. --- components/sceneutil/mwshadowtechnique.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 0bb8a26c98..56be0b8a01 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1039,6 +1039,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); double minZ = DBL_MAX; double maxZ = -DBL_MAX; + clsb._bb._max[2] = 1.0; for (unsigned int i = 0; i < 8; i++) { osg::Vec3 corner = clsb._bb.corner(i); From b25b356081d080cdd76bc296f369b59c73856fd3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 22 Jun 2018 01:02:01 +0100 Subject: [PATCH 115/410] Sort out shader indentation --- files/shaders/lighting.glsl | 6 +-- files/shaders/objects_fragment.glsl | 48 +++++++++++------------ files/shaders/objects_vertex.glsl | 20 +++++----- files/shaders/terrain_fragment.glsl | 48 +++++++++++------------ files/shaders/terrain_vertex.glsl | 20 +++++----- files/shaders/water_fragment.glsl | 60 ++++++++++++++--------------- files/shaders/water_vertex.glsl | 32 +++++++-------- 7 files changed, 117 insertions(+), 117 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index e67ed295a3..d234aaaad0 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -3,12 +3,12 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; - float lightDistance; + float lightDistance; lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); lightDistance = length(lightDir); lightDir = normalize(lightDir); - float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); + float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); ambientOut = ambient * gl_LightSource[lightIndex].ambient.xyz * illumination; diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; @@ -38,7 +38,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow lightResult.xyz += ambientLight + diffuseLight * shadowing; #else shadowDiffuse = diffuseLight; - lightResult.xyz += ambientLight; + lightResult.xyz += ambientLight; #endif for (int i=1; i Date: Fri, 22 Jun 2018 01:05:45 +0100 Subject: [PATCH 116/410] Fix water shader alignment issues noticed while removing tabs. --- files/shaders/water_fragment.glsl | 12 ++++++------ files/shaders/water_vertex.glsl | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index e78909abee..c2628eb7fb 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -218,9 +218,9 @@ void main(void) vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + - normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + - rippleAdd); + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + + rippleAdd); normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); @@ -228,9 +228,9 @@ void main(void) // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + - normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + - rippleAdd).xyz; + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + + rippleAdd).xyz; lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index d38460caa9..f51baf9327 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -18,9 +18,9 @@ void main(void) gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, - 0.0, -0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0); + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); vec4 texcoordProj = ((scalemat) * ( gl_Position)); screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); From a7e53df278cf93bb98c964f23fc309dacb4471ed Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 24 Jun 2018 23:40:52 +0100 Subject: [PATCH 117/410] Move common shadow code to shared shadow shader headers --- files/shaders/CMakeLists.txt | 2 ++ files/shaders/objects_fragment.glsl | 34 ++------------------------- files/shaders/objects_vertex.glsl | 18 ++------------- files/shaders/shadows_fragment.glsl | 36 +++++++++++++++++++++++++++++ files/shaders/shadows_vertex.glsl | 20 ++++++++++++++++ files/shaders/terrain_fragment.glsl | 34 ++------------------------- files/shaders/terrain_vertex.glsl | 18 ++------------- files/shaders/water_fragment.glsl | 36 ++--------------------------- files/shaders/water_vertex.glsl | 20 ++-------------- 9 files changed, 70 insertions(+), 148 deletions(-) create mode 100644 files/shaders/shadows_fragment.glsl create mode 100644 files/shaders/shadows_vertex.glsl diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 7baca78ef1..41763f3e1d 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -18,6 +18,8 @@ set(SHADER_FILES parallax.glsl s360_fragment.glsl s360_vertex.glsl + shadows_vertex.glsl + shadows_fragment.glsl ) copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 4075416347..fffb9c83b3 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; @@ -57,13 +55,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS - +#include "shadows_fragment.glsl" #include "lighting.glsl" #include "parallax.glsl" @@ -122,29 +114,7 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = 1.0; -#if SHADOWS - #if @shadowMapsOverlap - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) - { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; - } - } - @endforeach - #else - @foreach shadow_texture_unit_index @shadow_texture_unit_list - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - @endforeach - #endif -#endif // SHADOWS + float shadowing = unshadowedLightRatio(); #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 02960e5b43..3d7f49eeeb 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -48,12 +46,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform int shadowTextureUnit@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_vertex.glsl" #include "lighting.glsl" @@ -110,12 +103,5 @@ void main(void) passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; -#if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - @endforeach -#endif // SHADOWS + setupShadowCoords(viewPos); } diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl new file mode 100644 index 0000000000..cc1b38b59e --- /dev/null +++ b/files/shaders/shadows_fragment.glsl @@ -0,0 +1,36 @@ +#define SHADOWS @shadows_enabled + +#if SHADOWS + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach +#endif // SHADOWS + +float unshadowedLightRatio() +{ + float shadowing = 1.0; +#if SHADOWS + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) + { + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } + } + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); + @endforeach + #endif +#endif // SHADOWS + return shadowing; +} \ No newline at end of file diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl new file mode 100644 index 0000000000..bbc1a40368 --- /dev/null +++ b/files/shaders/shadows_vertex.glsl @@ -0,0 +1,20 @@ +#define SHADOWS @shadows_enabled + +#if SHADOWS + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach +#endif // SHADOWS + +void setupShadowCoords(vec4 viewPos) +{ +#if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach +#endif // SHADOWS +} \ No newline at end of file diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 57403f1a43..219b92c990 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - varying vec2 uv; uniform sampler2D diffuseMap; @@ -27,13 +25,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS - +#include "shadows_fragment.glsl" #include "lighting.glsl" #include "parallax.glsl" @@ -74,29 +66,7 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = 1.0; -#if SHADOWS - #if @shadowMapsOverlap - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) - { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; - } - } - @endforeach - #else - @foreach shadow_texture_unit_index @shadow_texture_unit_list - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - @endforeach - #endif -#endif // SHADOWS + float shadowing = unshadowedLightRatio(); #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 57af0575cd..669eac0125 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - varying vec2 uv; varying float depth; @@ -16,12 +14,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform int shadowTextureUnit@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_vertex.glsl" #include "lighting.glsl" @@ -44,12 +37,5 @@ void main(void) uv = gl_MultiTexCoord0.xy; -#if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - @endforeach -#endif // SHADOWS + setupShadowCoords(viewPos); } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c2628eb7fb..a227e1e68b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,7 +1,6 @@ #version 120 #define REFRACTION @refraction_enabled -#define SHADOWS @shadows_enabled // Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) @@ -143,12 +142,7 @@ uniform vec3 nodePosition; uniform float rainIntensity; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_fragment.glsl" float frustumDepth; @@ -166,33 +160,7 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; -#if SHADOWS - float shadowing = 1.0; - #if @shadowMapsOverlap - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) - { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; - } - } - @endforeach - #else - @foreach shadow_texture_unit_index @shadow_texture_unit_list - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - @endforeach - #endif - - float shadow = shadowing; -#else // NOT SHADOWS - float shadow = 1.0; -#endif // SHADOWS + float shadow = unshadowedLightRatio(); vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index f51baf9327..b028d90d22 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,14 +4,7 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; -#define SHADOWS @shadows_enabled - -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform int shadowTextureUnit@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_vertex.glsl" void main(void) { @@ -29,14 +22,5 @@ void main(void) depthPassthrough = gl_Position.z; - #if SHADOWS - vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - - @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - @endforeach - #endif // SHADOWS + setupShadowCoords(gl_ModelViewMatrix * gl_Vertex); } From 85aba2e1dab9e1d0fde071e15f1395ea05a5016a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 28 Jun 2018 17:24:36 +0100 Subject: [PATCH 118/410] Add toggleable shadow debug overlay. --- components/sceneutil/shadow.cpp | 7 +++++ .../reference/modding/settings/shadows.rst | 10 +++++++ files/settings-default.cfg | 2 ++ files/shaders/objects_fragment.glsl | 2 ++ files/shaders/shadows_fragment.glsl | 27 +++++++++++++++++++ files/shaders/terrain_fragment.glsl | 2 ++ files/shaders/water_fragment.glsl | 2 ++ 7 files changed, 52 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 374faee8ce..6e45bdd22f 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -101,6 +101,11 @@ namespace SceneUtil else definesWithShadows["shadowMapsOverlap"] = "0"; + if (Settings::Manager::getBool("enable debug overlay", "Shadows")) + definesWithShadows["useShadowDebugOverlay"] = "1"; + else + definesWithShadows["useShadowDebugOverlay"] = "0"; + return definesWithShadows; } @@ -112,6 +117,8 @@ namespace SceneUtil definesWithShadows["shadowMapsOverlap"] = "0"; + definesWithShadows["useShadowDebugOverlay"] = "0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index f9ebd1f63e..271ecac20a 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -49,6 +49,16 @@ enable debug hud Enable or disable the debug hud to see what the shadow map(s) contain. This setting is only recommended for developers, bug reporting and advanced users performing fine-tuning of shadow settings. +enable debug overlay +---------------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable or disable the debug overlay to see the area covered by each shadow map. +This setting is only recommended for developers, bug reporting and advanced users performing fine-tuning of shadow settings. + compute tight scene bounds -------------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6cee10e055..277b5dd083 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -530,6 +530,8 @@ split point uniform logarithmic ratio = 0.5 split point bias = 0.0 # Enable the debug hud to see what the shadow map(s) contain. enable debug hud = false +# Enable the debug overlay to see where each shadow map affects. +enable debug overlay = false # Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. compute tight scene bounds = false # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index fffb9c83b3..64435f001a 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -155,4 +155,6 @@ void main() float fogValue = clamp((depth - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + + applyShadowDebugOverlay(); } diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index cc1b38b59e..ce9e958d19 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -33,4 +33,31 @@ float unshadowedLightRatio() #endif #endif // SHADOWS return shadowing; +} + +void applyShadowDebugOverlay() +{ +#if SHADOWS && @useShadowDebugOverlay + bool doneOverlay = false; + float colourIndex = 0.0; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneOverlay) + { + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + colourIndex = mod(@shadow_texture_unit_index.0, 3.0); + if (colourIndex < 1.0) + gl_FragData[0].x += 0.1; + else if (colourIndex < 2.0) + gl_FragData[0].y += 0.1; + else + gl_FragData[0].z += 0.1; + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneOverlay = true; + } + } + @endforeach +#endif // SHADOWS } \ No newline at end of file diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 219b92c990..c946777bbd 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -86,4 +86,6 @@ void main() float fogValue = clamp((depth - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + + applyShadowDebugOverlay(); } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index a227e1e68b..0102a6eb95 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -280,4 +280,6 @@ void main(void) #else gl_FragData[0].w = clamp(fresnel*6.0 + specular, 0.0, 1.0); //clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif + + applyShadowDebugOverlay(); } From 02ab3b466ab3ef16e2b6f9fc04db57e025d25ec5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 31 Jul 2018 23:30:15 +0100 Subject: [PATCH 119/410] Use simplified convex hull clipping maths from the other function doing hte same thing --- components/sceneutil/mwshadowtechnique.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 56be0b8a01..31c10faff3 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2416,13 +2416,12 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render osg::Vec3d nearPoint = frustum.eye + frustum.frustumCenterLine * viewNear; osg::Vec3d farPoint = frustum.eye + frustum.frustumCenterLine * viewFar; - // TODO: Aren't these just dot products? Also the double negation of farDist is silly. - double nearDist = frustum.frustumCenterLine.x() * nearPoint.x() + frustum.frustumCenterLine.y() * nearPoint.y() + frustum.frustumCenterLine.z() * nearPoint.z(); - double farDist = -frustum.frustumCenterLine.x() * farPoint.x() - frustum.frustumCenterLine.y() * farPoint.y() - frustum.frustumCenterLine.z() * farPoint.z(); - - convexHull.clip(osg::Plane(frustum.frustumCenterLine, -nearDist)); - convexHull.clip(osg::Plane(-frustum.frustumCenterLine, -farDist)); + double nearDist = -frustum.frustumCenterLine * nearPoint; + double farDist = frustum.frustumCenterLine * farPoint; + + convexHull.clip(osg::Plane(frustum.frustumCenterLine, nearDist)); + convexHull.clip(osg::Plane(-frustum.frustumCenterLine, farDist)); #if 0 OSG_NOTICE<<"ws ConvexHull xMin="<getSceneManager()->recreateShaders(mObjectRoot); - - if (mViewMode == VM_FirstPerson) - { - // Shadows made first-person meshes get erroneously culled. This stops that. - DisableCullingVisitor disableCullingVisitor; - mObjectRoot->accept(disableCullingVisitor); - } } From 6286f5a1d4581ab00e392a7af909c83004770b03 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:24:57 +0100 Subject: [PATCH 123/410] Ensure RigGeometry child geometries have sensible bounds without actually computing them. --- components/sceneutil/riggeometry.cpp | 10 ++++++++++ components/sceneutil/riggeometry.hpp | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 7f148cf5e3..fdb67d7dec 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -41,6 +41,8 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) to.setSupportsDisplayList(false); to.setUseVertexBufferObjects(true); to.setCullingActive(false); // make sure to disable culling since that's handled by this class + to.setComputeBoundingBoxCallback(new CopyBoundingBoxCallback()); + to.setComputeBoundingSphereCallback(new CopyBoundingSphereCallback()); // vertices and normals are modified every frame, so we need to deep copy them. // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO. @@ -273,6 +275,14 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) _boundingSphereComputed = true; for (unsigned int i=0; idirtyBound(); + + for (unsigned int i = 0; i < 2; ++i) + { + osg::Geometry& geom = *mGeometry[i]; + static_cast(geom.getComputeBoundingBoxCallback())->boundingBox = _boundingBox; + static_cast(geom.getComputeBoundingSphereCallback())->boundingSphere = _boundingSphere; + geom.dirtyBound(); + } } } diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 60b3edc9d8..0d8dcbddde 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -51,6 +51,20 @@ namespace SceneUtil virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } virtual void accept(osg::PrimitiveFunctor&) const; + struct CopyBoundingBoxCallback : osg::Drawable::ComputeBoundingBoxCallback + { + osg::BoundingBox boundingBox; + + virtual osg::BoundingBox computeBound(const osg::Drawable&) const override { return boundingBox; } + }; + + struct CopyBoundingSphereCallback : osg::Node::ComputeBoundingSphereCallback + { + osg::BoundingSphere boundingSphere; + + virtual osg::BoundingSphere computeBound(const osg::Node&) const override { return boundingSphere; } + }; + private: void cull(osg::NodeVisitor* nv); void updateBounds(osg::NodeVisitor* nv); From 1e48114492a1c69740879f1120d2d8df7947825d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:30:33 +0100 Subject: [PATCH 124/410] Use JDGBOLT's indoor 'sun' direction. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 410157d800..1b17ce4ea2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -453,7 +453,7 @@ namespace MWRender osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); mSunLight->setDiffuse(diffuse); mSunLight->setSpecular(diffuse); - mSunLight->setPosition(osg::Vec4f(-1.f, 1.f, 1.f, 0.f)); + mSunLight->setPosition(osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f)); } void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular) From 1e0f9827410259c5be02563b4cd6efbdc47aea94 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:55:01 +0100 Subject: [PATCH 125/410] Add missing documentation --- docs/source/reference/modding/settings/shadows.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 271ecac20a..34d484925e 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -111,9 +111,17 @@ terrain shadows Allow terrain to cast shadows. Potentially decreases performance. +object shadows +-------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow static objects to cast shadows. +Potentially decreases performance. -Note: Right now, there is no setting allowing toggling of shadows for statics Expert settings *************** From 3b3721897d80e4af6cdb5ab1ae30a377add4a8aa Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:56:11 +0100 Subject: [PATCH 126/410] Make indoor shadows disableable. --- components/sceneutil/shadow.cpp | 7 ++++++- docs/source/reference/modding/settings/shadows.rst | 9 +++++++++ files/settings-default.cfg | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 6e45bdd22f..6c71a9c0fd 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -123,10 +123,15 @@ namespace SceneUtil } void ShadowManager::enableIndoorMode() { - mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); + if (Settings::Manager::getBool("enable indoor shadows", "Shadows")) + mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); + else + mShadowTechnique->disableShadows(); } void ShadowManager::enableOutdoorMode() { + if (mEnableShadows) + mShadowTechnique->enableShadows(); mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); } } diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 34d484925e..b88df8942b 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -121,7 +121,16 @@ object shadows Allow static objects to cast shadows. Potentially decreases performance. +enable indoor shadows +--------------------- +:Type: boolean +:Range: True/False +:Default: False + +Allow shadows indoors. +Due to limitations with Morrowind's data, only actors can cast shadows indoors without the ceiling casting a shadow everywhere. +Some might feel this is distracting as shadows can be cast through other objects, so indoor shadows can be disabled completely. Expert settings *************** diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 41063929e5..21af225667 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -549,3 +549,5 @@ player shadows = false terrain shadows = false # Allow world objects to cast shadows. Potentially decreases performance. object shadows = false +# Allow shadows indoors. Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting. +enable indoor shadows = true \ No newline at end of file From 1098bd2467e0287787b8f503df007eaf9a63b2e2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 14 Aug 2018 21:35:23 +0100 Subject: [PATCH 127/410] Optimise lighting.glsl for Mesa users. --- files/shaders/lighting.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index d234aaaad0..c70d0a59ab 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -35,12 +35,12 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow vec3 diffuseLight, ambientLight; perLight(ambientLight, diffuseLight, 0, viewPos, viewNormal, diffuse, ambient); #if PER_PIXEL_LIGHTING - lightResult.xyz += ambientLight + diffuseLight * shadowing; + lightResult.xyz += diffuseLight * shadowing - diffuseLight; // This light gets added a second time in the loop to fix Mesa users' slowdown, so we need to negate its contribution here. #else shadowDiffuse = diffuseLight; - lightResult.xyz += ambientLight; + lightResult.xyz -= shadowDiffuse; // This light gets added a second time in the loop to fix Mesa users' slowdown, so we need to negate its contribution here. #endif - for (int i=1; i Date: Thu, 16 Aug 2018 23:48:19 +0100 Subject: [PATCH 128/410] Fix ConvexHull::extendTowardsNegativeZ --- components/sceneutil/mwshadowtechnique.cpp | 158 ++++++++++++--------- 1 file changed, 90 insertions(+), 68 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 963aa1c072..64cef25a63 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1831,42 +1831,58 @@ struct ConvexHull } }; - bool shouldBeDeleted(osg::Vec3d vertex, std::set &extremeVertices) + Vertices findInternalEdges(osg::Vec3d mainVertex, Vertices connectedVertices) { - // A vertex should be deleted if there is no route -Z-wards to an extreme vertex - // equivalent to all -Z-wards vertices being deletable. - if (extremeVertices.find(vertex) != extremeVertices.end()) - return false; - for (Edge edge : _edges) + Vertices internalEdgeVertices; + for (auto vertex : connectedVertices) { - osg::Vec3d otherEnd; - if (edge.first == vertex) - otherEnd = edge.second; - else if (edge.second == vertex) - otherEnd = edge.first; - else - continue; - - if (otherEnd.z() >= vertex.z()) - continue; - - if (!shouldBeDeleted(otherEnd, extremeVertices)) - return false; + osg::Matrixd matrix; + osg::Vec3d dir = vertex - mainVertex; + matrix.makeLookAt(mainVertex, vertex, dir.z() == 0 ? osg::Vec3d(0, 0, 1) : osg::Vec3d(1, 0, 0)); + Vertices testVertices; + for (auto testVertex : connectedVertices) + { + if (vertex != testVertex) + testVertices.push_back(testVertex); + } + std::vector bearings; + for (auto testVertex : testVertices) + { + osg::Vec3d transformedVertex = testVertex * matrix; + bearings.push_back(atan2(transformedVertex.y(), transformedVertex.x())); + } + std::sort(bearings.begin(), bearings.end()); + bool keep = false; + for (auto itr = bearings.begin(); itr + 1 != bearings.end(); ++itr) + { + if (*itr + osg::PI < *(itr + 1)) + { + keep = true; + break; + } + } + if (!keep && bearings[0] + osg::PI > bearings.back()) + keep = true; + if (!keep) + internalEdgeVertices.push_back(vertex); } - - return true; + return internalEdgeVertices; } void extendTowardsNegativeZ() { typedef std::set VertexSet; + double lowestPoint = DBL_MAX; + // Collect the set of vertices VertexSet vertices; for (Edge edge : _edges) { vertices.insert(edge.first); vertices.insert(edge.second); + lowestPoint = osg::minimum(lowestPoint, edge.first.z()); + lowestPoint = osg::minimum(lowestPoint, edge.second.z()); } if (vertices.size() == 0) @@ -1884,70 +1900,76 @@ struct ConvexHull // Add edge loop to 'seal' the hull for (auto itr = extremeVertices.cbegin(); itr != extremeVertices.cend() - 1; ++itr) finalEdges.push_back(Edge(osg::Vec3d(itr->x(), itr->y(), -DBL_MAX), osg::Vec3d((itr + 1)->x(), (itr + 1)->y(), -DBL_MAX))); - // The convex hull algorithm we are using places a point at both ends of the vector, so we don't need to add the last edge separately. - // finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX))); + // The convex hull algorithm we are using sometimes places a point at both ends of the vector, so we don't always need to add the last edge separately. + if (extremeVertices.front() != extremeVertices.back()) + finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX))); - // Collect the first layer of unneeded vertices and remove the edges connecting them to the rest of the mesh - VertexSet deletedVertices; - for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */ ) + // Just in case using -DBL_MAX upsets some of the maths, we pretend we've only extended the volume by a little bit. + lowestPoint -= 1.0; + // Remove internal edges connected to extreme vertices + for (auto vertex : extremeVertices) { - if (extremeVerticesSet.find(edgeItr->first) != extremeVerticesSet.end()) + Vertices connectedVertices; + for (Edge edge : _edges) { - if (extremeVerticesSet.find(edgeItr->second) == extremeVerticesSet.end()) + if (edge.first == vertex) + connectedVertices.push_back(edge.second); + else if (edge.second == vertex) + connectedVertices.push_back(edge.first); + } + connectedVertices.push_back(osg::Vec3d(vertex.x(), vertex.y(), lowestPoint)); + + Vertices unwantedEdgeEnds = findInternalEdges(vertex, connectedVertices); + for (auto edgeEnd : unwantedEdgeEnds) + { + for (auto itr = _edges.begin(); itr != _edges.end(); ++itr) { - if (edgeItr->first.z() >= edgeItr->second.z()) + if (*itr == Edge(vertex, edgeEnd)) { - // If we can travel along edges towards -Z and reach an extreme vertex, the current edge must be kept - if (shouldBeDeleted(edgeItr->second, extremeVerticesSet)) - { - deletedVertices.insert(edgeItr->second); - edgeItr = _edges.erase(edgeItr); - continue; - } + _edges.erase(itr); + break; + } + else if (*itr == Edge(edgeEnd, vertex)) + { + _edges.erase(itr); + break; } } } - else if (extremeVerticesSet.find(edgeItr->second) != extremeVerticesSet.end()) - { - if (edgeItr->second.z() >= edgeItr->first.z()) - { - if (shouldBeDeleted(edgeItr->first, extremeVerticesSet)) - { - deletedVertices.insert(edgeItr->first); - edgeItr = _edges.erase(edgeItr); - continue; - } - } - } - ++edgeItr; } - // Remove all edges connected to removed vertices - bool modifiedSomething = true; - while (modifiedSomething) + // Gather connected vertices + VertexSet unprocessedConnectedVertices(extremeVertices.begin(), extremeVertices.end()); + VertexSet connectedVertices; + while (unprocessedConnectedVertices.size() > 0) { - modifiedSomething = false; - for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */) + osg::Vec3d vertex = *unprocessedConnectedVertices.begin(); + unprocessedConnectedVertices.erase(unprocessedConnectedVertices.begin()); + connectedVertices.insert(vertex); + for (Edge edge : _edges) { - if (deletedVertices.find(edgeItr->first) != deletedVertices.end()) - { - deletedVertices.insert(edgeItr->second); - edgeItr = _edges.erase(edgeItr); - modifiedSomething = true; + osg::Vec3d otherEnd; + if (edge.first == vertex) + otherEnd = edge.second; + else if (edge.second == vertex) + otherEnd - edge.first; + else continue; - } - else if (deletedVertices.find(edgeItr->second) != deletedVertices.end()) - { - deletedVertices.insert(edgeItr->first); - edgeItr = _edges.erase(edgeItr); - modifiedSomething = true; + + if (connectedVertices.count(otherEnd)) continue; - } - ++edgeItr; + + unprocessedConnectedVertices.insert(otherEnd); } } - _edges.splice(_edges.end(), finalEdges); + for (Edge edge : _edges) + { + if (connectedVertices.count(edge.first) || connectedVertices.count(edge.second)) + finalEdges.push_back(edge); + } + + _edges = finalEdges; } void transform(const osg::Matrixd& m) From dd501f4132dac60c1f95640e564040f8bd2346d5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 17 Aug 2018 17:47:52 +0100 Subject: [PATCH 129/410] Make ConvexHull::clip more resilient against large values. --- components/sceneutil/mwshadowtechnique.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 64cef25a63..c3bf99c962 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2067,6 +2067,14 @@ struct ConvexHull ++itr) { center += *itr; + + center.x() = osg::maximum(center.x(), -DBL_MAX); + center.y() = osg::maximum(center.y(), -DBL_MAX); + center.z() = osg::maximum(center.z(), -DBL_MAX); + + center.x() = osg::minimum(center.x(), DBL_MAX); + center.y() = osg::minimum(center.y(), DBL_MAX); + center.z() = osg::minimum(center.z(), DBL_MAX); } center /= double(intersections.size()); From 3ce96997d154d7272874fcf63ea4ef9421531593 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 18 Aug 2018 00:09:40 +0100 Subject: [PATCH 130/410] Remove sneaky tabs. --- components/shader/shadermanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 94b87504bb..2ede0abc2d 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -172,7 +172,7 @@ namespace Shader size_t contentEnd = source.find("$endforeach", contentStart); if (contentEnd == std::string::npos) { - Log(Debug::Error) << "Unexpected EOF"; + Log(Debug::Error) << "Unexpected EOF"; return false; } std::string content = source.substr(contentStart, contentEnd - contentStart); @@ -234,7 +234,7 @@ namespace Shader size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); if (iterNameEnd == std::string::npos) { - Log(Debug::Error) << "Unexpected EOF"; + Log(Debug::Error) << "Unexpected EOF"; return false; } forIterators.push_back(source.substr(iterNameStart, iterNameEnd - iterNameStart)); @@ -244,7 +244,7 @@ namespace Shader source.replace(foundPos, 1, "$"); if (forIterators.empty()) { - Log(Debug::Error) << "endforeach without foreach"; + Log(Debug::Error) << "endforeach without foreach"; return false; } else @@ -264,7 +264,7 @@ namespace Shader } else { - Log(Debug::Error) << "Undefined " << define; + Log(Debug::Error) << "Undefined " << define; return false; } } From 15e820825fc6e6d159f4c524fc09a9fc89036e24 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 21 Aug 2018 14:00:29 +0100 Subject: [PATCH 131/410] Fix another convex hull clipping issue and restore z-clipping --- components/sceneutil/mwshadowtechnique.cpp | 34 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index c3bf99c962..b90f67ff6f 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2079,7 +2079,7 @@ struct ConvexHull center /= double(intersections.size()); - typedef std::map VertexMap; + typedef std::map>> VertexMap; VertexMap vertexMap; for(Vertices::iterator itr = intersections.begin(); itr != intersections.end(); @@ -2090,16 +2090,38 @@ struct ConvexHull double v = dv * up; double angle = atan2(h,v); // OSG_NOTICE<<"angle = "<second + std::string("UV")] = std::to_string(texIt->first); } - if (!reqs.mColorMaterial) - defineMap["colorMode"] = "0"; - else - { - switch (reqs.mVertexColorMode) - { - case GL_AMBIENT: - defineMap["colorMode"] = "3"; - break; - default: - case GL_AMBIENT_AND_DIFFUSE: - defineMap["colorMode"] = "2"; - break; - case GL_EMISSION: - defineMap["colorMode"] = "1"; - break; - } - } - defineMap["forcePPL"] = mForcePerPixelLighting ? "1" : "0"; defineMap["clamp"] = mClampLighting ? "1" : "0"; diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index cb0538d9d3..eab75acbb5 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -81,9 +81,6 @@ namespace Shader bool mShaderRequired; - bool mColorMaterial; - // osg::Material::ColorMode - int mVertexColorMode; bool mMaterialOverridden; bool mNormalHeight; // true if normal map has height info in alpha channel diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index a0f051524b..83684b5c91 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -218,7 +218,6 @@ namespace Terrain defineMap["clamp"] = clampLighting ? "1" : "0"; defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; defineMap["blendMap"] = !firstLayer ? "1" : "0"; - defineMap["colorMode"] = "2"; defineMap["specularMap"] = it->mSpecular ? "1" : "0"; defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0"; @@ -231,6 +230,7 @@ namespace Terrain } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); + stateset->addUniform(new osg::Uniform("colorMode", 2)); } else { diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index d234aaaad0..ff6ee94199 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,5 +1,7 @@ #define MAX_LIGHTS 8 +uniform int colorMode; + void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; @@ -20,16 +22,23 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) #endif { -#if @colorMode == 3 - vec4 diffuse = gl_FrontMaterial.diffuse; - vec3 ambient = vertexColor.xyz; -#elif @colorMode == 2 - vec4 diffuse = vertexColor; - vec3 ambient = vertexColor.xyz; -#else - vec4 diffuse = gl_FrontMaterial.diffuse; - vec3 ambient = gl_FrontMaterial.ambient.xyz; -#endif + vec4 diffuse; + vec3 ambient; + if (colorMode == 3) + { + diffuse = gl_FrontMaterial.diffuse; + ambient - vertexColor.xyz; + } + else if (colorMode == 2) + { + diffuse = vertexColor; + ambient = vertexColor.xyz; + } + else + { + diffuse = gl_FrontMaterial.diffuse; + ambient = gl_FrontMaterial.ambient.xyz; + } vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); vec3 diffuseLight, ambientLight; @@ -48,11 +57,10 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow lightResult.xyz += gl_LightModel.ambient.xyz * ambient; -#if @colorMode == 1 - lightResult.xyz += vertexColor.xyz; -#else - lightResult.xyz += gl_FrontMaterial.emission.xyz; -#endif + if (colorMode == 1) + lightResult.xyz += vertexColor.xyz; + else + lightResult.xyz += gl_FrontMaterial.emission.xyz; #if @clamp lightResult = clamp(lightResult, vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0)); From 474770eca87209f813cf11ff64f902b0e7e5cc0e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 16 Oct 2018 21:23:31 +0100 Subject: [PATCH 134/410] Switch shadow map rendering to a specialised, simplified shader. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/nifosg/nifloader.cpp | 1 + components/sceneutil/mwshadowtechnique.cpp | 18 +++++++++++++++ components/sceneutil/mwshadowtechnique.hpp | 4 ++++ components/sceneutil/shadow.cpp | 4 +++- components/sceneutil/shadow.hpp | 2 +- components/shader/shadervisitor.cpp | 7 ++++++ files/shaders/CMakeLists.txt | 2 ++ files/shaders/shadowcasting_fragment.glsl | 17 ++++++++++++++ files/shaders/shadowcasting_vertex.glsl | 27 ++++++++++++++++++++++ 10 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 files/shaders/shadowcasting_fragment.glsl create mode 100644 files/shaders/shadowcasting_vertex.glsl diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a186ed8e95..c3e68aa680 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -239,7 +239,7 @@ namespace MWRender if (Settings::Manager::getBool("object shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Object; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index eb20b77021..f37f271edc 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1249,6 +1249,7 @@ namespace NifOsg boundTextures.clear(); } + // If this loop is changed such that the base texture isn't guaranteed to end up in texture unit 0, the shadow casting shader will need to be updated accordingly. for (int i=0; itextures[i].inUse) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 36f7dfbb7d..8c36c5e715 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -820,6 +820,16 @@ void SceneUtil::MWShadowTechnique::setSplitPointDeltaBias(double bias) _splitPointDeltaBias = bias; } +void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) +{ + // This can't be part of the constructor as OSG mandates that there be a trivial constructor available + + _castingProgram = new osg::Program(); + + _castingProgram->addShader(shaderManager.getShader("shadowcasting_vertex.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::VERTEX)); + _castingProgram->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::FRAGMENT)); +} + MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) { return new ViewDependentData(this); @@ -1480,6 +1490,14 @@ void MWShadowTechnique::createShaders() _fallbackShadowMapTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); } + + if (!_castingProgram) + OSG_NOTICE << "Shadow casting shader has not been set up. Remember to call setupCastingShader(Shader::ShaderManager &)" << std::endl; + + _shadowCastingStateSet->setAttributeAndModes(_castingProgram, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied + _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); + _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); } osg::Polytope MWShadowTechnique::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 875edbc1c6..558ad49d95 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -27,6 +27,7 @@ #include +#include #include namespace SceneUtil { @@ -73,6 +74,8 @@ namespace SceneUtil { virtual void setSplitPointDeltaBias(double bias); + virtual void setupCastingShader(Shader::ShaderManager &shaderManager); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: @@ -265,6 +268,7 @@ namespace SceneUtil { }; osg::ref_ptr _debugHud; + osg::ref_ptr _castingProgram; }; } diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 6c71a9c0fd..65754629e5 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -68,7 +68,7 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask) : mShadowedScene(new osgShadow::ShadowedScene), + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene), mShadowTechnique(new MWShadowTechnique), mOutdoorShadowCastingMask(outdoorShadowCastingMask), mIndoorShadowCastingMask(indoorShadowCastingMask) @@ -81,6 +81,8 @@ namespace SceneUtil mShadowSettings = mShadowedScene->getShadowSettings(); setupShadowSettings(); + mShadowTechnique->setupCastingShader(shaderManager); + enableOutdoorMode(); } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 6829046506..26e119d88b 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -16,7 +16,7 @@ namespace SceneUtil public: static void disableShadowsForStateSet(osg::ref_ptr stateSet); - ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager); virtual ~ShadowManager() = default; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 4556c05a61..457da5c776 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -215,6 +215,13 @@ namespace Shader mRequirements.back().mShaderRequired = true; } } + + if (diffuseMap) + { + if (!writableStateSet) + writableStateSet = getWritableStateSet(node); + writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); + } } const osg::StateSet::AttributeList& attributes = stateset->getAttributeList(); diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 41763f3e1d..8012c2bc10 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -20,6 +20,8 @@ set(SHADER_FILES s360_vertex.glsl shadows_vertex.glsl shadows_fragment.glsl + shadowcasting_vertex.glsl + shadowcasting_fragment.glsl ) copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") diff --git a/files/shaders/shadowcasting_fragment.glsl b/files/shaders/shadowcasting_fragment.glsl new file mode 100644 index 0000000000..6459467b11 --- /dev/null +++ b/files/shaders/shadowcasting_fragment.glsl @@ -0,0 +1,17 @@ +#version 120 + +uniform sampler2D diffuseMap; +varying vec2 diffuseMapUV; + +varying float alphaPassthrough; + +uniform bool useDiffuseMapForShadowAlpha; + +void main() +{ + gl_FragData[0].rgb = vec3(1.0); + if (useDiffuseMapForShadowAlpha) + gl_FragData[0].a = texture2D(diffuseMap, diffuseMapUV).a * alphaPassthrough; + else + gl_FragData[0].a = alphaPassthrough; +} diff --git a/files/shaders/shadowcasting_vertex.glsl b/files/shaders/shadowcasting_vertex.glsl new file mode 100644 index 0000000000..d578e97b70 --- /dev/null +++ b/files/shaders/shadowcasting_vertex.glsl @@ -0,0 +1,27 @@ +#version 120 + +varying vec2 diffuseMapUV; + +varying float alphaPassthrough; + +uniform int colorMode; +uniform bool useDiffuseMapForShadowAlpha; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); + gl_ClipVertex = viewPos; + + if (useDiffuseMapForShadowAlpha) + diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; + else + diffuseMapUV = vec2(0.0); // Avoid undefined behaviour if running on hardware predating the concept of dynamically uniform expressions + + if (colorMode == 2) + alphaPassthrough = gl_Color.a; + else + // This is uniform, so if it's too low, we might be able to put the position/clip vertex outside the view frustum and skip the fragment shader and rasteriser + alphaPassthrough = gl_FrontMaterial.diffuse.a; +} From 85b97d19d302e55c2f767f5c45bb34527206a328 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 17 Oct 2018 14:02:26 +0100 Subject: [PATCH 135/410] Add alpha threshold for shadow casting. --- files/shaders/shadowcasting_fragment.glsl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/files/shaders/shadowcasting_fragment.glsl b/files/shaders/shadowcasting_fragment.glsl index 6459467b11..00b8f9aa1a 100644 --- a/files/shaders/shadowcasting_fragment.glsl +++ b/files/shaders/shadowcasting_fragment.glsl @@ -14,4 +14,8 @@ void main() gl_FragData[0].a = texture2D(diffuseMap, diffuseMapUV).a * alphaPassthrough; else gl_FragData[0].a = alphaPassthrough; + + // Prevent translucent things casting shadow (including the player using an invisibility effect) + if (gl_FragData[0].a < 0.5) + discard; } From a41ce42208350b2fdb7a93efa4db9d0653b882d8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 18 Oct 2018 16:00:51 +0100 Subject: [PATCH 136/410] Move setting of colorMode to ShaderRequirements in case they're reused --- components/shader/shadervisitor.cpp | 5 ++++- components/shader/shadervisitor.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 457da5c776..fad43a3a10 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -23,6 +23,7 @@ namespace Shader ShaderVisitor::ShaderRequirements::ShaderRequirements() : mShaderRequired(false) + , mColorMode(2) , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) @@ -257,7 +258,7 @@ namespace Shader break; } - writableStateSet->addUniform(new osg::Uniform("colorMode", colorMode)); + mRequirements.back().mColorMode = colorMode; } } } @@ -303,6 +304,8 @@ namespace Shader defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; + writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); + osg::ref_ptr vertexShader (mShaderManager.getShader(mDefaultVsTemplate, defineMap, osg::Shader::VERTEX)); osg::ref_ptr fragmentShader (mShaderManager.getShader(mDefaultFsTemplate, defineMap, osg::Shader::FRAGMENT)); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index eab75acbb5..8737baf599 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -81,6 +81,8 @@ namespace Shader bool mShaderRequired; + int mColorMode; + bool mMaterialOverridden; bool mNormalHeight; // true if normal map has height info in alpha channel From b0907f89296019babf4f528ede1d22377987770e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 18 Oct 2018 16:01:36 +0100 Subject: [PATCH 137/410] Add todos in case they're left until after the shadow PR is merged --- components/sceneutil/mwshadowtechnique.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 8c36c5e715..8f42f8fcd7 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1498,6 +1498,10 @@ void MWShadowTechnique::createShaders() // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + + // TODO: figure out if there's some way to disable depth sorting for translucent objects as we don't care about blending. + // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader + // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches } osg::Polytope MWShadowTechnique::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) From e22ab64ebf4a791c2b27228844b22ae771be34b6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 22 Oct 2018 17:35:01 +0100 Subject: [PATCH 138/410] Fix typo in lighting.glsl --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index ff6ee94199..5c21b7bee1 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -27,7 +27,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow if (colorMode == 3) { diffuse = gl_FrontMaterial.diffuse; - ambient - vertexColor.xyz; + ambient = vertexColor.xyz; } else if (colorMode == 2) { From 1ca7ea23d17760003b3441138cba1907c5ead3c7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 30 Oct 2018 17:07:11 +0000 Subject: [PATCH 139/410] Add extra uniforms to the disabled shadows StateSet so that the shadow texture samplers are bound ot the dummy shadow maps correctly. --- components/sceneutil/shadow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 65754629e5..c2c728e12a 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -65,7 +65,11 @@ namespace SceneUtil fakeShadowMapTexture->setShadowComparison(true); fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); for (int i = baseShadowTextureUnit; i < baseShadowTextureUnit + numberOfShadowMapsPerLight; ++i) + { stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + stateset->addUniform(new osg::Uniform(("shadowTexture" + std::to_string(i - baseShadowTextureUnit)).c_str(), i)); + stateset->addUniform(new osg::Uniform(("shadowTextureUnit" + std::to_string(i - baseShadowTextureUnit)).c_str(), i)); + } } ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene), From eb44de3e6bf006d24f315a2706908bf49c525f02 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 30 Oct 2018 22:34:53 +0000 Subject: [PATCH 140/410] Disable shadows properly for water reflection/refraction RTT targets, eliminating remaining OpenGL errors. --- apps/openmw/mwrender/water.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9ad7dc8dd9..376924d82d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -263,6 +264,8 @@ public: mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture); + + SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet()); } void setScene(osg::Node* scene) @@ -341,6 +344,8 @@ public: mClipCullNode = new ClipCullNode; addChild(mClipCullNode); + + SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet()); } void setWaterLevel(float waterLevel) From ad9dab8593bbe0536c7e92f2bbc250bda99f8e23 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Nov 2018 16:20:56 +0000 Subject: [PATCH 141/410] Switch alpha test from < to <= to fix weird shadows on actors with 50% chameleon --- files/shaders/shadowcasting_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/shadowcasting_fragment.glsl b/files/shaders/shadowcasting_fragment.glsl index 00b8f9aa1a..336bfe4a48 100644 --- a/files/shaders/shadowcasting_fragment.glsl +++ b/files/shaders/shadowcasting_fragment.glsl @@ -16,6 +16,6 @@ void main() gl_FragData[0].a = alphaPassthrough; // Prevent translucent things casting shadow (including the player using an invisibility effect) - if (gl_FragData[0].a < 0.5) + if (gl_FragData[0].a <= 0.5) discard; } From 0bafa4399bbd79ece70effbd880872e22a29afeb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Nov 2018 16:56:33 +0000 Subject: [PATCH 142/410] Use distant shadow maps when the current fragment is outside the depth range of the near ones. --- files/shaders/shadows_fragment.glsl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index ce9e958d19..220e00efaa 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -16,12 +16,13 @@ float unshadowedLightRatio() @foreach shadow_texture_unit_index @shadow_texture_unit_list if (!doneShadows) { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; + vec2 shadowXY = shadowXYZ.xy; if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) { shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + if (all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0)))) doneShadows = true; } } From 660e423e9933d85b897297ee21a344cb9f3e657d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 20 Nov 2018 23:01:04 +0000 Subject: [PATCH 143/410] Correct debug hud frustum colour --- 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 8f42f8fcd7..598a663d3e 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -115,7 +115,7 @@ std::string debugFragmentShaderSource = #endif "} \n"; -std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z;}"; +std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z / gl_Position.w;}"; std::string debugFrustumFragmentShaderSource = "varying float depth; \n" " \n" From 632b0d8979c56eb79df2fa7db9a2580bc8a0d8a9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 20 Nov 2018 23:02:28 +0000 Subject: [PATCH 144/410] Make shadow maps use their whole depth range for the overlap with the view frustum and rely on depth clamping to ensure objects outside the frustum still cast shadows. --- components/sceneutil/mwshadowtechnique.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 598a663d3e..e26cfbe76f 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1499,6 +1499,8 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); + // TODO: figure out if there's some way to disable depth sorting for translucent objects as we don't care about blending. // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches @@ -2437,12 +2439,12 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam xMax = osg::minimum(1.0, convexHull.max(0)); yMin = osg::maximum(-1.0, convexHull.min(1)); yMax = osg::minimum(1.0, convexHull.max(1)); + zMin = osg::maximum(-1.0, convexHull.min(2)); + zMax = osg::minimum(1.0, convexHull.max(2)); } else return false; - // we always want the lightspace to include the computed near plane. - zMin = -1.0; if (xMin != -1.0 || yMin != -1.0 || zMin != -1.0 || xMax != 1.0 || yMax != 1.0 || zMax != 1.0) { @@ -2464,11 +2466,14 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam xMax = convexHull.max(0); yMin = convexHull.min(1); yMax = convexHull.max(1); + zMax = convexHull.max(2); planeList.push_back(osg::Plane(0.0, -1.0, 0.0, yMax)); planeList.push_back(osg::Plane(0.0, 1.0, 0.0, -yMin)); planeList.push_back(osg::Plane(-1.0, 0.0, 0.0, xMax)); planeList.push_back(osg::Plane(1.0, 0.0, 0.0, -xMin)); + planeList.push_back(osg::Plane(0.0, 0.0, -1.0, zMax)); + // Don't add a zMin culling plane - we still want those objects, but don't care about their depth buffer value. } return true; From 061fa57335b5df1329204cbb45a516778e694031 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 21 Nov 2018 22:38:50 +0000 Subject: [PATCH 145/410] Switch to better-performing data types for debug hud geometry --- components/sceneutil/mwshadowtechnique.cpp | 13 +++++++++---- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e26cfbe76f..fa62ae1fae 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -942,7 +942,12 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) Frustum frustum(&cv, minZNear, maxZFar); if (_debugHud) - _debugHud->setFrustumVertices(new osg::Vec3dArray(8, &frustum.corners[0])); + { + osg::ref_ptr vertexArray = new osg::Vec3Array(8); + for (osg::Vec3d &vertex : frustum.corners) + vertexArray->push_back((osg::Vec3)vertex); + _debugHud->setFrustumVertices(vertexArray); + } double reducedNear, reducedFar; if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) @@ -2984,7 +2989,7 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) mFrustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); //mFrustumGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); + osg::ref_ptr frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP); mFrustumGeometry->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(0); frustumDrawElements->push_back(1); @@ -2997,7 +3002,7 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) frustumDrawElements->push_back(7); frustumDrawElements->push_back(4); - frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); + frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINES); mFrustumGeometry->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(1); frustumDrawElements->push_back(5); @@ -3044,7 +3049,7 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) mFrustumGeometry->releaseGLObjects(state); } -void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) +void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) { mFrustumGeometry->setVertexArray(vertices); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 558ad49d95..e1f2884958 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -253,7 +253,7 @@ namespace SceneUtil { virtual void releaseGLObjects(osg::State* state = 0) const; - virtual void setFrustumVertices(osg::ref_ptr vertices); + virtual void setFrustumVertices(osg::ref_ptr vertices); protected: virtual void addAnotherShadowMap(); From 7ad4882f0c0ee3aab47bf14abf504bfb364f9bb6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 21 Nov 2018 23:45:47 +0000 Subject: [PATCH 146/410] Fix debug hud frustum outline disappearence --- 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 fa62ae1fae..8f8b9aa961 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -943,7 +943,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) Frustum frustum(&cv, minZNear, maxZFar); if (_debugHud) { - osg::ref_ptr vertexArray = new osg::Vec3Array(8); + osg::ref_ptr vertexArray = new osg::Vec3Array(); for (osg::Vec3d &vertex : frustum.corners) vertexArray->push_back((osg::Vec3)vertex); _debugHud->setFrustumVertices(vertexArray); From aa118329498c681eca55d46f7ed8f082bc268d46 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 29 Nov 2018 01:17:58 +0000 Subject: [PATCH 147/410] Resolve bugs with depth-clamped shadow maps --- components/sceneutil/mwshadowtechnique.cpp | 46 +++++++++++++++++----- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 8f8b9aa961..0161891d35 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -326,9 +326,9 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) OSG_INFO<<"RTT Projection matrix after clamping "<setProjectionMatrix(projection); - - _projectionMatrix = cv->getProjectionMatrix(); } + + _projectionMatrix = cv->getProjectionMatrix(); } MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : @@ -552,9 +552,16 @@ MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData* //_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); _camera->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f)); - _camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + // Now we are using Depth Clamping, we want to not cull things on the wrong side of the near plane. + // When the near and far planes are computed, OSG always culls anything on the wrong side of the near plane, even if it's told not to. + // Even if that weren't an issue, the near plane can't go past any shadow receivers or the depth-clamped fragments which ended up on the near plane can't cast shadows on those receivers. + // Unfortunately, this change will make shadows have less depth precision when there are no casters outside the view frustum. + // TODO: Find a better solution. E.g. detect when there are no casters outside the view frustum, write a new cull visitor that does all the wacky things we'd need it to. + _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + // switch off small feature culling as this can cull out geometry that will still be large enough once perspective correction takes effect. _camera->setCullingMode(_camera->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING); @@ -2432,8 +2439,6 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam convexHull.transform(light_vp); - convexHull.extendTowardsNegativeZ(); - double xMin = -1.0, xMax = 1.0; double yMin = -1.0, yMax = 1.0; double zMin = -1.0, zMax = 1.0; @@ -2471,14 +2476,15 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam xMax = convexHull.max(0); yMin = convexHull.min(1); yMax = convexHull.max(1); - zMax = convexHull.max(2); + zMin = convexHull.min(2); planeList.push_back(osg::Plane(0.0, -1.0, 0.0, yMax)); planeList.push_back(osg::Plane(0.0, 1.0, 0.0, -yMin)); planeList.push_back(osg::Plane(-1.0, 0.0, 0.0, xMax)); planeList.push_back(osg::Plane(1.0, 0.0, 0.0, -xMin)); - planeList.push_back(osg::Plane(0.0, 0.0, -1.0, zMax)); - // Don't add a zMin culling plane - we still want those objects, but don't care about their depth buffer value. + // In view space, the light is at the most positive value, and we want to cull stuff beyond the minimum value. + planeList.push_back(osg::Plane(0.0, 0.0, 1.0, -zMin)); + // Don't add a zMax culling plane - we still want those objects, but don't care about their depth buffer value. } return true; @@ -2531,6 +2537,8 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render convexHull.transform(light_vp); + ConvexHull convexHullUnextended = convexHull; + convexHull.extendTowardsNegativeZ(); #if 0 @@ -2581,6 +2589,9 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render #if 1 convexHull.clip(osg::Plane(1.0,0.0,0.0,-rli.min_x)); convexHull.clip(osg::Plane(-1.0,0.0,0.0,rli.max_x)); + + convexHullUnextended.clip(osg::Plane(1.0, 0.0, 0.0, -rli.min_x)); + convexHullUnextended.clip(osg::Plane(-1.0, 0.0, 0.0, rli.max_x)); #else convexHull.clip(osg::Plane(1.0,0.0,0.0,widest_x)); convexHull.clip(osg::Plane(-1.0,0.0,0.0,widest_x)); @@ -2588,12 +2599,18 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render #if 1 convexHull.clip(osg::Plane(0.0,1.0,0.0,-rli.min_y)); convexHull.clip(osg::Plane(0.0,-1.0,0.0,rli.max_y)); + + convexHullUnextended.clip(osg::Plane(0.0, 1.0, 0.0, -rli.min_y)); + convexHullUnextended.clip(osg::Plane(0.0, -1.0, 0.0, rli.max_y)); #endif #endif #if 1 convexHull.clip(osg::Plane(0.0,0.0,1.0,-rli.min_z)); convexHull.clip(osg::Plane(0.0,0.0,-1.0,rli.max_z)); + + convexHullUnextended.clip(osg::Plane(0.0, 0.0, 1.0, -rli.min_z)); + convexHullUnextended.clip(osg::Plane(0.0, 0.0, -1.0, rli.max_z)); #elif 0 convexHull.clip(osg::Plane(0.0,0.0,1.0,1.0)); convexHull.clip(osg::Plane(0.0,0.0,-1.0,1.0)); @@ -2656,6 +2673,7 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render 2.0/(zMax-zMin))); convexHull.transform(m); + convexHullUnextended.transform(m); light_p.postMult(m); light_vp = light_v * light_p; @@ -2748,6 +2766,12 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render //min_z_ratio = convexHull.minRatio(virtual_eye,2); //max_z_ratio = convexHull.maxRatio(virtual_eye,2); + if (convexHullUnextended.valid()) + { + min_z_ratio = convexHullUnextended.minRatio(virtual_eye, 2); + max_z_ratio = convexHullUnextended.maxRatio(virtual_eye, 2); + } + #if 0 OSG_NOTICE<<"convexHull min_x_ratio = "<setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); + mShadowTechnique->setPolygonOffset(Settings::Manager::getFloat("polygon offset factor", "Shadows"), Settings::Manager::getFloat("polygon offset units", "Shadows")); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED); else diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index b88df8942b..8ab9c25390 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -135,10 +135,34 @@ Some might feel this is distracting as shadows can be cast through other objects Expert settings *************** -You probably shouldn't be changing these yourself if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. -If you have, then you may get better results tuning these for your specific view distance. +These settings are probably too complicated for regular users to judge what might be good values to set them to. +If you've got a good understanding of how shadow mapping works, or you've got enough time to try a large set of values, you may get better results tuning these yourself. Copying values from another user who's done careful tuning is the recommended way of arriving at an optimal value for these settings. +Understanding what some of these do might be easier for people who've read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. + +polygon offset factor +--------------------- + +:Type: float +:Range: Theoretically the whole range of 32-bit floating point, but values just above 1.0 are most sensible. +:Default: 1.1 + +Used as the factor parameter for the polygon offset used for shadow map rendering. +Higher values reduce shadow flicker, but risk increasing Peter Panning. +See `the OpenGL documentation for glPolygonOffset `_ for details. + +polygon offset units +--------------------- + +:Type: float +:Range: Theoretically the whole range of 32-bit floating point, but values between 1 and 10 are most sensible. +:Default: 4.0 + +Used as the units parameter for the polygon offset used for shadow map rendering. +Higher values reduce shadow flicker, but risk increasing Peter Panning. +See `the OpenGL documentation for glPolygonOffset `_ for details. + split point uniform logarithmic ratio ------------------------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 5e866dbfb0..0ca5ad93d1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -662,6 +662,10 @@ compute tight scene bounds = false shadow map resolution = 1024 # Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. Increasing this pushes detail further away. minimum lispsm near far ratio = 0.25 +# Used as the factor parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. +polygon offset factor = 1.1 +# Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. +polygon offset units = 4.0 # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false # Allow the player to cast shadows. Potentially decreases performance. From 0a409c0ab8f448df43a3921afbee5f22483a8168 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 1 Dec 2018 00:26:43 +0000 Subject: [PATCH 149/410] Make shadow map front-face culling configurable --- components/sceneutil/mwshadowtechnique.cpp | 20 +++++++++++++++++-- components/sceneutil/mwshadowtechnique.hpp | 6 ++++++ components/sceneutil/shadow.cpp | 5 +++++ .../reference/modding/settings/shadows.rst | 10 ++++++++++ files/settings-default.cfg | 2 ++ 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index eb7df28d1c..5ed5e5a99a 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -836,6 +836,22 @@ void SceneUtil::MWShadowTechnique::setPolygonOffset(float factor, float units) } } +void SceneUtil::MWShadowTechnique::enableFrontFaceCulling() +{ + _useFrontFaceCulling = true; + + if (_shadowCastingStateSet) + _shadowCastingStateSet->setAttribute(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); +} + +void SceneUtil::MWShadowTechnique::disableFrontFaceCulling() +{ + _useFrontFaceCulling = false; + + if (_shadowCastingStateSet) + _shadowCastingStateSet->removeAttribute(osg::StateAttribute::CULLFACE); +} + void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) { // This can't be part of the constructor as OSG mandates that there be a trivial constructor available @@ -1422,8 +1438,8 @@ void MWShadowTechnique::createShaders() // backface nor front face so they usually use CullMode off set here. // In this case we will draw them in their entirety. - _shadowCastingStateSet->setAttribute( new osg::CullFace( osg::CullFace::FRONT ), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); + if (_useFrontFaceCulling) + _shadowCastingStateSet->setAttribute(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); // make sure GL_CULL_FACE is off by default // we assume that if object has cull face attribute set to back diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index ccfb6094ba..16d44c5e2f 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -76,6 +76,10 @@ namespace SceneUtil { virtual void setPolygonOffset(float factor, float units); + virtual void enableFrontFaceCulling(); + + virtual void disableFrontFaceCulling(); + virtual void setupCastingShader(Shader::ShaderManager &shaderManager); class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack @@ -249,6 +253,8 @@ namespace SceneUtil { float _polygonOffsetFactor = 1.1; float _polygonOffsetUnits = 4.0; + bool _useFrontFaceCulling = true; + class DebugHUD : public osg::Referenced { public: diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e9091451dd..a6559e9b9e 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -44,6 +44,11 @@ namespace SceneUtil mShadowTechnique->setPolygonOffset(Settings::Manager::getFloat("polygon offset factor", "Shadows"), Settings::Manager::getFloat("polygon offset units", "Shadows")); + if (Settings::Manager::getBool("use front face culling", "Shadows")) + mShadowTechnique->enableFrontFaceCulling(); + else + mShadowTechnique->disableFrontFaceCulling(); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED); else diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 8ab9c25390..c8d3250a0e 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -163,6 +163,16 @@ Used as the units parameter for the polygon offset used for shadow map rendering Higher values reduce shadow flicker, but risk increasing Peter Panning. See `the OpenGL documentation for glPolygonOffset `_ for details. +use front face culling +---------------------- + +:Type: boolean +:Range: True/False +:Default: True + +Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. +In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. + split point uniform logarithmic ratio ------------------------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0ca5ad93d1..df9ea30083 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -666,6 +666,8 @@ minimum lispsm near far ratio = 0.25 polygon offset factor = 1.1 # Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset units = 4.0 +# Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. +use front face culling = true # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false # Allow the player to cast shadows. Potentially decreases performance. From 244bd289cba81d41dbedc6debd60bca7b75ac5b4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 3 Dec 2018 18:56:37 +0000 Subject: [PATCH 150/410] Change default colour mode (as apparently it actually gets used sometimes) --- components/shader/shadervisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index fad43a3a10..3080e1318a 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -23,7 +23,7 @@ namespace Shader ShaderVisitor::ShaderRequirements::ShaderRequirements() : mShaderRequired(false) - , mColorMode(2) + , mColorMode(0) , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) From 2d5da1a6fab2aba05ecdd477b36f026d336f2a73 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 8 Dec 2018 20:39:41 +0000 Subject: [PATCH 151/410] Don't exclusively rely on a shadow map if its bounds have been expanded since the cull traversal. --- components/sceneutil/mwshadowtechnique.cpp | 23 +++++++++++++++++ components/sceneutil/shadow.cpp | 8 ++++++ files/shaders/shadows_fragment.glsl | 30 ++++++++++++++++------ files/shaders/shadows_vertex.glsl | 9 +++++++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 5ed5e5a99a..ea52ec24a8 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1315,6 +1315,29 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (!orthographicViewFrustum && settings->getShadowMapProjectionHint()==ShadowSettings::PERSPECTIVE_SHADOW_MAP) { + { + osg::Matrix validRegionMatrix = cv.getCurrentCamera()->getInverseViewMatrix() * camera->getViewMatrix() * camera->getProjectionMatrix(); + + std::string validRegionUniformName = "validRegionMatrix" + std::to_string(sm_i); + osg::ref_ptr validRegionUniform; + + OpenThreads::ScopedLock lock(_accessUniformsAndProgramMutex); + + for (auto uniform : _uniforms) + { + if (uniform->getName() == validRegionUniformName) + validRegionUniform = uniform; + } + + if (!validRegionUniform) + { + validRegionUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, validRegionUniformName); + _uniforms.push_back(validRegionUniform); + } + + validRegionUniform->set(validRegionMatrix); + } + if (settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED) adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), cascaseNear, cascadeFar); else diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index a6559e9b9e..d3655dfb5c 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -119,6 +119,12 @@ namespace SceneUtil else definesWithShadows["useShadowDebugOverlay"] = "0"; + // switch this to reading settings if it's ever exposed to the user + if (mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP) + definesWithShadows["perspectiveShadowMaps"] = "1"; + else + definesWithShadows["perspectiveShadowMaps"] = "0"; + return definesWithShadows; } @@ -132,6 +138,8 @@ namespace SceneUtil definesWithShadows["useShadowDebugOverlay"] = "0"; + definesWithShadows["perspectiveShadowMaps"] = "0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index 220e00efaa..713473458b 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -4,6 +4,10 @@ @foreach shadow_texture_unit_index @shadow_texture_unit_list uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + +#if @perspectiveShadowMaps + varying vec4 shadowRegionCoords@shadow_texture_unit_index; +#endif @endforeach #endif // SHADOWS @@ -17,13 +21,18 @@ float unshadowedLightRatio() if (!doneShadows) { vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; - vec2 shadowXY = shadowXYZ.xy; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) +#if @perspectiveShadowMaps + vec3 shadowRegionXYZ = shadowRegionCoords@shadow_texture_unit_index.xyz / shadowRegionCoords@shadow_texture_unit_index.w; +#endif + if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) { shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); - if (all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0)))) - doneShadows = true; + + doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); +#if @perspectiveShadowMaps + doneShadows = doneShadows && all(lessThan(shadowRegionXYZ, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); +#endif } } @endforeach @@ -44,8 +53,11 @@ void applyShadowDebugOverlay() @foreach shadow_texture_unit_index @shadow_texture_unit_list if (!doneOverlay) { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; +#if @perspectiveShadowMaps + vec3 shadowRegionXYZ = shadowRegionCoords@shadow_texture_unit_index.xyz / shadowRegionCoords@shadow_texture_unit_index.w; +#endif + if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) { colourIndex = mod(@shadow_texture_unit_index.0, 3.0); if (colourIndex < 1.0) @@ -55,8 +67,10 @@ void applyShadowDebugOverlay() else gl_FragData[0].z += 0.1; - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneOverlay = true; + doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); +#if @perspectiveShadowMaps + doneOverlay = doneOverlay && all(lessThan(shadowRegionXYZ.xyz, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); +#endif } } @endforeach diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl index bbc1a40368..4baa249c11 100644 --- a/files/shaders/shadows_vertex.glsl +++ b/files/shaders/shadows_vertex.glsl @@ -4,6 +4,11 @@ @foreach shadow_texture_unit_index @shadow_texture_unit_list uniform int shadowTextureUnit@shadow_texture_unit_index; varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + +#if @perspectiveShadowMaps + uniform mat4 validRegionMatrix@shadow_texture_unit_index; + varying vec4 shadowRegionCoords@shadow_texture_unit_index; +#endif @endforeach #endif // SHADOWS @@ -15,6 +20,10 @@ void setupShadowCoords(vec4 viewPos) @foreach shadow_texture_unit_index @shadow_texture_unit_list eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + +#if @perspectiveShadowMaps + shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; +#endif @endforeach #endif // SHADOWS } \ No newline at end of file From b6b1b3980483ea96459298fd6fbff3ee69fb58e1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 10 Dec 2018 21:20:29 +0000 Subject: [PATCH 152/410] Make the terrain paging system use the view point rather than the eye point to determine which nodes to use so that it can be inherited by RTT cameras. --- components/terrain/quadtreenode.cpp | 2 +- components/terrain/quadtreeworld.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 2222cbb844..4b4df43659 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -134,7 +134,7 @@ ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv) { osgUtil::CullVisitor* cv = static_cast(&nv); ViewData* vd = mViewDataMap->getViewData(cv->getCurrentCamera()); - vd->setEyePoint(nv.getEyePoint()); + vd->setEyePoint(nv.getViewPoint()); return vd; } else // INTERSECTION_VISITOR diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 0d5b25697b..6ec89721ad 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -363,7 +363,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) traverseToCell(mRootNode.get(), vd, x,y); } else - traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getEyePoint(), true); + traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true); } else mRootNode->traverse(nv); From 7b108ae9a2cbc45524a86bf5d40cef34417ec357 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Dec 2018 01:45:05 +0000 Subject: [PATCH 153/410] Disable depth sorting for translucent objects in the shadow maps --- components/sceneutil/mwshadowtechnique.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index ea52ec24a8..6f3d34cb1a 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1554,7 +1554,8 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); - // TODO: figure out if there's some way to disable depth sorting for translucent objects as we don't care about blending. + _shadowCastingStateSet->setRenderBinDetails(osg::StateSet::OPAQUE_BIN, "RenderBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS); + // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches } From 305b9826df7bc72211066b2eb9375df090ad501c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Dec 2018 16:23:32 +0000 Subject: [PATCH 154/410] Use forward declaration to reduce build times. --- components/sceneutil/shadow.cpp | 2 ++ components/sceneutil/shadow.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index d3655dfb5c..7f356f51c4 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -9,6 +9,8 @@ #include +#include "mwshadowtechnique.hpp" + namespace SceneUtil { using namespace osgShadow; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 26e119d88b..acccd22037 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -7,10 +7,10 @@ #include #include -#include "mwshadowtechnique.hpp" - namespace SceneUtil { + class MWShadowTechnique; + class ShadowManager { public: From 199e6ed82ddc660adb47507bebd30af2406ada78 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Dec 2018 23:53:14 +0000 Subject: [PATCH 155/410] Revert "Use forward declaration to reduce build times." This reverts commit 305b9826df7bc72211066b2eb9375df090ad501c. --- components/sceneutil/shadow.cpp | 2 -- components/sceneutil/shadow.hpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 7f356f51c4..d3655dfb5c 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -9,8 +9,6 @@ #include -#include "mwshadowtechnique.hpp" - namespace SceneUtil { using namespace osgShadow; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index acccd22037..26e119d88b 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -7,10 +7,10 @@ #include #include +#include "mwshadowtechnique.hpp" + namespace SceneUtil { - class MWShadowTechnique; - class ShadowManager { public: From 8687a49c1925a5e2b3bc6264a4b5a1334e0b4bf4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 21 Dec 2018 16:17:09 +0400 Subject: [PATCH 156/410] Editor: Added basic info window --- apps/opencs/model/doc/document.cpp | 5 +++ apps/opencs/model/doc/document.hpp | 2 + apps/opencs/view/doc/view.cpp | 61 +++++++++++++++++++++++++++++ apps/opencs/view/doc/view.hpp | 6 +++ files/opencs/qt.png | Bin 0 -> 405 bytes files/opencs/resources.qrc | 1 + 6 files changed, 75 insertions(+) create mode 100644 files/opencs/qt.png diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 233b3e439d..76511f535f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -364,6 +364,11 @@ int CSMDoc::Document::getState() const return state; } +const boost::filesystem::path& CSMDoc::Document::getResourceDir() const +{ + return mResDir; +} + const boost::filesystem::path& CSMDoc::Document::getSavePath() const { return mSavePath; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4c442428e8..a2579af4c6 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -115,6 +115,8 @@ namespace CSMDoc int getState() const; + const boost::filesystem::path& getResourceDir() const; + const boost::filesystem::path& getSavePath() const; const boost::filesystem::path& getProjectPath() const; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ed4dcff76f..42dbe51ac3 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,8 @@ #include "../tools/subviews.hpp" +#include + #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -303,6 +306,17 @@ void CSVDoc::View::setupDebugMenu() connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView())); } +void CSVDoc::View::setupHelpMenu() +{ + QMenu *help = menuBar()->addMenu (tr ("Help")); + + QAction* about = createMenuEntry("About OpenMW-CS", ":./info.png", help, "document-help-about"); + connect (about, SIGNAL (triggered()), this, SLOT (infoAbout())); + + QAction* aboutQt = createMenuEntry("About Qt", ":./qt.png", help, "document-help-qt"); + connect (aboutQt, SIGNAL (triggered()), this, SLOT (infoAboutQt())); +} + QAction* CSVDoc::View::createMenuEntry(CSMWorld::UniversalId::Type type, QMenu* menu, const char* shortcutName) { const std::string title = CSMWorld::UniversalId (type).getTypeName(); @@ -339,6 +353,7 @@ void CSVDoc::View::setupUi() setupCharacterMenu(); setupAssetsMenu(); setupDebugMenu(); + setupHelpMenu(); } void CSVDoc::View::setupShortcut(const char* name, QAction* action) @@ -674,6 +689,52 @@ void CSVDoc::View::save() mDocument->save(); } +void CSVDoc::View::infoAbout() +{ + // Get current OpenMW version + QString versionInfo = (Version::getOpenmwVersionDescription(mDocument->getResourceDir().string())+ +#if defined(__x86_64__) || defined(_M_X64) + " (64-bit)").c_str(); +#else + " (32-bit)").c_str(); +#endif + + // Get current year + time_t now = time(NULL); + struct tm tstruct; + char copyrightInfo[40]; + tstruct = *localtime(&now); + strftime(copyrightInfo, sizeof(copyrightInfo), "Copyright © 2008-%Y OpenMW Team", &tstruct); + + QString aboutText = QString( + "

" + "

OpenMW Construction Set

" + "%1\n\n" + "%2\n\n" + "%3\n\n" + "" + "" + "" + "" + "" + "
%4https://openmw.org
%5https://forum.openmw.org
%6https://gitlab.com/OpenMW/openmw/issues
%7irc://irc.freenode.net/#openmw
" + "

") + .arg(versionInfo + , tr("OpenMW-CS is a content file editor for OpenMW, a modern, free and open source game engine.") + , tr(copyrightInfo) + , tr("Home Page:") + , tr("Forum:") + , tr("Bug Tracker:") + , tr("IRC:")); + + QMessageBox::about(this, "About OpenMW-CS", aboutText); +} + +void CSVDoc::View::infoAboutQt() +{ + QMessageBox::aboutQt(this); +} + void CSVDoc::View::verify() { addSubView (mDocument->verify()); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7a9a48b0f0..c4046a7a16 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -85,6 +85,8 @@ namespace CSVDoc void setupDebugMenu(); + void setupHelpMenu(); + void setupUi(); void setupShortcut(const char* name, QAction* action); @@ -165,6 +167,10 @@ namespace CSVDoc void exit(); + void infoAbout(); + + void infoAboutQt(); + void verify(); void addGlobalsSubView(); diff --git a/files/opencs/qt.png b/files/opencs/qt.png new file mode 100644 index 0000000000000000000000000000000000000000..381cb2251fcb072234d49752cdc5e1a79ff6e675 GIT binary patch literal 405 zcmV;G0c!qPx#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^7j^FlWO008Yt zL_t(IPhTD(84M=q?cdCl(i2XFH5286JKydjx#l+M23-Aew2+z^VBE z*Ka`BFzjobject.png pathgrid.png potion.png + qt.png race.png random-item.png random.png From 0ab53147558974c37842e662edeaa98ec088915b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 6 Dec 2018 18:31:47 +0300 Subject: [PATCH 157/410] Make scripted items not stack (bug #2969) --- CHANGELOG.md | 1 + apps/openmw/mwscript/containerextensions.cpp | 19 ++++++++++++++++++- apps/openmw/mwworld/containerstore.cpp | 6 ++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0da3ba67d9..f5c63a8925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.46.0 ------ + Bug #2969: Scripted items can stack Bug #2987: Editor: some chance and AI data fields can overflow Bug #3623: Fix HiDPI on Windows Bug #4411: Reloading a saved game while falling prevents damage in some cases diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index cf12d12c3a..8a25f0c015 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -64,7 +64,19 @@ namespace MWScript || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; - MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); + // Create a Ptr for the first added item to recover the item name later + MWWorld::Ptr itemPtr = *store.add (item, 1, ptr); + if (itemPtr.getClass().getScript(itemPtr).empty()) + { + store.add (item, count-1, ptr); + } + else + { + // Adding just one item per time to make sure there isn't a stack of scripted items + for (int i = 1; i < count; i++) + store.add (item, 1, ptr); + } // Spawn a messagebox (only for items added to player's inventory and if player is talking to someone) if (ptr == MWBase::Environment::get().getWorld ()->getPlayerPtr() ) @@ -143,8 +155,13 @@ namespace MWScript std::string itemName; for (MWWorld::ConstContainerStoreIterator iter(store.cbegin()); iter != store.cend(); ++iter) + { if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) + { itemName = iter->getClass().getName(*iter); + break; + } + } int numRemoved = store.remove(item, count, ptr); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ee30899018..6725fb9350 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -246,7 +246,9 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) && ptr1.getClass().getRemainingUsageTime(ptr1) == ptr2.getClass().getRemainingUsageTime(ptr2) - && cls1.getScript(ptr1) == cls2.getScript(ptr2) + // Items with scripts never stack + && cls1.getScript(ptr1).empty() + && cls2.getScript(ptr2).empty() // item that is already partly used up never stacks && (!cls1.hasItemHealth(ptr1) || ( @@ -306,7 +308,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.getCellRef().unsetRefNum(); // destroy link to content file std::string script = item.getClass().getScript(item); - if(script != "") + if (!script.empty()) { if (actorPtr == player) { From 05d5d7d57b97191f6c01ebcbb079b900d63e201c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 13 Jan 2019 05:11:51 +0300 Subject: [PATCH 158/410] Account for stances when the player is in air (bug #4797) Make GetPCRunning and GetPCSneaking return 1 if the player is in air while the stance is toggled Make sneaking skill usage possible if sneaking stance is toggled while in air --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/actors.cpp | 147 ++++++++++++--------- apps/openmw/mwmechanics/actors.hpp | 4 + apps/openmw/mwscript/controlextensions.cpp | 21 +-- 4 files changed, 99 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa5a91a9d7..36eb5bed16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Bug #4768: Fallback numerical value recovery chokes on invalid arguments Bug #4775: Slowfall effect resets player jumping flag Bug #4778: Interiors of Illusion puzzle in Sotha Sil Expanded mod is broken + Bug #4797: Player sneaking and running stances are not accounted for when in air Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4166ece11e..b91fb1d421 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1513,72 +1513,7 @@ namespace MWMechanics } killDeadActors(); - - static float sneakTimer = 0.f; // times update of sneak icon - - // if player is in sneak state see if anyone detects him - if (playerCharacter && playerCharacter->isSneaking()) - { - static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice" - - const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - const int radius = esmStore.get().find("fSneakUseDist")->mValue.getInteger(); - - static float fSneakUseDelay = esmStore.get().find("fSneakUseDelay")->mValue.getFloat(); - - if (sneakTimer >= fSneakUseDelay) - sneakTimer = 0.f; - - if (sneakTimer == 0.f) - { - // Set when an NPC is within line of sight and distance, but is still unaware. Used for skill progress. - bool avoidedNotice = false; - - bool detected = false; - - for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) - { - MWWorld::Ptr observer = iter->first; - - if (iter->first == player) // not the player - continue; - - if (observer.getClass().getCreatureStats(observer).isDead()) - continue; - - // is the player in range and can they be detected - if ((observer.getRefData().getPosition().asVec3() - playerPos).length2() <= radius*radius - && MWBase::Environment::get().getWorld()->getLOS(player, observer)) - { - if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer)) - { - detected = true; - avoidedNotice = false; - MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); - break; - } - else - avoidedNotice = true; - } - } - - if (sneakSkillTimer >= fSneakUseDelay) - sneakSkillTimer = 0.f; - - if (avoidedNotice && sneakSkillTimer == 0.f) - player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 0); - - if (!detected) - MWBase::Environment::get().getWindowManager()->setSneakVisibility(true); - } - sneakTimer += duration; - sneakSkillTimer += duration; - } - else - { - sneakTimer = 0.f; - MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); - } + updateSneaking(playerCharacter, duration); } updateCombatMusic(); @@ -1727,6 +1662,86 @@ namespace MWMechanics fastForwardAi(); } + void Actors::updateSneaking(CharacterController* ctrl, float duration) + { + static float sneakTimer = 0.f; // Times update of sneak icon + + if (!ctrl) + { + MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); + return; + } + + MWWorld::Ptr player = getPlayer(); + + CreatureStats& stats = player.getClass().getCreatureStats(player); + MWBase::World* world = MWBase::Environment::get().getWorld(); + + bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool inair = !world->isOnGround(player) && !world->isSwimming(player) && !world->isFlying(player); + sneaking = sneaking && (ctrl->isSneaking() || inair); + + if (!sneaking) + { + MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); + return; + } + + static float sneakSkillTimer = 0.f; // Times sneak skill progress from "avoid notice" + + const MWWorld::Store& gmst = world->getStore().get(); + static const float fSneakUseDist = gmst.find("fSneakUseDist")->mValue.getFloat(); + static const float fSneakUseDelay = gmst.find("fSneakUseDelay")->mValue.getFloat(); + + if (sneakTimer >= fSneakUseDelay) + sneakTimer = 0.f; + + if (sneakTimer == 0.f) + { + // Set when an NPC is within line of sight and distance, but is still unaware. Used for skill progress. + bool avoidedNotice = false; + bool detected = false; + + std::vector observers; + osg::Vec3f position(player.getRefData().getPosition().asVec3()); + float radius = std::min(fSneakUseDist, mActorsProcessingRange); + getObjectsInRange(position, radius, observers); + + for (const MWWorld::Ptr &observer : observers) + { + if (observer == player || observer.getClass().getCreatureStats(observer).isDead()) + continue; + + if (world->getLOS(player, observer)) + { + if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer)) + { + detected = true; + avoidedNotice = false; + MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); + break; + } + else + { + avoidedNotice = true; + } + } + } + + if (sneakSkillTimer >= fSneakUseDelay) + sneakSkillTimer = 0.f; + + if (avoidedNotice && sneakSkillTimer == 0.f) + player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 0); + + if (!detected) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(true); + } + + sneakTimer += duration; + sneakSkillTimer += duration; + } + int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const { float healthPerHour, magickaPerHour; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 61879c432f..75f1b394ec 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -19,6 +19,7 @@ namespace MWWorld namespace MWMechanics { class Actor; + class CharacterController; class CreatureStats; class Actors @@ -108,6 +109,9 @@ namespace MWMechanics void rest(bool sleep); ///< Update actors while the player is waiting or sleeping. This should be called every hour. + void updateSneaking(CharacterController* ctrl, float duration); + ///< Update the sneaking indicator state according to the given player character controller. + void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep); int getHoursToRest(const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 21b3b5587e..0d5b1bf3b0 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -16,7 +16,6 @@ #include "../mwworld/ptr.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/movement.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -168,12 +167,15 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - const MWWorld::Class &cls = ptr.getClass(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + MWBase::World* world = MWBase::Environment::get().getWorld(); - bool isRunning = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); + bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Run); + bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); + bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr); - runtime.push (isRunning && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)); + runtime.push(stanceOn && (running || inair)); } }; @@ -184,11 +186,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWWorld::Class &cls = ptr.getClass(); + MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + MWBase::World* world = MWBase::Environment::get().getWorld(); - bool isSneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr); + bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr); + bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr); - runtime.push (isSneaking && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)); + runtime.push(stanceOn && (sneaking || inair)); } }; From 8d036a79ebb1a81e656d5e219f526c20e2bc6bee Mon Sep 17 00:00:00 2001 From: Justin Ivany <1406666+jrivany@users.noreply.github.com> Date: Thu, 17 Jan 2019 19:02:45 -0400 Subject: [PATCH 159/410] Fixes #4703 Disable preview for item levelled list --- apps/opencs/view/world/table.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 14df4658d5..31180b3f11 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -141,13 +141,15 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Preview) { + const CSMWorld::UniversalId id = getUniversalId(currentRow); + const CSMWorld::UniversalId::Type type = id.getType(); + QModelIndex index = mModel->index (row, mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification)); - CSMWorld::RecordBase::State state = static_cast ( mModel->data (index).toInt()); - if (state!=CSMWorld::RecordBase::State_Deleted) + if (state!=CSMWorld::RecordBase::State_Deleted && type != CSMWorld::UniversalId::Type_ItemLevelledList) menu.addAction (mPreviewAction); } } From 33c7e4e948e07808191a59cd8905f71a044bc219 Mon Sep 17 00:00:00 2001 From: Justin Ivany <1406666+jrivany@users.noreply.github.com> Date: Thu, 17 Jan 2019 20:17:18 -0400 Subject: [PATCH 160/410] Don't remove whitespace... --- apps/opencs/view/world/table.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 31180b3f11..eb7b8e334b 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -146,6 +146,7 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) QModelIndex index = mModel->index (row, mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification)); + CSMWorld::RecordBase::State state = static_cast ( mModel->data (index).toInt()); From 9d84853903da4739f78052947c243f6cc5207254 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 24 Jan 2019 18:56:10 +0000 Subject: [PATCH 161/410] Fix nodemask snafu --- apps/openmw/mwrender/characterpreview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 18bbcee0a9..a3679e844c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -137,6 +137,7 @@ namespace MWRender mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); mCamera->setName("CharacterPreview"); mCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + mCamera->setCullMask(~(Mask_UpdateVisitor)); mCamera->setNodeMask(Mask_RenderToTexture); From 6660f2f8e6674e0ab111c5ed8b95363792537b46 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 9 Dec 2018 00:01:28 +0300 Subject: [PATCH 162/410] Use the skeleton from the NPC's set model (bug #4747) --- CHANGELOG.md | 1 + apps/openmw/mwrender/npcanimation.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31e086842c..83211e40ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Bug #4723: ResetActors command works incorrectly Bug #4745: Editor: Interior cell lighting field values are not displayed as colors Bug #4746: Non-solid player can't run or sneak + Bug #4747: Bones are not read from X.NIF file for NPC animation Bug #4750: Sneaking doesn't work in first person view if the player is in attack ready state Bug #4768: Fallback numerical value recovery chokes on invalid arguments Bug #4775: Slowfall effect resets player jumping flag diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 920e09a69a..825490bc22 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -465,8 +465,12 @@ void NpcAnimation::updateNpcBase() bool is1stPerson = mViewMode == VM_FirstPerson; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; - std::string smodel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); - smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); + std::string defaultSkeleton = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); + defaultSkeleton = Misc::ResourceHelpers::correctActorModelPath(defaultSkeleton, mResourceSystem->getVFS()); + + std::string smodel = defaultSkeleton; + if (!is1stPerson && !isWerewolf & !mNpc->mModel.empty()) + smodel = Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()); setObjectRoot(smodel, true, true, false); @@ -481,15 +485,13 @@ void NpcAnimation::updateNpcBase() if (smodel != base) addAnimSource(base, smodel); + if (smodel != defaultSkeleton && base != defaultSkeleton) + addAnimSource(defaultSkeleton, smodel); + addAnimSource(smodel, smodel); - if(!isWerewolf) - { - if(mNpc->mModel.length() > 0) - addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()), smodel); - if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\xargonian_swimkna.nif", smodel); - } + if(!isWerewolf && Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) + addAnimSource("meshes\\xargonian_swimkna.nif", smodel); } else { From 4438ab44934f84f04c68a37a6305320677a84444 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 24 Jan 2019 22:42:23 +0000 Subject: [PATCH 163/410] Use CullVisitor traversal mask for light manager. --- components/sceneutil/lightmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index e102653b90..cb6a12c879 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -399,7 +399,7 @@ namespace SceneUtil return false; } - if (!(cv->getCurrentCamera()->getCullMask() & mLightManager->getLightingMask())) + if (!(cv->getTraversalMask() & mLightManager->getLightingMask())) return false; // Possible optimizations: From d82c85913a402d402367b616b941084c17b380f5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 24 Jan 2019 23:07:38 +0000 Subject: [PATCH 164/410] Don't bother multiplying a matrix by its inverse and applying that to the light direction. Hopefully this will improve numerical stability and reduce shadow flicker a little. --- 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 6f3d34cb1a..08117b4f95 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -474,7 +474,7 @@ void MWShadowTechnique::LightData::setLightData(osg::RefMatrix* lm, const osg::L lightDir.set(-lightPos.x(), -lightPos.y(), -lightPos.z()); lightDir.normalize(); OSG_INFO<<" Directional light, lightPos="< Date: Fri, 14 Dec 2018 18:29:56 +0300 Subject: [PATCH 165/410] Move idle dialogue playback from AiWander (bug #4594) --- apps/openmw/mwmechanics/actors.cpp | 31 ++++++++++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 2 ++ apps/openmw/mwmechanics/aiwander.cpp | 33 ---------------------------- apps/openmw/mwmechanics/aiwander.hpp | 1 - 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4166ece11e..191b028090 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -348,6 +349,33 @@ namespace MWMechanics } } + void Actors::playIdleDialogue(const MWWorld::Ptr& actor) + { + if (!actor.getClass().isActor() || actor == getPlayer() || !MWBase::Environment::get().getSoundManager()->sayDone(actor)) + return; + + const CreatureStats &stats = actor.getClass().getCreatureStats(actor); + if (stats.getAiSetting(CreatureStats::AI_Hello).getModified() == 0) + return; + + const MWMechanics::AiSequence& seq = stats.getAiSequence(); + if (seq.isInCombat() || seq.hasPackage(AiPackage::TypeIdFollow) || seq.hasPackage(AiPackage::TypeIdEscort)) + return; + + const osg::Vec3f playerPos(getPlayer().getRefData().getPosition().asVec3()); + const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + MWBase::World* world = MWBase::Environment::get().getWorld(); + if (world->isSwimming(actor) || (playerPos - actorPos).length2() >= 3000 * 3000) + return; + + // Our implementation is not FPS-dependent unlike Morrowind's so it needs to be recalibrated. + // We chose to use the chance MW would have when run at 60 FPS with the default value of the GMST. + const float delta = MWBase::Environment::get().getFrameDuration() * 6.f; + static const float fVoiceIdleOdds = world->getStore().get().find("fVoiceIdleOdds")->mValue.getFloat(); + if (Misc::Rng::rollProbability() * 10000.f < fVoiceIdleOdds * delta && world->getLOS(getPlayer(), actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer) { // No combat for totally static creatures @@ -1408,7 +1436,10 @@ namespace MWMechanics { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) + { stats.getAiSequence().execute(iter->first, *ctrl, duration); + playIdleDialogue(iter->first); + } } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 61879c432f..79e35a8d18 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -102,6 +102,8 @@ namespace MWMechanics */ void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); + void playIdleDialogue(const MWWorld::Ptr& actor); + void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d2a57c354f..05465c6b05 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -8,7 +8,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -167,8 +166,6 @@ namespace MWMechanics doPerFrameActionsForState(actor, duration, storage); - playIdleDialogueRandomly(actor); - float& lastReaction = storage.mReaction; lastReaction += duration; if (AI_REACTION_TIME <= lastReaction) @@ -492,36 +489,6 @@ namespace MWMechanics } } - void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) - { - int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && MWBase::Environment::get().getSoundManager()->sayDone(actor)) - { - MWWorld::Ptr player = getPlayer(); - - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->mValue.getFloat(); - - float roll = Misc::Rng::rollProbability() * 10000.0f; - - // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds - // due to the roll being an integer. - // Our implementation does not have these issues, so needs to be recalibrated. We chose to - // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - const osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); - const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); - if (roll < x && (playerPos - actorPos).length2() < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } - } - void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index bba6f71135..d586bb0bc8 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -138,7 +138,6 @@ namespace MWMechanics void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); From b33016d89fa5a5c99f3033e08f82cdf4d90590bc Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 26 Jan 2019 16:50:19 +0300 Subject: [PATCH 166/410] Allow creatures to play Attack voiceover --- apps/openmw/mwmechanics/aicombat.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index ee7b4369e9..245e95e488 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -555,13 +555,13 @@ namespace MWMechanics if (actor.getClass().isNpc()) { baseDelay = store.get().find("fCombatDelayNPC")->mValue.getFloat(); + } - //say a provoking combat phrase - int chance = store.get().find("iVoiceAttackOdds")->mValue.getInteger(); - if (Misc::Rng::roll0to99() < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } + // Say a provoking combat phrase + const int iVoiceAttackOdds = store.get().find("iVoiceAttackOdds")->mValue.getInteger(); + if (Misc::Rng::roll0to99() < iVoiceAttackOdds) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } From 556c9a338269d421c96bdfb1dcd24180ac06b807 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 30 Jan 2019 22:28:00 +0000 Subject: [PATCH 167/410] Add normal-offset shadow mapping to remove shadow acne (flicker) --- components/sceneutil/shadow.cpp | 8 ++++++++ files/settings-default.cfg | 2 ++ files/shaders/objects_vertex.glsl | 2 +- files/shaders/shadows_vertex.glsl | 28 ++++++++++++++++++++++++++-- files/shaders/terrain_vertex.glsl | 5 +++-- files/shaders/water_vertex.glsl | 2 +- 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index d3655dfb5c..5220723fb4 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -125,6 +125,10 @@ namespace SceneUtil else definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithShadows["disableNormalOffsetShadows"] = Settings::Manager::getFloat("normal offset distance", "Shadows") == 0.0 ? "1" : "0"; + + definesWithShadows["shadowNormalOffset"] = std::to_string(Settings::Manager::getFloat("normal offset distance", "Shadows")); + return definesWithShadows; } @@ -140,6 +144,10 @@ namespace SceneUtil definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithShadows["enableNormalOffsetShadows"] = "0"; + + definesWithShadows["shadowNormalOffset"] = "0.0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 240530be04..345a3ee0d2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -669,6 +669,8 @@ minimum lispsm near far ratio = 0.25 polygon offset factor = 1.1 # Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset units = 4.0 +# How far along the surface normal to project shadow coordinates. Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. This value is in in-game units, so 1.0 is roughly 1.4 cm. +normal offset distance = 1.0 # Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. use front face culling = true # Allow actors to cast shadows. Potentially decreases performance. diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 3d7f49eeeb..dcb2412745 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -103,5 +103,5 @@ void main(void) passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; - setupShadowCoords(viewPos); + setupShadowCoords(viewPos, viewNormal); } diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl index 4baa249c11..f96e1a6735 100644 --- a/files/shaders/shadows_vertex.glsl +++ b/files/shaders/shadows_vertex.glsl @@ -10,20 +10,44 @@ varying vec4 shadowRegionCoords@shadow_texture_unit_index; #endif @endforeach + + // Enabling this may reduce peter panning. Probably unnecessary. + const bool onlyNormalOffsetUV = false; #endif // SHADOWS -void setupShadowCoords(vec4 viewPos) +void setupShadowCoords(vec4 viewPos, vec3 viewNormal) { #if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; + vec4 shadowOffset; @foreach shadow_texture_unit_index @shadow_texture_unit_list eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; #if @perspectiveShadowMaps shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; #endif + +#if @disableNormalOffsetShadows + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; +#else + shadowOffset = vec4(viewNormal * @shadowNormalOffset, 0.0); + + if (onlyNormalOffsetUV) + { + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + + vec4 lightSpaceXY = viewPos + shadowOffset; + lightSpaceXY = lightSpaceXY * eyePlaneMat; + + shadowSpaceCoords@shadow_texture_unit_index.xy = lightSpaceXY.xy; + } + else + { + vec4 offsetViewPosition = viewPos + shadowOffset; + shadowSpaceCoords@shadow_texture_unit_index = offsetViewPosition * eyePlaneMat; + } +#endif @endforeach #endif // SHADOWS } \ No newline at end of file diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 669eac0125..8a9cf82cc3 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -25,9 +25,10 @@ void main(void) vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); gl_ClipVertex = viewPos; + + vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); #if !PER_PIXEL_LIGHTING - vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); lighting = doLighting(viewPos.xyz, viewNormal, gl_Color, shadowDiffuseLighting); #else passColor = gl_Color; @@ -37,5 +38,5 @@ void main(void) uv = gl_MultiTexCoord0.xy; - setupShadowCoords(viewPos); + setupShadowCoords(viewPos, viewNormal); } diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index b028d90d22..575f8f3c2f 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -22,5 +22,5 @@ void main(void) depthPassthrough = gl_Position.z; - setupShadowCoords(gl_ModelViewMatrix * gl_Vertex); + setupShadowCoords(gl_ModelViewMatrix * gl_Vertex, normalize((gl_NormalMatrix * gl_Normal).xyz)); } From a24b8ec3d2bd5a2251d5e4b709dbb19ed92a6e23 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 14:57:56 +0000 Subject: [PATCH 168/410] Fix enable/disable mixup. --- components/sceneutil/shadow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 5220723fb4..ebb4868ad3 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -144,7 +144,7 @@ namespace SceneUtil definesWithShadows["perspectiveShadowMaps"] = "0"; - definesWithShadows["enableNormalOffsetShadows"] = "0"; + definesWithShadows["disableNormalOffsetShadows"] = "0"; definesWithShadows["shadowNormalOffset"] = "0.0"; From 57e10e26b2276898f0829060018cc4300ced2356 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 14:58:57 +0000 Subject: [PATCH 169/410] Make variable name less confusing --- components/sceneutil/shadow.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index ebb4868ad3..97d96f3f4e 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -134,21 +134,21 @@ namespace SceneUtil Shader::ShaderManager::DefineMap ShadowManager::getShadowsDisabledDefines() { - Shader::ShaderManager::DefineMap definesWithShadows; - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); - definesWithShadows["shadow_texture_unit_list"] = ""; + Shader::ShaderManager::DefineMap definesWithoutShadows; + definesWithoutShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); + definesWithoutShadows["shadow_texture_unit_list"] = ""; - definesWithShadows["shadowMapsOverlap"] = "0"; + definesWithoutShadows["shadowMapsOverlap"] = "0"; - definesWithShadows["useShadowDebugOverlay"] = "0"; + definesWithoutShadows["useShadowDebugOverlay"] = "0"; - definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithoutShadows["perspectiveShadowMaps"] = "0"; - definesWithShadows["disableNormalOffsetShadows"] = "0"; + definesWithoutShadows["disableNormalOffsetShadows"] = "0"; - definesWithShadows["shadowNormalOffset"] = "0.0"; + definesWithoutShadows["shadowNormalOffset"] = "0.0"; - return definesWithShadows; + return definesWithoutShadows; } void ShadowManager::enableIndoorMode() { From abe9ba736e02df60169e2c3b1569d53da1b73c6a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 15:00:04 +0000 Subject: [PATCH 170/410] Add line breaks to make settings more readable. --- files/settings-default.cfg | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 345a3ee0d2..1cd52a2802 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -645,41 +645,60 @@ enable nav mesh render = false enable agents paths render = false [Shadows] + # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false + # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 3 + # If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. allow shadow map overlap = true + # Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you might not want to change this, especially not without reading the associated papers first. When "allow shadow map overlap" is combined with a higher-than-default viewing distance, values closer to 1.0 will prevent nearby shadows losing a lot of quality. split point uniform logarithmic ratio = 0.5 + # Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. split point bias = 0.0 + # Enable the debug hud to see what the shadow map(s) contain. enable debug hud = false + # Enable the debug overlay to see where each shadow map affects. enable debug overlay = false + # Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. compute tight scene bounds = false + # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. shadow map resolution = 1024 + # Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. Increasing this pushes detail further away. minimum lispsm near far ratio = 0.25 + # Used as the factor parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset factor = 1.1 + # Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset units = 4.0 + # How far along the surface normal to project shadow coordinates. Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. This value is in in-game units, so 1.0 is roughly 1.4 cm. normal offset distance = 1.0 + # Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. use front face culling = true + # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false + # Allow the player to cast shadows. Potentially decreases performance. player shadows = false + # Allow terrain to cast shadows. Potentially decreases performance. terrain shadows = false + # Allow world objects to cast shadows. Potentially decreases performance. object shadows = false + # Allow shadows indoors. Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting. enable indoor shadows = true From 2761a3856254eb808702b26f4562f335ce651255 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 20:12:17 +0000 Subject: [PATCH 171/410] Prettify shadow define map setup. --- components/sceneutil/shadow.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 97d96f3f4e..9f854cc845 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -103,27 +103,20 @@ namespace SceneUtil return getShadowsDisabledDefines(); Shader::ShaderManager::DefineMap definesWithShadows; - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); + + definesWithShadows["shadows_enabled"] = "1"; + for (unsigned int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); - if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) - definesWithShadows["shadowMapsOverlap"] = "1"; - else - definesWithShadows["shadowMapsOverlap"] = "0"; + definesWithShadows["shadowMapsOverlap"] = Settings::Manager::getBool("allow shadow map overlap", "Shadows") ? "1" : "0"; - if (Settings::Manager::getBool("enable debug overlay", "Shadows")) - definesWithShadows["useShadowDebugOverlay"] = "1"; - else - definesWithShadows["useShadowDebugOverlay"] = "0"; + definesWithShadows["useShadowDebugOverlay"] = Settings::Manager::getBool("enable debug overlay", "Shadows") ? "1" : "0"; // switch this to reading settings if it's ever exposed to the user - if (mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP) - definesWithShadows["perspectiveShadowMaps"] = "1"; - else - definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithShadows["perspectiveShadowMaps"] = mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP ? "1" : "0"; definesWithShadows["disableNormalOffsetShadows"] = Settings::Manager::getFloat("normal offset distance", "Shadows") == 0.0 ? "1" : "0"; @@ -135,7 +128,9 @@ namespace SceneUtil Shader::ShaderManager::DefineMap ShadowManager::getShadowsDisabledDefines() { Shader::ShaderManager::DefineMap definesWithoutShadows; - definesWithoutShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); + + definesWithoutShadows["shadows_enabled"] = "0"; + definesWithoutShadows["shadow_texture_unit_list"] = ""; definesWithoutShadows["shadowMapsOverlap"] = "0"; @@ -150,6 +145,7 @@ namespace SceneUtil return definesWithoutShadows; } + void ShadowManager::enableIndoorMode() { if (Settings::Manager::getBool("enable indoor shadows", "Shadows")) @@ -157,6 +153,7 @@ namespace SceneUtil else mShadowTechnique->disableShadows(); } + void ShadowManager::enableOutdoorMode() { if (mEnableShadows) From cfe921fb824288f794efd7e62be5f97b21a52fd4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 20:12:42 +0000 Subject: [PATCH 172/410] Remove uneeded includes. --- components/sceneutil/shadow.cpp | 5 ----- components/sceneutil/shadow.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 9f854cc845..a69fd80909 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -1,11 +1,6 @@ #include "shadow.hpp" #include -#include -#include -#include -#include -#include #include diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 26e119d88b..24deff2531 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "mwshadowtechnique.hpp" From 15547750ba97cb2471cbf7f427e188a32c1e40d4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 1 Feb 2019 00:29:13 +0000 Subject: [PATCH 173/410] Correct behaviour of use front face culling setting to not use back face culling either when disabled. --- components/sceneutil/mwshadowtechnique.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 08117b4f95..0addb6f4bb 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -849,7 +849,7 @@ void SceneUtil::MWShadowTechnique::disableFrontFaceCulling() _useFrontFaceCulling = false; if (_shadowCastingStateSet) - _shadowCastingStateSet->removeAttribute(osg::StateAttribute::CULLFACE); + _shadowCastingStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) @@ -1462,12 +1462,16 @@ void MWShadowTechnique::createShaders() // In this case we will draw them in their entirety. if (_useFrontFaceCulling) + { _shadowCastingStateSet->setAttribute(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - // make sure GL_CULL_FACE is off by default - // we assume that if object has cull face attribute set to back - // it will also set cull face mode ON so no need for override - _shadowCastingStateSet->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); + // make sure GL_CULL_FACE is off by default + // we assume that if object has cull face attribute set to back + // it will also set cull face mode ON so no need for override + _shadowCastingStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + } + else + _shadowCastingStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } _polygonOffset = new osg::PolygonOffset(_polygonOffsetFactor, _polygonOffsetUnits); From 7940317e4277e3a5ac7260635a134962df049939 Mon Sep 17 00:00:00 2001 From: Azdul Date: Sun, 3 Feb 2019 09:32:32 +0100 Subject: [PATCH 174/410] Make sure that proper operator function is used for char[N] argument --- .../esm/test_fixed_string.cpp | 36 +++++++++++++++++++ components/esm/esmcommon.hpp | 5 ++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/apps/openmw_test_suite/esm/test_fixed_string.cpp b/apps/openmw_test_suite/esm/test_fixed_string.cpp index 89a390ff62..dc88a5f633 100644 --- a/apps/openmw_test_suite/esm/test_fixed_string.cpp +++ b/apps/openmw_test_suite/esm/test_fixed_string.cpp @@ -37,6 +37,42 @@ TEST(EsmFixedString, operator__eq_ne) EXPECT_TRUE(name == ss); } } +TEST(EsmFixedString, operator__eq_ne_const) +{ + { + SCOPED_TRACE("asdc == asdc (const)"); + ESM::NAME name; + name.assign("asdc"); + const char s[4] = { 'a', 's', 'd', 'c' }; + std::string ss(s, 4); + + EXPECT_TRUE(name == s); + EXPECT_TRUE(name == ss.c_str()); + EXPECT_TRUE(name == ss); + } + { + SCOPED_TRACE("asdc == asdcx (const)"); + ESM::NAME name; + name.assign("asdc"); + const char s[5] = { 'a', 's', 'd', 'c', 'x' }; + std::string ss(s, 5); + + EXPECT_TRUE(name != s); + EXPECT_TRUE(name != ss.c_str()); + EXPECT_TRUE(name != ss); + } + { + SCOPED_TRACE("asdc == asdc[NULL] (const)"); + ESM::NAME name; + name.assign("asdc"); + const char s[5] = { 'a', 's', 'd', 'c', '\0' }; + std::string ss(s, 5); + + EXPECT_TRUE(name == s); + EXPECT_TRUE(name == ss.c_str()); + EXPECT_TRUE(name == ss); + } +} TEST(EsmFixedString, empty_strings) { diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d635ba6dff..97ce88556c 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -35,7 +35,10 @@ public: return false; return std::strncmp(self()->ro_data(), str, size) == 0; } - bool operator==(const char* const str) const + + //this operator will not be used for char[N], only for char* + template::value>::type> + bool operator==(const T* const& str) const { char const* const data = self()->ro_data(); for(size_t i = 0; i < size; ++i) From 9b92943d1a649e2c1076a758742adfa3ad645984 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 5 Feb 2019 20:51:56 +0000 Subject: [PATCH 175/410] Don't rely exclusively on a shadow map when out of its depth range --- files/shaders/shadows_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index 713473458b..a925b2f07e 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -29,7 +29,7 @@ float unshadowedLightRatio() shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); - doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); + doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); #if @perspectiveShadowMaps doneShadows = doneShadows && all(lessThan(shadowRegionXYZ, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); #endif @@ -67,7 +67,7 @@ void applyShadowDebugOverlay() else gl_FragData[0].z += 0.1; - doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); + doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); #if @perspectiveShadowMaps doneOverlay = doneOverlay && all(lessThan(shadowRegionXYZ.xyz, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); #endif From 796b87fde744e5c4fc82879dcbb3f59dad70abe6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 6 Feb 2019 23:53:13 +0300 Subject: [PATCH 176/410] Fix upside-down night-time lighting --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 14d88a752d..719aef837e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -748,7 +748,7 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, } else { - theta = static_cast(osg::PI) + static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; + theta = static_cast(osg::PI) - static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; } osg::Vec3f final( From b1a5a72665aa7151d290dbf675a10928ee91dfea Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 7 Feb 2019 00:27:26 +0000 Subject: [PATCH 177/410] Restore previous night time directional light path --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7d3f41894d..dcd1eac8b0 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -739,7 +739,7 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, } else { - theta = static_cast(osg::PI) + static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; + theta = static_cast(osg::PI) - static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; } osg::Vec3f final( From cb0a34e28081ee36bf5f56c331b2a10df3c9e73f Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 6 Feb 2019 14:05:07 +0100 Subject: [PATCH 178/410] bump libbullet version for gitlab --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e0042a93e..0e513c2ee8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,8 +15,8 @@ Debian: - apt-get update -yq - apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-iostreams-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev # - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-3_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-3_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb From 41168ba98ba568e137fd3ee7c7894263961d728d Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 6 Feb 2019 14:15:32 +0100 Subject: [PATCH 179/410] use ubuntu version, good enough --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e513c2ee8..1e0042a93e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,8 +15,8 @@ Debian: - apt-get update -yq - apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-iostreams-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev # - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-3_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-3_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb From fb219cc660861ef98523326b172e14b5f0ba38ac Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 6 Feb 2019 14:20:03 +0100 Subject: [PATCH 180/410] updated mygui links for gitlab --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e0042a93e..5ebce646c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,9 +17,9 @@ Debian: # - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - - curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - - curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - - curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb + - curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-2+b2_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-2+b2_amd64.deb + - curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-2+b2_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-2+b2_amd64.deb + - curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-2+b2_amd64.deb -o libmygui-dev_3.2.2+dfsg-2+b2_amd64.deb - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb stage: build script: From 57cc2ec2b2d9523c69428f97d3d5ee20affe9954 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 6 Feb 2019 14:46:10 +0100 Subject: [PATCH 181/410] use ubuntu for mygui as well --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5ebce646c7..f55e124e8f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,9 +17,9 @@ Debian: # - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - - curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-2+b2_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-2+b2_amd64.deb - - curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-2+b2_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-2+b2_amd64.deb - - curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-2+b2_amd64.deb -o libmygui-dev_3.2.2+dfsg-2+b2_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb + - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb stage: build script: From 0535de6ca0093316d7d0a9d138bedd8300acf52f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 26 Jan 2019 01:03:52 +0300 Subject: [PATCH 182/410] Make quest status update handling closer to vanilla (bug #4815) Don't update quest status if we're simply updating the quest index Update quest status if a new entry is added regardless of its index --- CHANGELOG.md | 1 + apps/openmw/mwdialogue/quest.cpp | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a712229897..0134253a61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Bug #4803: Stray special characters before begin statement break script compilation Bug #4804: Particle system with the "Has Sizes = false" causes an exception Bug #4813: Creatures with known file but no "Sound Gen Creature" assigned use default sounds + Bug #4815: "Finished" journal entry with lower index doesn't close journal, SetJournalIndex closes journal Bug #4820: Spell absorption is broken Bug #4827: NiUVController is handled incorrectly Bug #4828: Potion looping effects VFX are not shown for NPCs diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 8465978863..5f20a8abb2 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -41,19 +41,6 @@ namespace MWDialogue void Quest::setIndex (int index) { - const ESM::Dialogue *dialogue = - MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); - - for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); - iter!=dialogue->mInfo.end(); ++iter) - if (iter->mData.mDisposition==index && iter->mQuestStatus!=ESM::DialInfo::QS_Name) - { - if (iter->mQuestStatus==ESM::DialInfo::QS_Finished) - mFinished = true; - else if (iter->mQuestStatus==ESM::DialInfo::QS_Restart) - mFinished = false; - } - // The index must be set even if no related journal entry was found mIndex = index; } @@ -81,8 +68,18 @@ namespace MWDialogue if (index==-1) throw std::runtime_error ("unknown journal entry for topic " + mTopic); + for (auto &info : dialogue->mInfo) + { + if (info.mData.mJournalIndex == index + && (info.mQuestStatus == ESM::DialInfo::QS_Finished || info.mQuestStatus == ESM::DialInfo::QS_Restart)) + { + mFinished = (info.mQuestStatus == ESM::DialInfo::QS_Finished); + break; + } + } + if (index > mIndex) - setIndex (index); + mIndex = index; for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter) if (iter->mInfoId==entry.mInfoId) From e9c6c114189aea9e401bfaa82190b38732a8fb42 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Feb 2019 10:52:17 +0300 Subject: [PATCH 183/410] Fix hiding three-tab (Cyrillic) topic index --- apps/openmw/mwgui/journalwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index a2f6ea1423..bda5b5a38a 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -554,7 +554,7 @@ namespace mQuestMode = true; setVisible (LeftTopicIndex, false); - setVisible (CenterTopicIndex, true); + setVisible (CenterTopicIndex, false); setVisible (RightTopicIndex, false); setVisible (TopicsList, false); setVisible (QuestsList, true); From 058e2891627e50e16b2f33c748ec4e25a7b73d28 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Feb 2019 12:24:58 +0400 Subject: [PATCH 184/410] Do not create a redundant parent node for LOD and Switch nodes (bug #4837) --- CHANGELOG.md | 1 + components/nifosg/nifloader.cpp | 54 +++++++++++++++------------------ 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a712229897..9821844543 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Bug #4820: Spell absorption is broken Bug #4827: NiUVController is handled incorrectly Bug #4828: Potion looping effects VFX are not shown for NPCs + Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 52e548a694..d45f37b256 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -434,8 +434,23 @@ namespace NifOsg osg::ref_ptr node; osg::Object::DataVariance dataVariance = osg::Object::UNSPECIFIED; + // TODO: it is unclear how to handle transformations of LOD and Switch nodes and controllers for them. switch (nifNode->recType) { + case Nif::RC_NiLODNode: + { + const Nif::NiLODNode* niLodNode = static_cast(nifNode); + node = handleLodNode(niLodNode); + dataVariance = osg::Object::STATIC; + break; + } + case Nif::RC_NiSwitchNode: + { + const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); + node = handleSwitchNode(niSwitchNode); + dataVariance = osg::Object::STATIC; + break; + } case Nif::RC_NiTriShape: case Nif::RC_NiAutoNormalParticles: case Nif::RC_NiRotatingParticles: @@ -597,35 +612,6 @@ namespace NifOsg if (nifNode->recType != Nif::RC_NiTriShape && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) handleNodeControllers(nifNode, static_cast(node.get()), animflags); - if (nifNode->recType == Nif::RC_NiLODNode) - { - const Nif::NiLODNode* niLodNode = static_cast(nifNode); - osg::ref_ptr lod = handleLodNode(niLodNode); - node->addChild(lod); // unsure if LOD should be above or below this node's transform - node = lod; - } - - if (nifNode->recType == Nif::RC_NiSwitchNode) - { - const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); - osg::ref_ptr switchNode = handleSwitchNode(niSwitchNode); - node->addChild(switchNode); - - if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel)) - rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel); - - const Nif::NodeList &children = niSwitchNode->children; - for(size_t i = 0;i < children.length();++i) - { - if(!children[i].empty()) - handleNode(children[i].getPtr(), switchNode, imageManager, boundTextures, animflags, skipMeshes, hasMarkers, isAnimated, textKeys, rootNode); - } - - // show only first child by default - switchNode->setSingleChildOn(0); - return switchNode; - } - const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -644,6 +630,16 @@ namespace NifOsg } } + if (nifNode->recType == Nif::RC_NiSwitchNode) + { + // show only first child by default + node->asSwitch()->setSingleChildOn(0); + + const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); + if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel)) + rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel); + } + return node; } From 2412017685c603cc2195767a6b47b8ab737b735a Mon Sep 17 00:00:00 2001 From: Azdul Date: Sun, 10 Feb 2019 08:04:39 +0100 Subject: [PATCH 185/410] Fix DetourNavigatorNavMeshTilesCacheTest on Windows --- .../detournavigator/navmeshtilescache.cpp | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index 17b17b97c4..a3a1816ad4 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -34,6 +34,14 @@ namespace const std::vector mOffMeshConnections {}; unsigned char* const mData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData mNavMeshData {mData, 1}; + + const size_t cRecastMeshKeySize = mRecastMesh.getIndices().size() * sizeof(int) + + mRecastMesh.getVertices().size() * sizeof(float) + + mRecastMesh.getAreaTypes().size() * sizeof(AreaType) + + mRecastMesh.getWater().size() * sizeof(RecastMesh::Water) + + mOffMeshConnections.size() * sizeof(OffMeshConnection); + + const size_t cRecastMeshWithWaterKeySize = cRecastMeshKeySize + sizeof(RecastMesh::Water); }; TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_empty_cache_should_return_empty_value) @@ -56,7 +64,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_return_cached_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -69,7 +77,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_existing_element_should_throw_exception) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); @@ -85,7 +93,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_should_return_cached_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -129,7 +137,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 117; + const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -149,7 +157,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_used_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -167,7 +175,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_set_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 117; + const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); @@ -199,7 +207,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 117; + const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); @@ -243,7 +251,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_cache_max_size) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); @@ -261,8 +269,8 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_size_of_unused_items) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize1 = 49; - const std::size_t navMeshKeySize2 = 117; + const std::size_t navMeshKeySize1 = cRecastMeshKeySize; + const std::size_t navMeshKeySize2 = cRecastMeshWithWaterKeySize; const std::size_t maxSize = 2 * navMeshDataSize + 2 * navMeshKeySize1 + 2 * navMeshKeySize2; NavMeshTilesCache cache(maxSize); @@ -290,7 +298,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_used_after_set_then_used_by_get_item_should_left_this_item_available) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -313,7 +321,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_twice_used_item_should_left_this_item_available) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); From 89d4d3be08c9bb4e8c1c4f7134b94a7b13a49d82 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 13 Feb 2019 14:49:36 +0000 Subject: [PATCH 186/410] Fix boost deprecation warning --- apps/openmw/mwgui/settingswindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 6e6924f28e..2b7dbc67dc 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include @@ -58,7 +58,7 @@ namespace std::string getAspect (int x, int y) { - int gcd = boost::math::gcd (x, y); + int gcd = boost::integer::gcd (x, y); int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 From c68ccbc6b69d07370387056974fd05e595103142 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 13 Feb 2019 18:37:01 +0000 Subject: [PATCH 187/410] Use new common_factor header in the launcher, too --- apps/launcher/graphicspage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 072f1f36f2..7424555132 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,6 +1,6 @@ #include "graphicspage.hpp" -#include +#include #include #include #include @@ -18,7 +18,7 @@ QString getAspect(int x, int y) { - int gcd = boost::math::gcd (x, y); + int gcd = boost::integer::gcd (x, y); int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 From 39dcbacf44a80bf3cee8111dc0d99313651fa968 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 15 Feb 2019 17:53:50 +0300 Subject: [PATCH 188/410] Option to disable controller (feature #3980) --- CHANGELOG.md | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 12 +++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 1 + .../reference/modding/settings/input.rst | 13 ++++++++++ files/mygui/openmw_settings_window.layout | 24 ++++++++++++------- files/settings-default.cfg | 3 +++ 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a712229897..c2ac066627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis + Feature #3980: In-game option to disable controller Feature #4209: Editor: Faction rank sub-table Feature #4673: Weapon sheathing Feature #4730: Native animated containers support diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index be1301aacf..3251a387cc 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -55,6 +55,7 @@ namespace MWInput , mInvertX (Settings::Manager::getBool("invert x axis", "Input")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mControlsDisabled(false) + , mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) , mPreviewPOVDelay(0.f) @@ -659,6 +660,9 @@ namespace MWInput if (it->first == "Input" && it->second == "grab cursor") mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); + if (it->first == "Input" && it->second == "enable controller") + mJoystickEnabled = Settings::Manager::getBool("enable controller", "Input"); + if (it->first == "Video" && ( it->second == "resolution x" || it->second == "resolution y" @@ -858,6 +862,9 @@ namespace MWInput void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) { + if (!mJoystickEnabled) + return; + mJoystickLastUsed = true; bool guiMode = false; @@ -892,6 +899,9 @@ namespace MWInput void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) { + if (!mJoystickEnabled) + return; + mJoystickLastUsed = true; if(mInputBinder->detectingBindingState()) mInputBinder->buttonReleased(deviceID, arg); @@ -915,7 +925,7 @@ namespace MWInput void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) { - if (!mControlsDisabled) + if (!mControlsDisabled && mJoystickEnabled) mInputBinder->axisMoved(deviceID, arg); } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 361babec49..41b0bd4040 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -179,6 +179,7 @@ namespace MWInput bool mInvertY; bool mControlsDisabled; + bool mJoystickEnabled; float mCameraSensitivity; float mCameraYMultiplier; diff --git a/docs/source/reference/modding/settings/input.rst b/docs/source/reference/modding/settings/input.rst index 321c28afdc..51c72e15dd 100644 --- a/docs/source/reference/modding/settings/input.rst +++ b/docs/source/reference/modding/settings/input.rst @@ -120,3 +120,16 @@ If this setting is true, moving the mouse away from the player will look down, while moving it towards the player will look up. This setting does not affect cursor movement in GUI mode. This setting can be toggled in game with the Invert Y Axis button in the Controls panel of the Options menu. + +enable controller +----------------- + +:Type: boolean +:Range: True/False +:Default: True + +Enable support of controller input — or rather not ignore controller events, +which are always sent if a controller is present and detected. +Disabling this setting can be useful for working around controller-related issues or for setting up split-screen gameplay configurations. + +This setting can be toggled in game with the Enable Joystick button in the Controls panel of the Options menu. diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 8062980ffe..2d9c13bc92 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -222,21 +222,19 @@ - - - + - + - + - + @@ -246,14 +244,24 @@ - + - + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 71a93d1a2c..e1f7fcaca3 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -339,6 +339,9 @@ invert x axis = false # Invert the vertical axis while not in GUI mode. invert y axis = false +# Enable controller support. +enable controller = true + [Saves] # Name of last character played, and default for loading save files. From c68e64a2a7c719f8df9d76ce55f0ca64b6966b5e Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 14:41:11 +0300 Subject: [PATCH 189/410] Make navigator from settings manager setting in separate function --- apps/openmw/mwworld/worldimp.cpp | 27 +-------------- components/CMakeLists.txt | 1 + components/detournavigator/settings.cpp | 44 +++++++++++++++++++++++++ components/detournavigator/settings.hpp | 2 ++ 4 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 components/detournavigator/settings.cpp diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 672e6db24a..a6f0616e22 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -198,35 +198,10 @@ namespace MWWorld mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode)); - DetourNavigator::Settings navigatorSettings; - navigatorSettings.mBorderSize = Settings::Manager::getInt("border size", "Navigator"); - navigatorSettings.mCellHeight = Settings::Manager::getFloat("cell height", "Navigator"); - navigatorSettings.mCellSize = Settings::Manager::getFloat("cell size", "Navigator"); - navigatorSettings.mDetailSampleDist = Settings::Manager::getFloat("detail sample dist", "Navigator"); - navigatorSettings.mDetailSampleMaxError = Settings::Manager::getFloat("detail sample max error", "Navigator"); + auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager(); navigatorSettings.mMaxClimb = MWPhysics::sStepSizeUp; - navigatorSettings.mMaxSimplificationError = Settings::Manager::getFloat("max simplification error", "Navigator"); navigatorSettings.mMaxSlope = MWPhysics::sMaxSlope; - navigatorSettings.mRecastScaleFactor = Settings::Manager::getFloat("recast scale factor", "Navigator"); navigatorSettings.mSwimHeightScale = mSwimHeightScale; - navigatorSettings.mMaxEdgeLen = Settings::Manager::getInt("max edge len", "Navigator"); - navigatorSettings.mMaxNavMeshQueryNodes = Settings::Manager::getInt("max nav mesh query nodes", "Navigator"); - navigatorSettings.mMaxPolys = Settings::Manager::getInt("max polygons per tile", "Navigator"); - navigatorSettings.mMaxVertsPerPoly = Settings::Manager::getInt("max verts per poly", "Navigator"); - navigatorSettings.mRegionMergeSize = Settings::Manager::getInt("region merge size", "Navigator"); - navigatorSettings.mRegionMinSize = Settings::Manager::getInt("region min size", "Navigator"); - navigatorSettings.mTileSize = Settings::Manager::getInt("tile size", "Navigator"); - navigatorSettings.mAsyncNavMeshUpdaterThreads = static_cast(Settings::Manager::getInt("async nav mesh updater threads", "Navigator")); - navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast(Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator")); - navigatorSettings.mMaxPolygonPathSize = static_cast(Settings::Manager::getInt("max polygon path size", "Navigator")); - navigatorSettings.mMaxSmoothPathSize = static_cast(Settings::Manager::getInt("max smooth path size", "Navigator")); - navigatorSettings.mTrianglesPerChunk = static_cast(Settings::Manager::getInt("triangles per chunk", "Navigator")); - navigatorSettings.mEnableWriteRecastMeshToFile = Settings::Manager::getBool("enable write recast mesh to file", "Navigator"); - navigatorSettings.mEnableWriteNavMeshToFile = Settings::Manager::getBool("enable write nav mesh to file", "Navigator"); - navigatorSettings.mRecastMeshPathPrefix = Settings::Manager::getString("recast mesh path prefix", "Navigator"); - navigatorSettings.mNavMeshPathPrefix = Settings::Manager::getString("nav mesh path prefix", "Navigator"); - navigatorSettings.mEnableRecastMeshFileNameRevision = Settings::Manager::getBool("enable recast mesh file name revision", "Navigator"); - navigatorSettings.mEnableNavMeshFileNameRevision = Settings::Manager::getBool("enable nav mesh file name revision", "Navigator"); if (Settings::Manager::getBool("enable log", "Navigator")) DetourNavigator::Log::instance().setSink(std::unique_ptr( new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator")))); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 76641899d7..bb45542e49 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -171,6 +171,7 @@ add_component_dir(detournavigator tilecachedrecastmeshmanager recastmeshobject navmeshtilescache + settings ) set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp new file mode 100644 index 0000000000..0b9210a90f --- /dev/null +++ b/components/detournavigator/settings.cpp @@ -0,0 +1,44 @@ +#include "settings.hpp" + +#include + +#include + +namespace DetourNavigator +{ + Settings makeSettingsFromSettingsManager() + { + Settings navigatorSettings; + + navigatorSettings.mBorderSize = ::Settings::Manager::getInt("border size", "Navigator"); + navigatorSettings.mCellHeight = ::Settings::Manager::getFloat("cell height", "Navigator"); + navigatorSettings.mCellSize = ::Settings::Manager::getFloat("cell size", "Navigator"); + navigatorSettings.mDetailSampleDist = ::Settings::Manager::getFloat("detail sample dist", "Navigator"); + navigatorSettings.mDetailSampleMaxError = ::Settings::Manager::getFloat("detail sample max error", "Navigator"); + navigatorSettings.mMaxClimb = 0; + navigatorSettings.mMaxSimplificationError = ::Settings::Manager::getFloat("max simplification error", "Navigator"); + navigatorSettings.mMaxSlope = 0; + navigatorSettings.mRecastScaleFactor = ::Settings::Manager::getFloat("recast scale factor", "Navigator"); + navigatorSettings.mSwimHeightScale = 0; + navigatorSettings.mMaxEdgeLen = ::Settings::Manager::getInt("max edge len", "Navigator"); + navigatorSettings.mMaxNavMeshQueryNodes = ::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"); + navigatorSettings.mMaxPolys = ::Settings::Manager::getInt("max polygons per tile", "Navigator"); + navigatorSettings.mMaxVertsPerPoly = ::Settings::Manager::getInt("max verts per poly", "Navigator"); + navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator"); + navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min size", "Navigator"); + navigatorSettings.mTileSize = ::Settings::Manager::getInt("tile size", "Navigator"); + navigatorSettings.mAsyncNavMeshUpdaterThreads = static_cast(::Settings::Manager::getInt("async nav mesh updater threads", "Navigator")); + navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast(::Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator")); + navigatorSettings.mMaxPolygonPathSize = static_cast(::Settings::Manager::getInt("max polygon path size", "Navigator")); + navigatorSettings.mMaxSmoothPathSize = static_cast(::Settings::Manager::getInt("max smooth path size", "Navigator")); + navigatorSettings.mTrianglesPerChunk = static_cast(::Settings::Manager::getInt("triangles per chunk", "Navigator")); + navigatorSettings.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator"); + navigatorSettings.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator"); + navigatorSettings.mRecastMeshPathPrefix = ::Settings::Manager::getString("recast mesh path prefix", "Navigator"); + navigatorSettings.mNavMeshPathPrefix = ::Settings::Manager::getString("nav mesh path prefix", "Navigator"); + navigatorSettings.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator"); + navigatorSettings.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator"); + + return navigatorSettings; + } +} diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index 3e537c2fb9..f4073b24b2 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -36,6 +36,8 @@ namespace DetourNavigator std::string mRecastMeshPathPrefix; std::string mNavMeshPathPrefix; }; + + Settings makeSettingsFromSettingsManager(); } #endif From a0ed981a7c235fb7535f2d6806697ef11fc765e9 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 15:09:57 +0300 Subject: [PATCH 190/410] Fix operator ++ for OutputTransformIterator --- components/detournavigator/findsmoothpath.hpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/components/detournavigator/findsmoothpath.hpp b/components/detournavigator/findsmoothpath.hpp index 81b732b744..c02e3315bd 100644 --- a/components/detournavigator/findsmoothpath.hpp +++ b/components/detournavigator/findsmoothpath.hpp @@ -81,21 +81,28 @@ namespace DetourNavigator return *this; } - OutputTransformIterator& operator ++(int) + OutputTransformIterator& operator ++() { - mImpl++; + ++mImpl.get(); return *this; } + OutputTransformIterator operator ++(int) + { + const auto copy = *this; + ++(*this); + return copy; + } + OutputTransformIterator& operator =(const osg::Vec3f& value) { - *mImpl = fromNavMeshCoordinates(mSettings, value); + *mImpl.get() = fromNavMeshCoordinates(mSettings, value); return *this; } private: - OutputIterator& mImpl; - const Settings& mSettings; + std::reference_wrapper mImpl; + std::reference_wrapper mSettings; }; inline void initNavMeshQuery(dtNavMeshQuery& value, const dtNavMesh& navMesh, const int maxNodes) From d63881e054324f26da77c2c710aba71c46d88ed1 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 15:14:05 +0300 Subject: [PATCH 191/410] Make Navigator::findPath independent from class fields --- components/detournavigator/navigator.cpp | 7 ++++++- components/detournavigator/navigator.hpp | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/components/detournavigator/navigator.cpp b/components/detournavigator/navigator.cpp index 73537ff6f6..ddd9850214 100644 --- a/components/detournavigator/navigator.cpp +++ b/components/detournavigator/navigator.cpp @@ -122,12 +122,17 @@ namespace DetourNavigator mNavMeshManager.wait(); } + SharedNavMeshCacheItem Navigator::getNavMesh(const osg::Vec3f& agentHalfExtents) const + { + return mNavMeshManager.getNavMesh(agentHalfExtents); + } + std::map Navigator::getNavMeshes() const { return mNavMeshManager.getNavMeshes(); } - const Settings& Navigator::getSettings() const + Settings Navigator::getSettings() const { return mSettings; } diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 351e0f9f84..0bdc79e8a1 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -175,19 +175,26 @@ namespace DetourNavigator >::value, "out is not an OutputIterator" ); - const auto navMesh = mNavMeshManager.getNavMesh(agentHalfExtents); - return findSmoothPath(navMesh.lock()->getValue(), toNavMeshCoordinates(mSettings, agentHalfExtents), - toNavMeshCoordinates(mSettings, start), toNavMeshCoordinates(mSettings, end), includeFlags, - mSettings, out); + const auto navMesh = getNavMesh(agentHalfExtents); + const auto settings = getSettings(); + return findSmoothPath(navMesh.lock()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), + toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings, end), includeFlags, + settings, out); } + /** + * @brief getNavMesh returns navmesh for specific agent half extents + * @return navmesh + */ + SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const; + /** * @brief getNavMeshes returns all current navmeshes * @return map of agent half extents to navmesh */ std::map getNavMeshes() const; - const Settings& getSettings() const; + Settings getSettings() const; private: Settings mSettings; From 1d3668cd2298f2120310aa5b871589f17fe19f6d Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 15:27:02 +0300 Subject: [PATCH 192/410] Add Navigator interface --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwworld/scene.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +- .../detournavigator/navigator.cpp | 4 +- components/CMakeLists.txt | 2 +- components/detournavigator/navigator.hpp | 60 +++++++---------- .../{navigator.cpp => navigatorimpl.cpp} | 42 ++++++------ components/detournavigator/navigatorimpl.hpp | 64 +++++++++++++++++++ 9 files changed, 115 insertions(+), 67 deletions(-) rename components/detournavigator/{navigator.cpp => navigatorimpl.cpp} (66%) create mode 100644 components/detournavigator/navigatorimpl.hpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1728af6597..217e6d3677 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -57,7 +57,7 @@ namespace MWMechanics namespace DetourNavigator { - class Navigator; + struct Navigator; } namespace MWWorld diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2a48097bd8..e04404f2b0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -59,7 +59,7 @@ namespace SceneUtil namespace DetourNavigator { - class Navigator; + struct Navigator; struct Settings; } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 00f5f98b83..0f1ae72989 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -30,7 +30,7 @@ namespace Loading namespace DetourNavigator { - class Navigator; + struct Navigator; class Water; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a6f0616e22..65d6293842 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include "../mwbase/environment.hpp" @@ -206,7 +206,7 @@ namespace MWWorld DetourNavigator::Log::instance().setSink(std::unique_ptr( new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator")))); DetourNavigator::RecastGlobalAllocator::init(); - mNavigator.reset(new DetourNavigator::Navigator(navigatorSettings)); + mNavigator.reset(new DetourNavigator::NavigatorImpl(navigatorSettings)); mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath, *mNavigator)); mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get())); diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index febbc03875..2883921432 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -1,6 +1,6 @@ #include "operators.hpp" -#include +#include #include #include @@ -61,7 +61,7 @@ namespace mSettings.mMaxSmoothPathSize = 1024; mSettings.mTrianglesPerChunk = 256; mSettings.mMaxPolys = 4096; - mNavigator.reset(new Navigator(mSettings)); + mNavigator.reset(new NavigatorImpl(mSettings)); } }; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index bb45542e49..50fd590068 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -164,7 +164,7 @@ add_component_dir(detournavigator recastmeshmanager cachedrecastmeshmanager navmeshmanager - navigator + navigatorimpl asyncnavmeshupdater chunkytrimesh recastmesh diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 0bdc79e8a1..529b539c85 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -3,9 +3,9 @@ #include "findsmoothpath.hpp" #include "flags.hpp" -#include "navmeshmanager.hpp" #include "settings.hpp" -#include "settingsutils.hpp" +#include "objectid.hpp" +#include "navmeshcacheitem.hpp" namespace DetourNavigator { @@ -33,33 +33,28 @@ namespace DetourNavigator }; /** - * @brief Top level class of detournavigator componenet. Navigator allows to build a scene with navmesh and find + * @brief Top level interface of detournavigator component. Navigator allows to build a scene with navmesh and find * a path for an agent there. Scene contains agents, geometry objects and water. Agent are distinguished only by * half extents. Each object has unique identifier and could be added, updated or removed. Water could be added once * for each world cell at given level of height. Navmesh builds asynchronously in separate threads. To start build * navmesh call update method. */ - class Navigator + struct Navigator { - public: - /** - * @brief Navigator constructor initializes all internal data. Constructed object is ready to build a scene. - * @param settings allows to customize navigator work. Constructor is only place to set navigator settings. - */ - Navigator(const Settings& settings); + virtual ~Navigator() = default; /** * @brief addAgent should be called for each agent even if all of them has same half extents. * @param agentHalfExtents allows to setup bounding cylinder for each agent, for each different half extents * there is different navmesh. */ - void addAgent(const osg::Vec3f& agentHalfExtents); + virtual void addAgent(const osg::Vec3f& agentHalfExtents) = 0; /** * @brief removeAgent should be called for each agent even if all of them has same half extents * @param agentHalfExtents allows determine which agent to remove */ - void removeAgent(const osg::Vec3f& agentHalfExtents); + virtual void removeAgent(const osg::Vec3f& agentHalfExtents) = 0; /** * @brief addObject is used to add object represented by single btCollisionShape and btTransform. @@ -68,7 +63,7 @@ namespace DetourNavigator * @param transform allows to setup object geometry according to its world state. * @return true if object is added, false if there is already object with given id. */ - bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform); + virtual bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) = 0; /** * @brief addObject is used to add complex object with allowed to walk and avoided to walk shapes @@ -77,7 +72,7 @@ namespace DetourNavigator * @param transform allows to setup objects geometry according to its world state * @return true if object is added, false if there is already object with given id */ - bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform); + virtual bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; /** * @brief addObject is used to add doors. @@ -86,7 +81,7 @@ namespace DetourNavigator * @param transform allows to setup objects geometry according to its world state. * @return true if object is added, false if there is already object with given id. */ - bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform); + virtual bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; /** * @brief updateObject replace object geometry by given data. @@ -95,7 +90,7 @@ namespace DetourNavigator * @param transform allows to setup objects geometry according to its world state. * @return true if object is updated, false if there is no object with given id. */ - bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform); + virtual bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) = 0; /** * @brief updateObject replace object geometry by given data. @@ -104,7 +99,7 @@ namespace DetourNavigator * @param transform allows to setup objects geometry according to its world state. * @return true if object is updated, false if there is no object with given id. */ - bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform); + virtual bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; /** * @brief updateObject replace object geometry by given data. @@ -113,14 +108,14 @@ namespace DetourNavigator * @param transform allows to setup objects geometry according to its world state. * @return true if object is updated, false if there is no object with given id. */ - bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform); + virtual bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; /** * @brief removeObject to make it no more available at the scene. * @param id is used to find object. * @return true if object is removed, false if there is no object with given id. */ - bool removeObject(const ObjectId id); + virtual bool removeObject(const ObjectId id) = 0; /** * @brief addWater is used to set water level at given world cell. @@ -132,26 +127,26 @@ namespace DetourNavigator * at least single object is added to the scene, false if there is already water for given cell or there is no * any other objects. */ - bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, - const btTransform& transform); + virtual bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, + const btTransform& transform) = 0; /** * @brief removeWater to make it no more available at the scene. * @param cellPosition allows to find cell. * @return true if there was water at given cell. */ - bool removeWater(const osg::Vec2i& cellPosition); + virtual bool removeWater(const osg::Vec2i& cellPosition) = 0; /** * @brief update start background navmesh update using current scene state. * @param playerPosition setup initial point to order build tiles of navmesh. */ - void update(const osg::Vec3f& playerPosition); + virtual void update(const osg::Vec3f& playerPosition) = 0; /** * @brief wait locks thread until all tiles are updated from last update call. */ - void wait(); + virtual void wait() = 0; /** * @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through. @@ -186,26 +181,15 @@ namespace DetourNavigator * @brief getNavMesh returns navmesh for specific agent half extents * @return navmesh */ - SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const; + virtual SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const = 0; /** * @brief getNavMeshes returns all current navmeshes * @return map of agent half extents to navmesh */ - std::map getNavMeshes() const; + virtual std::map getNavMeshes() const = 0; - Settings getSettings() const; - - private: - Settings mSettings; - NavMeshManager mNavMeshManager; - std::map mAgents; - std::unordered_map mAvoidIds; - std::unordered_map mWaterIds; - - void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId); - void updateWaterShapeId(const ObjectId id, const ObjectId waterId); - void updateId(const ObjectId id, const ObjectId waterId, std::unordered_map& ids); + virtual Settings getSettings() const = 0; }; } diff --git a/components/detournavigator/navigator.cpp b/components/detournavigator/navigatorimpl.cpp similarity index 66% rename from components/detournavigator/navigator.cpp rename to components/detournavigator/navigatorimpl.cpp index ddd9850214..1b83769f4c 100644 --- a/components/detournavigator/navigator.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -1,4 +1,4 @@ -#include "navigator.hpp" +#include "navigatorimpl.hpp" #include "debug.hpp" #include "settingsutils.hpp" @@ -6,19 +6,19 @@ namespace DetourNavigator { - Navigator::Navigator(const Settings& settings) + NavigatorImpl::NavigatorImpl(const Settings& settings) : mSettings(settings) , mNavMeshManager(mSettings) { } - void Navigator::addAgent(const osg::Vec3f& agentHalfExtents) + void NavigatorImpl::addAgent(const osg::Vec3f& agentHalfExtents) { ++mAgents[agentHalfExtents]; mNavMeshManager.addAgent(agentHalfExtents); } - void Navigator::removeAgent(const osg::Vec3f& agentHalfExtents) + void NavigatorImpl::removeAgent(const osg::Vec3f& agentHalfExtents) { const auto it = mAgents.find(agentHalfExtents); if (it == mAgents.end() || --it->second) @@ -27,12 +27,12 @@ namespace DetourNavigator mNavMeshManager.reset(agentHalfExtents); } - bool Navigator::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) + bool NavigatorImpl::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) { return mNavMeshManager.addObject(id, shape, transform, AreaType_ground); } - bool Navigator::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { bool result = addObject(id, shapes.mShape, transform); if (shapes.mAvoid) @@ -47,7 +47,7 @@ namespace DetourNavigator return result; } - bool Navigator::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) + bool NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) { if (addObject(id, static_cast(shapes), transform)) { @@ -61,12 +61,12 @@ namespace DetourNavigator return false; } - bool Navigator::updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) + bool NavigatorImpl::updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) { return mNavMeshManager.updateObject(id, shape, transform, AreaType_ground); } - bool Navigator::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { bool result = updateObject(id, shapes.mShape, transform); if (shapes.mAvoid) @@ -81,12 +81,12 @@ namespace DetourNavigator return result; } - bool Navigator::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) + bool NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) { return updateObject(id, static_cast(shapes), transform); } - bool Navigator::removeObject(const ObjectId id) + bool NavigatorImpl::removeObject(const ObjectId id) { bool result = mNavMeshManager.removeObject(id); const auto avoid = mAvoidIds.find(id); @@ -99,55 +99,55 @@ namespace DetourNavigator return result; } - bool Navigator::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, + bool NavigatorImpl::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, const btTransform& transform) { return mNavMeshManager.addWater(cellPosition, cellSize, btTransform(transform.getBasis(), btVector3(transform.getOrigin().x(), transform.getOrigin().y(), level))); } - bool Navigator::removeWater(const osg::Vec2i& cellPosition) + bool NavigatorImpl::removeWater(const osg::Vec2i& cellPosition) { return mNavMeshManager.removeWater(cellPosition); } - void Navigator::update(const osg::Vec3f& playerPosition) + void NavigatorImpl::update(const osg::Vec3f& playerPosition) { for (const auto& v : mAgents) mNavMeshManager.update(playerPosition, v.first); } - void Navigator::wait() + void NavigatorImpl::wait() { mNavMeshManager.wait(); } - SharedNavMeshCacheItem Navigator::getNavMesh(const osg::Vec3f& agentHalfExtents) const + SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const { return mNavMeshManager.getNavMesh(agentHalfExtents); } - std::map Navigator::getNavMeshes() const + std::map NavigatorImpl::getNavMeshes() const { return mNavMeshManager.getNavMeshes(); } - Settings Navigator::getSettings() const + Settings NavigatorImpl::getSettings() const { return mSettings; } - void Navigator::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId) + void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId) { updateId(id, avoidId, mWaterIds); } - void Navigator::updateWaterShapeId(const ObjectId id, const ObjectId waterId) + void NavigatorImpl::updateWaterShapeId(const ObjectId id, const ObjectId waterId) { updateId(id, waterId, mWaterIds); } - void Navigator::updateId(const ObjectId id, const ObjectId updateId, std::unordered_map& ids) + void NavigatorImpl::updateId(const ObjectId id, const ObjectId updateId, std::unordered_map& ids) { auto inserted = ids.insert(std::make_pair(id, updateId)); if (!inserted.second) diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp new file mode 100644 index 0000000000..9750559844 --- /dev/null +++ b/components/detournavigator/navigatorimpl.hpp @@ -0,0 +1,64 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORIMPL_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORIMPL_H + +#include "navigator.hpp" +#include "navmeshmanager.hpp" + +namespace DetourNavigator +{ + class NavigatorImpl final : public Navigator + { + public: + /** + * @brief Navigator constructor initializes all internal data. Constructed object is ready to build a scene. + * @param settings allows to customize navigator work. Constructor is only place to set navigator settings. + */ + NavigatorImpl(const Settings& settings); + + void addAgent(const osg::Vec3f& agentHalfExtents) override; + + void removeAgent(const osg::Vec3f& agentHalfExtents) override; + + bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) override; + + bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; + + bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; + + bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) override; + + bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; + + bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; + + bool removeObject(const ObjectId id) override; + + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, + const btTransform& transform) override; + + bool removeWater(const osg::Vec2i& cellPosition) override; + + void update(const osg::Vec3f& playerPosition) override; + + void wait() override; + + SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override; + + std::map getNavMeshes() const override; + + Settings getSettings() const override; + + private: + Settings mSettings; + NavMeshManager mNavMeshManager; + std::map mAgents; + std::unordered_map mAvoidIds; + std::unordered_map mWaterIds; + + void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId); + void updateWaterShapeId(const ObjectId id, const ObjectId waterId); + void updateId(const ObjectId id, const ObjectId waterId, std::unordered_map& ids); + }; +} + +#endif From 16675fd25495bd390b2e7018bde147877878d112 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 15:32:47 +0300 Subject: [PATCH 193/410] Return empty path when navmesh is not found for agent --- .../detournavigator/navigator.cpp | 10 ++++++---- components/detournavigator/navigator.hpp | 2 ++ components/detournavigator/navmeshmanager.cpp | 14 +++++++++----- components/detournavigator/navmeshmanager.hpp | 2 +- components/misc/guarded.hpp | 5 +++++ 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 2883921432..8e76b31541 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -65,9 +65,10 @@ namespace } }; - TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_throw_exception) + TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) { - EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), InvalidArgument); + mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + EXPECT_EQ(mPath, std::deque()); } TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception) @@ -76,11 +77,12 @@ namespace EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException); } - TEST_F(DetourNavigatorNavigatorTest, find_path_for_removed_agent_should_throw_exception) + TEST_F(DetourNavigatorNavigatorTest, find_path_for_removed_agent_should_return_empty) { mNavigator->addAgent(mAgentHalfExtents); mNavigator->removeAgent(mAgentHalfExtents); - EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), InvalidArgument); + mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + EXPECT_EQ(mPath, std::deque()); } TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent) diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 529b539c85..a06d97c563 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -171,6 +171,8 @@ namespace DetourNavigator "out is not an OutputIterator" ); const auto navMesh = getNavMesh(agentHalfExtents); + if (!navMesh) + return out; const auto settings = getSettings(); return findSmoothPath(navMesh.lock()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings, end), includeFlags, diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 66bf39aaf0..ddf0045a27 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -133,7 +133,13 @@ namespace DetourNavigator else lastPlayerTile->second = playerTile; std::map tilesToPost; - const auto& cached = getCached(agentHalfExtents); + const auto cached = getCached(agentHalfExtents); + if (!cached) + { + std::ostringstream stream; + stream << "Agent with half extents is not found: " << agentHalfExtents; + throw InvalidArgument(stream.str()); + } const auto changedTiles = mChangedTiles.find(agentHalfExtents); { const auto locked = cached.lock(); @@ -218,13 +224,11 @@ namespace DetourNavigator } } - const SharedNavMeshCacheItem& NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const + SharedNavMeshCacheItem NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const { const auto cached = mCache.find(agentHalfExtents); if (cached != mCache.end()) return cached->second; - std::ostringstream stream; - stream << "Agent with half extents is not found: " << agentHalfExtents; - throw InvalidArgument(stream.str()); + return SharedNavMeshCacheItem(); } } diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index f44cdd2515..ae006da735 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -67,7 +67,7 @@ namespace DetourNavigator void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType); - const SharedNavMeshCacheItem& getCached(const osg::Vec3f& agentHalfExtents) const; + SharedNavMeshCacheItem getCached(const osg::Vec3f& agentHalfExtents) const; }; } diff --git a/components/misc/guarded.hpp b/components/misc/guarded.hpp index 4cb0564b16..114a77b106 100644 --- a/components/misc/guarded.hpp +++ b/components/misc/guarded.hpp @@ -106,6 +106,11 @@ namespace Misc return Locked(*mMutex, *mValue); } + operator bool() const + { + return static_cast(mValue); + } + private: std::shared_ptr mMutex; std::shared_ptr mValue; From 34c594f01e1f647a96f5814408a0b25cb9d22ceb Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 15:39:06 +0300 Subject: [PATCH 194/410] Add default initializators for settings fields --- components/detournavigator/settings.hpp | 52 ++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index f4073b24b2..dda193fff1 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -7,32 +7,32 @@ namespace DetourNavigator { struct Settings { - bool mEnableWriteRecastMeshToFile; - bool mEnableWriteNavMeshToFile; - bool mEnableRecastMeshFileNameRevision; - bool mEnableNavMeshFileNameRevision; - float mCellHeight; - float mCellSize; - float mDetailSampleDist; - float mDetailSampleMaxError; - float mMaxClimb; - float mMaxSimplificationError; - float mMaxSlope; - float mRecastScaleFactor; - float mSwimHeightScale; - int mBorderSize; - int mMaxEdgeLen; - int mMaxNavMeshQueryNodes; - int mMaxPolys; - int mMaxVertsPerPoly; - int mRegionMergeSize; - int mRegionMinSize; - int mTileSize; - std::size_t mAsyncNavMeshUpdaterThreads; - std::size_t mMaxNavMeshTilesCacheSize; - std::size_t mMaxPolygonPathSize; - std::size_t mMaxSmoothPathSize; - std::size_t mTrianglesPerChunk; + bool mEnableWriteRecastMeshToFile = false; + bool mEnableWriteNavMeshToFile = false; + bool mEnableRecastMeshFileNameRevision = false; + bool mEnableNavMeshFileNameRevision = false; + float mCellHeight = 0; + float mCellSize = 0; + float mDetailSampleDist = 0; + float mDetailSampleMaxError = 0; + float mMaxClimb = 0; + float mMaxSimplificationError = 0; + float mMaxSlope = 0; + float mRecastScaleFactor = 0; + float mSwimHeightScale = 0; + int mBorderSize = 0; + int mMaxEdgeLen = 0; + int mMaxNavMeshQueryNodes = 0; + int mMaxPolys = 0; + int mMaxVertsPerPoly = 0; + int mRegionMergeSize = 0; + int mRegionMinSize = 0; + int mTileSize = 0; + std::size_t mAsyncNavMeshUpdaterThreads = 0; + std::size_t mMaxNavMeshTilesCacheSize = 0; + std::size_t mMaxPolygonPathSize = 0; + std::size_t mMaxSmoothPathSize = 0; + std::size_t mTrianglesPerChunk = 0; std::string mRecastMeshPathPrefix; std::string mNavMeshPathPrefix; }; From 9626b6ec422ffbc0b264e98031eac78340725736 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Feb 2019 15:50:58 +0300 Subject: [PATCH 195/410] Add option to disable DetourNavigator component to find paths --- apps/openmw/mwworld/worldimp.cpp | 25 +++--- components/detournavigator/navigatorstub.hpp | 83 ++++++++++++++++++++ components/detournavigator/settings.cpp | 5 +- components/detournavigator/settings.hpp | 4 +- files/settings-default.cfg | 4 + 5 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 components/detournavigator/navigatorstub.hpp diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 65d6293842..d7963fae13 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include "../mwbase/environment.hpp" @@ -198,15 +199,21 @@ namespace MWWorld mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode)); - auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager(); - navigatorSettings.mMaxClimb = MWPhysics::sStepSizeUp; - navigatorSettings.mMaxSlope = MWPhysics::sMaxSlope; - navigatorSettings.mSwimHeightScale = mSwimHeightScale; - if (Settings::Manager::getBool("enable log", "Navigator")) - DetourNavigator::Log::instance().setSink(std::unique_ptr( - new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator")))); - DetourNavigator::RecastGlobalAllocator::init(); - mNavigator.reset(new DetourNavigator::NavigatorImpl(navigatorSettings)); + if (auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager()) + { + navigatorSettings->mMaxClimb = MWPhysics::sStepSizeUp; + navigatorSettings->mMaxSlope = MWPhysics::sMaxSlope; + navigatorSettings->mSwimHeightScale = mSwimHeightScale; + if (Settings::Manager::getBool("enable log", "Navigator")) + DetourNavigator::Log::instance().setSink(std::unique_ptr( + new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator")))); + DetourNavigator::RecastGlobalAllocator::init(); + mNavigator.reset(new DetourNavigator::NavigatorImpl(*navigatorSettings)); + } + else + { + mNavigator.reset(new DetourNavigator::NavigatorStub()); + } mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath, *mNavigator)); mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get())); diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp new file mode 100644 index 0000000000..5d82d2f59f --- /dev/null +++ b/components/detournavigator/navigatorstub.hpp @@ -0,0 +1,83 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORSTUB_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORSTUB_H + +#include "navigator.hpp" + +namespace DetourNavigator +{ + struct NavigatorStub final : public Navigator + { + NavigatorStub() = default; + + void addAgent(const osg::Vec3f& /*agentHalfExtents*/) override {} + + void removeAgent(const osg::Vec3f& /*agentHalfExtents*/) override {} + + bool addObject(const ObjectId /*id*/, const btCollisionShape& /*shape*/, const btTransform& /*transform*/) override + { + return false; + } + + bool addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override + { + return false; + } + + bool addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override + { + return false; + } + + bool updateObject(const ObjectId /*id*/, const btCollisionShape& /*shape*/, const btTransform& /*transform*/) override + { + return false; + } + + bool updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override + { + return false; + } + + bool updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override + { + return false; + } + + bool removeObject(const ObjectId /*id*/) override + { + return false; + } + + bool addWater(const osg::Vec2i& /*cellPosition*/, const int /*cellSize*/, const btScalar /*level*/, + const btTransform& /*transform*/) override + { + return false; + } + + bool removeWater(const osg::Vec2i& /*cellPosition*/) override + { + return false; + } + + void update(const osg::Vec3f& /*playerPosition*/) override {} + + void wait() override {} + + SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override + { + return SharedNavMeshCacheItem(); + } + + std::map getNavMeshes() const override + { + return std::map(); + } + + Settings getSettings() const override + { + return Settings {}; + } + }; +} + +#endif diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index 0b9210a90f..f584e48f94 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -6,8 +6,11 @@ namespace DetourNavigator { - Settings makeSettingsFromSettingsManager() + boost::optional makeSettingsFromSettingsManager() { + if (!::Settings::Manager::getBool("enable", "Navigator")) + return boost::optional(); + Settings navigatorSettings; navigatorSettings.mBorderSize = ::Settings::Manager::getInt("border size", "Navigator"); diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index dda193fff1..0316092a0e 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_SETTINGS_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_SETTINGS_H +#include + #include namespace DetourNavigator @@ -37,7 +39,7 @@ namespace DetourNavigator std::string mNavMeshPathPrefix; }; - Settings makeSettingsFromSettingsManager(); + boost::optional makeSettingsFromSettingsManager(); } #endif diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 71a93d1a2c..81df700cc5 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -542,6 +542,10 @@ companion h = 0.63 [Navigator] +# Enable navigator (true, false). When enabled background threads are started to build navmesh for world geometry. +# Pathfinding system uses navmesh to build paths. When disabled only pathgrid is used to build paths. +enable = true + # Scale of NavMesh coordinates to world coordinates (value > 0.0). Recastnavigation builds voxels for world geometry. # Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size # "recast scale factor" / "cell size". Default value calculates by this equation: From da6df818ff56e794ecec1d57a6b4a223aff24eb2 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Feb 2019 00:48:07 +0300 Subject: [PATCH 196/410] Fix update navmesh Every updated object should produce a set of changed tiles where it is placed. Before this change only current object tiles were updated. If object was moved to another set of tiles then navmesh were not changed in new tiles. TileCachedRecastMeshManager::updateObject should add all new tiles if object was moved and remove all no more used tiles. Both new and old tiles should be marked as changed. Also add tests to show desired result for add, update, remove. --- apps/openmw_test_suite/CMakeLists.txt | 1 + .../tilecachedrecastmeshmanager.cpp | 123 ++++++++++++++++++ components/detournavigator/navmeshmanager.cpp | 6 +- .../tilecachedrecastmeshmanager.cpp | 120 +++++++++++------ .../tilecachedrecastmeshmanager.hpp | 16 ++- 5 files changed, 223 insertions(+), 43 deletions(-) create mode 100644 apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 9070528827..12775035ba 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -24,6 +24,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) detournavigator/gettilespositions.cpp detournavigator/recastmeshobject.cpp detournavigator/navmeshtilescache.cpp + detournavigator/tilecachedrecastmeshmanager.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp new file mode 100644 index 0000000000..0443fc9cef --- /dev/null +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -0,0 +1,123 @@ +#include "operators.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace +{ + using namespace testing; + using namespace DetourNavigator; + + struct DetourNavigatorTileCachedRecastMeshManagerTest : Test + { + Settings mSettings; + + DetourNavigatorTileCachedRecastMeshManagerTest() + { + mSettings.mBorderSize = 16; + mSettings.mCellSize = 0.2f; + mSettings.mRecastScaleFactor = 0.017647058823529415f; + mSettings.mTileSize = 64; + mSettings.mTrianglesPerChunk = 256; + } + }; + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_empty_should_return_nullptr) + { + TileCachedRecastMeshManager manager(mSettings); + EXPECT_EQ(manager.getMesh(TilePosition(0, 0)), nullptr); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, has_tile_for_empty_should_return_false) + { + TileCachedRecastMeshManager manager(mSettings); + EXPECT_FALSE(manager.hasTile(TilePosition(0, 0))); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_for_empty_should_return_zero) + { + const TileCachedRecastMeshManager manager(mSettings); + EXPECT_EQ(manager.getRevision(), 0); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, for_each_tile_position_for_empty_should_call_none) + { + TileCachedRecastMeshManager manager(mSettings); + std::size_t calls = 0; + manager.forEachTilePosition([&] (const TilePosition&) { ++calls; }); + EXPECT_EQ(calls, 0); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_recast_mesh_for_each_used_tile) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_nullptr_for_unused_tile) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_moved_object_should_return_recast_mesh_for_each_used_tile) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); + + manager.addObject(ObjectId(1ul), boxShape, transform, AreaType::AreaType_ground); + EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(1, 0)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(1, -1)), nullptr); + + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_moved_object_should_return_nullptr_for_unused_tile) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); + + manager.addObject(ObjectId(1ul), boxShape, transform, AreaType::AreaType_ground); + EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr); + EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr); + + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr); + EXPECT_EQ(manager.getMesh(TilePosition(1, -1)), nullptr); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_removed_object_should_return_nullptr_for_all_previously_used_tiles) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.removeObject(ObjectId(1ul)); + EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr); + EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr); + EXPECT_EQ(manager.getMesh(TilePosition(0, -1)), nullptr); + EXPECT_EQ(manager.getMesh(TilePosition(0, 0)), nullptr); + } +} diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 66bf39aaf0..3a31d010e8 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -44,9 +44,11 @@ namespace DetourNavigator bool NavMeshManager::updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType) { - if (!mRecastMeshManager.updateObject(id, transform, areaType)) + const auto changedTiles = mRecastMeshManager.updateObject(id, shape, transform, areaType); + if (changedTiles.empty()) return false; - addChangedTiles(shape, transform, ChangeType::update); + for (const auto& tile : changedTiles) + addChangedTile(tile, ChangeType::update); return true; } diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index d624800e92..7070603c72 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -15,48 +15,59 @@ namespace DetourNavigator bool result = false; auto& tilesPositions = mObjectsTilesPositions[id]; const auto border = getBorderSize(mSettings); - getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& tilePosition) - { - const auto tiles = mTiles.lock(); - auto tile = tiles->find(tilePosition); - if (tile == tiles->end()) + { + auto tiles = mTiles.lock(); + getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& tilePosition) { - auto tileBounds = makeTileBounds(mSettings, tilePosition); - tileBounds.mMin -= osg::Vec2f(border, border); - tileBounds.mMax += osg::Vec2f(border, border); - tile = tiles->insert(std::make_pair(tilePosition, - CachedRecastMeshManager(mSettings, tileBounds))).first; - } - if (tile->second.addObject(id, shape, transform, areaType)) - { - tilesPositions.push_back(tilePosition); - result = true; - } - }); + if (addTile(id, shape, transform, areaType, tilePosition, border, tiles.get())) + { + tilesPositions.insert(tilePosition); + result = true; + } + }); + } if (result) ++mRevision; return result; } - bool TileCachedRecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, - const AreaType areaType) + std::vector TileCachedRecastMeshManager::updateObject(const ObjectId id, const btCollisionShape& shape, + const btTransform& transform, const AreaType areaType) { const auto object = mObjectsTilesPositions.find(id); if (object == mObjectsTilesPositions.end()) - return false; - bool result = false; + return std::vector(); + auto& currentTiles = object->second; + const auto border = getBorderSize(mSettings); + std::vector changedTiles; + std::set newTiles; { - const auto tiles = mTiles.lock(); - for (const auto& tilePosition : object->second) + auto tiles = mTiles.lock(); + const auto onTilePosition = [&] (const TilePosition& tilePosition) { - const auto tile = tiles->find(tilePosition); - if (tile != tiles->end()) - result = tile->second.updateObject(id, transform, areaType) || result; - } + if (currentTiles.count(tilePosition)) + { + if (updateTile(id, transform, areaType, tilePosition, tiles.get())) + { + newTiles.insert(tilePosition); + changedTiles.push_back(tilePosition); + } + } + else if (addTile(id, shape, transform, areaType, tilePosition, border, tiles.get())) + { + newTiles.insert(tilePosition); + changedTiles.push_back(tilePosition); + } + }; + getTilesPositions(shape, transform, mSettings, onTilePosition); + for (const auto& tile : currentTiles) + if (!newTiles.count(tile) && removeTile(id, tile, tiles.get())) + changedTiles.push_back(tile); + std::swap(currentTiles, newTiles); } - if (result) + if (!changedTiles.empty()) ++mRevision; - return result; + return changedTiles; } boost::optional TileCachedRecastMeshManager::removeObject(const ObjectId id) @@ -65,17 +76,14 @@ namespace DetourNavigator if (object == mObjectsTilesPositions.end()) return boost::none; boost::optional result; - for (const auto& tilePosition : object->second) { - const auto tiles = mTiles.lock(); - const auto tile = tiles->find(tilePosition); - if (tile == tiles->end()) - continue; - const auto tileResult = tile->second.removeObject(id); - if (tile->second.isEmpty()) - tiles->erase(tile); - if (tileResult && !result) - result = tileResult; + auto tiles = mTiles.lock(); + for (const auto& tilePosition : object->second) + { + const auto removed = removeTile(id, tilePosition, tiles.get()); + if (removed && !result) + result = removed; + } } if (result) ++mRevision; @@ -172,4 +180,38 @@ namespace DetourNavigator { return mRevision; } + + bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape, + const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, + std::map& tiles) + { + auto tile = tiles.find(tilePosition); + if (tile == tiles.end()) + { + auto tileBounds = makeTileBounds(mSettings, tilePosition); + tileBounds.mMin -= osg::Vec2f(border, border); + tileBounds.mMax += osg::Vec2f(border, border); + tile = tiles.insert(std::make_pair(tilePosition, CachedRecastMeshManager(mSettings, tileBounds))).first; + } + return tile->second.addObject(id, shape, transform, areaType); + } + + bool TileCachedRecastMeshManager::updateTile(const ObjectId id, const btTransform& transform, + const AreaType areaType, const TilePosition& tilePosition, std::map& tiles) + { + const auto tile = tiles.find(tilePosition); + return tile != tiles.end() && tile->second.updateObject(id, transform, areaType); + } + + boost::optional TileCachedRecastMeshManager::removeTile(const ObjectId id, + const TilePosition& tilePosition, std::map& tiles) + { + const auto tile = tiles.find(tilePosition); + if (tile == tiles.end()) + return boost::optional(); + const auto tileResult = tile->second.removeObject(id); + if (tile->second.isEmpty()) + tiles.erase(tile); + return tileResult; + } } diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index f82ef85c5c..a3d0ae1e53 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace DetourNavigator { @@ -19,7 +20,8 @@ namespace DetourNavigator bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType); - bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); + std::vector updateObject(const ObjectId id, const btCollisionShape& shape, + const btTransform& transform, const AreaType areaType); boost::optional removeObject(const ObjectId id); @@ -43,9 +45,19 @@ namespace DetourNavigator private: const Settings& mSettings; Misc::ScopeGuarded> mTiles; - std::unordered_map> mObjectsTilesPositions; + std::unordered_map> mObjectsTilesPositions; std::map> mWaterTilesPositions; std::size_t mRevision = 0; + + bool addTile(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + const AreaType areaType, const TilePosition& tilePosition, float border, + std::map& tiles); + + bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType, + const TilePosition& tilePosition, std::map& tiles); + + boost::optional removeTile(const ObjectId id, const TilePosition& tilePosition, + std::map& tiles); }; } From 18a59df0502f562426e83e2bb1fc5d1d1aa25d5a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 10:24:25 +0400 Subject: [PATCH 197/410] Throw exceptions by value instead of reference --- apps/openmw/mwgui/widgets.cpp | 2 +- components/sdlutil/sdlinputwrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index c3bc1ec196..c90d540721 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -41,7 +41,7 @@ namespace MWGui else if (skill < ESM::Skill::Length) setSkillId(static_cast(skill)); else - throw new std::runtime_error("Skill number out of range"); + throw std::runtime_error("Skill number out of range"); } void MWSkill::setSkillValue(const SkillValue& value) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index f7111fdf80..c67edfbf38 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -368,7 +368,7 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v } else { - throw new std::runtime_error("Tried to package non-motion event!"); + throw std::runtime_error("Tried to package non-motion event!"); } return pack_evt; From ad9412a117989cef87e4b43a7d06055a558fe6ab Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 11:42:22 +0400 Subject: [PATCH 198/410] Remove some redundant checks --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwrender/actoranimation.cpp | 46 ++++++++++++------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 317764e0cb..869b289796 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -780,7 +780,7 @@ namespace MWClass MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr()); if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name()) { - if (attacker.isEmpty() || (!attacker.isEmpty() && !(object.isEmpty() && !attacker.getClass().isNpc()))) // Unarmed creature attacks don't affect armor condition + if (!object.isEmpty() || attacker.isEmpty() || attacker.getClass().isNpc()) // Unarmed creature attacks don't affect armor condition { int armorhealth = armor.getClass().getItemHealth(armor); armorhealth -= std::min(damageDiff, armorhealth); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index de85f296dd..54476c48e3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -262,7 +262,7 @@ namespace MWGui if (mode == GM_Console) MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); - else if ((mode == GM_Container) || (mode == GM_Inventory)) + else //if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object if (!object.isEmpty()) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 9f2f961ec2..afe8f5cd31 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -328,32 +328,32 @@ void ActorAnimation::updateQuiver() suitableAmmo = ammo->get()->mBase->mData.mType == ESM::Weapon::Arrow; } - if (ammoNode && suitableAmmo) + if (!suitableAmmo) + return; + + // We should not show more ammo than equipped and more than quiver mesh has + ammoCount = std::min(ammoCount, ammoNode->getNumChildren()); + + // Remove existing ammo nodes + for (unsigned int i=0; igetNumChildren(); ++i) { - // We should not show more ammo than equipped and more than quiver mesh has - ammoCount = std::min(ammoCount, ammoNode->getNumChildren()); + osg::ref_ptr arrowNode = ammoNode->getChild(i)->asGroup(); + if (!arrowNode->getNumChildren()) + continue; - // Remove existing ammo nodes - for (unsigned int i=0; igetNumChildren(); ++i) - { - osg::ref_ptr arrowNode = ammoNode->getChild(i)->asGroup(); - if (!arrowNode->getNumChildren()) - continue; + osg::ref_ptr arrowChildNode = arrowNode->getChild(0); + arrowNode->removeChild(arrowChildNode); + } - osg::ref_ptr arrowChildNode = arrowNode->getChild(0); - arrowNode->removeChild(arrowChildNode); - } - - // Add new ones - osg::Vec4f glowColor = getEnchantmentColor(*ammo); - std::string model = ammo->getClass().getModel(*ammo); - for (unsigned int i=0; i arrowNode = ammoNode->getChild(i)->asGroup(); - osg::ref_ptr arrow = mResourceSystem->getSceneManager()->getInstance(model, arrowNode); - if (!ammo->getClass().getEnchantment(*ammo).empty()) - addGlow(arrow, glowColor); - } + // Add new ones + osg::Vec4f glowColor = getEnchantmentColor(*ammo); + std::string model = ammo->getClass().getModel(*ammo); + for (unsigned int i=0; i arrowNode = ammoNode->getChild(i)->asGroup(); + osg::ref_ptr arrow = mResourceSystem->getSceneManager()->getInstance(model, arrowNode); + if (!ammo->getClass().getEnchantment(*ammo).empty()) + addGlow(arrow, glowColor); } } From 80c62a4fe17f731f6e3d261dc8b2717d5289fe29 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 11:44:45 +0400 Subject: [PATCH 199/410] Fix endsWith() call --- apps/wizard/unshield/unshieldworker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 7aa84d3b15..a997c9324e 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -876,7 +876,7 @@ QStringList Wizard::UnshieldWorker::findFiles(const QString &fileName, const QSt result.append(info.absoluteFilePath()); break; case Qt::MatchEndsWith: - if (info.fileName().endsWith(fileName), Qt::CaseInsensitive) + if (info.fileName().endsWith(fileName, Qt::CaseInsensitive)) result.append(info.absoluteFilePath()); break; } From dc6ef15571377904d392db29554fc0a117d42f6d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 11:53:02 +0400 Subject: [PATCH 200/410] Simplify loop in the addSkills() --- apps/openmw/mwgui/review.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index f2f1cf8921..004a172b34 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -327,11 +327,9 @@ namespace MWGui addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + for (const int& skillId : skills) { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; From 229bd8505e021e3d1f991d0ef9c5ce1a9b6b6074 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 11:56:24 +0400 Subject: [PATCH 201/410] Init missing variables --- apps/essimporter/importercontext.hpp | 2 ++ apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwworld/player.cpp | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 86501b3cb4..1a91b7cead 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -84,6 +84,8 @@ namespace ESSImport mGlobalMapState.mBounds.mMaxX = 0; mGlobalMapState.mBounds.mMinY = 0; mGlobalMapState.mBounds.mMaxY = 0; + + mPlayerBase.blank(); } int generateActorId() diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index e7d1ecee12..8fc35de49d 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -12,7 +12,7 @@ #include "steering.hpp" MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr) -: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mAdjAngle(0) +: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mLastPos(ESM::Position()), mAdjAngle(0) { } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index faf15215a8..52a5ab4192 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -30,6 +30,7 @@ namespace MWWorld Player::Player (const ESM::NPC *player) : mCellStore(0), mLastKnownExteriorPosition(0,0,0), + mMarkedPosition(ESM::Position()), mMarkedCell(nullptr), mAutoMove(false), mForwardBackward(0), From 9de0c9045acc39f8f80eea9d4627e69b73b59f87 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 11:57:18 +0400 Subject: [PATCH 202/410] Fix API usage errors --- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index a2f6ea1423..fe74b9830b 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -631,7 +631,7 @@ namespace if (page+2 < book->pageCount()) { - MWBase::Environment::get().getWindowManager()->playSound("book page", true); + MWBase::Environment::get().getWindowManager()->playSound("book page"); page += 2; updateShowingPages (); @@ -649,7 +649,7 @@ namespace if(page >= 2) { - MWBase::Environment::get().getWindowManager()->playSound("book page", true); + MWBase::Environment::get().getWindowManager()->playSound("book page"); page -= 2; updateShowingPages (); From ff9afda18d79babf9c40412a2a5dcc4938dc9ec2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Feb 2019 12:07:14 +0400 Subject: [PATCH 203/410] Avoid to keep reference to the local 'encoder' variable outside the Engine::go() --- apps/openmw/engine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 15a8f0f32b..cb106c711c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -258,6 +258,9 @@ OMW::Engine::~Engine() mViewer = nullptr; + delete mEncoder; + mEncoder = nullptr; + if (mWindow) { SDL_DestroyWindow(mWindow); @@ -657,8 +660,7 @@ void OMW::Engine::go() settingspath = loadSettings (settings); // Create encoder - ToUTF8::Utf8Encoder encoder (mEncoding); - mEncoder = &encoder; + mEncoder = new ToUTF8::Utf8Encoder(mEncoding); // Setup viewer mViewer = new osgViewer::Viewer; From c20030d8c9538e998270d8fa423fd29e15084b52 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 18 Feb 2019 16:21:42 +0300 Subject: [PATCH 204/410] Correct jumping velocity --- apps/openmw/mwclass/npc.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 317764e0cb..eb48c68549 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -935,8 +935,12 @@ namespace MWClass const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Run); + bool swimming = world->isSwimming(ptr); + bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr); + bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); + sneaking = sneaking && (inair || MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr)); + bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run); + running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr)); float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()* (gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat()); @@ -961,7 +965,7 @@ namespace MWClass flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; } - else if (world->isSwimming(ptr)) + else if (swimming) { float swimSpeed = walkSpeed; if(running) @@ -971,7 +975,7 @@ namespace MWClass gmst.fSwimRunAthleticsMult->mValue.getFloat(); moveSpeed = swimSpeed; } - else if (running) + else if (running && !sneaking) moveSpeed = runSpeed; else moveSpeed = walkSpeed; From c03ed4cd505c7bdef9df22f3c632b98c922605c2 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 19 Feb 2019 01:10:55 +0300 Subject: [PATCH 205/410] Include cleanup --- apps/openmw/mwgui/enchantingdialog.cpp | 3 +++ apps/openmw/mwgui/spellbuyingwindow.hpp | 6 ++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwmechanics/actors.cpp | 7 ++----- apps/openmw/mwmechanics/actors.hpp | 17 +++++++++++++++-- apps/openmw/mwmechanics/actorutil.hpp | 5 ++++- apps/openmw/mwmechanics/aicast.cpp | 1 + apps/openmw/mwmechanics/aicast.hpp | 7 +++++-- apps/openmw/mwmechanics/aiescort.hpp | 2 -- apps/openmw/mwmechanics/aiface.cpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 2 -- apps/openmw/mwmechanics/aipursue.cpp | 1 + apps/openmw/mwmechanics/aipursue.hpp | 4 ---- apps/openmw/mwmechanics/aistate.hpp | 1 - apps/openmw/mwmechanics/aitravel.hpp | 2 -- apps/openmw/mwmechanics/autocalcspell.hpp | 11 ++++++++--- apps/openmw/mwmechanics/combat.hpp | 10 +++++++++- apps/openmw/mwmechanics/enchanting.cpp | 2 ++ apps/openmw/mwmechanics/enchanting.hpp | 3 --- apps/openmw/mwmechanics/objects.cpp | 1 + apps/openmw/mwmechanics/objects.hpp | 8 +++++++- apps/openmw/mwmechanics/spellpriority.cpp | 1 + apps/openmw/mwmechanics/spellpriority.hpp | 12 ++++++++++-- apps/openmw/mwmechanics/trading.hpp | 5 ++++- apps/openmw/mwworld/actionalchemy.cpp | 2 -- apps/openmw/mwworld/actionapply.hpp | 1 - apps/openmw/mwworld/actioneat.cpp | 3 --- apps/openmw/mwworld/actioneat.hpp | 1 - apps/openmw/mwworld/actionequip.cpp | 1 - apps/openmw/mwworld/actionopen.cpp | 3 --- apps/openmw/mwworld/actionopen.hpp | 2 -- apps/openmw/mwworld/actionread.hpp | 1 - apps/openmw/mwworld/actionsoulgem.cpp | 3 +-- apps/openmw/mwworld/actionsoulgem.hpp | 1 - apps/openmw/mwworld/actiontake.hpp | 1 - apps/openmw/mwworld/actiontalk.hpp | 1 - apps/openmw/mwworld/actiontrap.hpp | 1 - apps/openmw/mwworld/recordcmp.hpp | 2 -- apps/openmw/mwworld/refdata.hpp | 1 - 39 files changed, 80 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 98980e3397..af6567afb7 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -9,7 +9,10 @@ #include #include +#include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 30727a545d..c68ec24830 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -4,7 +4,10 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" -#include "../mwworld/esmstore.hpp" +namespace ESM +{ + struct Spell; +} namespace MyGUI { @@ -17,7 +20,6 @@ namespace MWGui class WindowManager; } - namespace MWGui { class SpellBuyingWindow : public ReferenceInterface, public WindowBase diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index dc82cad9c3..7e4ba09982 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -54,6 +54,7 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwrender/vismask.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7694250530..a3906b98c8 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,10 +1,7 @@ #include "actors.hpp" -#include -#include #include #include -#include #include #include @@ -507,7 +504,7 @@ namespace MWMechanics MagicEffects now = creatureStats.getSpells().getMagicEffects(); - if (creature.getTypeName()==typeid (ESM::NPC).name()) + if (creature.getClass().isNpc()) { MWWorld::InventoryStore& store = creature.getClass().getInventoryStore (creature); now += store.getMagicEffects(); @@ -1423,7 +1420,7 @@ namespace MWMechanics } } - if(iter->first.getTypeName() == typeid(ESM::NPC).name()) + if(iter->first.getClass().isNpc()) { updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer); calculateNpcStatModifiers(iter->first, duration); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 61879c432f..3b1b9e8150 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -5,10 +5,23 @@ #include #include #include +#include -#include "../mwbase/world.hpp" +namespace ESM +{ + class ESMReader; + class ESMWriter; +} -#include "movement.hpp" +namespace osg +{ + class Vec3f; +} + +namespace Loading +{ + class Listener; +} namespace MWWorld { diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 510e41db35..3c6dc940c5 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -1,7 +1,10 @@ #ifndef OPENMW_MWMECHANICS_ACTORUTIL_H #define OPENMW_MWMECHANICS_ACTORUTIL_H -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/aicast.cpp b/apps/openmw/mwmechanics/aicast.cpp index 38dc2fa732..e448313bf8 100644 --- a/apps/openmw/mwmechanics/aicast.cpp +++ b/apps/openmw/mwmechanics/aicast.cpp @@ -2,6 +2,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/aicast.hpp b/apps/openmw/mwmechanics/aicast.hpp index 70a8a6bbdc..7128fe7a2a 100644 --- a/apps/openmw/mwmechanics/aicast.hpp +++ b/apps/openmw/mwmechanics/aicast.hpp @@ -1,10 +1,13 @@ #ifndef GAME_MWMECHANICS_AICAST_H #define GAME_MWMECHANICS_AICAST_H -#include "../mwbase/world.hpp" - #include "aipackage.hpp" +namespace MWWorld +{ + class Ptr; +} + namespace MWMechanics { /// AiPackage which makes an actor to cast given spell. diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 82dba960ee..56c9b1c85f 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -5,8 +5,6 @@ #include -#include "pathfinding.hpp" - namespace ESM { namespace AiSequence diff --git a/apps/openmw/mwmechanics/aiface.cpp b/apps/openmw/mwmechanics/aiface.cpp index 7d15cabf25..b99a8c1f45 100644 --- a/apps/openmw/mwmechanics/aiface.cpp +++ b/apps/openmw/mwmechanics/aiface.cpp @@ -1,6 +1,6 @@ #include "aiface.hpp" -#include "../mwbase/world.hpp" +#include "../mwworld/ptr.hpp" #include "steering.hpp" diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 5be858b0bf..d7287cd2fc 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -7,8 +7,6 @@ #include "obstacle.hpp" #include "aistate.hpp" -#include - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 4bec050d7f..4dd644e6b6 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -4,6 +4,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index 455b0a2fde..ea83a10e52 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -3,10 +3,6 @@ #include "aipackage.hpp" -#include "../mwbase/world.hpp" - -#include "pathfinding.hpp" - namespace ESM { namespace AiSequence diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp index 40f4ab1d4e..949fb74ddc 100644 --- a/apps/openmw/mwmechanics/aistate.hpp +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -2,7 +2,6 @@ #define AISTATE_H #include -#include namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index c297771d07..f9f9f43fc4 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -3,8 +3,6 @@ #include "aipackage.hpp" -#include "pathfinding.hpp" - namespace ESM { namespace AiSequence diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp index 50be8a5d98..460713ae37 100644 --- a/apps/openmw/mwmechanics/autocalcspell.hpp +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -1,9 +1,14 @@ #ifndef OPENMW_AUTOCALCSPELL_H #define OPENMW_AUTOCALCSPELL_H -#include -#include -#include +#include +#include + +namespace ESM +{ + struct Spell; + struct Race; +} namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 8b93ca2040..e5b6b5dd88 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -1,7 +1,15 @@ #ifndef OPENMW_MECHANICS_COMBAT_H #define OPENMW_MECHANICS_COMBAT_H -#include "../mwworld/ptr.hpp" +namespace osg +{ + class Vec3f; +} + +namespace MWWorld +{ + class Ptr; +} namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index e4bb0cf3f0..20121c2d97 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 8e3b00e5a1..2751476711 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -7,9 +7,6 @@ #include "../mwworld/ptr.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" - namespace MWMechanics { class Enchanting diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index 7265081613..d4a393c723 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" +#include "character.hpp" #include "movement.hpp" namespace MWMechanics diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 81b95baf8a..1bcf646a44 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -3,8 +3,12 @@ #include #include +#include -#include "character.hpp" +namespace osg +{ + class Vec3f; +} namespace MWWorld { @@ -14,6 +18,8 @@ namespace MWWorld namespace MWMechanics { + class CharacterController; + class Objects { typedef std::map PtrControllerMap; diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 3b242266c2..c55d5ab10c 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/spellpriority.hpp b/apps/openmw/mwmechanics/spellpriority.hpp index 4e5ff5c713..0305f24b5c 100644 --- a/apps/openmw/mwmechanics/spellpriority.hpp +++ b/apps/openmw/mwmechanics/spellpriority.hpp @@ -1,9 +1,17 @@ #ifndef OPENMW_SPELL_PRIORITY_H #define OPENMW_SPELL_PRIORITY_H -#include +namespace ESM +{ + struct Spell; + struct EffectList; + struct ENAMstruct; +} -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/trading.hpp b/apps/openmw/mwmechanics/trading.hpp index e006370dde..e30b82f5e8 100644 --- a/apps/openmw/mwmechanics/trading.hpp +++ b/apps/openmw/mwmechanics/trading.hpp @@ -1,7 +1,10 @@ #ifndef OPENMW_MECHANICS_TRADING_H #define OPENMW_MECHANICS_TRADING_H -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} namespace MWMechanics { diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index 37d811eb67..62b673dd23 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -2,9 +2,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" #include "../mwmechanics/actorutil.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/actionapply.hpp b/apps/openmw/mwworld/actionapply.hpp index 5294745a61..4a1d2aefa6 100644 --- a/apps/openmw/mwworld/actionapply.hpp +++ b/apps/openmw/mwworld/actionapply.hpp @@ -4,7 +4,6 @@ #include #include "action.hpp" -#include "ptr.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 84805c70e1..ef435cca92 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -2,9 +2,6 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - #include "../mwworld/containerstore.hpp" #include "../mwmechanics/actorutil.hpp" diff --git a/apps/openmw/mwworld/actioneat.hpp b/apps/openmw/mwworld/actioneat.hpp index ce5330db77..db21ffa179 100644 --- a/apps/openmw/mwworld/actioneat.hpp +++ b/apps/openmw/mwworld/actioneat.hpp @@ -2,7 +2,6 @@ #define GAME_MWWORLD_ACTIONEAT_H #include "action.hpp" -#include "ptr.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index da794bcd29..30f9691937 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -1,7 +1,6 @@ #include "actionequip.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/actorutil.hpp" diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index f678037cea..f9866cd41b 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -6,9 +6,6 @@ #include "../mwmechanics/disease.hpp" -#include "class.hpp" -#include "containerstore.hpp" - namespace MWWorld { ActionOpen::ActionOpen (const MWWorld::Ptr& container) diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 3bce25c6b3..e36b971a24 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -2,8 +2,6 @@ #define GAME_MWWORLD_ACTIONOPEN_H #include "action.hpp" -#include "ptr.hpp" - namespace MWWorld { diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index c23bf29008..7c4d7d2f45 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -2,7 +2,6 @@ #define GAME_MWWORLD_ACTIONREAD_H #include "action.hpp" -#include "ptr.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index 98fe8ee34d..f7823dabaa 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -2,8 +2,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" + #include "../mwmechanics/actorutil.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/actionsoulgem.hpp b/apps/openmw/mwworld/actionsoulgem.hpp index 0dd5266570..6a8f220bc5 100644 --- a/apps/openmw/mwworld/actionsoulgem.hpp +++ b/apps/openmw/mwworld/actionsoulgem.hpp @@ -2,7 +2,6 @@ #define GAME_MWWORLD_ACTIONSOULGEM_H #include "action.hpp" -#include "ptr.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index b0a9b82478..fb8d2f4ceb 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -2,7 +2,6 @@ #define GAME_MWWORLD_ACTIONTAKE_H #include "action.hpp" -#include "ptr.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index b88b168d8c..01738a0bb9 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -1,7 +1,6 @@ #ifndef GAME_MWWORLD_ACTIONTALK_H #define GAME_MWWORLD_ACTIONTALK_H -#include "ptr.hpp" #include "action.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/actiontrap.hpp b/apps/openmw/mwworld/actiontrap.hpp index 5ff91613f8..5b0d429c48 100644 --- a/apps/openmw/mwworld/actiontrap.hpp +++ b/apps/openmw/mwworld/actiontrap.hpp @@ -4,7 +4,6 @@ #include #include "action.hpp" -#include "ptr.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/recordcmp.hpp b/apps/openmw/mwworld/recordcmp.hpp index 500f86b1eb..f749351cea 100644 --- a/apps/openmw/mwworld/recordcmp.hpp +++ b/apps/openmw/mwworld/recordcmp.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MWWORLD_RECORDCMP_H #define OPENMW_MWWORLD_RECORDCMP_H -#include - #include #include diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 75eec6742d..6a59d97974 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -7,7 +7,6 @@ #include "../mwscript/locals.hpp" #include -#include namespace SceneUtil { From 0c8ad0a3bbd50a6c2a7539317de04c76455d600b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 19 Feb 2019 18:13:03 +0000 Subject: [PATCH 206/410] Double buffer debug HUD frustum geometries to prevent race conditions. --- components/sceneutil/mwshadowtechnique.cpp | 49 ++++++++++++++++------ components/sceneutil/mwshadowtechnique.hpp | 4 +- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 0addb6f4bb..64c2e6e55f 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -978,7 +978,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) osg::ref_ptr vertexArray = new osg::Vec3Array(); for (osg::Vec3d &vertex : frustum.corners) vertexArray->push_back((osg::Vec3)vertex); - _debugHud->setFrustumVertices(vertexArray); + _debugHud->setFrustumVertices(vertexArray, cv.getTraversalNumber()); } double reducedNear, reducedFar; @@ -3042,6 +3042,25 @@ void MWShadowTechnique::releaseGLObjects(osg::State* state) const _debugHud->releaseGLObjects(state); } +class DoubleBufferCallback : public osg::Callback +{ +public: + DoubleBufferCallback(osg::NodeList &children) : mChildren(children) {} + + virtual bool run(osg::Object* node, osg::Object* visitor) override + { + // We can't use a static cast as NodeVisitor virtually inherits from Object + osg::ref_ptr nodeVisitor = visitor->asNodeVisitor(); + unsigned int traversalNumber = nodeVisitor->getTraversalNumber(); + mChildren[traversalNumber % 2]->accept(*nodeVisitor); + + return true; + } + +protected: + osg::NodeList mChildren; +}; + SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) : mDebugProgram(new osg::Program) { osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); @@ -3049,20 +3068,23 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); mDebugProgram->addShader(fragmentShader); - mFrustumGeometry = new osg::Geometry(); - mFrustumGeometry->setCullingActive(false); - osg::ref_ptr frustumProgram = new osg::Program; vertexShader = new osg::Shader(osg::Shader::VERTEX, debugFrustumVertexShaderSource); frustumProgram->addShader(vertexShader); fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFrustumFragmentShaderSource); frustumProgram->addShader(fragmentShader); - mFrustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); - //mFrustumGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + for (int i = 0; i < 2; ++i) + { + mFrustumGeometries.emplace_back(new osg::Geometry()); + mFrustumGeometries[i]->setCullingActive(false); + + mFrustumGeometries[i]->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); + } osg::ref_ptr frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP); - mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + for (auto & geom : mFrustumGeometries) + geom->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(0); frustumDrawElements->push_back(1); frustumDrawElements->push_back(2); @@ -3075,7 +3097,8 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) frustumDrawElements->push_back(4); frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINES); - mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + for (auto & geom : mFrustumGeometries) + geom->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(1); frustumDrawElements->push_back(5); frustumDrawElements->push_back(2); @@ -3118,12 +3141,13 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) node->releaseGLObjects(state); for (auto const& node : mFrustumTransforms) node->releaseGLObjects(state); - mFrustumGeometry->releaseGLObjects(state); + for (auto const& node : mFrustumGeometries) + node->releaseGLObjects(state); } -void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) +void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices, unsigned int traversalNumber) { - mFrustumGeometry->setVertexArray(vertices); + mFrustumGeometries[traversalNumber % 2]->setVertexArray(vertices); } void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() @@ -3146,7 +3170,8 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() stateSet->addUniform(textureUniform.get()); mFrustumTransforms.push_back(new osg::Group); - mFrustumTransforms[shadowMapNumber]->addChild(mFrustumGeometry); + osg::NodeList frustumGeometryNodeList(mFrustumGeometries.cbegin(), mFrustumGeometries.cend()); + mFrustumTransforms[shadowMapNumber]->setCullCallback(new DoubleBufferCallback(frustumGeometryNodeList)); mFrustumTransforms[shadowMapNumber]->setCullingActive(false); mDebugCameras[shadowMapNumber]->addChild(mFrustumTransforms[shadowMapNumber]); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 16d44c5e2f..6210667990 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -264,7 +264,7 @@ namespace SceneUtil { virtual void releaseGLObjects(osg::State* state = 0) const; - virtual void setFrustumVertices(osg::ref_ptr vertices); + virtual void setFrustumVertices(osg::ref_ptr vertices, unsigned int traversalNumber); protected: virtual void addAnotherShadowMap(); @@ -275,7 +275,7 @@ namespace SceneUtil { std::vector> mDebugGeometry; std::vector> mFrustumTransforms; std::vector> mFrustumUniforms; - osg::ref_ptr mFrustumGeometry; + std::vector> mFrustumGeometries; }; osg::ref_ptr _debugHud; From 60f112d11c00390c58e8b2c16b2a913981d99902 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Feb 2019 22:55:40 +0400 Subject: [PATCH 207/410] Add support for NiRollController (feature #4675) --- CHANGELOG.md | 1 + components/nif/controller.cpp | 12 ++++++++++ components/nif/controller.hpp | 9 +++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 1 + components/nifosg/controller.cpp | 40 ++++++++++++++++++++++++++++++++ components/nifosg/controller.hpp | 16 +++++++++++++ components/nifosg/nifloader.cpp | 11 +++++++++ 8 files changed, 91 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c3eba7e5b..ec43e9e521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Feature #3610: Option to invert X axis Feature #4209: Editor: Faction rank sub-table Feature #4673: Weapon sheathing + Feature #4675: Support for NiRollController Feature #4730: Native animated containers support Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 26c3f43f0c..6de720b527 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -173,6 +173,18 @@ namespace Nif data.post(nif); } + void NiRollController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiRollController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + void NiGeomMorpherController::read(NIFStream *nif) { Controller::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 7a05b0715e..113a7becdd 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -136,6 +136,15 @@ public: void post(NIFFile *nif); }; +class NiRollController : public Controller +{ +public: + NiFloatDataPtr data; + + void read(NIFStream *nif); + void post(NIFFile *nif); +}; + class NiGeomMorpherController : public Controller { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 66bbfdb65c..0519e0cc62 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -73,6 +73,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiGeomMorpherController", &construct , RC_NiGeomMorpherController )); newFactory.insert(makeEntry("NiKeyframeController", &construct , RC_NiKeyframeController )); newFactory.insert(makeEntry("NiAlphaController", &construct , RC_NiAlphaController )); + newFactory.insert(makeEntry("NiRollController", &construct , RC_NiRollController )); newFactory.insert(makeEntry("NiUVController", &construct , RC_NiUVController )); newFactory.insert(makeEntry("NiPathController", &construct , RC_NiPathController )); newFactory.insert(makeEntry("NiMaterialColorController", &construct , RC_NiMaterialColorController )); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index ee4d508abe..4a044ac471 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiGeomMorpherController, RC_NiKeyframeController, RC_NiAlphaController, + RC_NiRollController, RC_NiUVController, RC_NiPathController, RC_NiMaterialColorController, diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 83841e0e52..934b3b914e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -309,6 +309,46 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } +RollController::RollController(const Nif::NiFloatData *data) + : mData(data->mKeyList, 1.f) +{ +} + +RollController::RollController() +{ +} + +RollController::RollController(const RollController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mData(copy.mData) + , mStartingTime(0) +{ +} + +void RollController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + traverse(node, nv); + + if (hasInput()) + { + double newTime = nv->getFrameStamp()->getSimulationTime(); + double duration = newTime - mStartingTime; + mStartingTime = newTime; + + float value = mData.interpKey(getInputValue(nv)); + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + + // Rotate around "roll" axis. + // Note: in original game rotation speed is the framerate-dependent in a very tricky way. + // Do not replicate this behaviour until we will really need it. + // For now consider controller's current value as an angular speed in radians per 1/60 seconds. + matrix = osg::Matrix::rotate(value * duration * 60.f, 0, 0, 1) * matrix; + transform->setMatrix(matrix); + } +} + AlphaController::AlphaController(const Nif::NiFloatData *data) : mData(data->mKeyList, 1.f) { diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0e87af44f1..36217f31a3 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -246,6 +246,22 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; + class RollController : public osg::NodeCallback, public SceneUtil::Controller + { + private: + FloatInterpolator mData; + double mStartingTime; + + public: + RollController(const Nif::NiFloatData *data); + RollController(); + RollController(const RollController& copy, const osg::CopyOp& copyop); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + + META_Object(NifOsg, RollController) + }; + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a2dad247d9..f2403dd61c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -697,6 +697,10 @@ namespace NifOsg { handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); } + else if (ctrl->recType == Nif::RC_NiRollController) + { + handleRollController(static_cast(ctrl.getPtr()), transformNode, animflags); + } else Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } @@ -709,6 +713,13 @@ namespace NifOsg node->addUpdateCallback(callback); } + void handleRollController(const Nif::NiRollController* rollctrl, osg::Node* node, int animflags) + { + osg::ref_ptr callback(new RollController(rollctrl->data.getPtr())); + setupController(rollctrl, callback, animflags); + node->addUpdateCallback(callback); + } + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) From 097c64988599a9a14638cf7ce2b7eff6e8937129 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 3 Feb 2019 14:02:54 +0400 Subject: [PATCH 208/410] Use enumerable instead of magic number --- apps/openmw/mwmechanics/actors.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7694250530..83c40f9636 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -26,6 +26,8 @@ #include "../mwmechanics/aibreathe.hpp" +#include "../mwrender/vismask.hpp" + #include "spellcasting.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" @@ -1461,7 +1463,7 @@ namespace MWMechanics continue; } else if (!isPlayer) - iter->first.getRefData().getBaseNode()->setNodeMask(1<<3); + iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor); if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) ctrl->skipAnim(); From 629a6be477b10bd06cbff7bd2e291148c6c4e309 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Feb 2019 19:11:12 +0400 Subject: [PATCH 209/410] Handle initial actor's transparency (bug #4860) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/actors.cpp | 52 +++++++++++++++++++++++------- apps/openmw/mwmechanics/actors.hpp | 3 ++ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c3eba7e5b..cd7be8561d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Bug #4827: NiUVController is handled incorrectly Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded + Bug #4860: Actors outside of processing range visible for one frame after spawning Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 83c40f9636..e01064f87b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1169,8 +1169,46 @@ namespace MWMechanics if (!anim) return; mActors.insert(std::make_pair(ptr, new Actor(ptr, anim))); + + CharacterController* ctrl = mActors[ptr]->getCharacterController(); if (updateImmediately) - mActors[ptr]->getCharacterController()->update(0); + ctrl->update(0); + + // We should initially hide actors outside of processing range. + // Note: since we update player after other actors, distance will be incorrect during teleportation. + // Do not update visibility if player was teleported, so actors will be visible during teleportation frame. + if (MWBase::Environment::get().getWorld()->getPlayer().wasTeleported()) + return; + + updateVisibility(ptr, ctrl); + } + + void Actors::updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl) + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + if (ptr == player) + return; + + const float dist = (player.getRefData().getPosition().asVec3() - ptr.getRefData().getPosition().asVec3()).length(); + if (dist > mActorsProcessingRange) + { + ptr.getRefData().getBaseNode()->setNodeMask(0); + return; + } + else + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor); + + // Fade away actors on large distance (>90% of actor's processing distance) + float visibilityRatio = 1.0; + float fadeStartDistance = mActorsProcessingRange*0.9f; + float fadeEndDistance = mActorsProcessingRange; + float fadeRatio = (dist - fadeStartDistance)/(fadeEndDistance - fadeStartDistance); + if (fadeRatio > 0) + visibilityRatio -= std::max(0.f, fadeRatio); + + visibilityRatio = std::min(1.f, visibilityRatio); + + ctrl->setVisibility(visibilityRatio); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -1479,17 +1517,7 @@ namespace MWMechanics world->setActorCollisionMode(iter->first, true, !iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished()); ctrl->update(duration); - // Fade away actors on large distance (>90% of actor's processing distance) - float visibilityRatio = 1.0; - float fadeStartDistance = mActorsProcessingRange*0.9f; - float fadeEndDistance = mActorsProcessingRange; - float fadeRatio = (dist - fadeStartDistance)/(fadeEndDistance - fadeStartDistance); - if (fadeRatio > 0) - visibilityRatio -= std::max(0.f, fadeRatio); - - visibilityRatio = std::min(1.f, visibilityRatio); - - ctrl->setVisibility(visibilityRatio); + updateVisibility(iter->first, ctrl); } if (playerCharacter) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 61879c432f..35da3c2d5d 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -19,6 +19,7 @@ namespace MWWorld namespace MWMechanics { class Actor; + class CharacterController; class CreatureStats; class Actors @@ -169,6 +170,8 @@ namespace MWMechanics bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const; private: + void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl); + PtrActorMap mActors; float mTimerDisposeSummonsCorpses; float mActorsProcessingRange; From 7a7e3900998f7a7e0b87c87952791e903e4536f9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 16 Dec 2018 16:03:17 +0300 Subject: [PATCH 210/410] Make unsuccessful magic teleportation attempts detectable (bug #3765) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/spellcasting.cpp | 55 ++++++++++++------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c3eba7e5b..7f063fbc2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Bug #2987: Editor: some chance and AI data fields can overflow Bug #3623: Fix HiDPI on Windows Bug #3733: Normal maps are inverted on mirrored UVs + Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4383: Bow model obscures crosshair when arrow is drawn Bug #4411: Reloading a saved game while falling prevents damage in some cases diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 9f272e1f3e..1e7f3fc649 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -295,17 +295,6 @@ namespace MWMechanics return true; // must still apply to get visual effect and have target regard it as attack } break; - case ESM::MagicEffect::AlmsiviIntervention: - case ESM::MagicEffect::DivineIntervention: - case ESM::MagicEffect::Mark: - case ESM::MagicEffect::Recall: - if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) - { - if (castByPlayer) - MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); - return false; - } - break; case ESM::MagicEffect::WaterWalking: if (target.getClass().isPureWaterCreature(target) && MWBase::Environment::get().getWorld()->isSwimming(target)) return false; @@ -747,21 +736,19 @@ namespace MWMechanics else if (target.getClass().isActor() && target == getPlayer()) { MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster); + bool teleportingEnabled = MWBase::Environment::get().getWorld()->isTeleportingEnabled(); - if (effectId == ESM::MagicEffect::DivineIntervention) + if (effectId == ESM::MagicEffect::DivineIntervention || effectId == ESM::MagicEffect::AlmsiviIntervention) { - MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker"); - anim->removeEffect(ESM::MagicEffect::DivineIntervention); - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_end"); - if (fx) - anim->addEffect("meshes\\" + fx->mModel, -1); - return true; - } - else if (effectId == ESM::MagicEffect::AlmsiviIntervention) - { - MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker"); - anim->removeEffect(ESM::MagicEffect::AlmsiviIntervention); + if (!teleportingEnabled) + { + if (caster == getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); + return true; + } + std::string marker = (effectId == ESM::MagicEffect::DivineIntervention) ? "divinemarker" : "templemarker"; + MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, marker); + anim->removeEffect(effectId); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() .search("VFX_Summon_end"); if (fx) @@ -770,12 +757,26 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::Mark) { - MWBase::Environment::get().getWorld()->getPlayer().markPosition( - target.getCell(), target.getRefData().getPosition()); + if (teleportingEnabled) + { + MWBase::Environment::get().getWorld()->getPlayer().markPosition( + target.getCell(), target.getRefData().getPosition()); + } + else if (caster == getPlayer()) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); + } return true; } else if (effectId == ESM::MagicEffect::Recall) { + if (!teleportingEnabled) + { + if (caster == getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); + return true; + } + MWWorld::CellStore* markedCell = nullptr; ESM::Position markedPosition; @@ -785,7 +786,7 @@ namespace MWMechanics MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->getCell()->mName, markedPosition, false); action.execute(target); - anim->removeEffect(ESM::MagicEffect::Recall); + anim->removeEffect(effectId); } return true; } From 808b8ce8db18b40c889163e7baa6ecc7f270f91d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 8 Dec 2018 21:17:15 +0300 Subject: [PATCH 211/410] Refactor normal weapon resistance --- apps/openmw/mwclass/creature.cpp | 4 +--- apps/openmw/mwclass/npc.cpp | 4 ++++ apps/openmw/mwmechanics/combat.cpp | 38 ++++++++++++++++++++---------- apps/openmw/mwmechanics/combat.hpp | 6 ++++- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 962a5bab50..94f75dfc6a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -308,6 +308,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -382,9 +383,6 @@ namespace MWClass if (!object.isEmpty()) stats.setLastHitObject(object.getCellRef().getRefId()); - if (damage > 0.0f && !object.isEmpty()) - MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); - if (damage < 0.001f) damage = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index eb48c68549..14973336bc 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -604,6 +604,7 @@ namespace MWClass } bool healthdmg; + bool resisted = false; float damage = 0.0f; if(!weapon.isEmpty()) { @@ -619,6 +620,7 @@ namespace MWClass damage = attack[0] + ((attack[1]-attack[0])*attackStrength); } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + resisted = MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } @@ -629,6 +631,8 @@ namespace MWClass if(ptr == MWMechanics::getPlayer()) { skillUsageSucceeded(ptr, weapskill, 0); + if (resisted) + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); const MWMechanics::AiSequence& seq = victim.getClass().getCreatureStats(victim).getAiSequence(); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 41e2485ce0..dcab2a244d 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -148,28 +148,38 @@ namespace MWMechanics return false; } - void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) + bool isNormalWeapon(const MWWorld::Ptr &weapon) { - const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); - float resistance = std::min(100.f, effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() - - effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); + if (weapon.isEmpty()) + return false; - float multiplier = 1.f - resistance / 100.f; + const int &flags = weapon.get()->mBase->mData.mFlags; + bool isSilver = flags & ESM::Weapon::Silver; + bool isMagical = flags & ESM::Weapon::Magical; + bool isEnchanted = !weapon.getClass().getEnchantment(weapon).empty(); - if (!(weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver - || weapon.get()->mBase->mData.mFlags & ESM::Weapon::Magical)) + return !isSilver && !isMagical && (!isEnchanted || !Settings::Manager::getBool("enchanted weapons are magical", "Game")); + } + + bool resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) + { + if (damage == 0) + return false; + + if (isNormalWeapon(weapon)) { - if (weapon.getClass().getEnchantment(weapon).empty() - || !Settings::Manager::getBool("enchanted weapons are magical", "Game")) - damage *= multiplier; + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); + const float resistance = effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() / 100.f; + const float weakness = effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude() / 100.f; + + damage *= 1.f - std::min(1.f, resistance-weakness); } if ((weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver) && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); - if (damage == 0 && attacker == getPlayer()) - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); + return (damage == 0); } void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, @@ -208,9 +218,13 @@ namespace MWMechanics damage += attack[0] + ((attack[1] - attack[0]) * attackStrength); adjustWeaponDamage(damage, weapon, attacker); + bool resisted = resistNormalWeapon(victim, attacker, projectile, damage); if (attacker == getPlayer()) { + if (resisted) + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); + attacker.getClass().skillUsageSucceeded(attacker, weaponSkill, 0); const MWMechanics::AiSequence& sequence = victim.getClass().getCreatureStats(victim).getAiSequence(); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 8b93ca2040..ef2541bbc8 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -12,7 +12,11 @@ bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& /// @return can we block the attack? bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength); -void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); +/// @return does normal weapon resistance and weakness apply to the weapon? +bool isNormalWeapon (const MWWorld::Ptr& weapon); + +/// @return was the damage fully resisted? +bool resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor From 64d5cd17d62e55427147c98e4047ec0447450d20 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 8 Dec 2018 21:47:39 +0300 Subject: [PATCH 212/410] Move werewolf silver damage mult applying into a new function --- apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/npc.cpp | 1 + apps/openmw/mwmechanics/combat.cpp | 30 +++++++++++++--------- apps/openmw/mwmechanics/combat.hpp | 2 ++ apps/openmw/mwmechanics/weaponpriority.cpp | 3 +++ 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 94f75dfc6a..0a652dfbf6 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -308,6 +308,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + MWMechanics::applyWerewolfDamageMult(victim, weapon, damage); MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 14973336bc..9e2fe90976 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -621,6 +621,7 @@ namespace MWClass } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); resisted = MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); + MWMechanics::applyWerewolfDamageMult(victim, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index dcab2a244d..1ab8078cbf 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -163,25 +163,30 @@ namespace MWMechanics bool resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) { - if (damage == 0) + if (damage == 0 || weapon.isEmpty() || !isNormalWeapon(weapon)) return false; - if (isNormalWeapon(weapon)) - { - const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); - const float resistance = effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() / 100.f; - const float weakness = effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude() / 100.f; + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); + const float resistance = effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() / 100.f; + const float weakness = effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude() / 100.f; - damage *= 1.f - std::min(1.f, resistance-weakness); - } - - if ((weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver) - && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) - damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + damage *= 1.f - std::min(1.f, resistance-weakness); return (damage == 0); } + void applyWerewolfDamageMult(const MWWorld::Ptr &actor, const MWWorld::Ptr &weapon, float &damage) + { + if (damage == 0 || weapon.isEmpty()) + return; + + const int &flags = weapon.get()->mBase->mData.mFlags; + bool isSilver = flags & ESM::Weapon::Silver; + + if (isSilver && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) + damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + } + void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, const osg::Vec3f& hitPosition, float attackStrength) { @@ -219,6 +224,7 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon, attacker); bool resisted = resistNormalWeapon(victim, attacker, projectile, damage); + applyWerewolfDamageMult(victim, projectile, damage); if (attacker == getPlayer()) { diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index ef2541bbc8..f7a8a555c7 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -18,6 +18,8 @@ bool isNormalWeapon (const MWWorld::Ptr& weapon); /// @return was the damage fully resisted? bool resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); +void applyWerewolfDamageMult (const MWWorld::Ptr& actor, const MWWorld::Ptr& weapon, float &damage); + /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 55fb2eaf09..1948db7fa6 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -78,7 +78,10 @@ namespace MWMechanics adjustWeaponDamage(rating, item, actor); if (weapon->mData.mType != ESM::Weapon::MarksmanBow && weapon->mData.mType != ESM::Weapon::MarksmanCrossbow) + { resistNormalWeapon(enemy, actor, item, rating); + applyWerewolfDamageMult(enemy, item, rating); + } else if (weapon->mData.mType == ESM::Weapon::MarksmanBow) { if (arrowRating <= 0.f) From b738cc038377d73094c4ead7e1f60d480c8fcf1c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 8 Dec 2018 21:55:08 +0300 Subject: [PATCH 213/410] Make normal weapon resistance behavior closer to vanilla (bug #4384) Check both the ranged weapon and the projectile before modifying the damage Don't attempt to apply NPC-specific werewolf damage mult to damage to creatures --- CHANGELOG.md | 1 + apps/openmw/mwclass/creature.cpp | 1 - apps/openmw/mwclass/npc.cpp | 5 +---- apps/openmw/mwmechanics/combat.cpp | 26 ++++++++++++++------------ apps/openmw/mwmechanics/combat.hpp | 3 +-- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c3eba7e5b..f3e9f4267b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Bug #3733: Normal maps are inverted on mirrored UVs Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4383: Bow model obscures crosshair when arrow is drawn + Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4540: Rain delay when exiting water Bug #4701: PrisonMarker record is not hardcoded like other markers diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 0a652dfbf6..94f75dfc6a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -308,7 +308,6 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); - MWMechanics::applyWerewolfDamageMult(victim, weapon, damage); MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 9e2fe90976..471cb873f4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -604,7 +604,6 @@ namespace MWClass } bool healthdmg; - bool resisted = false; float damage = 0.0f; if(!weapon.isEmpty()) { @@ -620,7 +619,7 @@ namespace MWClass damage = attack[0] + ((attack[1]-attack[0])*attackStrength); } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); - resisted = MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); + MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::applyWerewolfDamageMult(victim, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; @@ -632,8 +631,6 @@ namespace MWClass if(ptr == MWMechanics::getPlayer()) { skillUsageSucceeded(ptr, weapskill, 0); - if (resisted) - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); const MWMechanics::AiSequence& seq = victim.getClass().getCreatureStats(victim).getAiSequence(); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 1ab8078cbf..a3e5e532be 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -153,7 +153,7 @@ namespace MWMechanics if (weapon.isEmpty()) return false; - const int &flags = weapon.get()->mBase->mData.mFlags; + const int flags = weapon.get()->mBase->mData.mFlags; bool isSilver = flags & ESM::Weapon::Silver; bool isMagical = flags & ESM::Weapon::Magical; bool isEnchanted = !weapon.getClass().getEnchantment(weapon).empty(); @@ -161,10 +161,10 @@ namespace MWMechanics return !isSilver && !isMagical && (!isEnchanted || !Settings::Manager::getBool("enchanted weapons are magical", "Game")); } - bool resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) + void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) { if (damage == 0 || weapon.isEmpty() || !isNormalWeapon(weapon)) - return false; + return; const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); const float resistance = effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() / 100.f; @@ -172,19 +172,23 @@ namespace MWMechanics damage *= 1.f - std::min(1.f, resistance-weakness); - return (damage == 0); + if (damage == 0 && attacker == getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } void applyWerewolfDamageMult(const MWWorld::Ptr &actor, const MWWorld::Ptr &weapon, float &damage) { - if (damage == 0 || weapon.isEmpty()) + if (damage == 0 || weapon.isEmpty() || !actor.getClass().isNpc()) return; - const int &flags = weapon.get()->mBase->mData.mFlags; + const int flags = weapon.get()->mBase->mData.mFlags; bool isSilver = flags & ESM::Weapon::Silver; - if (isSilver && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) - damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + if (isSilver && actor.getClass().getNpcStats(actor).isWerewolf()) + { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + damage *= store.get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + } } void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, @@ -223,14 +227,12 @@ namespace MWMechanics damage += attack[0] + ((attack[1] - attack[0]) * attackStrength); adjustWeaponDamage(damage, weapon, attacker); - bool resisted = resistNormalWeapon(victim, attacker, projectile, damage); + if (weapon == projectile || isNormalWeapon(weapon)) // NB: both the weapon and the projectile need to be normal + resistNormalWeapon(victim, attacker, projectile, damage); applyWerewolfDamageMult(victim, projectile, damage); if (attacker == getPlayer()) { - if (resisted) - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); - attacker.getClass().skillUsageSucceeded(attacker, weaponSkill, 0); const MWMechanics::AiSequence& sequence = victim.getClass().getCreatureStats(victim).getAiSequence(); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index f7a8a555c7..77dd2a7224 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -15,8 +15,7 @@ bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker /// @return does normal weapon resistance and weakness apply to the weapon? bool isNormalWeapon (const MWWorld::Ptr& weapon); -/// @return was the damage fully resisted? -bool resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); +void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); void applyWerewolfDamageMult (const MWWorld::Ptr& actor, const MWWorld::Ptr& weapon, float &damage); From 73734fc04da2901bc78d7c421498ac34ac9089d8 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 22 Feb 2019 11:34:53 +0300 Subject: [PATCH 214/410] Fix update navmesh for not changed objects When update method is called for not changed object befor this change all object tiles were considered as not object tiles and were removed. Also this marked those tiles as changed. This lead to alternation between remove and add each tile update method was called. Problem was detected by using Animated Containers mod. --- .../tilecachedrecastmeshmanager.cpp | 18 ++++++++++++++++++ .../tilecachedrecastmeshmanager.cpp | 4 +--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index 0443fc9cef..b84f7a22ec 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -120,4 +120,22 @@ namespace EXPECT_EQ(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(0, 0)), nullptr); } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_not_changed_object_after_update_should_return_recast_mesh_for_same_tiles) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); + + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); + EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); + } } diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 7070603c72..b878c2d3e4 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -47,11 +47,9 @@ namespace DetourNavigator { if (currentTiles.count(tilePosition)) { + newTiles.insert(tilePosition); if (updateTile(id, transform, areaType, tilePosition, tiles.get())) - { - newTiles.insert(tilePosition); changedTiles.push_back(tilePosition); - } } else if (addTile(id, shape, transform, areaType, tilePosition, border, tiles.get())) { From 2342a31addabff88cd1238033bc98c6f884abde8 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 22 Feb 2019 11:35:09 +0300 Subject: [PATCH 215/410] Add more tests for TileCachedRecastMeshManager --- .../tilecachedrecastmeshmanager.cpp | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index b84f7a22ec..5275d9119e 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace { @@ -56,6 +57,45 @@ namespace EXPECT_EQ(calls, 0); } + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_new_object_should_return_true) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + EXPECT_TRUE(manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_existing_object_should_return_false) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_FALSE(manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_changed_object_should_return_changed_tiles) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); + manager.addObject(ObjectId(1ul), boxShape, transform, AreaType::AreaType_ground); + EXPECT_THAT( + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground), + ElementsAre(TilePosition(-1, -1), TilePosition(-1, 0), TilePosition(0, -1), TilePosition(0, 0), + TilePosition(1, -1), TilePosition(1, 0)) + ); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_not_changed_object_should_return_empty) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ( + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground), + std::vector() + ); + } + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_recast_mesh_for_each_used_tile) { TileCachedRecastMeshManager manager(mSettings); @@ -138,4 +178,62 @@ namespace EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_add_object_new_should_return_incremented_value) + { + TileCachedRecastMeshManager manager(mSettings); + const auto initialRevision = manager.getRevision(); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ(manager.getRevision(), initialRevision + 1); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_add_object_existing_should_return_same_value) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const auto beforeAddRevision = manager.getRevision(); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ(manager.getRevision(), beforeAddRevision); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_update_moved_object_should_return_incremented_value) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); + manager.addObject(ObjectId(1ul), boxShape, transform, AreaType::AreaType_ground); + const auto beforeUpdateRevision = manager.getRevision(); + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_update_not_changed_object_should_return_same_value) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const auto beforeUpdateRevision = manager.getRevision(); + manager.updateObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_EQ(manager.getRevision(), beforeUpdateRevision); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_remove_existing_object_should_return_incremented_value) + { + TileCachedRecastMeshManager manager(mSettings); + const btBoxShape boxShape(btVector3(20, 20, 100)); + manager.addObject(ObjectId(1ul), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const auto beforeRemoveRevision = manager.getRevision(); + manager.removeObject(ObjectId(1ul)); + EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1); + } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_remove_absent_object_should_return_same_value) + { + TileCachedRecastMeshManager manager(mSettings); + const auto beforeRemoveRevision = manager.getRevision(); + manager.removeObject(ObjectId(1ul)); + EXPECT_EQ(manager.getRevision(), beforeRemoveRevision); + } } From 4138e29ca44b526bb6d99e39ce865395c2dfeb9f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 22 Feb 2019 17:18:23 +0300 Subject: [PATCH 216/410] Add option to restore the previous ammo behavior --- apps/launcher/advancedpage.cpp | 2 ++ apps/openmw/mwmechanics/combat.cpp | 2 +- docs/source/reference/modding/settings/game.rst | 13 +++++++++++++ files/settings-default.cfg | 3 +++ files/ui/advancedpage.ui | 10 ++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 41f546af46..68fe235ce3 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -80,6 +80,7 @@ bool Launcher::AdvancedPage::loadSettings() int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game"); if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2) unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex); + loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); // Input Settings loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); @@ -139,6 +140,7 @@ void Launcher::AdvancedPage::saveSettings() int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex(); if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game")) mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex); + saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); // Input Settings saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index a3e5e532be..3f87363a32 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -227,7 +227,7 @@ namespace MWMechanics damage += attack[0] + ((attack[1] - attack[0]) * attackStrength); adjustWeaponDamage(damage, weapon, attacker); - if (weapon == projectile || isNormalWeapon(weapon)) // NB: both the weapon and the projectile need to be normal + if (weapon == projectile || Settings::Manager::getBool("only appropriate ammunition bypasses resistance", "Game") || isNormalWeapon(weapon)) resistNormalWeapon(victim, attacker, projectile, damage); applyWerewolfDamageMult(victim, projectile, damage); diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 6af0118de7..2497b9e2fe 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -211,3 +211,16 @@ disposition change of merchants caused by trading will be permanent and won't be This imitates the option that Morrowind Code Patch offers. This setting can be toggled in Advanced tab of the launcher. + +only appropriate ammunition bypasses resistance +----------------------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +If this setting is true, you will have to use the appropriate ammunition to bypass normal weapon resistance (or weakness). +An enchanted bow with chitin arrows will no longer be enough for the purpose, while a steel longbow with glass arrows will still work. +This was previously the default engine behavior that diverged from Morrowind design. + +This setting can be toggled in Advanced tab of the launcher. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 89f4f82ea6..0d932ca49d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -242,6 +242,9 @@ strength influences hand to hand = 0 # Render holstered weapons (with quivers and scabbards), requires modded assets weapon sheathing = false +# Allow non-standard ammunition solely to bypass normal weapon resistance or weakness +only appropriate ammunition bypasses resistance = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 0793345c8d..23c860f897 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -96,6 +96,16 @@ + + + + <html><head/><body><p>Allow non-standard ammunition solely to bypass normal weapon resistance or weakness.</p></body></html> + + + Only appropriate ammunition bypasses normal weapon resistance + + + From f8118272f4c28759c9a34e476d66472284e77ccb Mon Sep 17 00:00:00 2001 From: Alexander Olofsson Date: Fri, 22 Feb 2019 18:37:49 +0100 Subject: [PATCH 217/410] Package FreeType plugin for OSG in Windows Fixes #4872 --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 4a114490c6..77220cbb72 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -609,7 +609,7 @@ printf "OSG 3.4.1-scrawl... " fi add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer,Shadow}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,freetype,jpeg,osg,png,tga}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll echo Done. } From 58788de7c46fdacbea0a81adc16882f7b286672b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 22 Feb 2019 21:40:21 +0300 Subject: [PATCH 218/410] Get rid of Boost.Array --- apps/openmw/mwgui/charactercreation.cpp | 2 +- apps/openmw/mwgui/review.cpp | 4 +--- apps/openmw/mwgui/statswindow.cpp | 4 +--- components/esm/loadskil.cpp | 2 +- components/esm/loadskil.hpp | 5 ++--- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index e3effa995b..0d3db87b7e 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -554,7 +554,7 @@ namespace MWGui { if (mGenerateClassStep == 10) { - static boost::array classes = { { + static std::array classes = { { {"Acrobat", {6, 2, 2}}, {"Agent", {6, 1, 3}}, {"Archer", {3, 5, 2}}, diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 004a172b34..fb8b48a612 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -228,11 +228,9 @@ namespace MWGui std::set skillSet; std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + for (const int skill : ESM::Skill::sSkillIds) { - int skill = *it; if (skillSet.find(skill) == skillSet.end()) mMiscSkills.push_back(skill); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index df292cfaa6..862660fc7a 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -278,11 +278,9 @@ namespace MWGui std::set skillSet; std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + for (const int skill : ESM::Skill::sSkillIds) { - int skill = *it; if (skillSet.find(skill) == skillSet.end()) mMiscSkills.push_back(skill); } diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index 36204c9401..e77c2def03 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -97,7 +97,7 @@ namespace ESM "stealth_speechcraft.dds", "stealth_handtohand.dds", }; - const boost::array Skill::sSkillIds = {{ + const std::array Skill::sSkillIds = {{ Block, Armorer, MediumArmor, diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 5430b422d1..099264fab7 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -1,10 +1,9 @@ #ifndef OPENMW_ESM_SKIL_H #define OPENMW_ESM_SKIL_H +#include #include -#include - #include "defs.hpp" namespace ESM { @@ -76,7 +75,7 @@ struct Skill static const std::string sSkillNames[Length]; static const std::string sSkillNameIds[Length]; static const std::string sIconNames[Length]; - static const boost::array sSkillIds; + static const std::array sSkillIds; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; From 3032b177a16e513446b77ff14a37c320b4d8cef5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Feb 2019 23:16:47 +0400 Subject: [PATCH 219/410] Remove redundant includes --- apps/openmw/engine.cpp | 1 - apps/openmw/mwclass/activator.cpp | 1 - apps/openmw/mwclass/actor.cpp | 1 - apps/openmw/mwclass/apparatus.cpp | 2 -- apps/openmw/mwclass/armor.cpp | 1 - apps/openmw/mwclass/clothing.cpp | 1 - apps/openmw/mwclass/container.cpp | 1 - apps/openmw/mwclass/door.cpp | 2 -- apps/openmw/mwclass/ingredient.cpp | 1 - apps/openmw/mwclass/light.cpp | 4 ---- apps/openmw/mwclass/lockpick.cpp | 2 -- apps/openmw/mwclass/misc.cpp | 1 - apps/openmw/mwclass/potion.cpp | 2 -- apps/openmw/mwclass/probe.cpp | 2 -- apps/openmw/mwclass/repair.cpp | 3 --- apps/openmw/mwclass/weapon.cpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 --- apps/openmw/mwdialogue/scripttest.cpp | 1 - apps/openmw/mwdialogue/selectwrapper.cpp | 3 --- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/containeritemmodel.cpp | 2 -- apps/openmw/mwgui/formatting.cpp | 2 -- apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/itemmodel.cpp | 4 ---- apps/openmw/mwgui/journalbooks.cpp | 2 -- apps/openmw/mwgui/journalwindow.cpp | 1 - apps/openmw/mwgui/levelupdialog.cpp | 1 - apps/openmw/mwgui/timeadvancer.cpp | 3 --- apps/openmw/mwgui/windowbase.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ----- apps/openmw/mwmechanics/aiactivate.cpp | 1 - apps/openmw/mwmechanics/aicast.cpp | 1 - apps/openmw/mwmechanics/aicombat.cpp | 3 --- apps/openmw/mwmechanics/aiescort.cpp | 1 - apps/openmw/mwmechanics/aipackage.cpp | 2 -- apps/openmw/mwmechanics/aipursue.cpp | 1 - apps/openmw/mwmechanics/aisequence.cpp | 1 - apps/openmw/mwmechanics/aitravel.cpp | 2 -- apps/openmw/mwmechanics/alchemy.cpp | 1 - apps/openmw/mwmechanics/magiceffects.cpp | 2 -- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 1 - apps/openmw/mwmechanics/npcstats.cpp | 1 - apps/openmw/mwmechanics/obstacle.cpp | 2 -- apps/openmw/mwmechanics/repair.cpp | 1 - apps/openmw/mwmechanics/security.cpp | 1 - apps/openmw/mwmechanics/spellcasting.cpp | 1 - apps/openmw/mwmechanics/spellpriority.cpp | 2 -- apps/openmw/mwmechanics/spells.cpp | 2 -- apps/openmw/mwmechanics/weaponpriority.cpp | 1 - apps/openmw/mwphysics/object.cpp | 2 -- apps/openmw/mwphysics/physicssystem.cpp | 17 ----------------- apps/openmw/mwphysics/trace.cpp | 2 -- apps/openmw/mwrender/npcanimation.cpp | 1 - apps/openmw/mwrender/objects.hpp | 1 - apps/openmw/mwrender/pathgrid.cpp | 2 -- apps/openmw/mwrender/pathgrid.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 1 - apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/sky.hpp | 1 - apps/openmw/mwscript/animationextensions.cpp | 1 - apps/openmw/mwscript/cellextensions.cpp | 1 - apps/openmw/mwscript/consoleextensions.cpp | 5 ----- apps/openmw/mwscript/containerextensions.cpp | 4 +--- apps/openmw/mwscript/globalscripts.cpp | 2 -- apps/openmw/mwscript/guiextensions.cpp | 1 - apps/openmw/mwscript/interpretercontext.cpp | 3 +-- apps/openmw/mwscript/interpretercontext.hpp | 1 - apps/openmw/mwscript/locals.cpp | 2 -- apps/openmw/mwscript/miscextensions.cpp | 1 - apps/openmw/mwscript/skyextensions.cpp | 1 - apps/openmw/mwscript/soundextensions.cpp | 3 +-- apps/openmw/mwscript/statsextensions.cpp | 2 -- .../mwscript/transformationextensions.cpp | 2 -- apps/openmw/mwsound/movieaudiofactory.cpp | 2 -- apps/openmw/mwsound/openal_output.cpp | 1 - apps/openmw/mwstate/character.cpp | 1 + apps/openmw/mwstate/charactermanager.cpp | 3 ++- apps/openmw/mwstate/statemanagerimp.cpp | 1 - apps/openmw/mwworld/actionrepair.cpp | 1 - apps/openmw/mwworld/cellpreloader.cpp | 2 -- apps/openmw/mwworld/cells.cpp | 1 - apps/openmw/mwworld/class.cpp | 1 - apps/openmw/mwworld/contentloader.hpp | 1 - apps/openmw/mwworld/inventorystore.cpp | 3 --- apps/openmw/mwworld/player.cpp | 1 - apps/openmw/mwworld/projectilemanager.cpp | 1 - apps/openmw/mwworld/scene.cpp | 1 - apps/openmw/mwworld/weather.cpp | 1 - apps/openmw/mwworld/worldimp.cpp | 2 -- components/compiler/locals.cpp | 1 - components/compiler/parser.cpp | 4 ---- components/compiler/scanner.cpp | 1 - components/contentselector/view/combobox.cpp | 3 --- .../contentselector/view/contentselector.cpp | 3 --- .../detournavigator/asyncnavmeshupdater.cpp | 2 -- components/detournavigator/makenavmesh.cpp | 1 - components/detournavigator/navmeshmanager.cpp | 5 ----- .../detournavigator/navmeshtilescache.cpp | 2 -- .../detournavigator/recastmeshmanager.cpp | 1 - components/detournavigator/recastmeshobject.cpp | 1 - components/detournavigator/settings.cpp | 2 -- components/esm/aisequence.cpp | 2 -- components/esm/esmreader.hpp | 3 +-- components/esm/loadskil.cpp | 2 -- components/esmterrain/storage.cpp | 1 - components/fontloader/fontloader.cpp | 1 - components/interpreter/miscopcodes.hpp | 1 - components/misc/stringops.hpp | 1 - components/myguiplatform/myguirendermanager.cpp | 2 -- components/myguiplatform/myguitexture.cpp | 1 - components/nifbullet/bulletnifloader.cpp | 5 ----- components/nifosg/nifloader.cpp | 1 - components/nifosg/particle.cpp | 1 - components/process/processinvoker.cpp | 2 -- components/resource/bulletshape.cpp | 1 - components/sceneutil/agentpath.cpp | 1 - components/sceneutil/attach.cpp | 1 - components/sceneutil/clone.cpp | 2 -- components/sceneutil/optimizer.cpp | 2 -- components/sceneutil/pathgridutil.cpp | 1 - .../sceneutil/positionattitudetransform.cpp | 2 -- components/sceneutil/riggeometry.cpp | 3 --- components/sdlutil/sdlcursormanager.cpp | 1 - components/shader/shadermanager.cpp | 1 - components/shader/shadervisitor.cpp | 2 -- components/terrain/material.cpp | 3 --- components/to_utf8/to_utf8.cpp | 1 - components/vfs/manager.cpp | 1 - components/widgets/list.cpp | 1 - 129 files changed, 8 insertions(+), 230 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index cb106c711c..16c945e2f9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -37,7 +37,6 @@ #include "mwgui/windowmanagerimp.hpp" #include "mwscript/scriptmanagerimp.hpp" -#include "mwscript/extensions.hpp" #include "mwscript/interpretercontext.hpp" #include "mwsound/soundmanagerimp.hpp" diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 42ea99b007..ab38515c27 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -5,7 +5,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index 73a4d37d76..aa356f62d1 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -4,7 +4,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index e151e39c5a..5e7c1b9333 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -3,11 +3,9 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" #include "../mwphysics/physicssystem.hpp" diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 0a4958eb99..7ab1d49fed 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -9,7 +9,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 21c0d89c22..7e3e77d586 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -7,7 +7,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index e1784d5937..47dfa27b36 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index a261180298..78aadb05ba 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -7,10 +7,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/actionteleport.hpp" #include "../mwworld/actiondoor.hpp" diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 70339564c6..84117f59d4 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -7,7 +7,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwphysics/physicssystem.hpp" diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index ea0abd6f64..38b7137f35 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -5,20 +5,16 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwphysics/physicssystem.hpp" -#include "../mwworld/customdata.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 5673465a0b..013808bb28 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -4,11 +4,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 40ec2b34b7..51b641d4d5 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -7,7 +7,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwphysics/physicssystem.hpp" diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 39b1cc6c2e..4e95c62943 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -7,11 +7,9 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionapply.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 734b6b1fd0..b53e2418ae 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -4,11 +4,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 7cd7ef10d4..922858623c 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -3,14 +3,11 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwphysics/physicssystem.hpp" -#include "../mwworld/nullaction.hpp" #include "../mwworld/actionrepair.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 508cf47ae2..dd6d631663 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -10,7 +10,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 17f69d69b7..1ada7b9494 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -1,9 +1,6 @@ #include "dialoguemanagerimp.hpp" -#include -#include #include -#include #include #include diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index 4f0b7422c7..791a4da7eb 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "filter.hpp" diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 793963e48f..28dbd214ba 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -1,9 +1,6 @@ #include "selectwrapper.hpp" -#include - #include -#include #include #include diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 51c0603ca3..f89cd4ff32 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" @@ -18,7 +17,6 @@ #include "inventorywindow.hpp" #include "itemview.hpp" -#include "itemwidget.hpp" #include "inventoryitemmodel.hpp" #include "containeritemmodel.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 24e7f8d004..d34f15a0a4 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -13,8 +13,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwmechanics/actorutil.hpp" - namespace { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 78359608ec..d4d6a0af56 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -4,14 +4,12 @@ #include #include #include -#include // correctBookartPath #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include -#include #include #include diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 54476c48e3..de66295157 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -25,7 +25,6 @@ #include "itemmodel.hpp" #include "draganddrop.hpp" -#include "itemmodel.hpp" #include "itemwidget.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index c7c10e8e4b..08c5bff359 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -1,13 +1,9 @@ #include "itemmodel.hpp" -#include - #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/store.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 4302740f67..065a503e69 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -1,7 +1,5 @@ #include "journalbooks.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index f45d73ca92..095d74e8a6 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -1,6 +1,5 @@ #include "journalwindow.hpp" -#include #include #include #include diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 286405f797..415c8e31c9 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -12,7 +12,6 @@ #include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp index 43504ce870..a07da16825 100644 --- a/apps/openmw/mwgui/timeadvancer.cpp +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -1,8 +1,5 @@ #include "timeadvancer.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { TimeAdvancer::TimeAdvancer(float delay) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 86c780325a..727493892e 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7e4ba09982..b3b8eec75f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,13 +1,11 @@ #include "windowmanagerimp.hpp" #include -#include #include #include #include -#include #include #include #include @@ -38,7 +36,6 @@ #include #include -#include #include #include #include @@ -47,8 +44,6 @@ #include -#include - #include #include "../mwbase/inputmanager.hpp" diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index c4a8417dbb..e222c82bc0 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -8,7 +8,6 @@ #include "../mwworld/class.hpp" #include "creaturestats.hpp" -#include "steering.hpp" #include "movement.hpp" namespace MWMechanics diff --git a/apps/openmw/mwmechanics/aicast.cpp b/apps/openmw/mwmechanics/aicast.cpp index e448313bf8..b7c9bac3ba 100644 --- a/apps/openmw/mwmechanics/aicast.cpp +++ b/apps/openmw/mwmechanics/aicast.cpp @@ -8,7 +8,6 @@ #include "aicombataction.hpp" #include "creaturestats.hpp" -#include "spellcasting.hpp" #include "steering.hpp" MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 245e95e488..32b3f9f2b5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -15,15 +15,12 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwrender/animation.hpp" - #include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" #include "character.hpp" #include "aicombataction.hpp" -#include "combat.hpp" #include "coordinateconverter.hpp" #include "actorutil.hpp" diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 3d018d780c..03951d2798 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -11,7 +11,6 @@ #include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" -#include "steering.hpp" #include "movement.hpp" /* diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 4646875fda..91449498da 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -1,7 +1,5 @@ #include "aipackage.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 4dd644e6b6..925f3adaa1 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -1,7 +1,6 @@ #include "aipursue.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index cf572abc0f..e337c63492 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -5,7 +5,6 @@ #include #include -#include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "aipackage.hpp" diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index d870298095..a2876da4fc 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,7 +1,6 @@ #include "aitravel.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -10,7 +9,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" -#include "steering.hpp" #include "movement.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index facac4291f..87ee47b49a 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,7 +1,6 @@ #include "alchemy.hpp" #include -#include #include #include diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 021691d6a9..1a1a44f638 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,7 +1,5 @@ #include "magiceffects.hpp" -#include - #include #include diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b909d7df1e..eead405379 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -21,7 +21,6 @@ #include "aicombat.hpp" #include "aipursue.hpp" -#include "aitravel.hpp" #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index bdd4e69688..70c2004f02 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -9,7 +9,6 @@ #include #include -#include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 9562c74df0..3d8fe7919c 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,9 +1,7 @@ #include "obstacle.hpp" -#include #include -#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 8c5e698960..8ab3c605d2 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -6,7 +6,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 18d4ec2e5a..f1aa6bf8e2 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -8,7 +8,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1e7f3fc649..2a359cb52c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -23,7 +23,6 @@ #include "../mwworld/inventorystore.hpp" #include "../mwrender/animation.hpp" -#include "../mwrender/vismask.hpp" #include "npcstats.hpp" #include "actorutil.hpp" diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index c55d5ab10c..79606fda6b 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -12,12 +12,10 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/actionequip.hpp" #include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "spellcasting.hpp" -#include "combat.hpp" namespace { diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 0a11ed6414..3214b3fc9a 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,7 +1,5 @@ #include "spells.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 55fb2eaf09..04a39fcbd3 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -1,7 +1,6 @@ #include "weaponpriority.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index 2f28668215..549b450a97 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include #include diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 18fc064819..f6f7aac39c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,15 +1,7 @@ #include "physicssystem.hpp" -#include -#include -#include -#include - -#include - #include -#include #include #include #include @@ -21,12 +13,6 @@ #include -#include -#include -#include -#include -#include - #include #include #include @@ -50,9 +36,6 @@ #include "../mwrender/bulletdebugdraw.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" - #include "../mwworld/class.hpp" #include "collisiontype.hpp" diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 204ec14678..07465ada02 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -1,7 +1,5 @@ #include "trace.h" -#include - #include #include diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4b36686f1c..a775f9391d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 6598537632..98ebb95d98 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -2,7 +2,6 @@ #define GAME_RENDER_OBJECTS_H #include -#include #include #include diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index ee4120d6f8..8a7bc8b5ee 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -6,14 +6,12 @@ #include #include -#include #include #include #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" diff --git a/apps/openmw/mwrender/pathgrid.hpp b/apps/openmw/mwrender/pathgrid.hpp index 22bfa8e73f..77f1a7f337 100644 --- a/apps/openmw/mwrender/pathgrid.hpp +++ b/apps/openmw/mwrender/pathgrid.hpp @@ -4,7 +4,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 51a92a280c..c1f2b390f5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,6 +1,5 @@ #include "renderingmanager.hpp" -#include #include #include diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3daf810716..8cede92d07 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -13,6 +13,7 @@ #include "rendermode.hpp" #include +#include namespace osg { diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e70f165213..f6472fbdec 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index e737d8ea19..6e959c0c0f 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index f01fed2ce1..80d4f7eb86 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -4,7 +4,6 @@ #include "../mwworld/esmstore.hpp" -#include #include #include diff --git a/apps/openmw/mwscript/consoleextensions.cpp b/apps/openmw/mwscript/consoleextensions.cpp index d2e07d3e14..749ec80969 100644 --- a/apps/openmw/mwscript/consoleextensions.cpp +++ b/apps/openmw/mwscript/consoleextensions.cpp @@ -1,11 +1,6 @@ #include "consoleextensions.hpp" -#include -#include - #include -#include -#include namespace MWScript { diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 8a25f0c015..7d555e632a 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -8,7 +8,6 @@ #include -#include #include #include @@ -22,14 +21,13 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/actionequip.hpp" +#include "../mwworld/action.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/actorutil.hpp" -#include "interpretercontext.hpp" #include "ref.hpp" namespace MWScript diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index a52a4938ad..63b0236c88 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -1,7 +1,5 @@ #include "globalscripts.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index cea176ff6c..64f45b4c09 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -1,6 +1,5 @@ #include "guiextensions.hpp" -#include #include #include diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 07b7a3bffd..30c56406ef 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include @@ -18,6 +16,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwworld/action.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 5f1f4f7ab8..0e001d6923 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -4,7 +4,6 @@ #include #include "../mwworld/ptr.hpp" -#include "../mwworld/action.hpp" namespace MWSound { diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 4c55731688..6992005907 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -13,8 +13,6 @@ #include "../mwworld/esmstore.hpp" -#include - namespace MWScript { void Locals::ensure (const std::string& scriptName) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index d3b49239ce..c480cfec89 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -2,7 +2,6 @@ #include -#include #include #include diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index 479c9d70ce..efcef68275 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -2,7 +2,6 @@ #include -#include #include #include diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 4d199c299f..fe6f7bac36 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -1,6 +1,5 @@ -#include "extensions.hpp" +#include "soundextensions.hpp" -#include #include #include diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 10d1252b91..092faa9267 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -14,7 +14,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -27,7 +26,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "interpretercontext.hpp" #include "ref.hpp" namespace diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9f0784d6c0..0d0d6f29e3 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -4,7 +4,6 @@ #include -#include #include #include @@ -18,7 +17,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwmechanics/actorutil.hpp" diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 146023bc16..b0bfd52e17 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -1,7 +1,5 @@ #include "movieaudiofactory.hpp" -#include - #include #include diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index ccb3f22b52..ba75534b65 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index a8fffaec60..3c5c4f8b2a 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -1,5 +1,6 @@ #include "character.hpp" +#include #include #include diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index d440ba8696..856264d03b 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -1,5 +1,6 @@ #include "charactermanager.hpp" +#include #include #include @@ -58,7 +59,7 @@ MWState::Character* MWState::CharacterManager::createCharacter(const std::string // The character name is user-supplied, so we need to escape the path for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) { - if (isalnum(*it)) // Ignores multibyte characters and non alphanumeric characters + if (std::isalnum(*it)) // Ignores multibyte characters and non alphanumeric characters stream << *it; else stream << "_"; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 946c5eef7f..01da76e900 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -32,7 +32,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 4fb7f7adab..4fe48b4b4c 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -3,7 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" #include "../mwmechanics/actorutil.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 89e5357f06..96461c1178 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -10,9 +10,7 @@ #include #include #include -#include #include -#include #include #include diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 2b032e1d70..4d2583d53f 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -11,7 +11,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "class.hpp" #include "esmstore.hpp" #include "containerstore.hpp" #include "cellstore.hpp" diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 70fde33cfb..9786ed32b4 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -20,7 +20,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/magiceffects.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp index 2069a78fc8..b529ae9db8 100644 --- a/apps/openmw/mwworld/contentloader.hpp +++ b/apps/openmw/mwworld/contentloader.hpp @@ -1,7 +1,6 @@ #ifndef CONTENTLOADER_HPP #define CONTENTLOADER_HPP -#include #include #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 8b35d8dcc0..a0895a1538 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -12,9 +12,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwgui/inventorywindow.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 52a5ab4192..a615c9978a 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -15,7 +15,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwmechanics/movement.hpp" diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ff449acf57..6e163b0d57 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -34,7 +34,6 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/aipackage.hpp" -#include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" #include "../mwrender/vismask.hpp" #include "../mwrender/renderingmanager.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1d5293b7ce..a8f573ac37 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 719aef837e..6ef9535e9f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d7963fae13..e3658285d1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -35,7 +35,6 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/levelledlist.hpp" @@ -48,7 +47,6 @@ #include "../mwrender/camera.hpp" #include "../mwrender/vismask.hpp" -#include "../mwscript/interpretercontext.hpp" #include "../mwscript/globalscripts.hpp" #include "../mwclass/door.hpp" diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index 768fc077ca..2b485abecf 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -1,6 +1,5 @@ #include "locals.hpp" -#include #include #include #include diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index fe019718a6..62265d8a1b 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -1,9 +1,5 @@ #include "parser.hpp" -#include -#include -#include - #include "errorhandler.hpp" #include "exception.hpp" #include "scanner.hpp" diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index b56dbb95bc..c5ef483f3c 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "exception.hpp" diff --git a/components/contentselector/view/combobox.cpp b/components/contentselector/view/combobox.cpp index 18cafc2dc1..959eca2890 100644 --- a/components/contentselector/view/combobox.cpp +++ b/components/contentselector/view/combobox.cpp @@ -1,7 +1,4 @@ -#include -#include #include -#include #include #include "combobox.hpp" diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 4f95b7fe46..89c389556f 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -8,10 +8,7 @@ #include #include -#include -#include #include -#include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index f4efc744b7..1e158667b0 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -5,8 +5,6 @@ #include -#include - namespace { using DetourNavigator::ChangeType; diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 26f86da321..7bd2fee77c 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -7,7 +7,6 @@ #include "settings.hpp" #include "settingsutils.hpp" #include "sharednavmesh.hpp" -#include "settingsutils.hpp" #include "flags.hpp" #include "navmeshtilescache.hpp" diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index aa2d621843..2a29d1dd4a 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -5,14 +5,9 @@ #include "makenavmesh.hpp" #include "navmeshcacheitem.hpp" #include "settings.hpp" -#include "sharednavmesh.hpp" #include -#include - -#include - namespace { using DetourNavigator::ChangeType; diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 6bfbfb3954..64edab0ad0 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -1,8 +1,6 @@ #include "navmeshtilescache.hpp" #include "exceptions.hpp" -#include - namespace DetourNavigator { namespace diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 1c3a72b59c..39afdf56ed 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -1,6 +1,5 @@ #include "recastmeshmanager.hpp" -#include #include namespace DetourNavigator diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index acaf398c16..24d3e6b5a8 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -5,7 +5,6 @@ #include #include -#include namespace DetourNavigator { diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index f584e48f94..ddffd0d1f5 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -2,8 +2,6 @@ #include -#include - namespace DetourNavigator { boost::optional makeSettingsFromSettingsManager() diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index 6e41ba3023..7891299e32 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -3,8 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "defs.hpp" - #include namespace ESM diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6e84fa7d4f..9cf56e8a91 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -1,8 +1,7 @@ #ifndef OPENMW_ESM_READER_H #define OPENMW_ESM_READER_H -#include -#include +#include #include #include #include diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index 36204c9401..09b0258174 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -2,8 +2,6 @@ #include -#include - #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index dfdc9718df..567d93bbd2 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,7 +1,6 @@ #include "storage.hpp" #include -#include #include diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 0378e294eb..dae83a1f9b 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -3,7 +3,6 @@ #include #include -#include #include diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 77e5a00790..29d1c063b1 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -1,7 +1,6 @@ #ifndef INTERPRETER_MISCOPCODES_H_INCLUDED #define INTERPRETER_MISCOPCODES_H_INCLUDED -#include #include #include #include diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 79fa36d1ee..76a585d61d 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,7 +1,6 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H -#include #include #include #include diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index a3f7f76a22..33cc31e2e8 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -1,7 +1,5 @@ #include "myguirendermanager.hpp" -#include - #include #include diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 756893974b..598f5a14e9 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -1,7 +1,6 @@ #include "myguitexture.hpp" #include -#include #include diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 1a526c63b6..72933fc32a 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -1,9 +1,6 @@ #include "bulletnifloader.hpp" -#include #include -#include -#include #include #include @@ -15,8 +12,6 @@ #include #include -#include -#include #include namespace diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a2dad247d9..ba3543ce75 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c1f6a2819b..eeb6777ce5 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "userdata.hpp" diff --git a/components/process/processinvoker.cpp b/components/process/processinvoker.cpp index cc842fd615..78cf70038b 100644 --- a/components/process/processinvoker.cpp +++ b/components/process/processinvoker.cpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index e3f6b22b4a..7dd0964e8b 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include diff --git a/components/sceneutil/agentpath.cpp b/components/sceneutil/agentpath.cpp index aaee4dd1ef..abe332f758 100644 --- a/components/sceneutil/agentpath.cpp +++ b/components/sceneutil/agentpath.cpp @@ -2,7 +2,6 @@ #include "detourdebugdraw.hpp" #include -#include #include diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index f143d19a8d..5126a37764 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -1,7 +1,6 @@ #include "attach.hpp" #include -#include #include #include diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 99dd7bad3c..d1cca5b315 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -1,12 +1,10 @@ #include "clone.hpp" #include -#include #include #include #include -#include #include diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index 25ad03fbad..aaff38797b 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -36,7 +35,6 @@ #include #include #include -#include #include diff --git a/components/sceneutil/pathgridutil.cpp b/components/sceneutil/pathgridutil.cpp index 1497beb2b8..58c5d8ad28 100644 --- a/components/sceneutil/pathgridutil.cpp +++ b/components/sceneutil/pathgridutil.cpp @@ -2,7 +2,6 @@ #include -#include #include namespace SceneUtil diff --git a/components/sceneutil/positionattitudetransform.cpp b/components/sceneutil/positionattitudetransform.cpp index 5f6b57e979..6129c33b4d 100644 --- a/components/sceneutil/positionattitudetransform.cpp +++ b/components/sceneutil/positionattitudetransform.cpp @@ -1,7 +1,5 @@ #include "positionattitudetransform.hpp" -#include - namespace SceneUtil { diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index f1acf33e99..0c81980553 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -1,8 +1,5 @@ #include "riggeometry.hpp" -#include -#include - #include #include diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 6d21175753..82854cb2f8 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 0f4dc2e738..97fc79562d 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -1,7 +1,6 @@ #include "shadermanager.hpp" #include -#include #include #include diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 3080e1318a..911a8cbbf1 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -1,7 +1,5 @@ #include "shadervisitor.hpp" -#include - #include #include #include diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 83684b5c91..c61bdb455b 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,13 +1,10 @@ #include "material.hpp" -#include - #include #include #include #include #include -#include #include #include diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index d4ab00381b..bcb174b7be 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 4f3994bace..c198823811 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -1,6 +1,5 @@ #include "manager.hpp" -#include #include #include diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 9318e32ed4..73e01675a7 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -3,7 +3,6 @@ #include #include #include -#include namespace Gui { From fcdb0c16bf24e1312685160099b37229b3bdd468 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 25 Jan 2019 20:04:35 +0400 Subject: [PATCH 220/410] Update jail state once instead of for every single hour --- CHANGELOG.md | 1 + apps/openmw/mwbase/mechanicsmanager.hpp | 4 ++-- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwgui/jailscreen.cpp | 3 +-- apps/openmw/mwgui/trainingwindow.cpp | 3 +-- apps/openmw/mwgui/travelwindow.cpp | 5 +---- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 14 +++++++------- apps/openmw/mwmechanics/actors.hpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 +++++----- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 4 ++-- apps/openmw/mwworld/cells.cpp | 6 +++--- apps/openmw/mwworld/cells.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 6 +++--- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 17 files changed, 36 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6013ce552..30585f9d67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Bug #4813: Creatures with known file but no "Sound Gen Creature" assigned use default sounds Bug #4815: "Finished" journal entry with lower index doesn't close journal, SetJournalIndex closes journal Bug #4820: Spell absorption is broken + Bug #4823: Jail progress bar works incorrectly Bug #4827: NiUVController is handled incorrectly Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 1bdd8f8b54..5c5821bca2 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -90,9 +90,9 @@ namespace MWBase virtual void setPlayerClass (const ESM::Class& class_) = 0; ///< Set player class to custom class. - virtual void restoreDynamicStats(MWWorld::Ptr actor, bool sleep) = 0; + virtual void restoreDynamicStats(MWWorld::Ptr actor, double hours, bool sleep) = 0; - virtual void rest(bool sleep) = 0; + virtual void rest(double hours, bool sleep) = 0; ///< If the player is sleeping or waiting, this should be called every hour. /// @param sleep is the player sleeping or waiting? diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 217e6d3677..cbbd76c2f8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -587,7 +587,7 @@ namespace MWBase virtual bool isPlayerInJail() const = 0; - virtual void rest() = 0; + virtual void rest(double hours) = 0; virtual void setPlayerTraveling(bool traveling) = 0; virtual bool isPlayerTraveling() const = 0; diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 1761e13460..ee0c893bac 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -78,8 +78,7 @@ namespace MWGui MWWorld::Ptr player = MWMechanics::getPlayer(); - for (int i=0; irest(true); + MWBase::Environment::get().getMechanicsManager()->rest(mDays * 24, true); MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); std::set skills; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 60e6584c7a..acc2ef72a1 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -169,8 +169,7 @@ namespace MWGui npcStats.setGoldPool(npcStats.getGoldPool() + price); // advance time - MWBase::Environment::get().getMechanicsManager()->rest(false); - MWBase::Environment::get().getMechanicsManager()->rest(false); + MWBase::Environment::get().getMechanicsManager()->rest(2, false); MWBase::Environment::get().getWorld ()->advanceTime (2); setVisible(false); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 1bcbc2d128..0ce864556c 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -174,10 +174,7 @@ namespace MWGui ESM::Position playerPos = player.getRefData().getPosition(); float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length(); int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->mValue.getFloat()); - for(int i = 0;i < hours;i++) - { - MWBase::Environment::get().getMechanicsManager ()->rest (true); - } + MWBase::Environment::get().getMechanicsManager ()->rest (hours, true); MWBase::Environment::get().getWorld()->advanceTime(hours); } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 037fcb19be..48384d4b52 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -232,7 +232,7 @@ namespace MWGui void WaitDialog::onWaitingProgressChanged(int cur, int total) { mProgressBar.setProgress(cur, total); - MWBase::Environment::get().getMechanicsManager()->rest(mSleeping); + MWBase::Environment::get().getMechanicsManager()->rest(1, mSleeping); MWBase::Environment::get().getWorld()->advanceTime(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 427bf9e7de..31d4ef42cb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -568,7 +568,7 @@ namespace MWMechanics creatureStats.setMagicka(magicka); } - void Actors::restoreDynamicStats (const MWWorld::Ptr& ptr, bool sleep) + void Actors::restoreDynamicStats (const MWWorld::Ptr& ptr, double hours, bool sleep) { MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); if (stats.isDead()) @@ -582,11 +582,11 @@ namespace MWMechanics getRestorationPerHourOfSleep(ptr, health, magicka); DynamicStat stat = stats.getHealth(); - stat.setCurrent(stat.getCurrent() + health); + stat.setCurrent(stat.getCurrent() + health * hours); stats.setHealth(stat); stat = stats.getMagicka(); - stat.setCurrent(stat.getCurrent() + magicka); + stat.setCurrent(stat.getCurrent() + magicka * hours); stats.setMagicka(stat); } @@ -610,7 +610,7 @@ namespace MWMechanics float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; - fatigue.setCurrent (fatigue.getCurrent() + 3600 * x); + fatigue.setCurrent (fatigue.getCurrent() + 3600 * x * hours); stats.setFatigue (fatigue); } @@ -1685,9 +1685,9 @@ namespace MWMechanics } } - void Actors::rest(bool sleep) + void Actors::rest(double hours, bool sleep) { - float duration = 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + float duration = hours * 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); @@ -1697,7 +1697,7 @@ namespace MWMechanics continue; if (!sleep || iter->first == player) - restoreDynamicStats(iter->first, sleep); + restoreDynamicStats(iter->first, hours, sleep); if ((!iter->first.getRefData().getBaseNode()) || (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > mActorsProcessingRange*mActorsProcessingRange) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4ed0a50b1d..07e60e1d11 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -121,13 +121,13 @@ namespace MWMechanics void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); - void rest(bool sleep); - ///< Update actors while the player is waiting or sleeping. This should be called every hour. + void rest(double hours, bool sleep); + ///< Update actors while the player is waiting or sleeping. void updateSneaking(CharacterController* ctrl, float duration); ///< Update the sneaking indicator state according to the given player character controller. - void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep); + void restoreDynamicStats(const MWWorld::Ptr& actor, double hours, bool sleep); int getHoursToRest(const MWWorld::Ptr& ptr) const; ///< Calculate how many hours the given actor needs to rest in order to be fully healed diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b909d7df1e..e6c7796d75 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -479,17 +479,17 @@ namespace MWMechanics return mActors.isSneaking(ptr); } - void MechanicsManager::rest(bool sleep) + void MechanicsManager::rest(double hours, bool sleep) { if (sleep) - MWBase::Environment::get().getWorld()->rest(); + MWBase::Environment::get().getWorld()->rest(hours); - mActors.rest(sleep); + mActors.rest(hours, sleep); } - void MechanicsManager::restoreDynamicStats(MWWorld::Ptr actor, bool sleep) + void MechanicsManager::restoreDynamicStats(MWWorld::Ptr actor, double hours, bool sleep) { - mActors.restoreDynamicStats(actor, sleep); + mActors.restoreDynamicStats(actor, hours, sleep); } int MechanicsManager::getHoursToRest() const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 2dda376f57..a81a6bd75e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -95,9 +95,9 @@ namespace MWMechanics virtual void setPlayerClass (const ESM::Class& class_) override; ///< Set player class to custom class. - virtual void restoreDynamicStats(MWWorld::Ptr actor, bool sleep) override; + virtual void restoreDynamicStats(MWWorld::Ptr actor, double hours, bool sleep) override; - virtual void rest(bool sleep) override; + virtual void rest(double hours, bool sleep) override; ///< If the player is sleeping or waiting, this should be called every hour. /// @param sleep is the player sleeping or waiting? diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 2b032e1d70..20e3c60d91 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -151,16 +151,16 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) return &result->second; } -void MWWorld::Cells::rest () +void MWWorld::Cells::rest (double hours) { for (auto &interior : mInteriors) { - interior.second.rest(); + interior.second.rest(hours); } for (auto &exterior : mExteriors) { - exterior.second.rest(); + exterior.second.rest(hours); } } diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index bd730329bb..dce42d996d 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -61,7 +61,7 @@ namespace MWWorld /// @note name must be lower case Ptr getPtr (const std::string& name); - void rest (); + void rest (double hours); /// Get all Ptrs referencing \a name in exterior cells /// @note Due to the current implementation of getPtr this only supports one Ptr per cell. diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index e291951ae3..12430ebde5 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -966,7 +966,7 @@ namespace MWWorld } } - void CellStore::rest() + void CellStore::rest(double hours) { if (mState == State_Loaded) { @@ -975,7 +975,7 @@ namespace MWWorld Ptr ptr = getCurrentPtr(&*it); if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) { - MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, true); + MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true); } } for (CellRefList::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) @@ -983,7 +983,7 @@ namespace MWWorld Ptr ptr = getCurrentPtr(&*it); if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) { - MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, true); + MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true); } } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ce8bb3da4e..baecfb5ea5 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -183,7 +183,7 @@ namespace MWWorld /// @return updated MWWorld::Ptr with the new CellStore pointer set. MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); - void rest(); + void rest(double hours); /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d7963fae13..2c3cc59d7a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3266,9 +3266,9 @@ namespace MWWorld return closestMarker; } - void World::rest() + void World::rest(double hours) { - mCells.rest(); + mCells.rest(hours); } void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 98e82bb86d..af1ed46a51 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -574,7 +574,7 @@ namespace MWWorld RestPermitted canRest() const override; ///< check if the player is allowed to rest - void rest() override; + void rest(double hours) override; /// \todo Probably shouldn't be here MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; From f5eacfcf63e412eb9c6133528f3f258f8d9c8ed3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Feb 2019 22:40:50 +0400 Subject: [PATCH 221/410] Support for temporary stunted magicka effects --- apps/openmw/mwmechanics/actors.cpp | 71 +++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 31d4ef42cb..b627bdafa9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -130,23 +130,45 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); const MWWorld::Store& settings = MWBase::Environment::get().getWorld()->getStore().get(); - bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).getMagnitude() > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - health = 0.1f * endurance; - magicka = 0; - if (!stunted) - { - float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat (); - magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); - } + float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat (); + magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); } } namespace MWMechanics { + class GetStuntedMagickaDuration : public MWMechanics::EffectSourceVisitor + { + public: + float mRemainingTime; + + GetStuntedMagickaDuration(const MWWorld::Ptr& actor) + : mRemainingTime(0.f){} + + virtual void visit (MWMechanics::EffectKey key, + const std::string& sourceName, const std::string& sourceId, int casterActorId, + float magnitude, float remainingTime = -1, float totalTime = -1) + { + if (mRemainingTime == -1) return; + + if (key.mId == ESM::MagicEffect::StuntedMagicka) + { + if (totalTime == -1) + { + mRemainingTime = -1; + return; + } + + if (remainingTime > mRemainingTime) + mRemainingTime = remainingTime; + } + } + }; + class SoulTrap : public MWMechanics::EffectSourceVisitor { MWWorld::Ptr mCreature; @@ -585,9 +607,33 @@ namespace MWMechanics stat.setCurrent(stat.getCurrent() + health * hours); stats.setHealth(stat); - stat = stats.getMagicka(); - stat.setCurrent(stat.getCurrent() + magicka * hours); - stats.setMagicka(stat); + double restoreHours = hours; + bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).getMagnitude() > 0; + if (stunted) + { + // Stunted Magicka effect should be taken into account. + GetStuntedMagickaDuration visitor(ptr); + stats.getActiveSpells().visitEffectSources(visitor); + stats.getSpells().visitEffectSources(visitor); + if (ptr.getClass().hasInventoryStore(ptr)) + ptr.getClass().getInventoryStore(ptr).visitEffectSources(visitor); + + // Take a maximum remaining duration of Stunted Magicka effects (-1 is a constant one) in game hours. + if (visitor.mRemainingTime > 0) + { + double timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + restoreHours = std::max(0.0, hours - visitor.mRemainingTime * timeScale / 3600.f); + } + else if (visitor.mRemainingTime == -1) + restoreHours = 0; + } + + if (restoreHours > 0) + { + stat = stats.getMagicka(); + stat.setCurrent(stat.getCurrent() + magicka * restoreHours); + stats.setMagicka(stat); + } } // Current fatigue can be above base value due to a fortify effect. @@ -1809,11 +1855,12 @@ namespace MWMechanics getRestorationPerHourOfSleep(ptr, healthPerHour, magickaPerHour); CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).getMagnitude() > 0; float healthHours = healthPerHour > 0 ? (stats.getHealth().getModified() - stats.getHealth().getCurrent()) / healthPerHour : 1.0f; - float magickaHours = magickaPerHour > 0 + float magickaHours = magickaPerHour > 0 && !stunted ? (stats.getMagicka().getModified() - stats.getMagicka().getCurrent()) / magickaPerHour : 1.0f; From 75c204cdd8d27ce90d0a3315cbddf9ef31f2cfca Mon Sep 17 00:00:00 2001 From: Adam Fandrejewski Date: Sat, 23 Feb 2019 13:35:25 +0000 Subject: [PATCH 222/410] Fix #4835 - undefined behavior - uninitialized mCtx --- components/esm/esmreader.cpp | 20 +++++++++++++------- components/esm/esmreader.hpp | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index a6b947dd3e..2f4f4917c6 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -27,6 +27,7 @@ ESMReader::ESMReader() , mEncoder(nullptr) , mFileSize(0) { + clearCtx(); } int ESMReader::getFormat() const @@ -50,16 +51,21 @@ void ESMReader::restoreContext(const ESM_Context &rc) void ESMReader::close() { mEsm.reset(); - mCtx.filename.clear(); - mCtx.leftFile = 0; - mCtx.leftRec = 0; - mCtx.leftSub = 0; - mCtx.subCached = false; - mCtx.recName.clear(); - mCtx.subName.clear(); + clearCtx(); mHeader.blank(); } +void ESMReader::clearCtx() +{ + mCtx.filename.clear(); + mCtx.leftFile = 0; + mCtx.leftRec = 0; + mCtx.leftSub = 0; + mCtx.subCached = false; + mCtx.recName.clear(); + mCtx.subName.clear(); +} + void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) { close(); diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6e84fa7d4f..25a3393759 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -269,6 +269,8 @@ public: size_t getFileSize() const { return mFileSize; } private: + void clearCtx(); + Files::IStreamPtr mEsm; ESM_Context mCtx; From b5c92fbb0e00fd8378b2bcb0a04939835212af1a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 23 Feb 2019 14:25:50 +0000 Subject: [PATCH 223/410] Add missing documentation for shadow normal offset distance setting. --- docs/source/reference/modding/settings/shadows.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index c8d3250a0e..d7e39d202e 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -163,6 +163,17 @@ Used as the units parameter for the polygon offset used for shadow map rendering Higher values reduce shadow flicker, but risk increasing Peter Panning. See `the OpenGL documentation for glPolygonOffset `_ for details. +normal offset distance +---------------------- + +:Type: float +:Range: Theoretically the whole range of 32-bit floating point, but values between 0 and 2 are most sensible. +:Default: 1.0 + +How far along the surface normal to project shadow coordinates. +Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. +This value is in in-game units, so 1.0 is roughly 1.4 cm. + use front face culling ---------------------- From 594ea39f5df8f62031007071087b1ba115a73d10 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Feb 2019 16:32:34 +0300 Subject: [PATCH 224/410] Revise AI data handling Make Hello 16-bit unsigned as it's intended to be Get rid of redundant mHasAI boolean Always save AI data subrecord Adjust creature and NPC default rating values to Morrowind defaults --- CHANGELOG.md | 1 + apps/esmtool/record.cpp | 6 ++---- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/refidadapterimp.hpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/world/util.cpp | 7 +++++++ apps/openmw/mwclass/creature.cpp | 6 +----- apps/openmw/mwclass/npc.cpp | 6 +----- components/esm/aipackage.cpp | 2 +- components/esm/aipackage.hpp | 5 ++--- components/esm/loadcrea.cpp | 16 +++++----------- components/esm/loadcrea.hpp | 1 - components/esm/loadnpc.cpp | 14 +++----------- components/esm/loadnpc.hpp | 1 - 14 files changed, 29 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f51650473b..d27c0e6392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Bug #4860: Actors outside of processing range visible for one frame after spawning + Bug #4876: AI ratings handling inconsistencies Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 6cd32077c1..cfd658fc94 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -660,7 +660,7 @@ void Record::print() printTransport(mData.getTransport()); - std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; + std::cout << " Artificial Intelligence: " << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; @@ -668,7 +668,6 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; - std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) @@ -1079,7 +1078,7 @@ void Record::print() printTransport(mData.getTransport()); - std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; + std::cout << " Artificial Intelligence: " << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; @@ -1087,7 +1086,6 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; - std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 94ebbef554..b4eee86308 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -87,6 +87,7 @@ namespace CSMWorld //CONCRETE TYPES ENDS HERE Display_UnsignedInteger8, + Display_UnsignedInteger16, Display_Integer, Display_Float, Display_Double, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index c05a20d078..16b7739f70 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -627,12 +627,12 @@ namespace CSMWorld RecordT record2 = record.get(); if (column==mActors.mHello) record2.mAiData.mHello = value.toInt(); - else if (column==mActors.mFlee) - record2.mAiData.mFlee = value.toInt(); + else if (column==mActors.mFlee) // Flee, Fight and Alarm ratings are probabilities. + record2.mAiData.mFlee = std::min(100, value.toInt()); else if (column==mActors.mFight) - record2.mAiData.mFight = value.toInt(); + record2.mAiData.mFight = std::min(100, value.toInt()); else if (column==mActors.mAlarm) - record2.mAiData.mAlarm = value.toInt(); + record2.mAiData.mAlarm = std::min(100, value.toInt()); else { typename std::map::const_iterator iter = diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 89d3462043..bd68494922 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -128,7 +128,7 @@ CSMWorld::RefIdCollection::RefIdCollection() ActorColumns actorsColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger8)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger16)); actorsColumns.mHello = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mFlee = &mColumns.back(); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index fef805d566..3aee51e980 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -219,6 +219,13 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return sb; } + case CSMWorld::ColumnBase::Display_UnsignedInteger16: + { + DialogueSpinBox *sb = new DialogueSpinBox(parent); + sb->setRange(0, std::numeric_limits::max()); + return sb; + } + case CSMWorld::ColumnBase::Display_Var: return new QLineEdit(parent); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 94f75dfc6a..8f17a30389 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -608,11 +608,7 @@ namespace MWClass int Creature::getServices(const MWWorld::ConstPtr &actor) const { - const MWWorld::LiveCellRef* ref = actor.get(); - if (ref->mBase->mHasAI) - return ref->mBase->mAiData.mServices; - else - return 0; + return actor.get()->mBase->mAiData.mServices; } bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1fe7eec4ee..5e03477c4a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1205,11 +1205,7 @@ namespace MWClass int Npc::getServices(const MWWorld::ConstPtr &actor) const { - const MWWorld::LiveCellRef* ref = actor.get(); - if (ref->mBase->mHasAI) - return ref->mBase->mAiData.mServices; - else - return 0; + return actor.get()->mBase->mAiData.mServices; } diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index efcd6651ea..abbd2c62cd 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -7,7 +7,7 @@ namespace ESM { void AIData::blank() { - mHello = mU1 = mFight = mFlee = mAlarm = mU2 = mU3 = mU4 = 0; + mHello = mFight = mFlee = mAlarm = mU1 = mU2 = mU3 = 0; mServices = 0; } diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 5e08806c8b..026e65dd82 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -16,10 +16,9 @@ namespace ESM struct AIData { - unsigned char mHello; - char mU1; + unsigned short mHello; // This is the base value for greeting distance [0, 65535] unsigned char mFight, mFlee, mAlarm; // These are probabilities [0, 100] - char mU2, mU3, mU4; // Unknown values + char mU1, mU2, mU3; // Unknown values int mServices; // See the Services enum void blank(); diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index f04439041d..17f03c69b3 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -22,8 +22,9 @@ namespace ESM { mTransport.mList.clear(); mScale = 1.f; - mHasAI = false; mAiData.blank(); + mAiData.mFight = 90; + mAiData.mFlee = 20; bool hasName = false; bool hasNpdt = false; @@ -68,7 +69,6 @@ namespace ESM { break; case ESM::FourCC<'A','I','D','T'>::value: esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; break; case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','N','A','M'>::value: @@ -128,14 +128,7 @@ namespace ESM { mInventory.save(esm); mSpells.save(esm); - if (mAiData.mHello != 0 - || mAiData.mFight != 0 - || mAiData.mFlee != 0 - || mAiData.mAlarm != 0 - || mAiData.mServices != 0) - { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); mTransport.save(esm); mAiPackage.save(esm); } @@ -159,8 +152,9 @@ namespace ESM { mOriginal.clear(); mInventory.mList.clear(); mSpells.mList.clear(); - mHasAI = false; mAiData.blank(); + mAiData.mFight = 90; + mAiData.mFlee = 20; mAiPackage.mList.clear(); mTransport.mList.clear(); } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index a5147619cf..be6a72b8d2 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -91,7 +91,6 @@ struct Creature InventoryList mInventory; SpellList mSpells; - bool mHasAI; AIData mAiData; AIPackageList mAiPackage; Transport mTransport; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6e7ba66c52..db6b6d31b8 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -19,7 +19,7 @@ namespace ESM mTransport.mList.clear(); mAiPackage.mList.clear(); mAiData.blank(); - mHasAI = false; + mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30; bool hasName = false; bool hasNpdt = false; @@ -96,7 +96,6 @@ namespace ESM break; case ESM::FourCC<'A','I','D','T'>::value: esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; break; case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','N','A','M'>::value: @@ -165,14 +164,7 @@ namespace ESM mInventory.save(esm); mSpells.save(esm); - if (mAiData.mHello != 0 - || mAiData.mFight != 0 - || mAiData.mFlee != 0 - || mAiData.mAlarm != 0 - || mAiData.mServices != 0) - { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); mTransport.save(esm); @@ -198,7 +190,7 @@ namespace ESM mInventory.mList.clear(); mSpells.mList.clear(); mAiData.blank(); - mHasAI = false; + mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30; mTransport.mList.clear(); mAiPackage.mList.clear(); mName.clear(); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index fbe1dca1f1..746913008e 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -122,7 +122,6 @@ struct NPC SpellList mSpells; AIData mAiData; - bool mHasAI; Transport mTransport; From 8ecd0b82a4604d7bc5e34b663c218c9c005dd34b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 23 Feb 2019 00:14:07 +0300 Subject: [PATCH 225/410] Replace Boost format and replace_all where possible --- apps/openmw/mwgui/enchantingdialog.cpp | 3 +-- apps/openmw/mwgui/formatting.cpp | 4 +-- apps/openmw/mwgui/recharge.cpp | 5 ++-- apps/openmw/mwgui/settingswindow.cpp | 3 ++- apps/openmw/mwgui/spellwindow.cpp | 5 ++-- apps/openmw/mwgui/tradewindow.cpp | 3 +-- apps/openmw/mwmechanics/disease.hpp | 3 +-- apps/openmw/mwmechanics/npcstats.cpp | 14 ++++------- apps/openmw/mwmechanics/repair.cpp | 5 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 4 +-- apps/openmw/mwscript/containerextensions.cpp | 12 ++++----- components/misc/stringops.hpp | 26 ++++++++++++++++++++ 12 files changed, 49 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index af6567afb7..fbdc1bf806 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -348,8 +348,7 @@ namespace MWGui if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr)) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->mValue.getString(); - if (msg.find("%s") != std::string::npos) - msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); + Misc::StringUtils::replace(msg, "%s", item.getClass().getName(item).c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index d4d6a0af56..fca05b05cd 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -9,8 +9,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include - #include #include #include @@ -28,7 +26,7 @@ namespace MWGui MWScript::InterpreterContext interpreterContext(nullptr, MWWorld::Ptr()); // empty arguments, because there is no locals or actor mText = Interpreter::fixDefinesBook(mText, interpreterContext); - boost::algorithm::replace_all(mText, "\r", ""); + Misc::StringUtils::replaceAll(mText, "\r", ""); // vanilla game does not show any text after the last EOL tag. const std::string lowerText = Misc::StringUtils::lowerCase(mText); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 56bd97d5e3..e42db715bc 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -1,7 +1,5 @@ #include "recharge.hpp" -#include - #include #include @@ -179,7 +177,8 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) if (gem.getRefData().getCount() == 0) { std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage51")->mValue.getString(); - message = boost::str(boost::format(message) % gem.getClass().getName(gem)); + Misc::StringUtils::replace(message, "%s", gem.getClass().getName(gem).c_str(), 2); + MWBase::Environment::get().getWindowManager()->messageBox(message); // special case: readd Azura's Star diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 6e6924f28e..c41d43b315 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -159,7 +160,7 @@ namespace MWGui MyGUI::TextBox* textBox; getWidget(textBox, labelWidgetName); std::string labelCaption = scroller->getUserString("SettingLabelCaption"); - boost::algorithm::replace_all(labelCaption, "%s", value); + Misc::StringUtils::replaceAll(labelCaption, "%s", value.c_str(), 2); textBox->setCaptionWithReplacing(labelCaption); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 2177e9e2af..254e731d0e 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,10 +1,9 @@ #include "spellwindow.hpp" -#include - #include #include +#include #include #include "../mwbase/windowmanager.hpp" @@ -157,7 +156,7 @@ namespace MWGui mSpellToDelete = spellId; ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); + Misc::StringUtils::replace(question, "%s", spell->mName.c_str(), 2); dialog->askForConfirmation(question); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 90698dfc4f..b21257eaf7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -311,8 +311,7 @@ namespace MWGui if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr)) { std::string msg = gmst.find("sNotifyMessage49")->mValue.getString(); - if (msg.find("%s") != std::string::npos) - msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); + Misc::StringUtils::replace(msg, "%s", it->mBase.getClass().getName(it->mBase).c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index fec3bdd376..8bca9f9b5b 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -60,8 +60,7 @@ namespace MWMechanics std::string msg = "sMagicContractDisease"; msg = MWBase::Environment::get().getWorld()->getStore().get().find(msg)->mValue.getString(); - if (msg.find("%s") != std::string::npos) - msg.replace(msg.find("%s"), 2, spell->mName); + Misc::StringUtils::replace(msg, "%s", spell->mName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); } } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 70c2004f02..df61ee93b4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include @@ -251,16 +249,14 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas /// \todo check if character is the player, if levelling is ever implemented for NPCs MWBase::Environment::get().getWindowManager()->playSound("skillraise"); - std::stringstream message; + std::string message = MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", ""); + Misc::StringUtils::replace(message, "%s", ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}").c_str(), 2); + Misc::StringUtils::replace(message, "%d", std::to_string(base).c_str(), 2); if (readBook) - message << std::string("#{sBookSkillMessage}\n"); - - message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) - % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") - % static_cast (base); + message = "#{sBookSkillMessage}\n" + message; - MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never); + MWBase::Environment::get().getWindowManager ()->messageBox(message, MWGui::ShowInDialogueMode_Never); if (mLevelProgress >= gmst.find("iLevelUpTotal")->mValue.getInteger()) { diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 8ab3c605d2..28dfab0cdc 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -1,7 +1,5 @@ #include "repair.hpp" -#include - #include #include "../mwbase/world.hpp" @@ -85,8 +83,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) std::string message = MWBase::Environment::get().getWorld()->getStore().get() .find("sNotifyMessage51")->mValue.getString(); + Misc::StringUtils::replace(message, "%s", mTool.getClass().getName(mTool).c_str(), 2); - MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % mTool.getClass().getName(mTool)).str()); + MWBase::Environment::get().getWindowManager()->messageBox(message); // try to find a new tool of the same ID for (MWWorld::ContainerStoreIterator iter (store.begin()); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 2a359cb52c..7b406cf9ae 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include @@ -1015,7 +1013,7 @@ namespace MWMechanics { // "X has no effect on you" std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage50")->mValue.getString(); - message = boost::str(boost::format(message) % ingredient->mName); + Misc::StringUtils::replace(message, "%s", ingredient->mName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(message); return false; } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 7d555e632a..47c46d65e9 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include @@ -85,13 +83,13 @@ namespace MWScript if (count == 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); - msgBox = boost::str(boost::format(msgBox) % itemName); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); - msgBox = boost::str(boost::format(msgBox) % count % itemName); + Misc::StringUtils::replace(msgBox, "%d", std::to_string(count).c_str(), 2); } + Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } @@ -170,16 +168,16 @@ namespace MWScript // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; - if(numRemoved > 1) + if (numRemoved > 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - msgBox = boost::str (boost::format(msgBox) % numRemoved % itemName); + Misc::StringUtils::replace(msgBox, "%d", std::to_string(numRemoved).c_str(), 2); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); - msgBox = boost::str (boost::format(msgBox) % itemName); } + Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 76a585d61d..58e1651b8e 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -240,6 +240,32 @@ public: } return str; } + + /** @brief Replaces the first occurrence of a string in another string. + * + * @param str The string to operate on. + * @param what The string to replace. + * @param with The replacement string. + * @param whatLen The length of the string to replace. + * @param withLen The length of the replacement string. + * + * @return A reference to the string passed in @p str. + */ + static std::string &replace(std::string &str, const char *what, const char *with, + std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) + { + if (whatLen == std::string::npos) + whatLen = strlen(what); + + if (withLen == std::string::npos) + withLen = strlen(with); + + std::size_t found; + if ((found = str.find(what)) != std::string::npos) + str.replace(found, whatLen, with, withLen); + + return str; + } }; } From e70cc1030512d7b8bc260ec973c764d5f63e1caf Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 23 Feb 2019 16:55:49 +0300 Subject: [PATCH 226/410] Some more de-boosting --- apps/opencs/view/doc/adjusterwidget.cpp | 6 +++--- apps/openmw/mwrender/terrainstorage.cpp | 2 -- components/files/configurationmanager.cpp | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 06da68ed80..509e656c33 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,7 +1,8 @@ #include "adjusterwidget.hpp" +#include + #include -#include #include #include @@ -70,8 +71,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { boost::filesystem::path path (name.toUtf8().data()); - std::string extension = path.extension().string(); - boost::algorithm::to_lower(extension); + std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); bool isLegacyPath = (extension == ".esm" || extension == ".esp"); diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index ff2a8bfc78..7894a8393f 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -1,7 +1,5 @@ #include "terrainstorage.hpp" -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/esmstore.hpp" diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index c58130f963..3df6faf623 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include /** * \namespace Files From 216e1ab16f88b9db6f8559bce2095e84c0ebbcbd Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 25 Feb 2019 18:47:42 +0300 Subject: [PATCH 227/410] Always include for smart pointers in MWGui --- apps/openmw/mwgui/alchemywindow.cpp | 1 + apps/openmw/mwgui/alchemywindow.hpp | 5 +---- apps/openmw/mwgui/bookpage.hpp | 1 + apps/openmw/mwgui/jailscreen.cpp | 14 ++++---------- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ apps/openmw/mwgui/mapwindow.hpp | 1 + apps/openmw/mwgui/race.hpp | 2 ++ apps/openmw/mwgui/savegamedialog.hpp | 2 ++ apps/openmw/mwgui/screenfader.hpp | 1 + apps/openmw/mwgui/spellview.hpp | 1 + apps/openmw/mwgui/videowidget.hpp | 2 ++ 11 files changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index fa8a96185f..4fc2a57a23 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index aa23fbaa50..c6eb00792f 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -1,12 +1,9 @@ #ifndef MWGUI_ALCHEMY_H #define MWGUI_ALCHEMY_H +#include #include -#include - -#include "../mwmechanics/alchemy.hpp" - #include #include "controllers.hpp" diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 4ea59414df..7f7dfd20af 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -6,6 +6,7 @@ #include "MyGUI_FontManager.h" #include +#include #include #include diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 1761e13460..31f565084a 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -103,24 +103,18 @@ namespace MWGui else message = gmst.find("sNotifyMessage43")->mValue.getString(); - std::stringstream dayStr; - dayStr << mDays; - if (message.find("%d") != std::string::npos) - message.replace(message.find("%d"), 2, dayStr.str()); + Misc::StringUtils::replace(message, "%d", std::to_string(mDays).c_str(), 2); for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) { std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->mValue.getString(); - std::stringstream skillValue; - skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); + int skillValue = player.getClass().getNpcStats(player).getSkill(*it).getBase(); std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString(); if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) skillMsg = gmst.find("sNotifyMessage39")->mValue.getString(); - if (skillMsg.find("%s") != std::string::npos) - skillMsg.replace(skillMsg.find("%s"), 2, skillName); - if (skillMsg.find("%d") != std::string::npos) - skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); + Misc::StringUtils::replace(skillMsg, "%s", skillName.c_str(), 2); + Misc::StringUtils::replace(skillMsg, "%d", std::to_string(skillValue).c_str(), 2); message += "\n" + skillMsg; } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index e74a602067..c054f3bbd6 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_LOADINGSCREEN_H #define MWGUI_LOADINGSCREEN_H +#include + #include #include diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index ed6e4874f9..3d9ca23d83 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -2,6 +2,7 @@ #define MWGUI_MAPWINDOW_H #include +#include #include "windowpinnablebase.hpp" diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index c9e31d42de..0fa4fdec5c 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H +#include + #include "windowbase.hpp" #include diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 0a87b6600d..a9915ee9df 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWGUI_SAVEGAMEDIALOG_H #define OPENMW_MWGUI_SAVEGAMEDIALOG_H +#include + #include "windowbase.hpp" namespace MWState diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 79bea30e5e..aa17ed4e8d 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -2,6 +2,7 @@ #define OPENMW_MWGUI_SCREENFADER_H #include +#include #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 0eb69f6ba1..66113d869f 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_GUI_SPELLVIEW_H #define OPENMW_GUI_SPELLVIEW_H +#include #include #include diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 20af579a25..dadd1471a3 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWGUI_VIDEOWIDGET_H #define OPENMW_MWGUI_VIDEOWIDGET_H +#include + #include namespace Video From 33f6fb258d15990707a16e86fa257c99e426ce42 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 24 Feb 2019 22:41:11 +0300 Subject: [PATCH 228/410] Option to set specific random seed for random number generator --- CHANGELOG.md | 1 + README.md | 1 + apps/openmw/engine.cpp | 8 +++++++- apps/openmw/engine.hpp | 3 +++ apps/openmw/main.cpp | 9 ++++++++- components/misc/rng.cpp | 8 ++++++-- components/misc/rng.hpp | 5 ++++- 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9fdd7c6e0..0fa1c7683e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Feature #4730: Native animated containers support Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch + Feature #4887: Add openmw command option to set initial random seed Task #4686: Upgrade media decoder to a more current FFmpeg API 0.45.0 diff --git a/README.md b/README.md index 9fbfc01788..6f453a7419 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,4 @@ Command line options --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG image and XML file in current directory --activate-dist arg (=-1) activation distance override + --random-seed arg (=) seed value for random number generator diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 16c945e2f9..2a4145c981 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -228,7 +228,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mNewGame (false) , mCfgMgr(configurationManager) { - Misc::Rng::init(); MWClass::registerClasses(); Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; @@ -653,6 +652,8 @@ void OMW::Engine::go() Log(Debug::Info) << "OSG version: " << osgGetVersion(); + Misc::Rng::init(mRandomSeed); + // Load settings Settings::Manager settings; std::string settingspath; @@ -821,3 +822,8 @@ void OMW::Engine::setSaveGameFile(const std::string &savegame) { mSaveGameFile = savegame; } + +void OMW::Engine::setRandomSeed(unsigned int seed) +{ + mRandomSeed = seed; +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e42a5c94f1..bfe9759cda 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -100,6 +100,7 @@ namespace OMW bool mGrab; bool mExportFonts; + unsigned int mRandomSeed; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; @@ -203,6 +204,8 @@ namespace OMW /// Set the save game file to load after initialising the engine. void setSaveGameFile(const std::string& savegame); + void setRandomSeed(unsigned int seed); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 7c39a785ea..a56cbfe8a9 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "engine.hpp" @@ -131,7 +132,12 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("export-fonts", bpo::value()->implicit_value(true) ->default_value(false), "Export Morrowind .fnt fonts to PNG image and XML file in current directory") - ("activate-dist", bpo::value ()->default_value (-1), "activation distance override"); + ("activate-dist", bpo::value ()->default_value (-1), "activation distance override") + + ("random-seed", bpo::value () + ->default_value(Misc::Rng::generateDefaultSeed()), + "seed value for random number generator") + ; bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) .options(desc).allow_unregistered().run(); @@ -231,6 +237,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setFallbackValues(variables["fallback"].as().mMap); engine.setActivationDistanceOverride (variables["activate-dist"].as()); engine.enableFontExport(variables["export-fonts"].as()); + engine.setRandomSeed(variables["random-seed"].as()); return true; } diff --git a/components/misc/rng.cpp b/components/misc/rng.cpp index e402f0b79e..09279e85ea 100644 --- a/components/misc/rng.cpp +++ b/components/misc/rng.cpp @@ -8,9 +8,9 @@ namespace Misc std::mt19937 Rng::generator = std::mt19937(); - void Rng::init() + void Rng::init(unsigned int seed) { - generator.seed(static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count())); + generator.seed(seed); } float Rng::rollProbability() @@ -28,4 +28,8 @@ namespace Misc return max > 0 ? std::uniform_int_distribution(0, max - 1)(generator) : 0; } + unsigned int Rng::generateDefaultSeed() + { + return static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + } } diff --git a/components/misc/rng.hpp b/components/misc/rng.hpp index ff56906d9e..65a554cf24 100644 --- a/components/misc/rng.hpp +++ b/components/misc/rng.hpp @@ -18,7 +18,7 @@ public: static std::mt19937 generator; /// seed the RNG - static void init(); + static void init(unsigned int seed = generateDefaultSeed()); /// return value in range [0.0f, 1.0f) <- note open upper range. static float rollProbability(); @@ -31,6 +31,9 @@ public: /// return value in range [0, 99] static int roll0to99() { return rollDice(100); } + + /// returns default seed for RNG + static unsigned int generateDefaultSeed(); }; } From cc855e065aea3b2d4f16087baf2abcee7fec44d6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 Feb 2019 16:58:16 +0300 Subject: [PATCH 229/410] Ignore stray references for variables in Set instruction --- components/compiler/lineparser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3f9d2e7903..1cfa70f733 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -506,6 +506,13 @@ namespace Compiler return true; } + if (code==Scanner::S_ref && mState==SetPotentialMemberVarState) + { + getErrorHandler().warning ("Ignoring stray explicit reference", loc); + mState = SetState; + return true; + } + if (code==Scanner::S_ref && mState==PotentialExplicitState) { mState = ExplicitState; From 9bc360267bb89352ee26de9f2c27d7fc6122fd0a Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 Feb 2019 17:22:57 +0300 Subject: [PATCH 230/410] Ignore stray explicit references for names in expressions --- components/compiler/exprparser.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6b849ec3aa..b3fd1e5ae1 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -277,10 +277,18 @@ namespace Compiler { if (!mExplicit.empty()) { - if (mMemberOp && handleMemberAccess (name)) - return true; + if (!mRefOp) + { + if (mMemberOp && handleMemberAccess (name)) + return true; - return Parser::parseName (name, loc, scanner); + return Parser::parseName (name, loc, scanner); + } + else + { + mExplicit.clear(); + getErrorHandler().warning ("Ignoring stray explicit reference", loc); + } } mFirst = false; From e940325b7869a3f7209b9c72b5d1987037c0a255 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 Feb 2019 19:13:46 +0300 Subject: [PATCH 231/410] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa1c7683e..fac0b4ac04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Bug #4860: Actors outside of processing range visible for one frame after spawning Bug #4876: AI ratings handling inconsistencies + Bug #4888: Global variable stray explicit reference calls break script compilation Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis From cd4303da23280ac4c10f297d6b4225a3c026372e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 26 Feb 2019 17:03:07 +0000 Subject: [PATCH 232/410] Add preprocessor check to determine which common_factor header to use. --- apps/launcher/graphicspage.cpp | 8 ++++++++ apps/openmw/mwgui/settingswindow.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 7424555132..18f744932d 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,6 +1,10 @@ #include "graphicspage.hpp" +#if BOOST_VERSION >= 106500 #include +#else +#include +#endif #include #include #include @@ -18,7 +22,11 @@ QString getAspect(int x, int y) { +#if BOOST_VERSION >= 106500 int gcd = boost::integer::gcd (x, y); +#else + int gcd = boost::math::gcd (x, y); +#endif int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 2b7dbc67dc..d06b4c5826 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -8,7 +8,11 @@ #include #include +#if BOOST_VERSION >= 106500 #include +#else +#include +#endif #include @@ -58,7 +62,11 @@ namespace std::string getAspect (int x, int y) { +#if BOOST_VERSION >= 106500 int gcd = boost::integer::gcd (x, y); +#else + int gcd = boost::math::gcd (x, y); +#endif int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 From 5ffb40e8bab4f1891cdec2493d99d5895fb552d6 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 233/410] Don't preload terrain when loading an interior save --- apps/openmw/mwworld/worldimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e3658285d1..502ff8843d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -409,7 +409,8 @@ namespace MWWorld if (getPlayerPtr().isInCell()) { mWorldScene->preloadCell(getPlayerPtr().getCell(), true); - mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); + if (getPlayerPtr().getCell()->isExterior()) + mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); } break; default: From 5bce3cbc6830ce0dfffd7698be4a18ffa55698a7 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 234/410] Don't use MWRender namespace in common terrain components --- components/terrain/cellborder.cpp | 2 +- components/terrain/cellborder.hpp | 3 --- components/terrain/terraingrid.cpp | 2 +- components/terrain/terraingrid.hpp | 2 +- components/terrain/world.cpp | 2 +- components/terrain/world.hpp | 2 +- 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/components/terrain/cellborder.cpp b/components/terrain/cellborder.cpp index d9e6d52fc1..64434727eb 100644 --- a/components/terrain/cellborder.cpp +++ b/components/terrain/cellborder.cpp @@ -7,7 +7,7 @@ #include "world.hpp" #include "../esm/loadland.hpp" -namespace MWRender +namespace Terrain { CellBorder::CellBorder(Terrain::World *world, osg::Group *root, int borderMask): diff --git a/components/terrain/cellborder.hpp b/components/terrain/cellborder.hpp index 530ea31ca3..908cdea097 100644 --- a/components/terrain/cellborder.hpp +++ b/components/terrain/cellborder.hpp @@ -7,10 +7,7 @@ namespace Terrain { class World; -} -namespace MWRender -{ /** * @Brief Handles the debug cell borders. */ diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index dbc1429da2..1888a02b34 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -84,7 +84,7 @@ void TerrainGrid::loadCell(int x, int y) void TerrainGrid::unloadCell(int x, int y) { - MWRender::CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x,y)); + CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x,y)); if (it == mGrid.end()) return; diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 87e3b432c0..eb30fb97d2 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -33,7 +33,7 @@ namespace Terrain // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks unsigned int mNumSplits; - MWRender::CellBorder::CellGrid mGrid; + CellBorder::CellGrid mGrid; }; } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index cc81dbef8e..6a8322bb54 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -47,7 +47,7 @@ World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSyst mTextureManager.reset(new TextureManager(mResourceSystem->getSceneManager())); mChunkManager.reset(new ChunkManager(mStorage, mResourceSystem->getSceneManager(), mTextureManager.get(), mCompositeMapRenderer)); - mCellBorder.reset(new MWRender::CellBorder(this,mTerrainRoot.get(),borderMask)); + mCellBorder.reset(new CellBorder(this,mTerrainRoot.get(),borderMask)); mResourceSystem->addResourceManager(mChunkManager.get()); mResourceSystem->addResourceManager(mTextureManager.get()); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index da10047832..4fb724ebbf 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -116,7 +116,7 @@ namespace Terrain std::unique_ptr mTextureManager; std::unique_ptr mChunkManager; - std::unique_ptr mCellBorder; + std::unique_ptr mCellBorder; bool mBorderVisible; From a567111400ff7ebf93fbd58203b04f417d05be7c Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 235/410] Use emplace instead of find-assign --- components/nifosg/nifloader.cpp | 4 +--- components/sceneutil/visitor.cpp | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index eef678b36d..a1aa74cab9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -244,10 +244,8 @@ namespace NifOsg osg::ref_ptr callback(new NifOsg::KeyframeController(key->data.getPtr())); callback->setFunction(std::shared_ptr(new NifOsg::ControllerFunction(key))); - if (target.mKeyframeControllers.find(strdata->string) != target.mKeyframeControllers.end()) + if (!target.mKeyframeControllers.emplace(strdata->string, callback).second) Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; - else - target.mKeyframeControllers[strdata->string] = callback; } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 3c3559a083..876ea920fa 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -61,10 +61,7 @@ namespace SceneUtil { // Take transformation for first found node in file const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName()); - if (mMap.find(nodeName) == mMap.end()) - { - mMap[nodeName] = &trans; - } + mMap.emplace(nodeName, &trans); traverse(trans); } From 8c649f05e60963e5f250dde8e0dd3adcc22037d7 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 236/410] Don't reallocate light list vector unnecessarily --- components/sceneutil/lightmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index cb6a12c879..f0fd0ef9f3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -234,6 +234,7 @@ namespace SceneUtil { osg::ref_ptr stateset = new osg::StateSet; std::vector > lights; + lights.reserve(lightList.size()); for (unsigned int i=0; imLightSource->getLight(frameNum)); From bcbee08a1be469eb11708485525ce1d3c652c1ff Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 237/410] Fix creature model instance preloading --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4b0eec7b96..f6df24358d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1436,7 +1436,7 @@ namespace MWRender return sceneMgr->createInstance(found->second); } else - return sceneMgr->createInstance(model); + return sceneMgr->getInstance(model); } void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) From c6fb94d6cbabd1a618c57d3447be2feafde6ae80 Mon Sep 17 00:00:00 2001 From: Perry Hugh Date: Wed, 27 Feb 2019 13:29:48 +0000 Subject: [PATCH 238/410] xbox-bindings --- apps/openmw/mwinput/inputmanagerimp.cpp | 69 +++++++++++++++++++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 1 + 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3251a387cc..9a63dcc0e1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -67,6 +67,7 @@ namespace MWInput , mGuiCursorX(0) , mGuiCursorY(0) , mMouseWheel(0) + , mGamepadZoom(0) , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) @@ -253,11 +254,29 @@ namespace MWInput { if (action == A_Use) { - MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState(); - mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing); + if(mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) + action = A_CycleWeaponRight; + + else if (mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) + action = A_CycleSpellRight; + + else + { + MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState(); + mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing); + } } else if (action == A_Jump) - mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); + { + if(mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) + action = A_CycleWeaponLeft; + + else if (mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) + action = A_CycleSpellLeft; + + else + mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); + } } if (currentValue == 1) @@ -607,6 +626,13 @@ namespace MWInput MWBase::Environment::get().getWorld()->togglePOV(); } mPreviewPOVDelay = 0.f; + mGamepadZoom = 0; + } + + if(mGamepadZoom) + { + MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom); + MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true); } } } @@ -623,6 +649,8 @@ namespace MWInput updateIdleTime(dt); } } + else + mGamepadZoom = 0; mAttemptJump = false; // Can only jump on first frame input is on } @@ -926,7 +954,29 @@ namespace MWInput void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) { if (!mControlsDisabled && mJoystickEnabled) + { + if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + { + mGamepadZoom = 0; + if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && mPreviewPOVDelay == 1.f && arg.value) + { + mGamepadZoom = static_cast(arg.value / 10000 * 8.5f); + return; // Do not propogate event. + } + } + + else if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) + { + mGamepadZoom = 0; + if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && mPreviewPOVDelay == 1.f && arg.value) + { + mGamepadZoom = static_cast(-(arg.value / 10000 * 8.5f)); + return; // Do not propogate event. + } + } + mInputBinder->axisMoved(deviceID, arg); + } } void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) @@ -1327,15 +1377,15 @@ namespace MWInput defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A; defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X; - defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_Y; //defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9) - defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; - defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y; - defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK; - defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; + defaultButtonBindings[A_QuickKeysMenu] = SDL_CONTROLLER_BUTTON_BACK; // Ideally a new menu, A_QuickButtonsMenu should be implemented with only 4 quick keys. defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; @@ -1348,6 +1398,7 @@ namespace MWInput defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY; defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX; defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + defaultAxisBindings[A_Jump] = SDL_CONTROLLER_AXIS_TRIGGERLEFT; for (int i = 0; i < A_Last; i++) { diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 41b0bd4040..d344e00c32 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -196,6 +196,7 @@ namespace MWInput float mGuiCursorX; float mGuiCursorY; int mMouseWheel; + float mGamepadZoom; bool mUserFileExists; bool mAlwaysRunActive; bool mSneakToggles; From 619a111a117a753fa1f02e61845774fe9713114a Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 23 Feb 2019 22:39:13 +0300 Subject: [PATCH 239/410] Run startup script once at engine start when game is running (bug #4877) --- CHANGELOG.md | 1 + apps/openmw/engine.cpp | 7 ++++++- apps/openmw/mwworld/worldimp.cpp | 9 +++------ apps/openmw/mwworld/worldimp.hpp | 4 +--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fac0b4ac04..da3b2b0cb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Bug #4860: Actors outside of processing range visible for one frame after spawning Bug #4876: AI ratings handling inconsistencies + Bug #4877: Startup script executes only on a new game start Bug #4888: Global variable stray explicit reference calls break script compilation Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2a4145c981..a68bf4c369 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -546,7 +546,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create the world mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mWorkQueue.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, - mActivationDistanceOverride, mCellName, mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string())); + mActivationDistanceOverride, mCellName, mResDir.string(), mCfgMgr.getUserDataPath().string())); mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); @@ -719,6 +719,11 @@ void OMW::Engine::go() mEnvironment.getStateManager()->newGame (!mNewGame); } + if (!mStartupScript.empty() && mEnvironment.getStateManager()->getState() == MWState::StateManager::State_Running) + { + mEnvironment.getWindowManager()->executeInConsole(mStartupScript); + } + // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e3658285d1..1109c9865c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -157,12 +157,12 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, - int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, - const std::string& resourcePath, const std::string& userDataPath) + int activationDistanceOverride, const std::string& startCell, + const std::string& resourcePath, const std::string& userDataPath) : mResourceSystem(resourceSystem), mFallback(fallbackMap), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), mUserDataPath(userDataPath), - mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript), + mActivationDistanceOverride (activationDistanceOverride), mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true), mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0), mPlayerTraveling(false), mPlayerInJail(false), mSpellPreloadTimer(0.f) @@ -307,9 +307,6 @@ namespace MWWorld if (!mPhysics->toggleCollisionMode()) mPhysics->toggleCollisionMode(); - if (!mStartupScript.empty()) - MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); - MWBase::Environment::get().getWindowManager()->updatePlayer(); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 98e82bb86d..88d77eed31 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -117,8 +117,6 @@ namespace MWWorld int mActivationDistanceOverride; - std::string mStartupScript; - std::map mDoorStates; ///< only holds doors that are currently moving. 1 = opening, 2 = closing @@ -198,7 +196,7 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, - int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, const std::string& resourcePath, const std::string& userDataPath); + int activationDistanceOverride, const std::string& startCell, const std::string& resourcePath, const std::string& userDataPath); virtual ~World(); From af7b6a09a885f1bf1b4b13b7114a433633a6c102 Mon Sep 17 00:00:00 2001 From: Grigory Date: Thu, 28 Feb 2019 00:24:43 +0300 Subject: [PATCH 240/410] Simplify Misc::StringUtils::toLower --- components/misc/stringops.hpp | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 58e1651b8e..f0b488f28e 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -25,36 +25,7 @@ public: /// Don't use tolower(int) because that depends on global locale. static char toLower(char c) { - switch(c) - { - case 'A':return 'a'; - case 'B':return 'b'; - case 'C':return 'c'; - case 'D':return 'd'; - case 'E':return 'e'; - case 'F':return 'f'; - case 'G':return 'g'; - case 'H':return 'h'; - case 'I':return 'i'; - case 'J':return 'j'; - case 'K':return 'k'; - case 'L':return 'l'; - case 'M':return 'm'; - case 'N':return 'n'; - case 'O':return 'o'; - case 'P':return 'p'; - case 'Q':return 'q'; - case 'R':return 'r'; - case 'S':return 's'; - case 'T':return 't'; - case 'U':return 'u'; - case 'V':return 'v'; - case 'W':return 'w'; - case 'X':return 'x'; - case 'Y':return 'y'; - case 'Z':return 'z'; - default:return c; - }; + return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c; } static Utf8Stream::UnicodeChar toLowerUtf8(Utf8Stream::UnicodeChar ch) From 3ac5481ab4b8c13efd79bef0e47ebd63f60b1707 Mon Sep 17 00:00:00 2001 From: Perry Hugh Date: Wed, 27 Feb 2019 14:03:16 -0800 Subject: [PATCH 241/410] Enable toggling sneak via gamepad. --- apps/openmw/mwinput/inputmanagerimp.cpp | 32 ++++++++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9a63dcc0e1..f071baaba8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -71,6 +71,8 @@ namespace MWInput , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) + , mSneakToggleShortcutTimer(0.f) + , mSneakGamepadShortcut(false) , mSneaking(false) , mAttemptJump(false) , mInvUiScalingFactor(1.f) @@ -579,7 +581,35 @@ namespace MWInput if (!mSneakToggles) { - mPlayer->setSneak(actionIsActive(A_Sneak)); + if(mJoystickLastUsed) + { + if(actionIsActive(A_Sneak)) + { + if(mSneakToggleShortcutTimer) // New Sneak Button Press + { + if(mSneakToggleShortcutTimer <= 0.3f) + { + mSneakGamepadShortcut = true; + toggleSneaking(); + } + else + mSneakGamepadShortcut = false; + } + + if(!mSneaking) + toggleSneaking(); + mSneakToggleShortcutTimer = 0.f; + } + else + { + if(!mSneakGamepadShortcut && mSneaking) + toggleSneaking(); + if(mSneakToggleShortcutTimer <= 0.3f) + mSneakToggleShortcutTimer += dt; + } + } + else + mPlayer->setSneak(actionIsActive(A_Sneak)); } if (mAttemptJump && mControlSwitch["playerjumping"]) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index d344e00c32..c383e544df 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -200,6 +200,8 @@ namespace MWInput bool mUserFileExists; bool mAlwaysRunActive; bool mSneakToggles; + float mSneakToggleShortcutTimer; + bool mSneakGamepadShortcut; bool mSneaking; bool mAttemptJump; From 8efde41a1edd912e18096c4b50e6a4fba83f02e5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Feb 2019 22:08:42 +0000 Subject: [PATCH 242/410] Add a line break to make label work --- docs/source/reference/modding/settings/shaders.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/reference/modding/settings/shaders.rst b/docs/source/reference/modding/settings/shaders.rst index b8a3b45b9f..a7e0bd3fc1 100644 --- a/docs/source/reference/modding/settings/shaders.rst +++ b/docs/source/reference/modding/settings/shaders.rst @@ -2,6 +2,7 @@ Shaders Settings ################ .. _force-shaders-label: + force shaders ------------- From aecbc2f01c098eda8acec02f025516647ead89b0 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 243/410] Fix crash when incremental compile operation is not used --- components/resource/scenemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 328a10cd1b..d360e92b19 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -729,6 +729,7 @@ namespace Resource void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const { + if (mIncrementalCompileOperation) { OpenThreads::ScopedLock lock(*mIncrementalCompileOperation->getToCompiledMutex()); stats->setAttribute(frameNumber, "Compiling", mIncrementalCompileOperation->getToCompile().size()); From 4f387fdf1cf99629fc0177b5a1fa79381db57eff Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 244/410] Prune empty quad tree nodes --- components/terrain/quadtreeworld.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 6ec89721ad..0c99ca66d9 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -163,7 +163,10 @@ public: boundingBox.expandBy(child->getBoundingBox()); } - parent->setBoundingBox(boundingBox); + if (!boundingBox.valid()) + parent->removeChildren(0, 4); + else + parent->setBoundingBox(boundingBox); } QuadTreeNode* addChild(QuadTreeNode* parent, ChildDirection direction, float size) From 172cb747633467f0afe029b54a82e56b5e098423 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 245/410] Delete composite map layers on demand --- components/terrain/compositemaprenderer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 3dc0aa41c5..0ef6491977 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -122,6 +122,8 @@ void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo & ++compositeMap.mCompiled; + compositeMap.mDrawables[i] = nullptr; + if (timeLeft) { *timeLeft -= timer.time_s(); @@ -131,6 +133,8 @@ void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo & break; } } + if (compositeMap.mCompiled == compositeMap.mDrawables.size()) + compositeMap.mDrawables = std::vector>(); state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT); From b2000b7642d9361800ede31984b8d37614d50766 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 246/410] Fix quad tree node child bounding box dimensions --- components/terrain/quadtreeworld.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 0c99ca66d9..594b2b755d 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -171,20 +171,21 @@ public: QuadTreeNode* addChild(QuadTreeNode* parent, ChildDirection direction, float size) { + float halfSize = size/2.f; osg::Vec2f center; switch (direction) { case SW: - center = parent->getCenter() + osg::Vec2f(-size/2.f,-size/2.f); + center = parent->getCenter() + osg::Vec2f(-halfSize,-halfSize); break; case SE: - center = parent->getCenter() + osg::Vec2f(size/2.f, -size/2.f); + center = parent->getCenter() + osg::Vec2f(halfSize, -halfSize); break; case NW: - center = parent->getCenter() + osg::Vec2f(-size/2.f, size/2.f); + center = parent->getCenter() + osg::Vec2f(-halfSize, halfSize); break; case NE: - center = parent->getCenter() + osg::Vec2f(size/2.f, size/2.f); + center = parent->getCenter() + osg::Vec2f(halfSize, halfSize); break; default: break; @@ -206,8 +207,8 @@ public: mStorage->getMinMaxHeights(size, center, minZ, maxZ); float cellWorldSize = mStorage->getCellWorldSize(); - osg::BoundingBox boundingBox(osg::Vec3f((center.x()-size)*cellWorldSize, (center.y()-size)*cellWorldSize, minZ), - osg::Vec3f((center.x()+size)*cellWorldSize, (center.y()+size)*cellWorldSize, maxZ)); + osg::BoundingBox boundingBox(osg::Vec3f((center.x()-halfSize)*cellWorldSize, (center.y()-halfSize)*cellWorldSize, minZ), + osg::Vec3f((center.x()+halfSize)*cellWorldSize, (center.y()+halfSize)*cellWorldSize, maxZ)); node->setBoundingBox(boundingBox); return node; From 5e95e120270d1b4406ef6449ab5285768435553b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Feb 2019 23:51:54 +0000 Subject: [PATCH 247/410] Switch from a manual label to using the automatic title-based one --- docs/source/reference/modding/settings/shaders.rst | 2 -- docs/source/reference/modding/settings/shadows.rst | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/source/reference/modding/settings/shaders.rst b/docs/source/reference/modding/settings/shaders.rst index a7e0bd3fc1..b36f642852 100644 --- a/docs/source/reference/modding/settings/shaders.rst +++ b/docs/source/reference/modding/settings/shaders.rst @@ -1,8 +1,6 @@ Shaders Settings ################ -.. _force-shaders-label: - force shaders ------------- diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index d7e39d202e..9b207c448f 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -13,7 +13,7 @@ enable shadows Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. -Bear in mind that this will force OpenMW to use shaders as if :ref:`force-shaders-label` was enabled. +Bear in mind that this will force OpenMW to use shaders as if :ref:`force shaders` was enabled. A keen developer may be able to implement compatibility with fixed-function mode using the advice of `this post `_, but it may be more difficult than it seems. From 567ad293fdf4f5d58d2520d0b0c8fbc0080bccef Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 248/410] Don't discard object cache with uninitialized timestamp This can happen during terrain loading --- components/resource/objectcache.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index e8c082f91b..ffe150c74e 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -75,10 +75,11 @@ void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double r itr!=_objectCache.end(); ++itr) { - // if ref count is greater the 1 the object has an external reference. - if (itr->second.first->referenceCount()>1) + // If ref count is greater than 1, the object has an external reference. + // If the timestamp is yet to be initialized, it needs to be updated too. + if (itr->second.first->referenceCount()>1 || itr->second.second == 0.0) { - // so update it time stamp. + // So update it. itr->second.second = referenceTime; } } From a14c832f4fa230b6d09bef073713df0bdf5a99bf Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 28 Feb 2019 15:11:30 +0400 Subject: [PATCH 249/410] Fix Boost version check in the launcher --- apps/launcher/graphicspage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 18f744932d..170f8a8e1c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,5 +1,6 @@ #include "graphicspage.hpp" +#include #if BOOST_VERSION >= 106500 #include #else From 3872d7476b3006b3087edaa7baba0c81a8e6734e Mon Sep 17 00:00:00 2001 From: Grigory Latyshev Date: Thu, 28 Feb 2019 20:03:42 +0000 Subject: [PATCH 250/410] Move makeOsgVec3f() to settingsutils.hpp Remove all other makeOsgVec3f() implementations --- apps/openmw/mwmechanics/aisequence.cpp | 2 +- apps/openmw/mwphysics/actor.cpp | 12 +++--- apps/openmw/mwphysics/object.cpp | 6 +-- apps/openmw/mwphysics/physicssystem.cpp | 40 +++++++++---------- apps/openmw/mwphysics/trace.cpp | 9 +++-- apps/openmw/mwscript/containerextensions.cpp | 8 ++-- apps/openmw/mwworld/scene.cpp | 8 ++-- components/detournavigator/findsmoothpath.cpp | 2 +- components/detournavigator/findsmoothpath.hpp | 12 +----- .../detournavigator/gettilespositions.hpp | 11 ++--- components/detournavigator/makenavmesh.cpp | 15 +++---- .../detournavigator/recastmeshbuilder.cpp | 11 +---- .../mwphysics => components/misc}/convert.hpp | 23 ++++++++--- components/sceneutil/detourdebugdraw.hpp | 5 +++ 14 files changed, 80 insertions(+), 84 deletions(-) rename {apps/openmw/mwphysics => components/misc}/convert.hpp (59%) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index e337c63492..13f34058cf 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -469,7 +469,7 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) for (std::vector::const_iterator it = sequence.mPackages.begin(); it != sequence.mPackages.end(); ++it) { - std::unique_ptr package (nullptr); + std::unique_ptr package; switch (it->mType) { case ESM::AiSequence::Ai_Wander: diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index b55c20455a..632d32c26d 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -7,10 +7,10 @@ #include #include #include +#include #include "../mwworld/class.hpp" -#include "convert.hpp" #include "collisiontype.hpp" namespace MWPhysics @@ -62,7 +62,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr } else { - mShape.reset(new btBoxShape(toBullet(mHalfExtents))); + mShape.reset(new btBoxShape(Misc::Convert::toBullet(mHalfExtents))); mRotationallyInvariant = false; } @@ -138,13 +138,13 @@ void Actor::updateCollisionObjectPosition() btTransform tr = mCollisionObject->getWorldTransform(); osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale); osg::Vec3f newPosition = scaledTranslation + mPosition; - tr.setOrigin(toBullet(newPosition)); + tr.setOrigin(Misc::Convert::toBullet(newPosition)); mCollisionObject->setWorldTransform(tr); } osg::Vec3f Actor::getCollisionObjectPosition() const { - return toOsg(mCollisionObject->getWorldTransform().getOrigin()); + return Misc::Convert::toOsg(mCollisionObject->getWorldTransform().getOrigin()); } void Actor::setPosition(const osg::Vec3f &position) @@ -169,7 +169,7 @@ void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); - tr.setRotation(toBullet(mRotation)); + tr.setRotation(Misc::Convert::toBullet(mRotation)); mCollisionObject->setWorldTransform(tr); updateCollisionObjectPosition(); @@ -187,7 +187,7 @@ void Actor::updateScale() mPtr.getClass().adjustScale(mPtr, scaleVec, false); mScale = scaleVec; - mShape->setLocalScaling(toBullet(mScale)); + mShape->setLocalScaling(Misc::Convert::toBullet(mScale)); scaleVec = osg::Vec3f(scale,scale,scale); mPtr.getClass().adjustScale(mPtr, scaleVec, true); diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index 549b450a97..9506301416 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -1,10 +1,10 @@ #include "object.hpp" -#include "convert.hpp" #include #include #include #include +#include #include #include @@ -26,7 +26,7 @@ namespace MWPhysics mCollisionObject->setUserPointer(static_cast(this)); setScale(ptr.getCellRef().getScale()); - setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); const float* pos = ptr.getRefData().getPosition().pos; setOrigin(btVector3(pos[0], pos[1], pos[2])); } @@ -112,7 +112,7 @@ namespace MWPhysics matrix.orthoNormalize(matrix); btTransform transform; - transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling()); + transform.setOrigin(Misc::Convert::toBullet(matrix.getTrans()) * compound->getLocalScaling()); for (int i=0; i<3; ++i) for (int j=0; j<3; ++j) transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f6f7aac39c..d12f7fe6cb 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include // FindRecIndexVisitor @@ -40,7 +41,6 @@ #include "collisiontype.hpp" #include "actor.hpp" -#include "convert.hpp" #include "trace.h" #include "object.hpp" #include "heightfield.hpp" @@ -243,7 +243,7 @@ namespace MWPhysics // Check if we actually found a valid spawn point (use an infinitely thin ray this time). // Required for some broken door destinations in Morrowind.esm, where the spawn point // intersects with other geometry if the actor's base is taken into account - btVector3 from = toBullet(position); + btVector3 from = Misc::Convert::toBullet(position); btVector3 to = from - btVector3(0,0,maxHeight); btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); @@ -253,11 +253,11 @@ namespace MWPhysics collisionWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && - ( (toOsg(resultCallback1.m_hitPointWorld) - (tracer.mEndPos-offset)).length2() > 35*35 + ( (Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) - (tracer.mEndPos-offset)).length2() > 35*35 || !isWalkableSlope(tracer.mPlaneNormal))) { actor->setOnSlope(!isWalkableSlope(resultCallback1.m_hitNormalWorld)); - return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); + return Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); } else { @@ -696,7 +696,7 @@ namespace MWPhysics btCollisionObject object; object.setCollisionShape(&shape); - object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); + object.setWorldTransform(btTransform(Misc::Convert::toBullet(orient), Misc::Convert::toBullet(center))); const btCollisionObject* me = nullptr; std::vector targetCollisionObjects; @@ -715,7 +715,7 @@ namespace MWPhysics } } - DeepestNotMeContactTestResultCallback resultCallback(me, targetCollisionObjects, toBullet(origin)); + DeepestNotMeContactTestResultCallback resultCallback(me, targetCollisionObjects, Misc::Convert::toBullet(origin)); resultCallback.m_collisionFilterGroup = CollisionType_Actor; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; mCollisionWorld->contactTest(&object, resultCallback); @@ -724,7 +724,7 @@ namespace MWPhysics { PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); if (holder) - return std::make_pair(holder->getPtr(), toOsg(resultCallback.mContactPoint)); + return std::make_pair(holder->getPtr(), Misc::Convert::toOsg(resultCallback.mContactPoint)); } return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } @@ -740,7 +740,7 @@ namespace MWPhysics btTransform rayFrom; rayFrom.setIdentity(); - rayFrom.setOrigin(toBullet(point)); + rayFrom.setOrigin(Misc::Convert::toBullet(point)); // target the collision object's world origin, this should be the center of the collision object btTransform rayTo; @@ -756,7 +756,7 @@ namespace MWPhysics return 0.f; } else - return (point - toOsg(cb.m_hitPointWorld)).length(); + return (point - Misc::Convert::toOsg(cb.m_hitPointWorld)).length(); } class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback @@ -790,8 +790,8 @@ namespace MWPhysics PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore, std::vector targets, int mask, int group) const { - btVector3 btFrom = toBullet(from); - btVector3 btTo = toBullet(to); + btVector3 btFrom = Misc::Convert::toBullet(from); + btVector3 btTo = Misc::Convert::toBullet(to); const btCollisionObject* me = nullptr; std::vector targetCollisionObjects; @@ -829,8 +829,8 @@ namespace MWPhysics result.mHit = resultCallback.hasHit(); if (resultCallback.hasHit()) { - result.mHitPos = toOsg(resultCallback.m_hitPointWorld); - result.mHitNormal = toOsg(resultCallback.m_hitNormalWorld); + result.mHitPos = Misc::Convert::toOsg(resultCallback.m_hitPointWorld); + result.mHitNormal = Misc::Convert::toOsg(resultCallback.m_hitNormalWorld); if (PtrHolder* ptrHolder = static_cast(resultCallback.m_collisionObject->getUserPointer())) result.mHitObject = ptrHolder->getPtr(); } @@ -839,15 +839,15 @@ namespace MWPhysics PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) { - btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); + btCollisionWorld::ClosestConvexResultCallback callback(Misc::Convert::toBullet(from), Misc::Convert::toBullet(to)); callback.m_collisionFilterGroup = 0xff; callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door; btSphereShape shape(radius); const btQuaternion btrot = btQuaternion::getIdentity(); - btTransform from_ (btrot, toBullet(from)); - btTransform to_ (btrot, toBullet(to)); + btTransform from_ (btrot, Misc::Convert::toBullet(from)); + btTransform to_ (btrot, Misc::Convert::toBullet(to)); mCollisionWorld->convexSweepTest(&shape, from_, to_, callback); @@ -855,8 +855,8 @@ namespace MWPhysics result.mHit = callback.hasHit(); if (result.mHit) { - result.mHitPos = toOsg(callback.m_hitPointWorld); - result.mHitNormal = toOsg(callback.m_hitNormalWorld); + result.mHitPos = Misc::Convert::toOsg(callback.m_hitPointWorld); + result.mHitNormal = Misc::Convert::toOsg(callback.m_hitNormalWorld); } return result; } @@ -1131,7 +1131,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + found->second->setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } @@ -1152,7 +1152,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3())); + found->second->setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3())); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 07465ada02..57b0a83680 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -1,11 +1,12 @@ #include "trace.h" +#include + #include #include #include "collisiontype.hpp" #include "actor.hpp" -#include "convert.hpp" namespace MWPhysics { @@ -49,8 +50,8 @@ protected: void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world) { - const btVector3 btstart = toBullet(start); - const btVector3 btend = toBullet(end); + const btVector3 btstart = Misc::Convert::toBullet(start); + const btVector3 btend = Misc::Convert::toBullet(end); const btTransform &trans = actor->getWorldTransform(); btTransform from(trans); @@ -75,7 +76,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star mFraction = newTraceCallback.m_closestHitFraction; mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); mEndPos = (end-start)*mFraction + start; - mHitPoint = toOsg(newTraceCallback.m_hitPointWorld); + mHitPoint = Misc::Convert::toOsg(newTraceCallback.m_hitPointWorld); mHitObject = newTraceCallback.m_hitCollisionObject; } else diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 47c46d65e9..db50ff621d 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -87,9 +87,9 @@ namespace MWScript else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); - Misc::StringUtils::replace(msgBox, "%d", std::to_string(count).c_str(), 2); + ::Misc::StringUtils::replace(msgBox, "%d", std::to_string(count).c_str(), 2); } - Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); + ::Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } @@ -171,13 +171,13 @@ namespace MWScript if (numRemoved > 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - Misc::StringUtils::replace(msgBox, "%d", std::to_string(numRemoved).c_str(), 2); + ::Misc::StringUtils::replace(msgBox, "%d", std::to_string(numRemoved).c_str(), 2); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); } - Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); + ::Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index a8f573ac37..1e84188935 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -28,7 +29,6 @@ #include "../mwphysics/actor.hpp" #include "../mwphysics/object.hpp" #include "../mwphysics/heightfield.hpp" -#include "../mwphysics/convert.hpp" #include "player.hpp" #include "localscripts.hpp" @@ -135,16 +135,16 @@ namespace const auto& transform = object->getCollisionObject()->getWorldTransform(); const btTransform closedDoorTransform( - MWPhysics::toBullet(makeObjectOsgQuat(ptr.getCellRef().getPosition())), + Misc::Convert::toBullet(makeObjectOsgQuat(ptr.getCellRef().getPosition())), transform.getOrigin() ); - const auto start = DetourNavigator::makeOsgVec3f(closedDoorTransform(center + toPoint)); + const auto start = Misc::Convert::makeOsgVec3f(closedDoorTransform(center + toPoint)); const auto startPoint = physics.castRay(start, start - osg::Vec3f(0, 0, 1000), ptr, {}, MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water); const auto connectionStart = startPoint.mHit ? startPoint.mHitPos : start; - const auto end = DetourNavigator::makeOsgVec3f(closedDoorTransform(center - toPoint)); + const auto end = Misc::Convert::makeOsgVec3f(closedDoorTransform(center - toPoint)); const auto endPoint = physics.castRay(end, end - osg::Vec3f(0, 0, 1000), ptr, {}, MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water); const auto connectionEnd = endPoint.mHit ? endPoint.mHitPos : end; diff --git a/components/detournavigator/findsmoothpath.cpp b/components/detournavigator/findsmoothpath.cpp index e59b801144..ef0341d724 100644 --- a/components/detournavigator/findsmoothpath.cpp +++ b/components/detournavigator/findsmoothpath.cpp @@ -125,7 +125,7 @@ namespace DetourNavigator { // Stop at Off-Mesh link or when point is further than slop away. if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) || - !inRange(makeOsgVec3f(&steerPath[ns * 3]), startPos, minTargetDist, 1000.0f)) + !inRange(Misc::Convert::makeOsgVec3f(&steerPath[ns * 3]), startPos, minTargetDist, 1000.0f)) break; ns++; } diff --git a/components/detournavigator/findsmoothpath.hpp b/components/detournavigator/findsmoothpath.hpp index c02e3315bd..ce5febebe0 100644 --- a/components/detournavigator/findsmoothpath.hpp +++ b/components/detournavigator/findsmoothpath.hpp @@ -14,6 +14,8 @@ #include +#include + #include #include @@ -26,16 +28,6 @@ namespace DetourNavigator { struct Settings; - inline osg::Vec3f makeOsgVec3f(const float* values) - { - return osg::Vec3f(values[0], values[1], values[2]); - } - - inline osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } - inline bool inRange(const osg::Vec3f& v1, const osg::Vec3f& v2, const float r, const float h) { const auto d = v2 - v1; diff --git a/components/detournavigator/gettilespositions.hpp b/components/detournavigator/gettilespositions.hpp index 86ce77402d..e233795e68 100644 --- a/components/detournavigator/gettilespositions.hpp +++ b/components/detournavigator/gettilespositions.hpp @@ -5,17 +5,14 @@ #include "settingsutils.hpp" #include "tileposition.hpp" +#include + #include #include namespace DetourNavigator { - inline osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } - template void getTilesPositions(const osg::Vec3f& aabbMin, const osg::Vec3f& aabbMax, const Settings& settings, Callback&& callback) @@ -49,7 +46,7 @@ namespace DetourNavigator btVector3 aabbMax; shape.getAabb(transform, aabbMin, aabbMax); - getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward(callback)); + getTilesPositions(Misc::Convert::makeOsgVec3f(aabbMin), Misc::Convert::makeOsgVec3f(aabbMax), settings, std::forward(callback)); } template @@ -66,7 +63,7 @@ namespace DetourNavigator aabbMax.setX(std::max(aabbMin.x(), aabbMax.x())); aabbMax.setY(std::max(aabbMin.y(), aabbMax.y())); - getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward(callback)); + getTilesPositions(Misc::Convert::makeOsgVec3f(aabbMin), Misc::Convert::makeOsgVec3f(aabbMax), settings, std::forward(callback)); } } diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 7bd2fee77c..f1f6205c70 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -10,6 +10,8 @@ #include "flags.hpp" #include "navmeshtilescache.hpp" +#include + #include #include #include @@ -44,11 +46,6 @@ namespace using PolyMeshDetailStackPtr = std::unique_ptr; - osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } - struct WaterBounds { osg::Vec3f mMin; @@ -61,8 +58,8 @@ namespace if (water.mCellSize == std::numeric_limits::max()) { const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z()); - const auto min = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-1, -1, 0)))); - const auto max = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(1, 1, 0)))); + const auto min = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-1, -1, 0)))); + const auto max = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(1, 1, 0)))); return WaterBounds { osg::Vec3f(-std::numeric_limits::max(), min.y(), -std::numeric_limits::max()), osg::Vec3f(std::numeric_limits::max(), max.y(), std::numeric_limits::max()) @@ -73,8 +70,8 @@ namespace const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z()); const auto halfCellSize = water.mCellSize / 2.0f; return WaterBounds { - toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), - toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) + toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), + toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) }; } } diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index e325b7eaf1..71c4f04051 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -6,6 +6,7 @@ #include "exceptions.hpp" #include +#include #include #include @@ -15,14 +16,6 @@ #include -namespace -{ - osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } -} - namespace DetourNavigator { using BulletHelpers::makeProcessTriangleCallback; @@ -175,7 +168,7 @@ namespace DetourNavigator void RecastMeshBuilder::addVertex(const btVector3& worldPosition) { - const auto navMeshPosition = toNavMeshCoordinates(mSettings, makeOsgVec3f(worldPosition)); + const auto navMeshPosition = toNavMeshCoordinates(mSettings, Misc::Convert::makeOsgVec3f(worldPosition)); mVertices.push_back(navMeshPosition.x()); mVertices.push_back(navMeshPosition.y()); mVertices.push_back(navMeshPosition.z()); diff --git a/apps/openmw/mwphysics/convert.hpp b/components/misc/convert.hpp similarity index 59% rename from apps/openmw/mwphysics/convert.hpp rename to components/misc/convert.hpp index c5075a2c33..c5671f0169 100644 --- a/apps/openmw/mwphysics/convert.hpp +++ b/components/misc/convert.hpp @@ -1,14 +1,25 @@ -#ifndef OPENMW_MWPHYSICS_CONVERT_H -#define OPENMW_MWPHYSICS_CONVERT_H +#ifndef OPENMW_COMPONENTS_MISC_CONVERT_H +#define OPENMW_COMPONENTS_MISC_CONVERT_H +#include #include #include - #include #include -namespace MWPhysics +namespace Misc { +namespace Convert +{ + inline osg::Vec3f makeOsgVec3f(const float* values) + { + return osg::Vec3f(values[0], values[1], values[2]); + } + + inline osg::Vec3f makeOsgVec3f(const btVector3& value) + { + return osg::Vec3f(value.x(), value.y(), value.z()); + } inline btVector3 toBullet(const osg::Vec3f& vec) { @@ -29,7 +40,7 @@ namespace MWPhysics { return osg::Quat(quat.x(), quat.y(), quat.z(), quat.w()); } - +} } -#endif +#endif \ No newline at end of file diff --git a/components/sceneutil/detourdebugdraw.hpp b/components/sceneutil/detourdebugdraw.hpp index bb170e7ba2..9b6a28acea 100644 --- a/components/sceneutil/detourdebugdraw.hpp +++ b/components/sceneutil/detourdebugdraw.hpp @@ -1,3 +1,6 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_DETOURDEBUGDRAW_H +#define OPENMW_COMPONENTS_SCENEUTIL_DETOURDEBUGDRAW_H + #include #include @@ -48,3 +51,5 @@ namespace SceneUtil void addColor(osg::Vec4f&& value); }; } + +#endif \ No newline at end of file From f3c9b34a1a92f6b162251688c4f5f4e7dc0c24b0 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 1 Mar 2019 00:47:20 +0300 Subject: [PATCH 251/410] Add Navigator settings documentation --- .../reference/modding/settings/index.rst | 1 + .../reference/modding/settings/navigator.rst | 359 ++++++++++++++++++ 2 files changed, 360 insertions(+) create mode 100644 docs/source/reference/modding/settings/navigator.rst diff --git a/docs/source/reference/modding/settings/index.rst b/docs/source/reference/modding/settings/index.rst index b4bf1d2d37..53b097a542 100644 --- a/docs/source/reference/modding/settings/index.rst +++ b/docs/source/reference/modding/settings/index.rst @@ -55,3 +55,4 @@ The ranges included with each setting are the physically possible ranges, not re video water windows + navigator diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst new file mode 100644 index 0000000000..ab174e45c2 --- /dev/null +++ b/docs/source/reference/modding/settings/navigator.rst @@ -0,0 +1,359 @@ +Navigator Settings +################ + +Main settings +************* + +This section is for players. + +enable +------ + +:Type: boolean +:Range: True/False +:Default: True + +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. + +Advanced settings +***************** + +This section is for advanced PC uses who understands concepts of OS thread and memory. + +async nav mesh updater threads +------------------------------ + +:Type: integer +:Range: >= 1 +:Default: 1 + +Number of background threads to update nav mesh. +Increasing this value may decrease performance, but also may decrease or increase nav mesh update latency depending on number of CPU cores. +On systems with not less than 4 CPU cores latency dependens approximately like 1/log(n) from number of threads. +Don't expect twice better latency by doubling this value. + +max nav mesh tiles cache size +----------------------------- + +:Type: integer +:Range: >= 0 +:Default: 268435456 + +Maximum total cached size of all nav mesh tiles in bytes. +Setting greater than zero value will reduce nav mesh update latency for previously visited locations. +Increasing this value may increase total memory consumption, but potentially will reduce latency for recently visited locations. +Limit this value by total available physical memory minus base game memory consumption and other applications. +Game will not eat all memory at once. +Memory will be consumed in approximately linear dependency from number of nav mesh updates. +But only for new locations or already dropped from cache. + +Developer's settings +******************** + +This section is for developers or anyone who wants to investigate how nav mesh system works in OpenMW. + +enable log +---------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable debug log. +Detournavigator module will write own debug log into separate file. +Potentially decreases performance. + +log path +-------- + +:Type: string +:Range: file system path +:Default: detournavigator.log + +Write debug log to this file. +Try use tmpfs or any other in-memory file system to reduce performance impact. + +enable write recast mesh to file +-------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write recast mesh to file in .obj format for each use to update nav mesh. +Option is used to find out what world geometry is used to build nav mesh. +Potentially decreases performance. + +enable write nav mesh to file +----------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write nav mesh to file to be able to open by RecastDemo application. +Usually it is more usefull to have both enable write recast mesh to file and this options enabled. +RecastDemo supports .obj files. +Potentially decreases performance. + +enable recast mesh file name revision +------------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write each recast mesh file with revision in name. +Otherwise will rewrite same file. +If it is unclear when geometry is changed use this option to dump multiple files for each state. + +enable nav mesh file name revision +---------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write each nav mesh file with revision in name. +Otherwise will rewrite same file. +If it is unclear when nav mesh is changed use this option to dump multiple files for each state. + +recast mesh path prefix +----------------------- + +:Type: string +:Range: file system path +:Default: "" + +Write recast mesh file at path with this prefix. + +nav mesh path prefix +-------------------- + +:Type: string +:Range: file system path +:Default: "" + +Write nav mesh file at path with this prefix. + +enable nav mesh render +---------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Render nav mesh. +Allows to do in-game debug. +Every nav mesh is visible and every update is noticable. +Potentially decreases performance. + +enable agents paths render +------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Render agents paths. +Make visible all NPC's and creaure's plans where they are going. +Works even if Navigator is disabled. +Potentially decreases performance. + +Expert settings +*************** + +This section is for developers who wants to go deeper into Detournavigator component logic. + +recast scale factor +------------------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.017647058823529415 + +Scale of nav mesh coordinates to world coordinates. Recastnavigation builds voxels for world geometry. +Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size +"recast scale factor" / "cell size". Default value calculates by this equation: +sStepSizeUp * "recast scale factor" / "cell size" = 3 (max climb height should be equal to 3 voxels). +Changing this value will change generated nav mesh. Some locations may become unavailable for NPC and creatures. +Pay attention to slopes and roofs when change it. Increasing this value will reduce nav mesh update latency. + +max polygon path size +--------------------- + +:Type: integer +:Range: > 0 +:Default: 1024 + +Maximum size of path over polygons. + +max smooth path size +-------------------- + +:Type: integer +:Range: > 0 +:Default: 1024 + +Maximum size of smoothed path. + +triangles per chunk +------------------- + +:Type: integer +:Range: > 0 +:Default: 256 + +Maximum number of triangles in each node of mesh AABB tree. + +recast scale factor +------------------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.013 + +Scale of nav mesh coordinates to world coordinates. + +Expert Recastnavigation related settings +**************************************** + +This section is for OpenMW developers who knows about Recastnavigation `_ library and understands how it works. + +cell height +----------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.2 + +The z-axis cell size to use for fields. +Defines voxel/grid/cell size. So their values have significant +side effects on all parameters defined in voxel units. +The minimum value for this parameter depends on the platform's floating point +accuracy, with the practical minimum usually around 0.05. +Same default value is used in RecastDemo. + +cell size +--------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.2 + +The xy-plane cell size to use for fields. +Defines voxel/grid/cell size. So their values have significant +side effects on all parameters defined in voxel units. +The minimum value for this parameter depends on the platform's floating point +accuracy, with the practical minimum usually around 0.05. +Same default value is used in RecastDemo. + +detail sample dist +------------------ + +:Type: floating point +:Range: = 0.0 or >= 0.9 +:Default: 6.0 + +Sets the sampling distance to use when generating the detail mesh. + +detail sample max error +----------------------- + +:Type: floating point +:Range: >= 0.0 +:Default: 1.0 + +The maximum distance the detail mesh surface should deviate from heightfield data. + +max simplification error +------------------------ + +:Type: floating point +:Range: >= 0.0 +:Default: 1.3 + +The maximum distance a simplfied contour's border edges should deviate the original raw contour. + +tile size +--------- + +:Type: integer +:Range: > 0 +:Default: 64 + +The width and height of each tile. + +border size +----------- + +:Type: integer +:Range: >= 0 +:Default: 16 + +The size of the non-navigable border around the heightfield. + +max edge len +------------ + +:Type: integer +:Range: >= 0 +:Default: 12 + +The maximum allowed length for contour edges along the border of the mesh. + +max nav mesh query nodes +------------------------ + +:Type: integer +:Range: 0 < value <= 65535 +:Default: 2048 + +Maximum number of search nodes. + +max polygons per tile +--------------------- + +:Type: integer +:Range: 2^n, 0 < n < 22 +:Default: 4096 + +Maximum number of polygons per nav mesh tile. Maximum number of nav mesh tiles depends on +this value. 22 bits is a limit to store both tile identifier and polygon identifier (tiles = 2^(22 - log2(polygons))). +See recastnavigation `_ for more details. + +max verts per poly +------------------ + +:Type: integer +:Range: >= 3 +:Default: 6 + +The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process. + +region merge size +----------------- + +:Type: integer +:Range: >= 0 +:Default: 20 + +Any regions with a span count smaller than this value will, if possible, be merged with larger regions. + +region min size +--------------- + +:Type: integer +:Range: >= 0 +:Default: 8 + +The minimum number of cells allowed to form isolated island areas. From fd94d7f7ff3aae7ba200dd135b96644316f69f37 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 27 Feb 2019 19:41:07 +0400 Subject: [PATCH 252/410] Make Distant Terrain more configurable (feature #4890) --- CHANGELOG.md | 1 + apps/openmw/mwrender/renderingmanager.cpp | 22 +++++++++--- components/terrain/chunkmanager.cpp | 8 ++--- components/terrain/chunkmanager.hpp | 7 ++-- components/terrain/quadtreeworld.cpp | 22 ++++++++---- components/terrain/quadtreeworld.hpp | 3 +- .../reference/modding/settings/terrain.rst | 35 ++++++++++++++++++- files/settings-default.cfg | 12 ++++++- 8 files changed, 87 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fac0b4ac04..fad734ec04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch Feature #4887: Add openmw command option to set initial random seed + Feature #4890: Make Distant Terrain configurable Task #4686: Upgrade media decoder to a more current FFmpeg API 0.45.0 diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c1f2b390f5..4a96960646 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,7 +244,7 @@ namespace MWRender int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; if (Settings::Manager::getBool("object shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Object; - + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); @@ -283,12 +283,24 @@ namespace MWRender mDistantFog = Settings::Manager::getBool("use distant fog", "Fog"); mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); - mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"), - Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), - Settings::Manager::getBool("auto use terrain specular maps", "Shaders")); + + const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders"); + const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders"); + const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders"); + const bool useTerrainNormalMaps = Settings::Manager::getBool("auto use terrain normal maps", "Shaders"); + const bool useTerrainSpecularMaps = Settings::Manager::getBool("auto use terrain specular maps", "Shaders"); + + mTerrainStorage = new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps); if (mDistantTerrain) - mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); + { + const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain"); + int compMapPower = Settings::Manager::getInt("composite map level", "Terrain"); + compMapPower = std::max(-3, compMapPower); + float compMapLevel = pow(2, compMapPower); + const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); + mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor)); + } else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index b23b0b76c0..9e31b9a20e 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -28,6 +28,7 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T , mTextureManager(textureManager) , mCompositeMapRenderer(renderer) , mCompositeMapSize(512) + , mCompositeMapLevel(1.f) , mCullingActive(true) { @@ -68,11 +69,6 @@ void ChunkManager::releaseGLObjects(osg::State *state) mBufferCache.releaseGLObjects(state); } -void ChunkManager::setCullingActive(bool active) -{ - mCullingActive = active; -} - osg::ref_ptr ChunkManager::createCompositeMapRTT() { osg::ref_ptr texture = new osg::Texture2D; @@ -199,7 +195,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags)); - bool useCompositeMap = chunkSize >= 1.f; + bool useCompositeMap = chunkSize >= mCompositeMapLevel; unsigned int numUvSets = useCompositeMap ? 1 : 2; for (unsigned int i=0; i getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); + void setCullingActive(bool active) { mCullingActive = active; } + void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; } + void setCompositeMapLevel(float level) { mCompositeMapLevel = level; } + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; void clearCache() override; void releaseGLObjects(osg::State* state) override; - void setCullingActive(bool active); - private: osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); @@ -56,6 +58,7 @@ namespace Terrain BufferCache mBufferCache; unsigned int mCompositeMapSize; + float mCompositeMapLevel; bool mCullingActive; }; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 594b2b755d..f531e241f5 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -75,8 +75,9 @@ namespace Terrain class DefaultLodCallback : public LodCallback { public: - DefaultLodCallback(float minSize) - : mMinSize(minSize) + DefaultLodCallback(float factor, float minSize) + : mFactor(factor) + , mMinSize(minSize) { } @@ -84,12 +85,13 @@ public: { float dist = distanceToBox(node->getBoundingBox(), eyePoint); int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); - int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize))); + int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize*mFactor))); return nativeLodLevel <= lodLevel; } private: + float mFactor; float mMinSize; }; @@ -123,8 +125,9 @@ private: class QuadTreeBuilder { public: - QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float minSize) + QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float lodFactor, float minSize) : mStorage(storage) + , mLodFactor(lodFactor) , mMinX(0.f), mMaxX(0.f), mMinY(0.f), mMaxY(0.f) , mMinSize(minSize) , mViewDataMap(viewDataMap) @@ -146,7 +149,7 @@ public: mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY)); mRootNode->setViewDataMap(mViewDataMap); - mRootNode->setLodCallback(new DefaultLodCallback(mMinSize)); + mRootNode->setLodCallback(new DefaultLodCallback(mLodFactor, mMinSize)); addChildren(mRootNode); mRootNode->initNeighbours(); @@ -222,6 +225,7 @@ public: private: Terrain::Storage* mStorage; + float mLodFactor; float mMinX, mMaxX, mMinY, mMaxY; float mMinSize; ViewDataMap* mViewDataMap; @@ -229,13 +233,17 @@ private: osg::ref_ptr mRootNode; }; -QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask) +QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor) : World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) + , mLodFactor(lodFactor) { // No need for culling on the Drawable / Transform level as the quad tree performs the culling already. mChunkManager->setCullingActive(false); + + mChunkManager->setCompositeMapSize(compMapResolution); + mChunkManager->setCompositeMapLevel(compMapLevel); } QuadTreeWorld::~QuadTreeWorld() @@ -402,7 +410,7 @@ void QuadTreeWorld::ensureQuadTreeBuilt() return; const float minSize = 1/8.f; - QuadTreeBuilder builder(mStorage, mViewDataMap.get(), minSize); + QuadTreeBuilder builder(mStorage, mViewDataMap.get(), mLodFactor, minSize); builder.build(); mRootNode = builder.getRootNode(); diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index c166a9cb1d..9c47057c42 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,7 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { public: - QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask=~0, int borderMask=0); + QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor); ~QuadTreeWorld(); void accept(osg::NodeVisitor& nv); @@ -44,6 +44,7 @@ namespace Terrain OpenThreads::Mutex mQuadTreeMutex; bool mQuadTreeBuilt; + float mLodFactor; }; } diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index 687f55e5e3..9d4ac93795 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -12,7 +12,7 @@ Controls whether the engine will use paging and LOD algorithms to load the terra Otherwise, only the terrain of the surrounding cells is loaded. .. note:: - When enabling distant terrain, make sure the 'viewing distance' in the camera section is set to a larger value so + When enabling distant terrain, make sure the 'viewing distance' in the camera section is set to a larger value so that you can actually see the additional terrain. To avoid frame drops as the player moves around, nearby terrain pages are always preloaded in the background, @@ -23,3 +23,36 @@ will still be controlled by cell preloading settings. The distant terrain engine is currently considered experimental and may receive updates and/or further configuration options in the future. The glaring omission of non-terrain objects in the distance somewhat limits this setting's usefulness. + +lod factor +---------- + +:Type: float +:Range: >0 +:Default: 1.0 + +Controls the level of detail if distant terrain is enabled. Higher values increase detail at the cost of performance, lower values reduce detail but increase performance. + +composite map level +------------------- + +:Type: integer +:Range: >= -3 +:Default: 0 + +Controls at what size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures. +With value -3 composite maps are used everywhere. +With value >= 1 the map window will not use composited textures. + +A composite map is a pre-rendered texture that contains all the texture layers combined. Note that resolution of composite maps is currently always fixed at 'composite map resolution', regardless of the resolution of the underlying terrain textures. If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value. + +composite map resolution +------------------------ + +:Type: integer +:Range: >0 +:Default: 512 + +Controls the resolution of composite maps. Larger values result in increased detail, but may take longer to prepare and thus could result in longer loading times and an increased chance of frame drops during play. As with most other texture resolution settings, it's most efficient to use values that are powers of two. + +An easy way to observe changes to loading time is to load a save in an interior next to an exterior door (so it will start preloding terrain) and watch how long it takes for the 'Composite' counter on the F4 panel to fall to zero. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index db3d7e75b1..99d4a4eb59 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -90,6 +90,16 @@ pointers cache size = 40 # If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells distant terrain = false +# Controls the level of detail for distant terrain. Lower values = less detail, higher = more detail, should be > 0 +lod factor = 1.0 + +# Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3. +# Higher value is more detailed textures. +composite map level = 0 + +# Controls the resolution of composite maps. +composite map resolution = 512 + [Fog] # If true, use extended fog parameters for distant terrain not controlled by @@ -236,7 +246,7 @@ barter disposition change is permanent = false # Uses the MCP formula (damage * (strength / 40)) to factor Strength into hand-to-hand combat. # (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and -# 2 means werewolves are ignored) +# 2 means werewolves are ignored) strength influences hand to hand = 0 # Render holstered weapons (with quivers and scabbards), requires modded assets From 03f23b235ae82ef7d324a6a08c22ae3d53d754bb Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 253/410] Optimize terrain QuadTree build --- components/terrain/quadtreenode.cpp | 10 ---------- components/terrain/quadtreenode.hpp | 15 ++++++++++++--- components/terrain/quadtreeworld.cpp | 8 +++++--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 4b4df43659..f8237306ea 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -71,16 +71,6 @@ QuadTreeNode::~QuadTreeNode() { } -QuadTreeNode* QuadTreeNode::getParent() -{ - return mParent; -} - -QuadTreeNode *QuadTreeNode::getChild(unsigned int i) -{ - return static_cast(Group::getChild(i)); -} - QuadTreeNode *QuadTreeNode::getNeighbour(Direction dir) { return mNeighbours[dir]; diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 30e998119f..9c925a4d92 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -35,10 +35,19 @@ namespace Terrain QuadTreeNode(QuadTreeNode* parent, ChildDirection dir, float size, const osg::Vec2f& center); virtual ~QuadTreeNode(); - QuadTreeNode* getParent(); + inline QuadTreeNode* getParent() { return mParent; } + inline QuadTreeNode* getChild(unsigned int i) { return static_cast(Group::getChild(i)); } + inline unsigned int getNumChildren() const { return _children.size(); } - QuadTreeNode* getChild(unsigned int i); - using osg::Group::getNumChildren; + // osg::Group::addChild() does a lot of unrelated stuff, but we just really want to add a child node. + void addChild(QuadTreeNode* child) + { + // QuadTree node should not contain more than 4 child nodes. + // Reserve enough space if this node is supposed to have child nodes. + _children.reserve(4); + _children.push_back(child); + child->addParent(this); + }; /// Returns our direction relative to the parent node, or Root if we are the root node. ChildDirection getDirection() { return mDirection; } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 594b2b755d..b486f8d601 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -158,9 +158,12 @@ public: osg::BoundingBox boundingBox; for (unsigned int i=0; i<4; ++i) { - QuadTreeNode* child = addChild(parent, static_cast(i), halfSize); + osg::ref_ptr child = addChild(parent, static_cast(i), halfSize); if (child) + { boundingBox.expandBy(child->getBoundingBox()); + parent->addChild(child); + } } if (!boundingBox.valid()) @@ -169,7 +172,7 @@ public: parent->setBoundingBox(boundingBox); } - QuadTreeNode* addChild(QuadTreeNode* parent, ChildDirection direction, float size) + osg::ref_ptr addChild(QuadTreeNode* parent, ChildDirection direction, float size) { float halfSize = size/2.f; osg::Vec2f center; @@ -194,7 +197,6 @@ public: osg::ref_ptr node = new QuadTreeNode(parent, direction, size, center); node->setLodCallback(parent->getLodCallback()); node->setViewDataMap(mViewDataMap); - parent->addChild(node); if (node->getSize() > mMinSize) { From 9d44e18af63d63e8959f7afec0b8ad1edf93abdc Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 254/410] Allow to configure terrain vertex LOD --- apps/openmw/mwrender/renderingmanager.cpp | 3 +- components/terrain/quadtreeworld.cpp | 49 ++++++++++++++----- components/terrain/quadtreeworld.hpp | 4 +- .../reference/modding/settings/terrain.rst | 19 +++++++ files/settings-default.cfg | 5 +- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4a96960646..a14039d211 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -299,7 +299,8 @@ namespace MWRender compMapPower = std::max(-3, compMapPower); float compMapLevel = pow(2, compMapPower); const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); - mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor)); + const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain"); + mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor, vertexLodMod)); } else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f531e241f5..a0c353a730 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -233,11 +233,12 @@ private: osg::ref_ptr mRootNode; }; -QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor) +QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod) : World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) , mLodFactor(lodFactor) + , mVertexLodMod(vertexLodMod) { // No need for culling on the Drawable / Transform level as the quad tree performs the culling already. mChunkManager->setCullingActive(false); @@ -293,7 +294,30 @@ void traverseToCell(QuadTreeNode* node, ViewData* vd, int cellX, int cellY) } } -unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) +/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the data set. +unsigned int getVertexLod(QuadTreeNode* node, int vertexLodMod) +{ + int lod = Log2(int(node->getSize())); + if (vertexLodMod > 0) + { + lod = std::max(0, lod-vertexLodMod); + } + else if (vertexLodMod < 0) + { + float size = node->getSize(); + // Stop to simplify at this level since with size = 1 the node already covers the whole cell and has getCellVertices() vertices. + while (size < 1) + { + size *= 2; + vertexLodMod = std::min(0, vertexLodMod+1); + } + lod += std::abs(vertexLodMod); + } + return lod; +} + +/// get the flags to use for stitching in the index buffer so that chunks of different LOD connect seamlessly +unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, ViewData* vd) { unsigned int lodFlags = 0; for (unsigned int i=0; i<4; ++i) @@ -308,7 +332,7 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) neighbour = neighbour->getParent(); int lod = 0; if (neighbour) - lod = Log2(int(neighbour->getSize())); + lod = getVertexLod(neighbour, vertexLodMod); if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are - lod = 0; // neighbours with more detail will do the stitching themselves @@ -321,13 +345,17 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) return lodFlags; } -void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunkManager) +void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, ChunkManager* chunkManager) { + if (!vd->hasChanged() && entry.mRenderingNode) + return; + + int ourLod = getVertexLod(entry.mNode, vertexLodMod); + if (vd->hasChanged()) { // have to recompute the lodFlags in case a neighbour has changed LOD. - int ourLod = Log2(int(entry.mNode->getSize())); - unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vd); + unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vertexLodMod, vd); if (lodFlags != entry.mLodFlags) { entry.mRenderingNode = nullptr; @@ -336,10 +364,7 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk } if (!entry.mRenderingNode) - { - int ourLod = Log2(int(entry.mNode->getSize())); entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags); - } } void QuadTreeWorld::accept(osg::NodeVisitor &nv) @@ -384,7 +409,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); if (entry.mVisible) { @@ -441,7 +466,7 @@ void QuadTreeWorld::cacheCell(View *view, int x, int y) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); } } @@ -460,7 +485,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); } } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 9c47057c42..252f930fa4 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,8 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { public: - QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor); + QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod); + ~QuadTreeWorld(); void accept(osg::NodeVisitor& nv); @@ -45,6 +46,7 @@ namespace Terrain OpenThreads::Mutex mQuadTreeMutex; bool mQuadTreeBuilt; float mLodFactor; + int mVertexLodMod; }; } diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index 9d4ac93795..e14bb1e628 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -24,6 +24,19 @@ The distant terrain engine is currently considered experimental and may receive updates and/or further configuration options in the future. The glaring omission of non-terrain objects in the distance somewhat limits this setting's usefulness. +vertex lod mod +-------------- + +:Type: integer +:Range: any +:Default: 0 + +Controls only the Vertex LOD of the terrain. The amount of terrain chunks and the detail of composite maps is left unchanged. + +Must be changed in increments of 1. Each increment will double (for positive values) or halve (for negative values) the number of vertices rendered. For example: -2 means 4x reduced detail, +3 means 8x increased detail. + +Note this setting will typically not affect near terrain. When set to increase detail, the detail of near terrain can not be increased because the detail is simply not there in the data files, and when set to reduce detail, the detail of near terrain will not be reduced because it was already less detailed than the far terrain (in view relative terms) to begin with. + lod factor ---------- @@ -33,6 +46,12 @@ lod factor Controls the level of detail if distant terrain is enabled. Higher values increase detail at the cost of performance, lower values reduce detail but increase performance. +Note this also changes how the Quad Tree is split. Increasing detail with this setting results in the visible terrain being divided into more chunks, where as reducing detail with this setting would reduce the number of chunks. + +Fewer terrain chunks is faster for rendering, but on the other hand a larger proportion of the entire terrain must be rebuilt when LOD levels change as the camera moves. This could result in frame drops if moving across the map at high speed. + +For this reason, it is not recommended to change this setting if you want to change the LOD. If you want to do that, first try using the 'vertex lod mod' setting to configure the detail of the terrain outlines to your liking and then use 'composite map resolution' to configure the texture detail to your liking. But these settings can only be changed in multiples of two, so you may want to adjust 'lod factor' afterwards for even more fine-tuning. + composite map level ------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 99d4a4eb59..92b76146d0 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -90,9 +90,12 @@ pointers cache size = 40 # If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells distant terrain = false -# Controls the level of detail for distant terrain. Lower values = less detail, higher = more detail, should be > 0 +# Controls how the Quad Tree is split. This affects Vertex LOD, Texture LOD and load times. Values > 1 increase detail, values < 1 reduce detail. lod factor = 1.0 +# Controls only the Vertex LOD. Change in increments of 1, each change doubles (or halves) the number of vertices. Values > 0 increase detail, values < 0 reduce detail. +vertex lod mod = 0 + # Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3. # Higher value is more detailed textures. composite map level = 0 From 56fea4b062ce393959d51aefcb6ae3e9756b8930 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 28 Feb 2019 12:48:04 +0400 Subject: [PATCH 255/410] Add setting to control composite geometry size --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++- components/terrain/chunkmanager.cpp | 3 +- components/terrain/chunkmanager.hpp | 2 + components/terrain/quadtreeworld.cpp | 3 +- components/terrain/quadtreeworld.hpp | 2 +- .../reference/modding/settings/terrain.rst | 48 ++++++++++++++----- files/settings-default.cfg | 3 ++ 7 files changed, 52 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a14039d211..1bbed37404 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -300,7 +300,11 @@ namespace MWRender float compMapLevel = pow(2, compMapPower); const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain"); - mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor, vertexLodMod)); + float maxCompGeometrySize = Settings::Manager::getFloat("max composite geometry size", "Terrain"); + maxCompGeometrySize = std::max(maxCompGeometrySize, 1.f); + mTerrain.reset(new Terrain::QuadTreeWorld( + sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, + compMapResolution, compMapLevel, lodFactor, vertexLodMod, maxCompGeometrySize)); } else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 9e31b9a20e..27d87b0310 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -29,6 +29,7 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T , mCompositeMapRenderer(renderer) , mCompositeMapSize(512) , mCompositeMapLevel(1.f) + , mMaxCompGeometrySize(1.f) , mCullingActive(true) { @@ -85,7 +86,7 @@ osg::ref_ptr ChunkManager::createCompositeMapRTT() void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap) { - if (chunkSize > 1.f) + if (chunkSize > mMaxCompGeometrySize) { createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 83182cf46f..27201864f7 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -35,6 +35,7 @@ namespace Terrain void setCullingActive(bool active) { mCullingActive = active; } void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; } void setCompositeMapLevel(float level) { mCompositeMapLevel = level; } + void setMaxCompositeGeometrySize(float maxCompGeometrySize) { mMaxCompGeometrySize = maxCompGeometrySize; } void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; @@ -59,6 +60,7 @@ namespace Terrain unsigned int mCompositeMapSize; float mCompositeMapLevel; + float mMaxCompGeometrySize; bool mCullingActive; }; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index a0c353a730..e324672ff8 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -233,7 +233,7 @@ private: osg::ref_ptr mRootNode; }; -QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod) +QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize) : World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) @@ -245,6 +245,7 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour mChunkManager->setCompositeMapSize(compMapResolution); mChunkManager->setCompositeMapLevel(compMapLevel); + mChunkManager->setMaxCompositeGeometrySize(maxCompGeometrySize); } QuadTreeWorld::~QuadTreeWorld() diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 252f930fa4..f724c44b1c 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,7 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { public: - QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod); + QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize); ~QuadTreeWorld(); diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index e14bb1e628..e15a0035dd 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -33,9 +33,12 @@ vertex lod mod Controls only the Vertex LOD of the terrain. The amount of terrain chunks and the detail of composite maps is left unchanged. -Must be changed in increments of 1. Each increment will double (for positive values) or halve (for negative values) the number of vertices rendered. For example: -2 means 4x reduced detail, +3 means 8x increased detail. +Must be changed in increments of 1. Each increment will double (for positive values) or halve (for negative values) the number of vertices rendered. +For example: -2 means 4x reduced detail, +3 means 8x increased detail. -Note this setting will typically not affect near terrain. When set to increase detail, the detail of near terrain can not be increased because the detail is simply not there in the data files, and when set to reduce detail, the detail of near terrain will not be reduced because it was already less detailed than the far terrain (in view relative terms) to begin with. +Note this setting will typically not affect near terrain. When set to increase detail, the detail of near terrain can not be increased +because the detail is simply not there in the data files, and when set to reduce detail, +the detail of near terrain will not be reduced because it was already less detailed than the far terrain (in view relative terms) to begin with. lod factor ---------- @@ -44,13 +47,21 @@ lod factor :Range: >0 :Default: 1.0 -Controls the level of detail if distant terrain is enabled. Higher values increase detail at the cost of performance, lower values reduce detail but increase performance. +Controls the level of detail if distant terrain is enabled. +Higher values increase detail at the cost of performance, lower values reduce detail but increase performance. -Note this also changes how the Quad Tree is split. Increasing detail with this setting results in the visible terrain being divided into more chunks, where as reducing detail with this setting would reduce the number of chunks. +Note: it also changes how the Quad Tree is split. +Increasing detail with this setting results in the visible terrain being divided into more chunks, +where as reducing detail with this setting would reduce the number of chunks. -Fewer terrain chunks is faster for rendering, but on the other hand a larger proportion of the entire terrain must be rebuilt when LOD levels change as the camera moves. This could result in frame drops if moving across the map at high speed. +Fewer terrain chunks is faster for rendering, but on the other hand a larger proportion of the entire terrain +must be rebuilt when LOD levels change as the camera moves. +This could result in frame drops if moving across the map at high speed. -For this reason, it is not recommended to change this setting if you want to change the LOD. If you want to do that, first try using the 'vertex lod mod' setting to configure the detail of the terrain outlines to your liking and then use 'composite map resolution' to configure the texture detail to your liking. But these settings can only be changed in multiples of two, so you may want to adjust 'lod factor' afterwards for even more fine-tuning. +For this reason, it is not recommended to change this setting if you want to change the LOD. +If you want to do that, first try using the 'vertex lod mod' setting to configure the detail of the terrain outlines +to your liking and then use 'composite map resolution' to configure the texture detail to your liking. +But these settings can only be changed in multiples of two, so you may want to adjust 'lod factor' afterwards for even more fine-tuning. composite map level ------------------- @@ -59,11 +70,13 @@ composite map level :Range: >= -3 :Default: 0 -Controls at what size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures. +Controls at which minimum size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures. With value -3 composite maps are used everywhere. -With value >= 1 the map window will not use composited textures. -A composite map is a pre-rendered texture that contains all the texture layers combined. Note that resolution of composite maps is currently always fixed at 'composite map resolution', regardless of the resolution of the underlying terrain textures. If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value. +A composite map is a pre-rendered texture that contains all the texture layers combined. +Note that resolution of composite maps is currently always fixed at 'composite map resolution', +regardless of the resolution of the underlying terrain textures. +If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value. composite map resolution ------------------------ @@ -72,6 +85,19 @@ composite map resolution :Range: >0 :Default: 512 -Controls the resolution of composite maps. Larger values result in increased detail, but may take longer to prepare and thus could result in longer loading times and an increased chance of frame drops during play. As with most other texture resolution settings, it's most efficient to use values that are powers of two. +Controls the resolution of composite maps. Larger values result in increased detail, +but may take longer to prepare and thus could result in longer loading times and an increased chance of frame drops during play. +As with most other texture resolution settings, it's most efficient to use values that are powers of two. -An easy way to observe changes to loading time is to load a save in an interior next to an exterior door (so it will start preloding terrain) and watch how long it takes for the 'Composite' counter on the F4 panel to fall to zero. +An easy way to observe changes to loading time is to load a save in an interior next to an exterior door +(so it will start preloding terrain) and watch how long it takes for the 'Composite' counter on the F4 panel to fall to zero. + +max composite geometry size +--------------------------- + +:Type: float +:Range: >=1.0 +:Default: 4.0 + +Controls the maximum size of simple composite geometry chunk in cell units. With small values there will more draw calls and small textures, +but higher values create more overdraw (not every texture layer is used everywhere). diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 92b76146d0..d3f5c6a2e8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -103,6 +103,9 @@ composite map level = 0 # Controls the resolution of composite maps. composite map resolution = 512 +# Controls the maximum size of composite geometry, should be >= 1.0. With low values there will be many small chunks, with high values - lesser count of bigger chunks. +max composite geometry size = 4.0 + [Fog] # If true, use extended fog parameters for distant terrain not controlled by From 909d25320eabb63d73afd29f2af254c5f5fbec7f Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 1 Mar 2019 21:12:57 +0300 Subject: [PATCH 256/410] Remove duplicated option --- docs/source/reference/modding/settings/navigator.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index ab174e45c2..0b952a9159 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -215,15 +215,6 @@ triangles per chunk Maximum number of triangles in each node of mesh AABB tree. -recast scale factor -------------------- - -:Type: floating point -:Range: > 0.0 -:Default: 0.013 - -Scale of nav mesh coordinates to world coordinates. - Expert Recastnavigation related settings **************************************** From 298af7f6a69dc349609abdbd1a1056ab73996550 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 1 Mar 2019 21:13:06 +0300 Subject: [PATCH 257/410] Fix links --- docs/source/reference/modding/settings/navigator.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index 0b952a9159..1b65c35a85 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -218,7 +218,7 @@ Maximum number of triangles in each node of mesh AABB tree. Expert Recastnavigation related settings **************************************** -This section is for OpenMW developers who knows about Recastnavigation `_ library and understands how it works. +This section is for OpenMW developers who knows about `Recastnavigation `_ library and understands how it works. cell height ----------- @@ -320,7 +320,7 @@ max polygons per tile Maximum number of polygons per nav mesh tile. Maximum number of nav mesh tiles depends on this value. 22 bits is a limit to store both tile identifier and polygon identifier (tiles = 2^(22 - log2(polygons))). -See recastnavigation `_ for more details. +See `recastnavigation `_ for more details. max verts per poly ------------------ From 8df8bd3f37eecddfd66edf576dfadaef345ee924 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 2 Mar 2019 13:27:59 +0400 Subject: [PATCH 258/410] Use C++11-style loops in the GUI instead of iterators --- apps/openmw/mwgui/alchemywindow.cpp | 10 ++-- apps/openmw/mwgui/birth.cpp | 20 +++---- apps/openmw/mwgui/charactercreation.cpp | 10 ++-- apps/openmw/mwgui/class.cpp | 43 +++++++-------- apps/openmw/mwgui/console.cpp | 28 ++++++---- apps/openmw/mwgui/containeritemmodel.cpp | 50 ++++++++--------- apps/openmw/mwgui/dialogue.cpp | 48 ++++++++--------- apps/openmw/mwgui/inventoryitemmodel.cpp | 4 +- apps/openmw/mwgui/itemchargeview.cpp | 8 +-- apps/openmw/mwgui/jailscreen.cpp | 8 +-- apps/openmw/mwgui/layout.cpp | 11 ++-- apps/openmw/mwgui/mainmenu.cpp | 26 ++++----- apps/openmw/mwgui/mapwindow.cpp | 46 ++++++++-------- apps/openmw/mwgui/messagebox.cpp | 59 ++++++++++---------- apps/openmw/mwgui/quickkeysmenu.cpp | 14 ++--- apps/openmw/mwgui/race.cpp | 30 +++++------ apps/openmw/mwgui/review.cpp | 30 +++++------ apps/openmw/mwgui/settingswindow.cpp | 17 +++--- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +- apps/openmw/mwgui/spellcreationdialog.cpp | 47 ++++++++-------- apps/openmw/mwgui/spellicons.cpp | 66 +++++++++++++---------- apps/openmw/mwgui/spellview.cpp | 28 +++++----- apps/openmw/mwgui/statswindow.cpp | 18 +++---- apps/openmw/mwgui/tooltips.cpp | 62 ++++++++++----------- apps/openmw/mwgui/tradeitemmodel.cpp | 47 ++++++++-------- apps/openmw/mwgui/tradewindow.cpp | 20 +++---- apps/openmw/mwgui/widgets.cpp | 49 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.cpp | 13 +++-- apps/openmw/mwgui/windowpinnablebase.cpp | 6 +-- 29 files changed, 398 insertions(+), 424 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 4fc2a57a23..9db7a055be 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -238,15 +238,15 @@ namespace MWGui std::set effectIds = mAlchemy->listEffects(); Widgets::SpellEffectList list; unsigned int effectIndex=0; - for (std::set::iterator it2 = effectIds.begin(); it2 != effectIds.end(); ++it2) + for (const MWMechanics::EffectKey& effectKey : effectIds) { Widgets::SpellEffectParams params; - params.mEffectID = it2->mId; - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(it2->mId); + params.mEffectID = effectKey.mId; + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectKey.mId); if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) - params.mSkill = it2->mArg; + params.mSkill = effectKey.mArg; else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - params.mAttribute = it2->mArg; + params.mAttribute = effectKey.mArg; params.mIsConstant = true; params.mNoTarget = true; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index c1867541b3..6f6a621adf 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -145,35 +145,35 @@ namespace MWGui // sort by name std::vector < std::pair > birthSigns; - MWWorld::Store::iterator it = signs.begin(); - for (; it != signs.end(); ++it) + for (const ESM::BirthSign& sign : signs) { - birthSigns.push_back(std::make_pair(it->mId, &(*it))); + birthSigns.push_back(std::make_pair(sign.mId, &sign)); } std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); int index = 0; - for (std::vector >::const_iterator it2 = birthSigns.begin(); - it2 != birthSigns.end(); ++it2, ++index) + for (auto& birthsignPair : birthSigns) { - mBirthList->addItem(it2->second->mName, it2->first); + mBirthList->addItem(birthsignPair.second->mName, birthsignPair.first); if (mCurrentBirthId.empty()) { mBirthList->setIndexSelected(index); - mCurrentBirthId = it2->first; + mCurrentBirthId = birthsignPair.first; } - else if (Misc::StringUtils::ciEqual(it2->first, mCurrentBirthId)) + else if (Misc::StringUtils::ciEqual(birthsignPair.first, mCurrentBirthId)) { mBirthList->setIndexSelected(index); } + + index++; } } void BirthDialog::updateSpells() { - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + for (MyGUI::Widget* widget : mSpellItems) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSpellItems.clear(); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 0d3db87b7e..64b8cb7c68 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -257,19 +257,17 @@ namespace MWGui { std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map::iterator it = attributes.begin(); - it != attributes.end(); ++it) + for (auto& attributePair : attributes) { - mReviewDialog->setAttribute(static_cast (it->first), it->second); + mReviewDialog->setAttribute(static_cast (attributePair.first), attributePair.second); } } { std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map::iterator it = skills.begin(); - it != skills.end(); ++it) + for (auto& skillPair : skills) { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); + mReviewDialog->setSkillValue(static_cast (skillPair.first), skillPair.second); } mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 45abe889ed..a92ad934cd 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -207,25 +207,25 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - std::vector > items; // class id, class name - for (MWWorld::Store::iterator it = store.get().begin(); it != store.get().end(); ++it) + std::vector > items; // class id, class name + for (const ESM::Class& classInfo : store.get()) { - bool playable = (it->mData.mIsPlayable != 0); + bool playable = (classInfo.mData.mIsPlayable != 0); if (!playable) // Only display playable classes continue; - if (store.get().isDynamic(it->mId)) + if (store.get().isDynamic(classInfo.mId)) continue; // custom-made class not relevant for this dialog - items.push_back(std::make_pair(it->mId, it->mName)); + items.push_back(std::make_pair(classInfo.mId, classInfo.mName)); } std::sort(items.begin(), items.end(), sortClasses); int index = 0; - for (std::vector >::const_iterator it = items.begin(); it != items.end(); ++it) + for (auto& itemPair : items) { - const std::string &id = it->first; - mClassList->addItem(it->second, id); + const std::string &id = itemPair.first; + mClassList->addItem(itemPair.second, id); if (mCurrentClassId.empty()) { mCurrentClassId = id; @@ -332,19 +332,17 @@ namespace MWGui void InfoBoxDialog::setButtons(ButtonList &buttons) { - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + for (MyGUI::Button* button : this->mButtons) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(button); } this->mButtons.clear(); // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget MyGUI::Button* button; MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); - ButtonList::const_iterator end = buttons.end(); - for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + for (const std::string &text : buttons) { - const std::string &text = *it; button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); button->getSubWidgetText()->setWordWrap(true); button->setCaption(text); @@ -368,11 +366,10 @@ namespace MWGui void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) { - std::vector::const_iterator end = mButtons.end(); int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + for (MyGUI::Button* button : mButtons) { - if (*it == _sender) + if (button == _sender) { eventButtonSelected(i); return; @@ -430,10 +427,9 @@ namespace MWGui mSkills.push_back(mMinorSkill[i]); } - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + for (Widgets::MWSkillPtr& skill : mSkills) { - (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + skill->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); } setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); @@ -642,14 +638,13 @@ namespace MWGui ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); // Avoid duplicate skills by swapping any skill field that matches the selected one - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + for (Widgets::MWSkillPtr& skill : mSkills) { - if (*it == mAffectedSkill) + if (skill == mAffectedSkill) continue; - if ((*it)->getSkillId() == id) + if (skill->getSkillId() == id) { - (*it)->setSkillId(mAffectedSkill->getSkillId()); + skill->setSkillId(mAffectedSkill->getSkillId()); break; } } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index dc22e4193b..929dffe48c 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -231,11 +231,13 @@ namespace MWGui { int i = 0; printOK(""); - for(std::vector::iterator it=matches.begin(); it < matches.end(); ++it,++i ) + for(std::string& match : matches) { - printOK( *it ); - if( i == 50 ) + if(i == 50) break; + + printOK(match); + i++; } } } @@ -352,15 +354,16 @@ namespace MWGui } /* Iterate through the vector. */ - for(std::vector::iterator it=mNames.begin(); it < mNames.end();++it) { + for(std::string& name : mNames) + { bool string_different=false; /* Is the string shorter than the input string? If yes skip it. */ - if( (*it).length() < tmp.length() ) + if(name.length() < tmp.length()) continue; /* Is the beginning of the string different from the input string? If yes skip it. */ - for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();++iter, ++iter2) { + for( std::string::iterator iter=tmp.begin(), iter2=name.begin(); iter < tmp.end();++iter, ++iter2) { if( Misc::StringUtils::toLower(*iter) != Misc::StringUtils::toLower(*iter2) ) { string_different=true; break; @@ -371,7 +374,7 @@ namespace MWGui continue; /* The beginning of the string matches the input string, save it for the next test. */ - matches.push_back(*it); + matches.push_back(name); } /* There are no matches. Return the unchanged input. */ @@ -399,11 +402,14 @@ namespace MWGui /* Check if all matching strings match further than input. If yes complete to this match. */ int i = tmp.length(); - for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); ++iter, ++i) { - for(std::vector::iterator it=matches.begin(); it < matches.end();++it) { - if( Misc::StringUtils::toLower((*it)[i]) != Misc::StringUtils::toLower(*iter) ) { + for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); ++iter, ++i) + { + for(std::string& match : matches) + { + if(Misc::StringUtils::toLower(match[i]) != Misc::StringUtils::toLower(*iter)) + { /* Append the longest match to the end of the output string*/ - output.append(matches.front().substr( 0, i)); + output.append(matches.front().substr(0, i)); return output; } } diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index d34f15a0a4..5ba5bb0ebc 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -82,9 +82,9 @@ size_t ContainerItemModel::getItemCount() ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item) { size_t i = 0; - for (std::vector::iterator it = mItems.begin(); it != mItems.end(); ++it) + for (ItemStack& itemStack : mItems) { - if (*it == item) + if (itemStack == item) return i; ++i; } @@ -103,29 +103,29 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) { int toRemove = count; - for (std::vector::iterator source = mItemSources.begin(); source != mItemSources.end(); ++source) + for (MWWorld::Ptr& source : mItemSources) { - MWWorld::ContainerStore& store = source->getClass().getContainerStore(*source); + MWWorld::ContainerStore& store = source.getClass().getContainerStore(source); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { if (stacks(*it, item.mBase)) { - toRemove -= store.remove(*it, toRemove, *source); + toRemove -= store.remove(*it, toRemove, source); if (toRemove <= 0) return; } } } - for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + for (MWWorld::Ptr& source : mWorldItems) { - if (stacks(*source, item.mBase)) + if (stacks(source, item.mBase)) { - int refCount = source->getRefData().getCount(); + int refCount = source.getRefData().getCount(); if (refCount - toRemove <= 0) - MWBase::Environment::get().getWorld()->deleteObject(*source); + MWBase::Environment::get().getWorld()->deleteObject(source); else - source->getRefData().setCount(std::max(0, refCount - toRemove)); + source.getRefData().setCount(std::max(0, refCount - toRemove)); toRemove -= refCount; if (toRemove <= 0) return; @@ -138,27 +138,28 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) void ContainerItemModel::update() { mItems.clear(); - for (std::vector::iterator source = mItemSources.begin(); source != mItemSources.end(); ++source) + for (MWWorld::Ptr& source : mItemSources) { - MWWorld::ContainerStore& store = source->getClass().getContainerStore(*source); + MWWorld::ContainerStore& store = source.getClass().getContainerStore(source); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { if (!(*it).getClass().showsInInventory(*it)) continue; - std::vector::iterator itemStack = mItems.begin(); - for (; itemStack != mItems.end(); ++itemStack) + bool found = false; + for (ItemStack& itemStack : mItems) { - if (stacks(*it, itemStack->mBase)) + if (stacks(*it, itemStack.mBase)) { // we already have an item stack of this kind, add to it - itemStack->mCount += it->getRefData().getCount(); + itemStack.mCount += it->getRefData().getCount(); + found = true; break; } } - if (itemStack == mItems.end()) + if (!found) { // no stack yet, create one ItemStack newItem (*it, this, it->getRefData().getCount()); @@ -166,23 +167,24 @@ void ContainerItemModel::update() } } } - for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + for (MWWorld::Ptr& source : mWorldItems) { - std::vector::iterator itemStack = mItems.begin(); - for (; itemStack != mItems.end(); ++itemStack) + bool found = false; + for (ItemStack& itemStack : mItems) { - if (stacks(*source, itemStack->mBase)) + if (stacks(source, itemStack.mBase)) { // we already have an item stack of this kind, add to it - itemStack->mCount += source->getRefData().getCount(); + itemStack.mCount += source.getRefData().getCount(); + found = true; break; } } - if (itemStack == mItems.end()) + if (!found) { // no stack yet, create one - ItemStack newItem (*source, this, source->getRefData().getCount()); + ItemStack newItem (source, this, source.getRefData().getCount()); mItems.push_back(newItem); } } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index dfb2b15b99..6b400c1724 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -184,16 +184,16 @@ namespace MWGui BookTypesetter::Style* style = typesetter->createStyle("", textColours.normal, false); size_t formatted = 0; // points to the first character that is not laid out yet - for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) + for (auto& hyperLink : hyperLinks) { - intptr_t topicId = it->second; + intptr_t topicId = hyperLink.second; BookTypesetter::Style* hotStyle = typesetter->createHotStyle (style, textColours.link, textColours.linkOver, textColours.linkPressed, topicId); - if (formatted < it->first.first) - typesetter->write(style, formatted, it->first.first); - typesetter->write(hotStyle, it->first.first, it->first.second); - formatted = it->first.second; + if (formatted < hyperLink.first.first) + typesetter->write(style, formatted, hyperLink.first.first); + typesetter->write(hotStyle, hyperLink.first.first, hyperLink.first.second); + formatted = hyperLink.first.second; } if (formatted < text.size()) typesetter->write(style, formatted, text.size()); @@ -204,9 +204,8 @@ namespace MWGui keywordSearch->highlightKeywords(text.begin(), text.end(), matches); std::string::const_iterator i = text.begin (); - for (std::vector::iterator it = matches.begin(); it != matches.end(); ++it) + for (KeywordSearchT::Match& match : matches) { - KeywordSearchT::Match match = *it; if (i != match.mBeg) addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ()); @@ -419,13 +418,13 @@ namespace MWGui bool sameActor = (mPtr == actor); if (!sameActor) { - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - delete (*it); + for (DialogueText* text : mHistoryContents) + delete text; mHistoryContents.clear(); mKeywords.clear(); mTopicsList->clear(); - for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) - mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers + for (Link* link : mLinks) + mDeleteLater.push_back(link); // Links are not deleted right away to prevent issues with event handlers mLinks.clear(); } @@ -489,8 +488,8 @@ namespace MWGui void DialogueWindow::updateTopicsPane() { mTopicsList->clear(); - for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) - mDeleteLater.push_back(it->second); + for (auto& linkPair : mTopicLinks) + mDeleteLater.push_back(linkPair.second); mTopicLinks.clear(); mKeywordSearch.clear(); @@ -533,15 +532,15 @@ namespace MWGui mTopicsList->addSeparator(); - for(std::list::iterator it = mKeywords.begin(); it != mKeywords.end(); ++it) + for(std::string& keyword : mKeywords) { - mTopicsList->addItem(*it); + mTopicsList->addItem(keyword); - Topic* t = new Topic(*it); + Topic* t = new Topic(keyword); t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); - mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t; + mTopicLinks[Misc::StringUtils::lowerCase(keyword)] = t; - mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); + mKeywordSearch.seed(Misc::StringUtils::lowerCase(keyword), intptr_t(t)); } mTopicsList->adjustSize(); @@ -563,9 +562,8 @@ namespace MWGui BookTypesetter::Ptr typesetter = BookTypesetter::create (mHistory->getWidth(), std::numeric_limits::max()); - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - (*it)->write(typesetter, &mKeywordSearch, mTopicLinks); - + for (DialogueText* text : mHistoryContents) + text->write(typesetter, &mKeywordSearch, mTopicLinks); BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White, false); @@ -573,9 +571,9 @@ namespace MWGui // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); - for (std::vector >::const_iterator it = mChoices.begin(); it != mChoices.end(); ++it) + for (std::pair& choice : mChoices) { - Choice* link = new Choice(it->second); + Choice* link = new Choice(choice.second); link->eventChoiceActivated += MyGUI::newDelegate(this, &DialogueWindow::onChoiceActivated); mLinks.push_back(link); @@ -583,7 +581,7 @@ namespace MWGui BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, textColours.answerPressed, TypesetBook::InteractiveId(link)); - typesetter->write(questionStyle, to_utf8_span(it->first.c_str())); + typesetter->write(questionStyle, to_utf8_span(choice.first.c_str())); } mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index c9f55d3520..d74819a894 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -37,9 +37,9 @@ size_t InventoryItemModel::getItemCount() ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item) { size_t i = 0; - for (std::vector::iterator it = mItems.begin(); it != mItems.end(); ++it) + for (ItemStack& itemStack : mItems) { - if (*it == item) + if (itemStack == item) return i; ++i; } diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 10c36c73f8..44fa94f3a2 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -130,13 +130,13 @@ namespace MWGui { int currentY = 0; - for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter) + for (Line& line : mLines) { - iter->mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18); + line.mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18); currentY += 19; - iter->mIcon->setCoord(16, currentY, 32, 32); - iter->mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20); + line.mIcon->setCoord(16, currentY, 32, 32); + line.mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20); currentY += 32 + 4; } diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 31f565084a..1ac23f42bc 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -105,12 +105,12 @@ namespace MWGui Misc::StringUtils::replace(message, "%d", std::to_string(mDays).c_str(), 2); - for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) + for (const int& skill : skills) { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->mValue.getString(); - int skillValue = player.getClass().getNpcStats(player).getSkill(*it).getBase(); + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[skill])->mValue.getString(); + int skillValue = player.getClass().getNpcStats(player).getSkill(skill).getBase(); std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString(); - if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) + if (skill == ESM::Skill::Sneak || skill == ESM::Skill::Security) skillMsg = gmst.find("sNotifyMessage39")->mValue.getString(); Misc::StringUtils::replace(skillMsg, "%s", skillName.c_str(), 2); diff --git a/apps/openmw/mwgui/layout.cpp b/apps/openmw/mwgui/layout.cpp index 3035adebbc..ae1c096599 100644 --- a/apps/openmw/mwgui/layout.cpp +++ b/apps/openmw/mwgui/layout.cpp @@ -21,11 +21,11 @@ namespace MWGui mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent); const std::string main_name = mPrefix + MAIN_WINDOW; - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter) + for (MyGUI::Widget* widget : mListWindowRoot) { - if ((*iter)->getName() == main_name) + if (widget->getName() == main_name) { - mMainWidget = (*iter); + mMainWidget = widget; break; } } @@ -66,10 +66,9 @@ namespace MWGui MyGUI::Widget* Layout::getWidget(const std::string &_name) { - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); - iter!=mListWindowRoot.end(); ++iter) + for (MyGUI::Widget* widget : mListWindowRoot) { - MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name); + MyGUI::Widget* find = widget->findWidget(mPrefix + _name); if (nullptr != find) { return find; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 1b9e024ba6..8c06859e44 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -253,36 +253,36 @@ namespace MWGui // Create new buttons if needed std::vector allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; - for (std::vector::iterator it = allButtons.begin(); it != allButtons.end(); ++it) + for (std::string& buttonId : allButtons) { - if (mButtons.find(*it) == mButtons.end()) + if (mButtons.find(buttonId) == mButtons.end()) { Gui::ImageButton* button = mButtonBox->createWidget ("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default); - button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds"); - button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds"); - button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds"); + button->setProperty("ImageHighlighted", "textures\\menu_" + buttonId + "_over.dds"); + button->setProperty("ImageNormal", "textures\\menu_" + buttonId + ".dds"); + button->setProperty("ImagePushed", "textures\\menu_" + buttonId + "_pressed.dds"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); - button->setUserData(std::string(*it)); - mButtons[*it] = button; + button->setUserData(std::string(buttonId)); + mButtons[buttonId] = button; } } // Start by hiding all buttons int maxwidth = 0; - for (std::map::iterator it = mButtons.begin(); it != mButtons.end(); ++it) + for (auto& buttonPair : mButtons) { - it->second->setVisible(false); - MyGUI::IntSize requested = it->second->getRequestedSize(); + buttonPair.second->setVisible(false); + MyGUI::IntSize requested = buttonPair.second->getRequestedSize(); if (requested.width > maxwidth) maxwidth = requested.width; } // Now show and position the ones we want - for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + for (std::string& buttonId : buttons) { - assert(mButtons.find(*it) != mButtons.end()); - Gui::ImageButton* button = mButtons[*it]; + assert(mButtons.find(buttonId) != mButtons.end()); + Gui::ImageButton* button = mButtons[buttonId]; button->setVisible(true); MyGUI::IntSize requested = button->getRequestedSize(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index b9b59965db..f3bdd4c7d0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -312,8 +312,8 @@ namespace MWGui void LocalMapBase::updateCustomMarkers() { - for (std::vector::iterator it = mCustomMarkerWidgets.begin(); it != mCustomMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (MyGUI::Widget* widget : mCustomMarkerWidgets) + MyGUI::Gui::getInstance().destroyWidget(widget); mCustomMarkerWidgets.clear(); for (int dX = -mCellDistance; dX <= mCellDistance; ++dX) @@ -487,9 +487,9 @@ namespace MWGui } int counter = 0; - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + for (const MWWorld::Ptr& ptr : markers) { - const ESM::Position& worldPos = it->getRefData().getPosition(); + const ESM::Position& worldPos = ptr.getRefData().getPosition(); MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, @@ -526,8 +526,8 @@ namespace MWGui void LocalMapBase::updateDoorMarkers() { // clear all previous door markers - for (std::vector::iterator it = mDoorMarkerWidgets.begin(); it != mDoorMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (MyGUI::Widget* widget : mDoorMarkerWidgets) + MyGUI::Gui::getInstance().destroyWidget(widget); mDoorMarkerWidgets.clear(); MWBase::World* world = MWBase::Environment::get().getWorld(); @@ -553,10 +553,8 @@ namespace MWGui // Create a widget for each marker int counter = 0; - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + for (MWBase::World::DoorMarker& marker : doors) { - MWBase::World::DoorMarker marker = *it; - std::vector destNotes; CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter) @@ -589,8 +587,8 @@ namespace MWGui void LocalMapBase::updateMagicMarkers() { // clear all previous markers - for (std::vector::iterator it = mMagicMarkerWidgets.begin(); it != mMagicMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (MyGUI::Widget* widget : mMagicMarkerWidgets) + MyGUI::Gui::getInstance().destroyWidget(widget); mMagicMarkerWidgets.clear(); addDetectionMarkers(MWBase::World::Detect_Creature); @@ -848,9 +846,9 @@ namespace MWGui mGlobalMapRender->cleanupCameras(); - for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) + for (CellId& cellId : mQueuedToExplore) { - mGlobalMapRender->exploreCell(it->first, it->second, mLocalMapRender->getMapTexture(it->first, it->second)); + mGlobalMapRender->exploreCell(cellId.first, cellId.second, mLocalMapRender->getMapTexture(cellId.first, cellId.second)); } mQueuedToExplore.clear(); @@ -888,11 +886,11 @@ namespace MWGui { LocalMapBase::updateCustomMarkers(); - for (std::map, MyGUI::Widget*>::iterator widgetIt = mGlobalMapMarkers.begin(); widgetIt != mGlobalMapMarkers.end(); ++widgetIt) + for (auto& widgetPair : mGlobalMapMarkers) { - int x = widgetIt->first.first; - int y = widgetIt->first.second; - MyGUI::Widget* markerWidget = widgetIt->second; + int x = widgetPair.first.first; + int y = widgetPair.first.second; + MyGUI::Widget* markerWidget = widgetPair.second; setGlobalMapMarkerTooltip(markerWidget, x, y); } } @@ -1017,8 +1015,8 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - for (std::map, MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(it->second); + for (auto& widgetPair : mGlobalMapMarkers) + MyGUI::Gui::getInstance().destroyWidget(widgetPair.second); mGlobalMapMarkers.clear(); } @@ -1043,11 +1041,11 @@ namespace MWGui mGlobalMapRender->read(map); - for (std::set::iterator it = map.mMarkers.begin(); it != map.mMarkers.end(); ++it) + for (const ESM::GlobalMap::CellId& cellId : map.mMarkers) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first, it->second); + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(cellId.first, cellId.second); if (cell && !cell->mName.empty()) - addVisitedLocation(cell->mName, it->first, it->second); + addVisitedLocation(cell->mName, cellId.first, cellId.second); } } } @@ -1057,8 +1055,8 @@ namespace MWGui NoDrop::setAlpha(alpha); // can't allow showing map with partial transparency, as the fog of war will also go transparent // and reveal parts of the map you shouldn't be able to see - for (std::vector::iterator it = mMapWidgets.begin(); it != mMapWidgets.end(); ++it) - (*it)->setVisible(alpha == 1); + for (MyGUI::ImageBox* widget : mMapWidgets) + widget->setVisible(alpha == 1); } void MapWindow::customMarkerCreated(MyGUI::Widget *marker) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6c2d85dd9e..d64ec9c37a 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -28,10 +28,9 @@ namespace MWGui MessageBoxManager::~MessageBoxManager () { - std::vector::iterator it(mMessageBoxes.begin()); - for (; it != mMessageBoxes.end(); ++it) + for (MessageBox* messageBox : mMessageBoxes) { - delete *it; + delete messageBox; } } @@ -50,12 +49,11 @@ namespace MWGui mInterMessageBoxe = nullptr; } - std::vector::iterator it(mMessageBoxes.begin()); - for (; it != mMessageBoxes.end(); ++it) + for (MessageBox* messageBox : mMessageBoxes) { - if (*it == mStaticMessageBox) + if (messageBox == mStaticMessageBox) mStaticMessageBox = nullptr; - delete *it; + delete messageBox; } mMessageBoxes.clear(); @@ -81,9 +79,9 @@ namespace MWGui it = mMessageBoxes.begin(); while(it != mMessageBoxes.end()) { - (*it)->update(static_cast(height)); - height += (*it)->getHeight(); - ++it; + (*it)->update(static_cast(height)); + height += (*it)->getHeight(); + ++it; } if(mInterMessageBoxe != nullptr && mInterMessageBoxe->mMarkedToDelete) { @@ -114,10 +112,10 @@ namespace MWGui } int height = 0; - for(std::vector::iterator it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + for (MessageBox* messageBox : mMessageBoxes) { - (*it)->update(height); - height += (*it)->getHeight(); + messageBox->update(height); + height += messageBox->getHeight(); } } @@ -240,14 +238,14 @@ namespace MWGui int buttonHeight = 0; MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - for(std::vector::const_iterator it = buttons.begin(); it != buttons.end(); ++it) + for(const std::string& buttonId : buttons) { MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, std::string("MW_Button"), dummyCoord, MyGUI::Align::Default); - button->setCaptionWithReplacing(*it); + button->setCaptionWithReplacing(buttonId); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); @@ -300,16 +298,16 @@ namespace MWGui MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2; - for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) + for(MyGUI::Button* button : mButtons) { buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; - buttonSize.width = (*button)->getTextSize().width + 2*buttonLabelLeftPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonLabelTopPadding; + buttonSize.width = button->getTextSize().width + 2*buttonLabelLeftPadding; + buttonSize.height = button->getTextSize().height + 2*buttonLabelTopPadding; - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); + button->setCoord(buttonCord); + button->setSize(buttonSize); left += buttonSize.width + buttonLeftPadding; } @@ -329,16 +327,16 @@ namespace MWGui int top = textPadding + textSize.height + textButtonPadding; - for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) + for(MyGUI::Button* button : mButtons) { - buttonSize.width = (*button)->getTextSize().width + buttonLabelLeftPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonLabelTopPadding*2; + buttonSize.width = button->getTextSize().width + buttonLabelLeftPadding*2; + buttonSize.height = button->getTextSize().height + buttonLabelTopPadding*2; buttonCord.top = top; buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2; - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); + button->setCoord(buttonCord); + button->setSize(buttonSize); top += buttonSize.height + buttonTopPadding; } @@ -368,13 +366,13 @@ namespace MWGui MyGUI::Widget* InteractiveMessageBox::getDefaultKeyFocus() { std::vector keywords { "sOk", "sYes" }; - for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) + for(MyGUI::Button* button : mButtons) { for (const std::string& keyword : keywords) { - if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), (*button)->getCaption())) + if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), button->getCaption())) { - return *button; + return button; } } } @@ -390,10 +388,9 @@ namespace MWGui { mMarkedToDelete = true; int index = 0; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(const MyGUI::Button* button : mButtons) { - if(*button == pressed) + if(button == pressed) { mButtonPressed = index; mMessageBoxManager.onButtonPressed(mButtonPressed); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 23ad87fd68..6ac1f2b63f 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -540,32 +540,32 @@ namespace MWGui MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); int i=0; - for (std::vector::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it) + for (ESM::QuickKeys::QuickKey& quickKey : keys.mKeys) { if (i >= 10) return; mSelected = &mKey[i]; - switch (it->mType) + switch (quickKey.mType) { case Type_Magic: - if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mId)) - onAssignMagic(it->mId); + if (MWBase::Environment::get().getWorld()->getStore().get().search(quickKey.mId)) + onAssignMagic(quickKey.mId); break; case Type_Item: case Type_MagicItem: { // Find the item by id - MWWorld::Ptr item = store.findReplacement(it->mId); + MWWorld::Ptr item = store.findReplacement(quickKey.mId); if (item.isEmpty()) unassign(mSelected); else { - if (it->mType == Type_Item) + if (quickKey.mType == Type_Item) onAssignItem(item); - else // if (it->mType == Type_MagicItem) + else // if (quickKey.mType == Type_MagicItem) onAssignMagicItem(item); } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index be0dff6600..cf69ecca38 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -290,9 +290,8 @@ namespace MWGui const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); - for (MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + for (const ESM::BodyPart& bodypart : store) { - const ESM::BodyPart& bodypart = *it; if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) continue; if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) @@ -353,22 +352,21 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); std::vector > items; // ID, name - MWWorld::Store::iterator it = races.begin(); - for (; it != races.end(); ++it) + for (const ESM::Race& race : races) { - bool playable = it->mData.mFlags & ESM::Race::Playable; + bool playable = race.mData.mFlags & ESM::Race::Playable; if (!playable) // Only display playable races continue; - items.push_back(std::make_pair(it->mId, it->mName)); + items.push_back(std::make_pair(race.mId, race.mName)); } std::sort(items.begin(), items.end(), sortRaces); int index = 0; - for (std::vector >::const_iterator iter = items.begin(); iter != items.end(); ++iter) + for (auto& item : items) { - mRaceList->addItem(iter->second, iter->first); - if (Misc::StringUtils::ciEqual(iter->first, mCurrentRaceId)) + mRaceList->addItem(item.second, item.first); + if (Misc::StringUtils::ciEqual(item.first, mCurrentRaceId)) mRaceList->setIndexSelected(index); ++index; } @@ -376,9 +374,9 @@ namespace MWGui void RaceDialog::updateSkills() { - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + for (MyGUI::Widget* widget : mSkillItems) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSkillItems.clear(); @@ -413,9 +411,9 @@ namespace MWGui void RaceDialog::updateSpellPowers() { - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + for (MyGUI::Widget* widget : mSpellPowerItems) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSpellPowerItems.clear(); @@ -428,11 +426,9 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mCurrentRaceId); - std::vector::const_iterator it = race->mPowers.mList.begin(); - std::vector::const_iterator end = race->mPowers.mList.end(); - for (int i = 0; it != end; ++it) + int i = 0; + for (const std::string& spellpower : race->mPowers.mList) { - const std::string &spellpower = *it; Widgets::MWSpellPtr spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + MyGUI::utility::toString(i)); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index fb8b48a612..e76cbe7706 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -353,9 +353,9 @@ namespace MWGui void ReviewDialog::updateSkillArea() { - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (MyGUI::Widget* skillWidget : mSkillWidgets) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(skillWidget); } mSkillWidgets.clear(); @@ -388,19 +388,18 @@ namespace MWGui attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase(); std::vector selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race); - for (std::vector::iterator iter = selectedSpells.begin(); iter != selectedSpells.end(); ++iter) + for (std::string& spellId : selectedSpells) { - std::string lower = Misc::StringUtils::lowerCase(*iter); + std::string lower = Misc::StringUtils::lowerCase(spellId); if (std::find(spells.begin(), spells.end(), lower) == spells.end()) spells.push_back(lower); } if (race) { - for (std::vector::const_iterator iter = race->mPowers.mList.begin(); - iter != race->mPowers.mList.end(); ++iter) + for (const std::string& spellId : race->mPowers.mList) { - std::string lower = Misc::StringUtils::lowerCase(*iter); + std::string lower = Misc::StringUtils::lowerCase(spellId); if (std::find(spells.begin(), spells.end(), lower) == spells.end()) spells.push_back(lower); } @@ -409,10 +408,9 @@ namespace MWGui if (!mBirthSignId.empty()) { const ESM::BirthSign* sign = MWBase::Environment::get().getWorld()->getStore().get().find(mBirthSignId); - for (std::vector::const_iterator iter = sign->mPowers.mList.begin(); - iter != sign->mPowers.mList.end(); ++iter) + for (const std::string& spellId : sign->mPowers.mList) { - std::string lower = Misc::StringUtils::lowerCase(*iter); + std::string lower = Misc::StringUtils::lowerCase(spellId); if (std::find(spells.begin(), spells.end(), lower) == spells.end()) spells.push_back(lower); } @@ -421,27 +419,27 @@ namespace MWGui if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeAbility", "Abilities"), coord1, coord2); - for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + for (std::string& spellId : spells) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); if (spell->mData.mType == ESM::Spell::ST_Ability) addItem(spell, coord1, coord2); } addSeparator(coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypePower", "Powers"), coord1, coord2); - for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + for (std::string& spellId : spells) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); if (spell->mData.mType == ESM::Spell::ST_Power) addItem(spell, coord1, coord2); } addSeparator(coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeSpell", "Spells"), coord1, coord2); - for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + for (std::string& spellId : spells) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); if (spell->mData.mType == ESM::Spell::ST_Spell) addItem(spell, coord1, coord2); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 7a46f31899..de46c05ef0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -235,11 +235,10 @@ namespace MWGui resolutions.push_back(std::make_pair(mode.w, mode.h)); } std::sort(resolutions.begin(), resolutions.end(), sortResolutions); - for (std::vector < std::pair >::const_iterator it=resolutions.begin(); - it!=resolutions.end(); ++it) + for (std::pair& resolution : resolutions) { - std::string str = MyGUI::utility::toString(it->first) + " x " + MyGUI::utility::toString(it->second) - + " (" + getAspect(it->first,it->second) + ")"; + std::string str = MyGUI::utility::toString(resolution.first) + " x " + MyGUI::utility::toString(resolution.second) + + " (" + getAspect(resolution.first, resolution.second) + ")"; if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); @@ -484,17 +483,17 @@ namespace MWGui else actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); - for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) + for (const int& action : actions) { - std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (action); if (desc == "") continue; std::string binding; if(mKeyboardMode) - binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(*it); + binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(action); else - binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); + binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(action); Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); @@ -502,7 +501,7 @@ namespace MWGui Gui::SharedStateButton* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default); rightText->setCaptionWithReplacing(binding); rightText->setTextAlign (MyGUI::Align::Right); - rightText->setUserData(*it); // save the action id for callbacks + rightText->setUserData(action); // save the action id for callbacks rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction); rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index bc5d161d83..5fb361579d 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -122,9 +122,9 @@ namespace MWGui std::stable_sort(spellsToSort.begin(), spellsToSort.end(), sortSpells); - for (std::vector::iterator it = spellsToSort.begin() ; it != spellsToSort.end(); ++it) + for (const ESM::Spell* spell : spellsToSort) { - addSpell(**it); + addSpell(*spell); } spellsToSort.clear(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 46d8b38ecb..23f24e321f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -455,10 +455,8 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + for (const ESM::ENAMstruct& effect : mEffects) { - const ESM::ENAMstruct& effect = *it; - y += std::max(1.f, MWMechanics::calcEffectCost(effect)); if (effect.mRange == ESM::RT_Target) @@ -530,18 +528,17 @@ namespace MWGui if (spell->mData.mType != ESM::Spell::ST_Spell) continue; - const std::vector& list = spell->mEffects.mList; - for (std::vector::const_iterator it2 = list.begin(); it2 != list.end(); ++it2) + for (const ESM::ENAMstruct& effectInfo : spell->mEffects.mList) { - const ESM::MagicEffect * effect = MWBase::Environment::get().getWorld()->getStore().get().find(it2->mEffectID); + const ESM::MagicEffect * effect = MWBase::Environment::get().getWorld()->getStore().get().find(effectInfo.mEffectID); // skip effects that do not allow spellmaking/enchanting int requiredFlags = (mType == Spellmaking) ? ESM::MagicEffect::AllowSpellmaking : ESM::MagicEffect::AllowEnchanting; if (!(effect->mData.mFlags & requiredFlags)) continue; - if (std::find(knownEffects.begin(), knownEffects.end(), it2->mEffectID) == knownEffects.end()) - knownEffects.push_back(it2->mEffectID); + if (std::find(knownEffects.begin(), knownEffects.end(), effectInfo.mEffectID) == knownEffects.end()) + knownEffects.push_back(effectInfo.mEffectID); } } @@ -550,23 +547,23 @@ namespace MWGui mAvailableEffectsList->clear (); int i=0; - for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) + for (const short effectId : knownEffects) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( - ESM::MagicEffect::effectIdToString (*it))->mValue.getString()); - mButtonMapping[i] = *it; + ESM::MagicEffect::effectIdToString(effectId))->mValue.getString()); + mButtonMapping[i] = effectId; ++i; } mAvailableEffectsList->adjustSize (); mAvailableEffectsList->scrollToTop(); - for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) + for (const short effectId : knownEffects) { std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( - ESM::MagicEffect::effectIdToString (*it))->mValue.getString(); + ESM::MagicEffect::effectIdToString(effectId))->mValue.getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); - ToolTips::createMagicEffectToolTip (w, *it); + ToolTips::createMagicEffectToolTip (w, effectId); } mEffects.clear(); @@ -646,9 +643,9 @@ namespace MWGui } else { - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + for (const ESM::ENAMstruct& effectInfo : mEffects) { - if (it->mEffectID == mSelectedKnownEffectId) + if (effectInfo.mEffectID == mSelectedKnownEffectId) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}"); return; @@ -680,17 +677,17 @@ namespace MWGui MyGUI::IntSize size(0,0); int i = 0; - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + for (const ESM::ENAMstruct& effectInfo : mEffects) { Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; + params.mEffectID = effectInfo.mEffectID; + params.mSkill = effectInfo.mSkill; + params.mAttribute = effectInfo.mAttribute; + params.mDuration = effectInfo.mDuration; + params.mMagnMin = effectInfo.mMagnMin; + params.mMagnMax = effectInfo.mMagnMax; + params.mRange = effectInfo.mRange; + params.mArea = effectInfo.mArea; params.mIsConstant = mConstantEffect; MyGUI::Button* button = mUsedEffectsView->createWidget("", MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c0f56e654e..c1bd421dba 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -65,10 +65,11 @@ namespace MWGui int w=2; - for (std::map >::const_iterator it = effects.begin(); it != effects.end(); ++it) + for (auto& effectInfoPair : effects) { + const int effectId = effectInfoPair.first; const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld ()->getStore ().get().find(it->first); + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectId); float remainingDuration = 0; float totalDuration = 0; @@ -77,46 +78,50 @@ namespace MWGui static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get().find("fMagicStartIconBlink")->mValue.getFloat(); - for (std::vector::const_iterator effectIt = it->second.begin(); - effectIt != it->second.end(); ++effectIt) + std::vector& effectInfos = effectInfoPair.second; + bool addNewLine = true; + for (const MagicEffectInfo& effectInfo : effectInfos) { - if (effectIt != it->second.begin()) + if (addNewLine) + { sourcesDescription += "\n"; + addNewLine = false; + } // if at least one of the effect sources is permanent, the effect will never wear off - if (effectIt->mPermanent) + if (effectInfo.mPermanent) { remainingDuration = fadeTime; totalDuration = fadeTime; } else { - remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime); - totalDuration = std::max(totalDuration, effectIt->mTotalTime); + remainingDuration = std::max(remainingDuration, effectInfo.mRemainingTime); + totalDuration = std::max(totalDuration, effectInfo.mTotalTime); } - sourcesDescription += effectIt->mSource; + sourcesDescription += effectInfo.mSource; if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) sourcesDescription += " (" + MWBase::Environment::get().getWindowManager()->getGameSettingString( - ESM::Skill::sSkillNameIds[effectIt->mKey.mArg], "") + ")"; + ESM::Skill::sSkillNameIds[effectInfo.mKey.mArg], "") + ")"; if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) sourcesDescription += " (" + MWBase::Environment::get().getWindowManager()->getGameSettingString( - ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")"; + ESM::Attribute::sGmstAttributeIds[effectInfo.mKey.mArg], "") + ")"; ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType(); if (displayType == ESM::MagicEffect::MDT_TimesInt) { std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", ""); std::stringstream formatter; - formatter << std::fixed << std::setprecision(1) << " " << (effectIt->mMagnitude / 10.0f) << timesInt; + formatter << std::fixed << std::setprecision(1) << " " << (effectInfo.mMagnitude / 10.0f) << timesInt; sourcesDescription += formatter.str(); } else if ( displayType != ESM::MagicEffect::MDT_None ) { - sourcesDescription += ": " + MyGUI::utility::toString(effectIt->mMagnitude); + sourcesDescription += ": " + MyGUI::utility::toString(effectInfo.mMagnitude); if ( displayType == ESM::MagicEffect::MDT_Percentage ) sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); @@ -124,32 +129,35 @@ namespace MWGui sourcesDescription += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", ""); else if ( displayType == ESM::MagicEffect::MDT_Level ) { - sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? + sourcesDescription += " " + ((effectInfo.mMagnitude > 1) ? MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", "") ); } else // ESM::MagicEffect::MDT_Points { - sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? + sourcesDescription += " " + ((effectInfo.mMagnitude > 1) ? MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } } - if (effectIt->mRemainingTime > -1 && + if (effectInfo.mRemainingTime > -1 && Settings::Manager::getBool("show effect duration","Game")) { sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { + float duration = effectInfo.mRemainingTime; + if (duration > 3600) + { int hour = duration / 3600; duration -= hour*3600; sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; } - if (duration > 60) { + if (duration > 60) + { int minute = duration / 60; duration -= minute*60; sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; } - if (duration > 0.1) { + if (duration > 0.1) + { sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; } } @@ -158,15 +166,15 @@ namespace MWGui if (remainingDuration > 0.f) { MyGUI::ImageBox* image; - if (mWidgetMap.find(it->first) == mWidgetMap.end()) + if (mWidgetMap.find(effectId) == mWidgetMap.end()) { image = parent->createWidget ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); - mWidgetMap[it->first] = image; + mWidgetMap[effectId] = image; image->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); - std::string name = ESM::MagicEffect::effectIdToString (it->first); + std::string name = ESM::MagicEffect::effectIdToString (effectId); ToolTipInfo tooltipInfo; tooltipInfo.caption = "#{" + name + "}"; @@ -178,7 +186,7 @@ namespace MWGui image->setUserString("ToolTipType", "ToolTipInfo"); } else - image = mWidgetMap[it->first]; + image = mWidgetMap[effectId]; image->setPosition(w,2); image->setVisible(true); @@ -191,9 +199,9 @@ namespace MWGui if (totalDuration >= fadeTime && fadeTime > 0.f) image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); } - else if (mWidgetMap.find(it->first) != mWidgetMap.end()) + else if (mWidgetMap.find(effectId) != mWidgetMap.end()) { - mWidgetMap[it->first]->setVisible(false); + mWidgetMap[effectId]->setVisible(false); } } @@ -208,10 +216,10 @@ namespace MWGui } // hide inactive effects - for (std::map::iterator it = mWidgetMap.begin(); it != mWidgetMap.end(); ++it) + for (auto& widgetPair : mWidgetMap) { - if (effects.find(it->first) == effects.end()) - it->second->setVisible(false); + if (effects.find(widgetPair.first) == effects.end()) + widgetPair.second->setVisible(false); } } diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 879ce471f0..f03c1cedbd 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -149,13 +149,13 @@ namespace MWGui mModel->update(); bool fullUpdateRequired = false; SpellModel::ModelIndex maxSpellIndexFound = -1; - for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) + for (LineInfo& line : mLines) { // only update the lines that are "updateable" - SpellModel::ModelIndex spellIndex(it->mSpellIndex); + SpellModel::ModelIndex spellIndex(line.mSpellIndex); if (spellIndex != NoSpellIndex) { - Gui::SharedStateButton* nameButton = reinterpret_cast(it->mLeftWidget); + Gui::SharedStateButton* nameButton = reinterpret_cast(line.mLeftWidget); // match model against line // if don't match, then major change has happened, so do a full update @@ -176,7 +176,7 @@ namespace MWGui else { maxSpellIndexFound = spellIndex; - Gui::SharedStateButton* costButton = reinterpret_cast(it->mRightWidget); + Gui::SharedStateButton* costButton = reinterpret_cast(line.mRightWidget); if ((costButton != nullptr) && (costButton->getCaption() != spell.mCostColumn)) { costButton->setCaption(spell.mCostColumn); @@ -198,27 +198,25 @@ namespace MWGui void SpellView::layoutWidgets() { int height = 0; - for (std::vector< LineInfo >::iterator it = mLines.begin(); - it != mLines.end(); ++it) + for (LineInfo& line : mLines) { - height += (it->mLeftWidget)->getHeight(); + height += line.mLeftWidget->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); int width = mScrollView->getWidth() - (scrollVisible ? 18 : 0); height = 0; - for (std::vector< LineInfo >::iterator it = mLines.begin(); - it != mLines.end(); ++it) + for (LineInfo& line : mLines) { - int lineHeight = (it->mLeftWidget)->getHeight(); - (it->mLeftWidget)->setCoord(4, height, width - 8, lineHeight); - if (it->mRightWidget) + int lineHeight = line.mLeftWidget->getHeight(); + line.mLeftWidget->setCoord(4, height, width - 8, lineHeight); + if (line.mRightWidget) { - (it->mRightWidget)->setCoord(4, height, width - 8, lineHeight); - MyGUI::TextBox* second = (it->mRightWidget)->castType(false); + line.mRightWidget->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = line.mRightWidget->castType(false); if (second) - (it->mLeftWidget)->setSize(width - 8 - second->getTextSize().width, lineHeight); + line.mLeftWidget->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 862660fc7a..fdc7bb6d20 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -433,10 +433,8 @@ namespace MWGui addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + for (const int skillId : skills) { - int skillId = *it; if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; @@ -499,9 +497,9 @@ namespace MWGui { mChanged = false; - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (MyGUI::Widget* widget : mSkillWidgets) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSkillWidgets.clear(); @@ -550,11 +548,11 @@ namespace MWGui const std::set &expelled = PCstats.getExpelled(); bool firstFaction=true; - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + for (auto& factionPair : mFactions) { + const std::string& factionId = factionPair.first; const ESM::Faction *faction = - store.get().find(it->first); + store.get().find(factionId); if (faction->mData.mIsHidden == 1) continue; @@ -575,11 +573,11 @@ namespace MWGui text += std::string("#{fontcolourhtml=header}") + faction->mName; - if (expelled.find(it->first) != expelled.end()) + if (expelled.find(factionId) != expelled.end()) text += "\n#{fontcolourhtml=normal}#{sExpelled}"; else { - int rank = it->second; + int rank = factionPair.second; rank = std::max(0, std::min(9, rank)); text += std::string("\n#{fontcolourhtml=normal}") + faction->mRanks[rank]; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a1879c2f91..f9775253ac 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -226,18 +226,17 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); info.caption = spell->mName; Widgets::SpellEffectList effects; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + for (const ESM::ENAMstruct& spellEffect : spell->mEffects.mList) { Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; + params.mEffectID = spellEffect.mEffectID; + params.mSkill = spellEffect.mSkill; + params.mAttribute = spellEffect.mAttribute; + params.mDuration = spellEffect.mDuration; + params.mMagnMin = spellEffect.mMagnMin; + params.mMagnMax = spellEffect.mMagnMax; + params.mRange = spellEffect.mRange; + params.mArea = spellEffect.mArea; params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); params.mNoTarget = false; effects.push_back(params); @@ -260,14 +259,13 @@ namespace MWGui tooltip->setVisible(true); std::map userStrings = focus->getUserStrings(); - for (std::map::iterator it = userStrings.begin(); - it != userStrings.end(); ++it) + for (auto& userStringPair : userStrings) { - size_t underscorePos = it->first.find("_"); + size_t underscorePos = userStringPair.first.find("_"); if (underscorePos == std::string::npos) continue; - std::string key = it->first.substr(0, underscorePos); - std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + std::string key = userStringPair.first.substr(0, underscorePos); + std::string widgetName = userStringPair.first.substr(underscorePos+1, userStringPair.first.size()-(underscorePos+1)); type = "Property"; size_t caretPos = key.find("^"); @@ -280,9 +278,9 @@ namespace MWGui MyGUI::Widget* w; getWidget(w, widgetName); if (type == "Property") - w->setProperty(key, it->second); + w->setProperty(key, userStringPair.second); else if (type == "UserData") - w->setUserString(key, it->second); + w->setUserString(key, userStringPair.second); } tooltipSize = tooltip->getSize(); @@ -458,7 +456,7 @@ namespace MWGui MyGUI::IntSize totalSize = MyGUI::IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - for (std::vector::const_iterator it = info.notes.begin(); it != info.notes.end(); ++it) + for (const std::string& note : info.notes) { MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); @@ -468,7 +466,7 @@ namespace MWGui MyGUI::Align::Default); edit->setEditMultiLine(true); edit->setEditWordWrap(true); - edit->setCaption(*it); + edit->setCaption(note); edit->setSize(edit->getWidth(), edit->getTextSize().height); icon->setPosition(icon->getLeft(),(edit->getTop()+edit->getBottom())/2-icon->getHeight()/2); totalSize.height += std::max(edit->getHeight(), icon->getHeight()); @@ -653,12 +651,12 @@ namespace MWGui std::vector > itemOwners = MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); - for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) + for (std::pair& owner : itemOwners) { - if (it->second == std::numeric_limits::max()) - ret += std::string("\nStolen from ") + it->first; // for legacy (ESS) savegames + if (owner.second == std::numeric_limits::max()) + ret += std::string("\nStolen from ") + owner.first; // for legacy (ESS) savegames else - ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + ret += std::string("\nStolen ") + MyGUI::utility::toString(owner.second) + " from " + owner.first; } ret += getMiscString(cellref.getGlobalVariable(), "Global"); @@ -732,17 +730,16 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); bool isFirst = true; - MWWorld::Store::iterator it = skills.begin(); - for (; it != skills.end(); ++it) + for (auto& skillPair : skills) { - if (it->second.mData.mSpecialization == specId) + if (skillPair.second.mData.mSpecialization == specId) { if (isFirst) isFirst = false; else specText += "\n"; - specText += std::string("#{") + ESM::Skill::sSkillNameIds[it->first] + "}"; + specText += std::string("#{") + ESM::Skill::sSkillNameIds[skillPair.first] + "}"; } } widget->setUserString("Caption_ColumnText", specText); @@ -767,9 +764,8 @@ namespace MWGui std::vector abilities, powers, spells; - for (std::vector::const_iterator it = sign->mPowers.mList.begin(); it != sign->mPowers.mList.end(); ++it) + for (const std::string& spellId : sign->mPowers.mList) { - const std::string &spellId = *it; const ESM::Spell *spell = store.get().search(spellId); if (!spell) continue; // Skip spells which cannot be found @@ -797,15 +793,15 @@ namespace MWGui for (int category = 0; category < 3; ++category) { - for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + bool addHeader = true; + for (const std::string& spellId : categories[category].spells) { - if (it == categories[category].spells.begin()) + if (addHeader) { text += std::string("\n\n#{fontcolourhtml=header}") + std::string("#{") + categories[category].label + "}"; + addHeader = false; } - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().find(spellId); text += "\n#{fontcolourhtml=normal}" + spell->mName; } diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index a26294a0e7..84b23ee2b6 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -36,13 +36,12 @@ namespace MWGui void TradeItemModel::borrowImpl(const ItemStack &item, std::vector &out) { - std::vector::iterator it = out.begin(); bool found = false; - for (; it != out.end(); ++it) + for (ItemStack& itemStack : out) { - if (it->mBase == item.mBase) + if (itemStack.mBase == item.mBase) { - it->mCount += item.mCount; + itemStack.mCount += item.mCount; found = true; break; } @@ -100,15 +99,15 @@ namespace MWGui void TradeItemModel::adjustEncumbrance(float &encumbrance) { - for (std::vector::iterator it = mBorrowedToUs.begin(); it != mBorrowedToUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedToUs) { - MWWorld::Ptr item = it->mBase; - encumbrance += item.getClass().getWeight(item) * it->mCount; + MWWorld::Ptr& item = itemStack.mBase; + encumbrance += item.getClass().getWeight(item) * itemStack.mCount; } - for (std::vector::iterator it = mBorrowedFromUs.begin(); it != mBorrowedFromUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedFromUs) { - MWWorld::Ptr item = it->mBase; - encumbrance -= item.getClass().getWeight(item) * it->mCount; + MWWorld::Ptr& item = itemStack.mBase; + encumbrance -= item.getClass().getWeight(item) * itemStack.mCount; } encumbrance = std::max(0.f, encumbrance); } @@ -126,15 +125,14 @@ namespace MWGui void TradeItemModel::transferItems() { - std::vector::iterator it = mBorrowedToUs.begin(); - for (; it != mBorrowedToUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedToUs) { // get index in the source model - ItemModel* sourceModel = it->mCreator; + ItemModel* sourceModel = itemStack.mCreator; size_t i=0; for (; igetItemCount(); ++i) { - if (it->mBase == sourceModel->getItem(i).mBase) + if (itemStack.mBase == sourceModel->getItem(i).mBase) break; } if (i == sourceModel->getItemCount()) @@ -142,9 +140,9 @@ namespace MWGui const ItemStack& item = sourceModel->getItem(i); // copy the borrowed items to our model - copyItem(item, it->mCount); + copyItem(item, itemStack.mCount); // then remove them from the source model - sourceModel->removeItem(item, it->mCount); + sourceModel->removeItem(item, itemStack.mCount); } mBorrowedToUs.clear(); mBorrowedFromUs.clear(); @@ -189,14 +187,13 @@ namespace MWGui } // don't show items that we borrowed to someone else - std::vector::iterator it = mBorrowedFromUs.begin(); - for (; it != mBorrowedFromUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedFromUs) { - if (it->mBase == item.mBase) + if (itemStack.mBase == item.mBase) { - if (item.mCount < it->mCount) + if (item.mCount < itemStack.mCount) throw std::runtime_error("Lent more items than present"); - item.mCount -= it->mCount; + item.mCount -= itemStack.mCount; } } @@ -205,12 +202,10 @@ namespace MWGui } // add items borrowed to us - std::vector::iterator it = mBorrowedToUs.begin(); - for (; it != mBorrowedToUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedToUs) { - ItemStack item = *it; - item.mType = ItemStack::Type_Barter; - mItems.push_back(item); + itemStack.mType = ItemStack::Type_Barter; + mItems.push_back(itemStack); } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index b21257eaf7..b197ecef65 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -106,9 +106,9 @@ namespace MWGui // Also restock any containers owned by this merchant, which are also available to buy in the trade window std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources); - for (std::vector::iterator it = itemSources.begin(); it != itemSources.end(); ++it) + for (MWWorld::Ptr& source : itemSources) { - it->getClass().restock(*it); + source.getClass().restock(source); } } @@ -306,15 +306,15 @@ namespace MWGui } // check if the player is attempting to sell back an item stolen from this actor - for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) + for (ItemStack& itemStack : merchantBought) { - if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr)) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(itemStack.mBase.getCellRef().getRefId(), mPtr)) { std::string msg = gmst.find("sNotifyMessage49")->mValue.getString(); - Misc::StringUtils::replace(msg, "%s", it->mBase.getClass().getName(it->mBase).c_str(), 2); + Misc::StringUtils::replace(msg, "%s", itemStack.mBase.getClass().getName(itemStack.mBase).c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, itemStack.mBase, mPtr, itemStack.mCount); onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); @@ -469,15 +469,15 @@ namespace MWGui int merchantOffer = 0; std::vector playerBorrowed = playerTradeModel->getItemsBorrowedToUs(); - for (std::vector::const_iterator it = playerBorrowed.begin(); it != playerBorrowed.end(); ++it) + for (const ItemStack& itemStack : playerBorrowed) { - merchantOffer -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(it->mBase, it->mCount), true); + merchantOffer -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(itemStack.mBase, itemStack.mCount), true); } std::vector merchantBorrowed = mTradeModel->getItemsBorrowedToUs(); - for (std::vector::const_iterator it = merchantBorrowed.begin(); it != merchantBorrowed.end(); ++it) + for (const ItemStack& itemStack : merchantBorrowed) { - merchantOffer += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(it->mBase, it->mCount), false); + merchantOffer += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(itemStack.mBase, itemStack.mCount), false); } int diff = merchantOffer - mCurrentMerchantOffer; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index c90d540721..093824d4bd 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -222,18 +222,17 @@ namespace MWGui const ESM::Spell *spell = store.get().search(mId); MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + for (const ESM::ENAMstruct& effectInfo : spell->mEffects.mList) { MWSpellEffectPtr effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; + params.mEffectID = effectInfo.mEffectID; + params.mSkill = effectInfo.mSkill; + params.mAttribute = effectInfo.mAttribute; + params.mDuration = effectInfo.mDuration; + params.mMagnMin = effectInfo.mMagnMin; + params.mMagnMax = effectInfo.mMagnMax; + params.mRange = effectInfo.mRange; params.mIsConstant = (flags & MWEffectList::EF_Constant) != 0; params.mNoTarget = (flags & MWEffectList::EF_NoTarget); effect->setSpellEffect(params); @@ -289,13 +288,12 @@ namespace MWGui MWSpellEffectPtr effect = nullptr; int maxwidth = coord.width; - for (SpellEffectList::iterator it=mEffectList.begin(); - it != mEffectList.end(); ++it) + for (auto& effectInfo : mEffectList) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; - it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; - effect->setSpellEffect(*it); + effectInfo.mIsConstant = (flags & EF_Constant) || effectInfo.mIsConstant; + effectInfo.mNoTarget = (flags & EF_NoTarget) || effectInfo.mNoTarget; + effect->setSpellEffect(effectInfo); effects.push_back(effect); if (effect->getRequestedWidth() > maxwidth) maxwidth = effect->getRequestedWidth(); @@ -304,9 +302,9 @@ namespace MWGui } // ... then adjust the size for all widgets - for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + for (MyGUI::Widget* effectWidget : effects) { - effect = (*it)->castType(); + effect = effectWidget->castType(); bool needcenter = center && (maxwidth > effect->getRequestedWidth()); int diff = maxwidth - effect->getRequestedWidth(); if (needcenter) @@ -339,18 +337,17 @@ namespace MWGui SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) { SpellEffectList result; - std::vector::const_iterator end = effects->mList.end(); - for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) + for (const ESM::ENAMstruct& effectInfo : effects->mList) { SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; + params.mEffectID = effectInfo.mEffectID; + params.mSkill = effectInfo.mSkill; + params.mAttribute = effectInfo.mAttribute; + params.mDuration = effectInfo.mDuration; + params.mMagnMin = effectInfo.mMagnMin; + params.mMagnMax = effectInfo.mMagnMax; + params.mRange = effectInfo.mRange; + params.mArea = effectInfo.mArea; result.push_back(params); } return result; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b3b8eec75f..badfa2f3c6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -670,9 +670,9 @@ namespace MWGui // Delete any dialogs which are no longer in use if (!mGarbageDialogs.empty()) { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + for (Layout* widget : mGarbageDialogs) { - delete *it; + delete widget; } mGarbageDialogs.clear(); } @@ -1211,14 +1211,13 @@ namespace MWGui { mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); - for (Settings::CategorySettingVector::const_iterator it = changed.begin(); - it != changed.end(); ++it) + for (const auto& setting : changed) { - if (it->first == "HUD" && it->second == "crosshair") + if (setting.first == "HUD" && setting.second == "crosshair") mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); - else if (it->first == "GUI" && it->second == "subtitles") + else if (setting.first == "GUI" && setting.second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); - else if (it->first == "GUI" && it->second == "menu transparency") + else if (setting.first == "GUI" && setting.second == "menu transparency") setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } } diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 271d4e3a85..88e88b4944 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -16,10 +16,10 @@ namespace MWGui MyGUI::Button* button = nullptr; MyGUI::VectorWidgetPtr widgets = window->getSkinWidgetsByName("Action"); - for (MyGUI::VectorWidgetPtr::iterator it = widgets.begin(); it != widgets.end(); ++it) + for (MyGUI::Widget* widget : widgets) { - if ((*it)->isUserString("HideWindowOnDoubleClick")) - button = (*it)->castType(); + if (widget->isUserString("HideWindowOnDoubleClick")) + button = widget->castType(); } if (button) From 00ab552184432536ad6514ff9968d4ea61a7e88e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Feb 2019 20:14:18 +0400 Subject: [PATCH 259/410] Add more settings to water reflections in exteriors (feature #4859) --- CHANGELOG.md | 1 + apps/openmw/mwclass/activator.cpp | 6 +++- apps/openmw/mwclass/door.cpp | 6 +++- apps/openmw/mwclass/static.cpp | 6 +++- apps/openmw/mwgui/settingswindow.cpp | 15 +++++++++- apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwrender/localmap.cpp | 4 +-- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/vismask.hpp | 17 ++++++----- apps/openmw/mwrender/water.cpp | 29 ++++++++++++++----- apps/openmw/mwrender/water.hpp | 1 + .../reference/modding/settings/water.rst | 19 +++++++----- files/mygui/openmw_settings_window.layout | 13 +++++---- files/settings-default.cfg | 4 +-- 14 files changed, 88 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fad734ec04..beef1c79fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Feature #4730: Native animated containers support Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch + Feature #4859: Make water reflections more configurable Feature #4887: Add openmw command option to set initial random seed Feature #4890: Make Distant Terrain configurable Task #4686: Upgrade media decoder to a more current FFmpeg API diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index ab38515c27..eabac16447 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -18,6 +19,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/vismask.hpp" #include "../mwgui/tooltips.hpp" @@ -29,8 +31,10 @@ namespace MWClass void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model, true); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 78aadb05ba..c47399fe7e 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -24,6 +25,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwrender/animation.hpp" +#include "../mwrender/vismask.hpp" #include "../mwmechanics/actorutil.hpp" @@ -53,8 +55,10 @@ namespace MWClass void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model, true); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 40a6b998cf..a6e4fe5e79 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,6 +1,7 @@ #include "static.hpp" #include +#include #include "../mwworld/ptr.hpp" #include "../mwphysics/physicssystem.hpp" @@ -8,14 +9,17 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/vismask.hpp" namespace MWClass { void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 7a46f31899..68e606ee74 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -193,6 +193,7 @@ namespace MWGui getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); getWidget(mWaterTextureSize, "WaterTextureSize"); + getWidget(mWaterReflectionDetail, "WaterReflectionDetail"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -216,6 +217,7 @@ namespace MWGui mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); + mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged); mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); @@ -249,7 +251,7 @@ namespace MWGui std::string tmip = Settings::Manager::getString("texture mipmap", "General"); mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); - int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); + int waterTextureSize = Settings::Manager::getInt("rtt size", "Water"); if (waterTextureSize >= 512) mWaterTextureSize->setIndexSelected(0); if (waterTextureSize >= 1024) @@ -257,6 +259,10 @@ namespace MWGui if (waterTextureSize >= 2048) mWaterTextureSize->setIndexSelected(2); + int waterReflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + waterReflectionDetail = std::min(3, std::max(0, waterReflectionDetail)); + mWaterReflectionDetail->setIndexSelected(waterReflectionDetail); + mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); mKeyboardSwitch->setStateSelected(true); @@ -336,6 +342,13 @@ namespace MWGui apply(); } + void SettingsWindow::onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos) + { + unsigned int level = std::min((unsigned int)3, (unsigned int)pos); + Settings::Manager::setInt("reflection detail", "Water", level); + apply(); + } + void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index c6e48819c0..37d671a5aa 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -33,6 +33,7 @@ namespace MWGui MyGUI::Widget* mAnisotropyBox; MyGUI::ComboBox* mWaterTextureSize; + MyGUI::ComboBox* mWaterReflectionDetail; // controls MyGUI::ScrollView* mControlsBox; @@ -52,6 +53,7 @@ namespace MWGui void highlightCurrentResolution(); void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); + void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index a7f9247f71..1060a5c0b2 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -178,7 +178,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object); + camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object | Mask_Static); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -380,7 +380,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object); + computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object | Mask_Static); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1bbed37404..038438f326 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -243,7 +243,7 @@ namespace MWRender int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; if (Settings::Manager::getBool("object shadows", "Shadows")) - shadowCastingTraversalMask |= Mask_Object; + shadowCastingTraversalMask |= (Mask_Object|Mask_Static); mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 1d94b4bf9d..f9f9dc74ca 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -34,25 +34,26 @@ namespace MWRender Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), Mask_Object = (1<<10), + Mask_Static = (1<<11), // child of Sky - Mask_Sun = (1<<11), - Mask_WeatherParticles = (1<<12), + Mask_Sun = (1<<12), + Mask_WeatherParticles = (1<<13), // top level masks - Mask_Scene = (1<<13), - Mask_GUI = (1<<14), + Mask_Scene = (1<<14), + Mask_GUI = (1<<15), // Set on a ParticleSystem Drawable - Mask_ParticleSystem = (1<<15), + Mask_ParticleSystem = (1<<16), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<16), + Mask_RenderToTexture = (1<<17), - Mask_PreCompile = (1<<17), + Mask_PreCompile = (1<<18), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<18) + Mask_Lighting = (1<<19) }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 376924d82d..e5c2be95d9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -225,7 +225,7 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("RefractionCamera"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Static|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -307,7 +307,7 @@ private: class Reflection : public osg::Camera { public: - Reflection() + Reflection(bool isInterior) { setRenderOrder(osg::Camera::PRE_RENDER); setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -316,9 +316,13 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("ReflectionCamera"); - bool reflectActors = Settings::Manager::getBool("reflect actors", "Water"); - - setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); + unsigned int reflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + reflectionDetail = std::max((unsigned int)isInterior, reflectionDetail); + unsigned int extraMask = 0; + if(reflectionDetail >= 1) extraMask |= Mask_Static; + if(reflectionDetail >= 2) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object; + if(reflectionDetail >= 3) extraMask |= Mask_Actor; + setCullMask(Mask_Scene|Mask_Terrain|Mask_Sky|Mask_Player|Mask_Lighting|extraMask); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); @@ -405,6 +409,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem , mEnabled(true) , mToggled(true) , mTop(0) + , mInterior(false) { mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); @@ -457,7 +462,7 @@ void Water::updateWaterMaterial() if (Settings::Manager::getBool("shader", "Water")) { - mReflection = new Reflection; + mReflection = new Reflection(mInterior); mReflection->setWaterLevel(mTop); mReflection->setScene(mSceneRoot); mParent->addChild(mReflection); @@ -630,10 +635,20 @@ void Water::setEnabled(bool enabled) void Water::changeCell(const MWWorld::CellStore* store) { - if (store->getCell()->isExterior()) + bool isInterior = !store->getCell()->isExterior(); + bool wasInterior = mInterior; + if (!isInterior) + { mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + mInterior = false; + } else + { mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); + mInterior = true; + } + if(mInterior != wasInterior) + updateWaterMaterial(); // create a new StateSet to prevent threading issues osg::ref_ptr nodeStateSet (new osg::StateSet); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 32a7977d2a..1ad16ca24c 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -70,6 +70,7 @@ namespace MWRender bool mEnabled; bool mToggled; float mTop; + bool mInterior; osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); diff --git a/docs/source/reference/modding/settings/water.rst b/docs/source/reference/modding/settings/water.rst index bd0741da92..b00c3cb9b8 100644 --- a/docs/source/reference/modding/settings/water.rst +++ b/docs/source/reference/modding/settings/water.rst @@ -58,17 +58,22 @@ This setting has no effect if the shader setting is false. This setting can be toggled with the 'Refraction' button in the Water tab of the Video panel of the Options menu. -reflect actors +reflection detail -------------- -:Type: boolean -:Range: True/False -:Default: False +:Type: integer +:Range: 0, 1, 2, 3 +:Default: 1 -This setting controls whether or not NPCs and creatures are drawn in water reflections. -Setting this to true will enable actors in reflections and increase realism with a likely decrease in performance. +Controls what kinds of things are rendered in water reflections. -This setting can be toggled with the 'Reflect actors' button in the Water tab of the Video panel of the Options menu. +0: only terrain and the sky are reflected (acts like level 1 in interiors) +1: statics, activators, and doors are also reflected +2: items, containers, and particles are also reflected +3: actors are also reflected + +The player is always reflected in third-person mode. +This setting can be changed ingame with the "Reflection shader detail" dropdown under the Water tab of the Video panel in the Options menu. small feature culling pixel size -------------------------------- diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2d9c13bc92..cc24adbe35 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -428,13 +428,14 @@ - - - - + + + + + - - + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d3f5c6a2e8..cddf94af95 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -462,8 +462,8 @@ rtt size = 512 # Enable refraction which affects visibility through water plane. refraction = false -# Draw NPCs and creatures on water reflections. -reflect actors = false +# Draw objects on water reflections. +reflection detail = 1 # Overrides the value in '[Camera] small feature culling pixel size' specifically for water reflection/refraction textures. small feature culling pixel size = 20.0 From 9398117ea77c2313b84a82f49383c42af66ad06c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Feb 2019 20:54:01 +0400 Subject: [PATCH 260/410] Allow to do not reflect terrain --- apps/openmw/mwgui/settingswindow.cpp | 4 ++-- apps/openmw/mwrender/water.cpp | 13 +++++++------ docs/source/reference/modding/settings/water.rst | 15 ++++++++------- files/mygui/openmw_settings_window.layout | 3 ++- files/settings-default.cfg | 2 +- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 68e606ee74..aedde7bde8 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -260,7 +260,7 @@ namespace MWGui mWaterTextureSize->setIndexSelected(2); int waterReflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); - waterReflectionDetail = std::min(3, std::max(0, waterReflectionDetail)); + waterReflectionDetail = std::min(4, std::max(0, waterReflectionDetail)); mWaterReflectionDetail->setIndexSelected(waterReflectionDetail); mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); @@ -344,7 +344,7 @@ namespace MWGui void SettingsWindow::onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos) { - unsigned int level = std::min((unsigned int)3, (unsigned int)pos); + unsigned int level = std::min((unsigned int)4, (unsigned int)pos); Settings::Manager::setInt("reflection detail", "Water", level); apply(); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e5c2be95d9..d047130d4a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -316,13 +316,14 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("ReflectionCamera"); - unsigned int reflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); - reflectionDetail = std::max((unsigned int)isInterior, reflectionDetail); + int reflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + reflectionDetail = std::min(4, std::max(isInterior ? 2 : 0, reflectionDetail)); unsigned int extraMask = 0; - if(reflectionDetail >= 1) extraMask |= Mask_Static; - if(reflectionDetail >= 2) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object; - if(reflectionDetail >= 3) extraMask |= Mask_Actor; - setCullMask(Mask_Scene|Mask_Terrain|Mask_Sky|Mask_Player|Mask_Lighting|extraMask); + if(reflectionDetail >= 1) extraMask |= Mask_Terrain; + if(reflectionDetail >= 2) extraMask |= Mask_Static; + if(reflectionDetail >= 3) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object; + if(reflectionDetail >= 4) extraMask |= Mask_Player|Mask_Actor; + setCullMask(Mask_Scene|Mask_Sky|Mask_Lighting|extraMask); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); diff --git a/docs/source/reference/modding/settings/water.rst b/docs/source/reference/modding/settings/water.rst index b00c3cb9b8..3581efb991 100644 --- a/docs/source/reference/modding/settings/water.rst +++ b/docs/source/reference/modding/settings/water.rst @@ -62,17 +62,18 @@ reflection detail -------------- :Type: integer -:Range: 0, 1, 2, 3 -:Default: 1 +:Range: 0, 1, 2, 3, 4 +:Default: 2 Controls what kinds of things are rendered in water reflections. -0: only terrain and the sky are reflected (acts like level 1 in interiors) -1: statics, activators, and doors are also reflected -2: items, containers, and particles are also reflected -3: actors are also reflected +0: only sky is reflected +1: terrain is also reflected +2: statics, activators, and doors are also reflected +3: items, containers, and particles are also reflected +4: actors are also reflected -The player is always reflected in third-person mode. +In interiors the lowest level is 2. This setting can be changed ingame with the "Reflection shader detail" dropdown under the Water tab of the Video panel in the Options menu. small feature culling pixel size diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index cc24adbe35..0e4f6e626e 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -429,10 +429,11 @@ + - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index cddf94af95..e3920a4bf9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -463,7 +463,7 @@ rtt size = 512 refraction = false # Draw objects on water reflections. -reflection detail = 1 +reflection detail = 2 # Overrides the value in '[Camera] small feature culling pixel size' specifically for water reflection/refraction textures. small feature culling pixel size = 20.0 From bf5f68a4d82ba8baf3235a9db58b957f19237d4d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 2 Mar 2019 14:55:42 +0400 Subject: [PATCH 261/410] Replace boost GCD to the homebrew implementation --- apps/launcher/graphicspage.cpp | 13 ++----------- apps/openmw/mwgui/settingswindow.cpp | 12 ++---------- components/CMakeLists.txt | 2 +- components/misc/gcd.hpp | 13 +++++++++++++ 4 files changed, 18 insertions(+), 22 deletions(-) create mode 100644 components/misc/gcd.hpp diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 170f8a8e1c..56cd086807 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,11 +1,5 @@ #include "graphicspage.hpp" -#include -#if BOOST_VERSION >= 106500 -#include -#else -#include -#endif #include #include #include @@ -20,14 +14,11 @@ #include #include +#include QString getAspect(int x, int y) { -#if BOOST_VERSION >= 106500 - int gcd = boost::integer::gcd (x, y); -#else - int gcd = boost::math::gcd (x, y); -#endif + int gcd = Misc::gcd (x, y); int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 7a46f31899..ed36447383 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -8,16 +8,12 @@ #include #include -#if BOOST_VERSION >= 106500 -#include -#else -#include -#endif #include #include #include +#include #include #include @@ -63,11 +59,7 @@ namespace std::string getAspect (int x, int y) { -#if BOOST_VERSION >= 106500 - int gcd = boost::integer::gcd (x, y); -#else - int gcd = boost::math::gcd (x, y); -#endif + int gcd = Misc::gcd (x, y); int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d26a92d448..ed52c8111f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -86,7 +86,7 @@ add_component_dir (esmterrain ) add_component_dir (misc - constants utf8stream stringops resourcehelpers rng messageformatparser weakcache + gcd constants utf8stream stringops resourcehelpers rng messageformatparser weakcache ) add_component_dir (debug diff --git a/components/misc/gcd.hpp b/components/misc/gcd.hpp new file mode 100644 index 0000000000..fd9e972e7a --- /dev/null +++ b/components/misc/gcd.hpp @@ -0,0 +1,13 @@ +#ifndef MISC_GCD_H +#define MISC_GCD_H + +namespace Misc +{ + // TODO: replace to the std::gcd() when the C++17 will be available. + int gcd(int a, int b) + { + return b == 0 ? a : gcd(b, a % b); + } +} + +#endif From 7b6f41c5c316bf0a6f2186ecc3b3a377d6fd633e Mon Sep 17 00:00:00 2001 From: Perry Hugh Date: Sat, 2 Mar 2019 14:28:26 +0000 Subject: [PATCH 262/410] Correct gamepad default bindings to exactly match vanilla XBOX, create fair interplay between toggling main menu and options menu, allow toggling menus at any time. --- apps/openmw/mwinput/inputmanagerimp.cpp | 43 ++++++++++++++++--------- apps/openmw/mwinput/inputmanagerimp.hpp | 3 ++ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f071baaba8..e875064080 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -289,6 +289,9 @@ namespace MWInput case A_GameMenu: toggleMainMenu (); break; + case A_OptionsMenu: + toggleOptionsMenu(); + break; case A_Screenshot: screenshot(); break; @@ -1042,19 +1045,29 @@ namespace MWInput void InputManager::toggleMainMenu() { - if (MyGUI::InputManager::getInstance().isModalAny()) { - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + bool state = MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + + if (mode == MWGui::GM_Settings || (!state && mode == MWGui::GM_MainMenu)) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + if(state || mode == MWGui::GM_MainMenu) + return; + + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); + } + + void InputManager::toggleOptionsMenu() + { + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + if (mode == MWGui::GM_Settings) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); return; } + else if (mode == MWGui::GM_MainMenu && !(MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame)) + MWBase::Environment::get().getWindowManager()->popGuiMode(); - if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); - } - else //Close current GUI - { - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); - } + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); } void InputManager::quickLoad() { @@ -1415,12 +1428,12 @@ namespace MWInput defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; - defaultButtonBindings[A_QuickKeysMenu] = SDL_CONTROLLER_BUTTON_BACK; // Ideally a new menu, A_QuickButtonsMenu should be implemented with only 4 quick keys. + defaultButtonBindings[A_OptionsMenu] = SDL_CONTROLLER_BUTTON_BACK; defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; - defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; - defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; - defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; - defaultButtonBindings[A_QuickKey4] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP; + defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + defaultButtonBindings[A_MoveBackward] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + defaultButtonBindings[A_MoveRight] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; std::map defaultAxisBindings; defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY; diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index c383e544df..9ac331a6ae 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -229,6 +229,7 @@ namespace MWInput private: void toggleMainMenu(); + void toggleOptionsMenu(); void toggleSpell(); void toggleWeapon(); void toggleInventory(); @@ -321,6 +322,8 @@ namespace MWInput A_MoveForwardBackward, A_MoveLeftRight, + A_OptionsMenu, + A_Last // Marker for the last item }; }; From 2f38e4fbb38109f776c3863dcd41a6b300bc75d6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 2 Mar 2019 20:01:42 +0300 Subject: [PATCH 263/410] Fix enchanted item icon update --- apps/openmw/mwgui/itemwidget.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index ba3039a16b..5ab69e7229 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -156,12 +156,19 @@ namespace MWGui void SpellWidget::setSpellIcon(const std::string& icon) { - if (mFrame) + if (mFrame && !mCurrentFrame.empty()) + { + mCurrentFrame.clear(); mFrame->setImageTexture(""); - if (mItemShadow) - mItemShadow->setImageTexture(icon); - if (mItem) - mItem->setImageTexture(icon); + } + if (mCurrentIcon != icon) + { + mCurrentIcon = icon; + if (mItemShadow) + mItemShadow->setImageTexture(icon); + if (mItem) + mItem->setImageTexture(icon); + } } } From 313611b79d6b325d9b9bc061cd2f2184089b7692 Mon Sep 17 00:00:00 2001 From: Perry Hugh Date: Sat, 2 Mar 2019 23:46:48 +0000 Subject: [PATCH 264/410] Analogue Joystick Movement --- apps/openmw/mwinput/inputmanagerimp.cpp | 19 ++++--------------- apps/openmw/mwmechanics/character.cpp | 17 +++++++++++++++++ apps/openmw/mwworld/player.cpp | 10 +++++----- apps/openmw/mwworld/player.hpp | 6 +++--- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e875064080..a09e66b316 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -518,28 +518,17 @@ namespace MWInput // joystick movement float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); - if (xAxis < .5) + if (xAxis != .5) { triedToMove = true; - mPlayer->setLeftRight (-1); - } - else if (xAxis > .5) - { - triedToMove = true; - mPlayer->setLeftRight (1); + mPlayer->setLeftRight((xAxis - 0.5f) * 2); } - if (yAxis < .5) + if (yAxis != .5) { triedToMove = true; mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); - } - else if (yAxis > .5) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); + mPlayer->setForwardBackward((yAxis - 0.5f) * 2 * -1); } else if(mPlayer->getAutoMove()) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cdeeece94e..44a0f87ff4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1956,6 +1956,23 @@ void CharacterController::update(float duration, bool animationOnly) osg::Vec3f rot = cls.getRotationVector(mPtr); speed = cls.getSpeed(mPtr); + if(isPlayer) + { + // Joystick anologue movement. + float xAxis = std::abs(cls.getMovementSettings(mPtr).mPosition[0]); + float yAxis = std::abs(cls.getMovementSettings(mPtr).mPosition[1]); + float analogueMovement = ((xAxis > yAxis) ? xAxis : yAxis); + + // If Strafing, our max speed is slower so multiply by X axis instead. + if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) + analogueMovement = xAxis; + + // 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 && analogueMovement <= 0.5f) + speed *= 2; + + speed *= (analogueMovement); + } vec.x() *= speed; vec.y() *= speed; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a615c9978a..f152b2cae3 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -154,16 +154,16 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); + ptr.getClass().getMovementSettings(ptr).mPosition[1] = value; } - void Player::setLeftRight (int value) + void Player::setLeftRight (float value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings(ptr).mPosition[0] = static_cast(value); + ptr.getClass().getMovementSettings(ptr).mPosition[0] = value; } - void Player::setForwardBackward (int value) + void Player::setForwardBackward (float value) { MWWorld::Ptr ptr = getPlayer(); @@ -172,7 +172,7 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); + ptr.getClass().getMovementSettings(ptr).mPosition[1] = value; } void Player::setUpDown(int value) diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 7f37de0100..e2632f2104 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -42,7 +42,7 @@ namespace MWWorld CellStore* mMarkedCell; bool mAutoMove; - int mForwardBackward; + float mForwardBackward; bool mTeleported; int mCurrentCrimeId; // the id assigned witnesses @@ -94,9 +94,9 @@ namespace MWWorld bool getAutoMove() const; void setAutoMove (bool enable); - void setLeftRight (int value); + void setLeftRight (float value); - void setForwardBackward (int value); + void setForwardBackward (float value); void setUpDown(int value); void setRunState(bool run); From 37f5ab210435ff7a015fc56ae309daba0051230a Mon Sep 17 00:00:00 2001 From: Perry Hugh Date: Sun, 3 Mar 2019 09:21:00 +0000 Subject: [PATCH 265/410] Gamepad controls now sent to keyboard input, excluding joystick. Added right thumbstick button to toggle mouse emulation. --- apps/openmw/mwinput/inputmanagerimp.cpp | 203 +++++++++++++++++++----- apps/openmw/mwinput/inputmanagerimp.hpp | 4 + 2 files changed, 165 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a09e66b316..b904dbcb71 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -62,6 +62,7 @@ namespace MWInput , mTimeIdle(0.f) , mMouseLookEnabled(false) , mGuiCursorEnabled(true) + , mGamepadGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) , mGuiCursorX(0) @@ -195,6 +196,8 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + // Temporary shut-down of this function until deemed necessary. + return; if (SDL_IsTextInputActive()) return; @@ -222,6 +225,96 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); } + bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release=false) + { + // Presumption of GUI mode will be removed in the future. + // MyGUI KeyCodes *may* change. + // Currently button releases are ignored. + if (release) + return false; + + MyGUI::KeyCode key = MyGUI::KeyCode::None; + switch (arg.button) + { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + key = MyGUI::KeyCode::ArrowUp; + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + key = MyGUI::KeyCode::ArrowRight; + break; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + key = MyGUI::KeyCode::ArrowDown; + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + key = MyGUI::KeyCode::ArrowLeft; + break; + case SDL_CONTROLLER_BUTTON_A: + // If we are using the joystick as a GUI mouse, A must be handled via mouse. + if (mGamepadGuiCursorEnabled) + return false; + key = MyGUI::KeyCode::Space; + break; + case SDL_CONTROLLER_BUTTON_B: + if (MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + else + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + return true; + case SDL_CONTROLLER_BUTTON_X: + key = MyGUI::KeyCode::Semicolon; + break; + case SDL_CONTROLLER_BUTTON_Y: + key = MyGUI::KeyCode::Apostrophe; + break; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + key = MyGUI::KeyCode::Period; + break; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + key = MyGUI::KeyCode::Slash; + break; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled; + MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled); + return true; + default: + return false; + } + + // Some keys will work even when Text Input windows/modals are in focus. + if (SDL_IsTextInputActive()) + return false; + + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); + return true; + } + + bool InputManager::gamepadToGuiControl(const SDL_ControllerAxisEvent &arg) + { + switch (arg.axis) + { + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); + break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); + break; + case SDL_CONTROLLER_AXIS_LEFTX: + case SDL_CONTROLLER_AXIS_LEFTY: + case SDL_CONTROLLER_AXIS_RIGHTX: + case SDL_CONTROLLER_AXIS_RIGHTY: + // If we are using the joystick as a GUI mouse, process mouse movement elsewhere. + if (mGamepadGuiCursorEnabled) + return false; + break; + default: + return false; + } + + return true; + } + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { resetIdleTime (); @@ -454,7 +547,7 @@ namespace MWInput updateCursorMode(); - if (mGuiCursorEnabled) + if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled)) { float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; @@ -687,7 +780,7 @@ namespace MWInput mMouseLookEnabled = !guiMode; if (guiMode) MWBase::Environment::get().getWindowManager()->showCrosshair(false); - MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode); + MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode && (mJoystickLastUsed && !mGamepadGuiCursorEnabled)); // if not in gui mode, the camera decides whether to show crosshair or not. } @@ -867,6 +960,8 @@ namespace MWInput if (mGuiCursorEnabled) { + if (!mGamepadGuiCursorEnabled) + mGamepadGuiCursorEnabled = true; // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor mGuiCursorX = static_cast(arg.x) * mInvUiScalingFactor; @@ -912,36 +1007,37 @@ namespace MWInput void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) { - if (!mJoystickEnabled) + if (!mJoystickEnabled || mInputBinder->detectingBindingState()) return; mJoystickLastUsed = true; - bool guiMode = false; - - if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - if(!mInputBinder->detectingBindingState()) + if (gamepadToGuiControl(arg, false)) + return; + else if (mGamepadGuiCursorEnabled) { - guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), - sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; - if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + // Temporary mouse binding until keyboard controls are available: + if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. { - MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); - if (b && b->getEnabled()) + bool mousePressSuccess = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(SDL_BUTTON_LEFT)); + if (MyGUI::InputManager::getInstance().getMouseFocusWidget()) { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); + MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType(false); + if (b && b->getEnabled()) + MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); } + + setPlayerControlsEnabled(!mousePressSuccess); } } } - - setPlayerControlsEnabled(!guiMode); + else + setPlayerControlsEnabled(true); //esc, to leave initial movie screen OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0)); if (!mControlsDisabled) mInputBinder->buttonPressed(deviceID, arg); @@ -949,56 +1045,69 @@ namespace MWInput void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) { - if (!mJoystickEnabled) + if(mInputBinder->detectingBindingState()) + { + mInputBinder->buttonReleased(deviceID, arg); + return; + } + if (!mJoystickEnabled || mControlsDisabled) return; mJoystickLastUsed = true; - if(mInputBinder->detectingBindingState()) - mInputBinder->buttonReleased(deviceID, arg); - else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (gamepadToGuiControl(arg, true)) + return; + else if (mGamepadGuiCursorEnabled) + { + // Temporary mouse binding until keyboard controls are available: + if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. + { + bool mousePressSuccess = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(SDL_BUTTON_LEFT)); + if (mInputBinder->detectingBindingState()) // If the player just triggered binding, don't let button release bind. + return; - if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind - - setPlayerControlsEnabled(!guiMode); - mInputBinder->buttonReleased(deviceID, arg); + setPlayerControlsEnabled(!mousePressSuccess); + } + } } else - mInputBinder->buttonReleased(deviceID, arg); + setPlayerControlsEnabled(true); - ///to escape initial movie + //esc, to leave initial movie screen OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + + mInputBinder->buttonReleased(deviceID, arg); } void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) { - if (!mControlsDisabled && mJoystickEnabled) + if(!mJoystickEnabled || mControlsDisabled) + return; + + mJoystickLastUsed = true; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + gamepadToGuiControl(arg); + } + else + { + if(mPreviewPOVDelay == 1.f && arg.value) // Preview Mode Gamepad Zooming { - mGamepadZoom = 0; - if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && mPreviewPOVDelay == 1.f && arg.value) + if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { mGamepadZoom = static_cast(arg.value / 10000 * 8.5f); return; // Do not propogate event. } - } - - else if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) - { - mGamepadZoom = 0; - if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && mPreviewPOVDelay == 1.f && arg.value) + else if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) { mGamepadZoom = static_cast(-(arg.value / 10000 * 8.5f)); return; // Do not propogate event. } } - - mInputBinder->axisMoved(deviceID, arg); } + mInputBinder->axisMoved(deviceID, arg); } void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) @@ -1038,7 +1147,11 @@ namespace MWInput MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); if (mode == MWGui::GM_Settings || (!state && mode == MWGui::GM_MainMenu)) + { + if (MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); MWBase::Environment::get().getWindowManager()->popGuiMode(); + } if(state || mode == MWGui::GM_MainMenu) return; @@ -1050,11 +1163,17 @@ namespace MWInput MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); if (mode == MWGui::GM_Settings) { + if (MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); MWBase::Environment::get().getWindowManager()->popGuiMode(); return; } else if (mode == MWGui::GM_MainMenu && !(MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame)) + { + if (MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); MWBase::Environment::get().getWindowManager()->popGuiMode(); + } MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9ac331a6ae..8b3253dcd1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -188,6 +188,7 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mGamepadGuiCursorEnabled; bool mDetectingKeyboard; @@ -222,6 +223,9 @@ namespace MWInput void setPlayerControlsEnabled(bool enabled); void handleGuiArrowKey(int action); + // Return true if GUI consumes input. + bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release); + bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg); void updateCursorMode(); From 2b3bc4fe61d7589a34b057382e7045ce93b3b130 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Feb 2019 00:49:32 +0300 Subject: [PATCH 266/410] Add detailed output for osg::Vec3f in tests --- apps/openmw_test_suite/detournavigator/operators.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw_test_suite/detournavigator/operators.hpp b/apps/openmw_test_suite/detournavigator/operators.hpp index 16d8f38f5e..a473632bab 100644 --- a/apps/openmw_test_suite/detournavigator/operators.hpp +++ b/apps/openmw_test_suite/detournavigator/operators.hpp @@ -29,7 +29,10 @@ namespace testing for (const auto& v : value) { std::ostringstream stream; - stream << v; + stream << "osg::Vec3f(" + << std::setprecision(std::numeric_limits::max_exponent10) << v.x() << ", " + << std::setprecision(std::numeric_limits::max_exponent10) << v.y() << ", " + << std::setprecision(std::numeric_limits::max_exponent10) << v.z() << ")"; (*this) << stream.str() << ",\n"; } return (*this) << "}"; From dbf6780dde91f1576664d6500b4cf50a2661b261 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 1 Mar 2019 21:25:25 +0300 Subject: [PATCH 267/410] Update Recastnavigation to 3a619d773deb7e3a15ee215217c825995fe71312 --- extern/recastnavigation/.travis.yml | 90 ++++++--- .../Detour/Include/DetourCommon.h | 22 +++ .../Detour/Include/DetourMath.h | 4 + .../Detour/Source/DetourCommon.cpp | 33 ++-- .../Detour/Source/DetourNavMeshQuery.cpp | 180 +++++++++++++----- .../RecastDemo/CMakeLists.txt | 6 +- 6 files changed, 245 insertions(+), 90 deletions(-) diff --git a/extern/recastnavigation/.travis.yml b/extern/recastnavigation/.travis.yml index 6044cd6b5b..0e63abad13 100644 --- a/extern/recastnavigation/.travis.yml +++ b/extern/recastnavigation/.travis.yml @@ -1,36 +1,72 @@ -sudo: false - language: cpp +branches: + only: + - master + - coverity_scan + - /recast-.*$/ -# Build with gcc and clang. -compiler: - - gcc - - clang - -# Build both debug and release configurations, through use of an environment variable in the build matrix. -env: - - BUILD_TYPE=debug CMAKE_BUILD_TYPE=Debug - - BUILD_TYPE=release CMAKE_BUILD_TYPE=Release +sudo: false addons: apt: - packages: - - libsdl2-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-7 + packages: [ cmake, clang-7, clang-tools-7, gcc-8, g++-8, libsdl2-dev ] -install: - - wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake.tar.gz - - tar -xf premake.tar.gz - - rm premake.tar.gz +matrix: + include: + - name: Recastnavigation (all) on MacOS xcode9.4 + os: osx + osx_image: xcode9.4 + before_install: + - brew update + - brew install sdl2 + if: branch != coverity_scan + - name: Recastnavigation on Ubuntu Xenial GCC-5 + os: linux + dist: xenial + sudo: required + if: branch != coverity_scan + - name: Recastnavigation on Ubuntu Xenial GCC-8 + os: linux + dist: xenial + sudo: required + env: + - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" + if: branch != coverity_scan + - name: Recastnavigation on Ubuntu Xenial GCC-5 using Premake5 + os: linux + dist: xenial + sudo: required + if: branch != coverity_scan + before_install: + - wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake.tar.gz + - tar -xf premake.tar.gz + env: + - PREMAKE=1 + - name: Recastnavigation on Ubuntu Xenial Clang-7 with Static Analysis + os: linux + dist: xenial + sudo: required + env: + - MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" + - ANALYZE="scan-build-7 --force-analyze-debug-code --use-cc clang-7 --use-c++ clang++-7" + if: branch != coverity_scan + compiler: clang + - name: Recastnavigation Coverity Scan + os: linux + dist: xenial + sudo: required + if: branch = coverity_scan -# Run premake to generate makefiles. -# Have to cd into directory and back out since premake5 doesn't appear to accept a directory argument. before_script: - - cd RecastDemo && ../premake5 gmake && cd .. - - mkdir build && cd build && cmake -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} .. && cd .. + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then eval "${MATRIX_EVAL}"; fi + - if [ "${PREMAKE}" = "1" ]; then cd RecastDemo && ../premake5 gmake && cd ..; fi + - if [ "${PREMAKE}" != "1" ]; then mkdir -p build && cd build && ${ANALYZE} cmake ../ && cd ..; fi -# Run make in the directory containing generated makefiles, on the configuration specified by the environment variable. -script: - - make -C RecastDemo/Build/gmake -j$(nproc) config=${BUILD_TYPE} - - RecastDemo/Bin/Tests - - make -C build -j$(nproc) - - cd build && ctest +script: # 2 CPUs on Travis-CI + 1 extra for IO bound process + - if [ "${PREMAKE}" = "1" ]; then make -C RecastDemo/Build/gmake -j3; fi + - if [ "${PREMAKE}" != "1" ]; then make -C build -j3; fi + - if [ "${PREMAKE}" = "1" ]; then RecastDemo/Bin/Tests; fi + - if [ "${PREMAKE}" != "1" ]; then cd build && ctest; fi diff --git a/extern/recastnavigation/Detour/Include/DetourCommon.h b/extern/recastnavigation/Detour/Include/DetourCommon.h index 739858cd9a..113e8c3361 100644 --- a/extern/recastnavigation/Detour/Include/DetourCommon.h +++ b/extern/recastnavigation/Detour/Include/DetourCommon.h @@ -283,6 +283,28 @@ inline bool dtVequal(const float* p0, const float* p1) return d < thr; } +/// Checks that the specified vector's components are all finite. +/// @param[in] v A point. [(x, y, z)] +/// @return True if all of the point's components are finite, i.e. not NaN +/// or any of the infinities. +inline bool dtVisfinite(const float* v) +{ + bool result = + dtMathIsfinite(v[0]) && + dtMathIsfinite(v[1]) && + dtMathIsfinite(v[2]); + + return result; +} + +/// Checks that the specified vector's 2D components are finite. +/// @param[in] v A point. [(x, y, z)] +inline bool dtVisfinite2D(const float* v) +{ + bool result = dtMathIsfinite(v[0]) && dtMathIsfinite(v[2]); + return result; +} + /// Derives the dot product of two vectors on the xz-plane. (@p u . @p v) /// @param[in] u A vector [(x, y, z)] /// @param[in] v A vector [(x, y, z)] diff --git a/extern/recastnavigation/Detour/Include/DetourMath.h b/extern/recastnavigation/Detour/Include/DetourMath.h index 95e14f8843..54af8af095 100644 --- a/extern/recastnavigation/Detour/Include/DetourMath.h +++ b/extern/recastnavigation/Detour/Include/DetourMath.h @@ -8,6 +8,9 @@ Members in this module are wrappers around the standard math library #define DETOURMATH_H #include +// This include is required because libstdc++ has problems with isfinite +// if cmath is included before math.h. +#include inline float dtMathFabsf(float x) { return fabsf(x); } inline float dtMathSqrtf(float x) { return sqrtf(x); } @@ -16,5 +19,6 @@ inline float dtMathCeilf(float x) { return ceilf(x); } inline float dtMathCosf(float x) { return cosf(x); } inline float dtMathSinf(float x) { return sinf(x); } inline float dtMathAtan2f(float y, float x) { return atan2f(y, x); } +inline bool dtMathIsfinite(float x) { return std::isfinite(x); } #endif diff --git a/extern/recastnavigation/Detour/Source/DetourCommon.cpp b/extern/recastnavigation/Detour/Source/DetourCommon.cpp index 41d0d7bd38..3886f14b04 100644 --- a/extern/recastnavigation/Detour/Source/DetourCommon.cpp +++ b/extern/recastnavigation/Detour/Source/DetourCommon.cpp @@ -204,32 +204,31 @@ void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const floa bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h) { float v0[3], v1[3], v2[3]; + dtVsub(v0, c,a); dtVsub(v1, b,a); dtVsub(v2, p,a); - - const float dot00 = dtVdot2D(v0, v0); - const float dot01 = dtVdot2D(v0, v1); - const float dot02 = dtVdot2D(v0, v2); - const float dot11 = dtVdot2D(v1, v1); - const float dot12 = dtVdot2D(v1, v2); - - // Compute barycentric coordinates - const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); - const float u = (dot11 * dot02 - dot01 * dot12) * invDenom; - const float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // Compute scaled barycentric coordinates + float denom = v0[0] * v1[2] - v0[2] * v1[0]; + float u = v1[2] * v2[0] - v1[0] * v2[2]; + float v = v0[0] * v2[2] - v0[2] * v2[0]; + + if (denom < 0) { + denom = -denom; + u = -u; + v = -v; + } // The (sloppy) epsilon is needed to allow to get height of points which // are interpolated along the edges of the triangles. - static const float EPS = 1e-4f; - + float epsilon = - 1e-4f * denom; + // If point lies inside the triangle, return interpolated ycoord. - if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS) - { - h = a[1] + v0[1]*u + v1[1]*v; + if (u >= epsilon && v >= epsilon && (u+v) <= denom - epsilon) { + h = a[1] + (v0[1]*u + v1[1]*v) / denom; return true; } - return false; } diff --git a/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp b/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp index 90999f2f62..c5ef385f95 100644 --- a/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp +++ b/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp @@ -222,7 +222,10 @@ dtStatus dtNavMeshQuery::findRandomPoint(const dtQueryFilter* filter, float (*fr dtPolyRef* randomRef, float* randomPt) const { dtAssert(m_nav); - + + if (!filter || !frand || !randomRef || !randomPt) + return DT_FAILURE | DT_INVALID_PARAM; + // Randomly pick one tile. Assume that all tiles cover roughly the same area. const dtMeshTile* tile = 0; float tsum = 0.0f; @@ -319,8 +322,13 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const f dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + maxRadius < 0 || !dtMathIsfinite(maxRadius) || + !filter || !frand || !randomRef || !randomPt) + { return DT_FAILURE | DT_INVALID_PARAM; + } const dtMeshTile* startTile = 0; const dtPoly* startPoly = 0; @@ -512,6 +520,9 @@ dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, flo return DT_FAILURE | DT_INVALID_PARAM; if (!tile) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite(pos) || !closest) + return DT_FAILURE | DT_INVALID_PARAM; // Off-mesh connections don't have detail polygons. if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) @@ -607,6 +618,9 @@ dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite(pos) || !closest) + return DT_FAILURE | DT_INVALID_PARAM; // Collect vertices. float verts[DT_VERTS_PER_POLYGON*3]; @@ -659,6 +673,9 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite2D(pos)) + return DT_FAILURE | DT_INVALID_PARAM; if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) { @@ -767,6 +784,8 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* halfE if (!nearestRef) return DT_FAILURE | DT_INVALID_PARAM; + + // queryPolygons below will check rest of params dtFindNearestPolyQuery query(this, center); @@ -972,8 +991,12 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* halfExt { dtAssert(m_nav); - if (!center || !halfExtents || !filter || !query) + if (!center || !dtVisfinite(center) || + !halfExtents || !dtVisfinite(halfExtents) || + !filter || !query) + { return DT_FAILURE | DT_INVALID_PARAM; + } float bmin[3], bmax[3]; dtVsub(bmin, center, halfExtents); @@ -1021,14 +1044,20 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, dtAssert(m_nav); dtAssert(m_nodePool); dtAssert(m_openList); - - if (pathCount) - *pathCount = 0; + + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + + *pathCount = 0; // Validate input if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) || - !startPos || !endPos || !filter || maxPath <= 0 || !path || !pathCount) + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || !path || maxPath <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } if (startRef == endRef) { @@ -1263,18 +1292,21 @@ dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef m_query.status = DT_FAILURE; m_query.startRef = startRef; m_query.endRef = endRef; - dtVcopy(m_query.startPos, startPos); - dtVcopy(m_query.endPos, endPos); + if (startPos) + dtVcopy(m_query.startPos, startPos); + if (endPos) + dtVcopy(m_query.endPos, endPos); m_query.filter = filter; m_query.options = options; m_query.raycastLimitSqr = FLT_MAX; - if (!startRef || !endRef) - return DT_FAILURE | DT_INVALID_PARAM; - // Validate input - if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef)) + if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || !filter) + { return DT_FAILURE | DT_INVALID_PARAM; + } // trade quality with performance? if (options & DT_FINDPATH_ANY_ANGLE) @@ -1530,7 +1562,13 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath) { + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *pathCount = 0; + + if (!path || maxPath <= 0) + return DT_FAILURE | DT_INVALID_PARAM; if (dtStatusFailed(m_query.status)) { @@ -1615,12 +1653,13 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize, dtPolyRef* path, int* pathCount, const int maxPath) { + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *pathCount = 0; - - if (existingSize == 0) - { - return DT_FAILURE; - } + + if (!existing || existingSize <= 0 || !path || !pathCount || maxPath <= 0) + return DT_FAILURE | DT_INVALID_PARAM; if (dtStatusFailed(m_query.status)) { @@ -1823,14 +1862,19 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en int* straightPathCount, const int maxStraightPath, const int options) const { dtAssert(m_nav); - + + if (!straightPathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *straightPathCount = 0; - - if (!maxStraightPath) - return DT_FAILURE | DT_INVALID_PARAM; - - if (!path[0]) + + if (!startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !path || pathSize <= 0 || !path[0] || + maxStraightPath <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } dtStatus stat = 0; @@ -2070,13 +2114,19 @@ dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* start dtAssert(m_nav); dtAssert(m_tinyNodePool); + if (!visitedCount) + return DT_FAILURE | DT_INVALID_PARAM; + *visitedCount = 0; - - // Validate input - if (!startRef) - return DT_FAILURE | DT_INVALID_PARAM; - if (!m_nav->isValidPolyRef(startRef)) + + if (!m_nav->isValidPolyRef(startRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || !resultPos || !visited || + maxVisitedSize <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } dtStatus status = DT_SUCCESS; @@ -2484,16 +2534,23 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons dtRaycastHit* hit, dtPolyRef prevRef) const { dtAssert(m_nav); - + + if (!hit) + return DT_FAILURE | DT_INVALID_PARAM; + hit->t = 0; hit->pathCount = 0; hit->pathCost = 0; // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; - if (prevRef && !m_nav->isValidPolyRef(prevRef)) + if (!m_nav->isValidPolyRef(startRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || + (prevRef && !m_nav->isValidPolyRef(prevRef))) + { return DT_FAILURE | DT_INVALID_PARAM; + } float dir[3], curPos[3], lastPos[3]; float verts[DT_VERTS_PER_POLYGON*3+3]; @@ -2735,11 +2792,18 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* dtAssert(m_nodePool); dtAssert(m_openList); - *resultCount = 0; - - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!resultCount) return DT_FAILURE | DT_INVALID_PARAM; + + *resultCount = 0; + + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + radius < 0 || !dtMathIsfinite(radius) || + !filter || maxResult < 0) + { + return DT_FAILURE | DT_INVALID_PARAM; + } m_nodePool->clear(); m_openList->clear(); @@ -2901,8 +2965,18 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v dtAssert(m_nav); dtAssert(m_nodePool); dtAssert(m_openList); - + + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; + + if (!m_nav->isValidPolyRef(startRef) || + !verts || nverts < 3 || + !filter || maxResult < 0) + { + return DT_FAILURE | DT_INVALID_PARAM; + } // Validate input if (!startRef || !m_nav->isValidPolyRef(startRef)) @@ -3088,13 +3162,20 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* { dtAssert(m_nav); dtAssert(m_tinyNodePool); - + + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + radius < 0 || !dtMathIsfinite(radius) || + !filter || maxResult < 0) + { return DT_FAILURE | DT_INVALID_PARAM; - + } + static const int MAX_STACK = 48; dtNode* stack[MAX_STACK]; int nstack = 0; @@ -3301,13 +3382,19 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* const int maxSegments) const { dtAssert(m_nav); + + if (!segmentCount) + return DT_FAILURE | DT_INVALID_PARAM; *segmentCount = 0; - + const dtMeshTile* tile = 0; const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!filter || !segmentVerts || maxSegments < 0) + return DT_FAILURE | DT_INVALID_PARAM; int n = 0; static const int MAX_INTERVAL = 16; @@ -3455,8 +3542,13 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + maxRadius < 0 || !dtMathIsfinite(maxRadius) || + !filter || !hitDist || !hitPos || !hitNormal) + { return DT_FAILURE | DT_INVALID_PARAM; + } m_nodePool->clear(); m_openList->clear(); diff --git a/extern/recastnavigation/RecastDemo/CMakeLists.txt b/extern/recastnavigation/RecastDemo/CMakeLists.txt index ffeac6a4b7..a6a1a7333f 100644 --- a/extern/recastnavigation/RecastDemo/CMakeLists.txt +++ b/extern/recastnavigation/RecastDemo/CMakeLists.txt @@ -38,11 +38,13 @@ endif() add_dependencies(RecastDemo DebugUtils Detour DetourCrowd DetourTileCache Recast) target_link_libraries(RecastDemo ${OPENGL_LIBRARIES} SDL2::SDL2main DebugUtils Detour DetourCrowd DetourTileCache Recast) -install(TARGETS RecastDemo RUNTIME DESTINATION bin) +install(TARGETS RecastDemo + RUNTIME DESTINATION bin + BUNDLE DESTINATION bin) install(DIRECTORY Bin/Meshes DESTINATION bin) install(DIRECTORY Bin/TestCases DESTINATION bin) install(FILES Bin/DroidSans.ttf DESTINATION bin) if (WIN32) install(FILES "${SDL2_RUNTIME_LIBRARY}" DESTINATION bin) -endif() +endif() \ No newline at end of file From 895899b25bb33d0a214e707081685bf6e3668ad5 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 1 Mar 2019 21:43:03 +0300 Subject: [PATCH 268/410] Fix tests --- .../detournavigator/navigator.cpp | 222 +++++++++--------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 8e76b31541..42b69d7f91 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -114,27 +114,27 @@ namespace EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; } @@ -164,27 +164,27 @@ namespace EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; @@ -196,13 +196,13 @@ namespace mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ - osg::Vec3f(-215, 215, 1.87827122211456298828125), + osg::Vec3f(-215, 215, 1.87826788425445556640625), osg::Vec3f(-199.7968292236328125, 191.09100341796875, -3.54876613616943359375), - osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847270965576171875), - osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.40817737579345703125), + osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847843170166015625), + osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.408184051513671875), osg::Vec3f(-154.1872711181640625, 119.36397552490234375, -19.837890625), - osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675952911376953125), - osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6972980499267578125), + osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675991058349609375), + osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6973056793212890625), osg::Vec3f(-108.57772064208984375, 47.636936187744140625, -36.12701416015625), osg::Vec3f(-93.3745269775390625, 23.7279262542724609375, -40.754688262939453125), osg::Vec3f(-78.17134857177734375, -0.18108306825160980224609375, -37.128787994384765625), @@ -210,15 +210,15 @@ namespace osg::Vec3f(-47.764972686767578125, -47.999103546142578125, -30.797946929931640625), osg::Vec3f(-23.852447509765625, -63.196765899658203125, -33.97112274169921875), osg::Vec3f(0.0600789971649646759033203125, -78.39443206787109375, -37.14543914794921875), - osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.7740936279296875), - osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.051288604736328125), - osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.62355804443359375), - osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958160400390625), + osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.774089813232421875), + osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.05129241943359375), + osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.6235561370849609375), + osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958255767822265625), osg::Vec3f(119.6226959228515625, -154.382720947265625, -19.7680912017822265625), - osg::Vec3f(143.53521728515625, -169.58038330078125, -14.3403491973876953125), - osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.91261768341064453125), - osg::Vec3f(191.360260009765625, -199.9757080078125, -3.484879016876220703125), - osg::Vec3f(215, -215, 1.87827455997467041015625), + osg::Vec3f(143.53521728515625, -169.58038330078125, -14.34035205841064453125), + osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.9126186370849609375), + osg::Vec3f(191.360260009765625, -199.9757080078125, -3.4848802089691162109375), + osg::Vec3f(215, -215, 1.87826788425445556640625), })) << mPath; } @@ -247,13 +247,13 @@ namespace mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ - osg::Vec3f(-215, 215, 1.87827122211456298828125), + osg::Vec3f(-215, 215, 1.87826788425445556640625), osg::Vec3f(-199.7968292236328125, 191.09100341796875, -3.54876613616943359375), - osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847270965576171875), - osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.40817737579345703125), + osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847843170166015625), + osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.408184051513671875), osg::Vec3f(-154.1872711181640625, 119.36397552490234375, -19.837890625), - osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675952911376953125), - osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6972980499267578125), + osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675991058349609375), + osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6973056793212890625), osg::Vec3f(-108.57772064208984375, 47.636936187744140625, -36.12701416015625), osg::Vec3f(-93.3745269775390625, 23.7279262542724609375, -40.754688262939453125), osg::Vec3f(-78.17134857177734375, -0.18108306825160980224609375, -37.128787994384765625), @@ -261,15 +261,15 @@ namespace osg::Vec3f(-47.764972686767578125, -47.999103546142578125, -30.797946929931640625), osg::Vec3f(-23.852447509765625, -63.196765899658203125, -33.97112274169921875), osg::Vec3f(0.0600789971649646759033203125, -78.39443206787109375, -37.14543914794921875), - osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.7740936279296875), - osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.051288604736328125), - osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.62355804443359375), - osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958160400390625), + osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.774089813232421875), + osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.05129241943359375), + osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.6235561370849609375), + osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958255767822265625), osg::Vec3f(119.6226959228515625, -154.382720947265625, -19.7680912017822265625), - osg::Vec3f(143.53521728515625, -169.58038330078125, -14.3403491973876953125), - osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.91261768341064453125), - osg::Vec3f(191.360260009765625, -199.9757080078125, -3.484879016876220703125), - osg::Vec3f(215, -215, 1.87827455997467041015625), + osg::Vec3f(143.53521728515625, -169.58038330078125, -14.34035205841064453125), + osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.9126186370849609375), + osg::Vec3f(191.360260009765625, -199.9757080078125, -3.4848802089691162109375), + osg::Vec3f(215, -215, 1.87826788425445556640625), })) << mPath; compoundShape.updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); @@ -283,27 +283,27 @@ namespace EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; } @@ -340,27 +340,27 @@ namespace EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.96328866481781005859375), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -0.2422157227993011474609375), - osg::Vec3f(-174.930633544921875, 174.930633544921875, -2.44772052764892578125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -4.653223514556884765625), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -6.858728885650634765625), - osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -9.0642337799072265625), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -11.26973724365234375), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -0.242215454578399658203125), + osg::Vec3f(-174.930633544921875, 174.930633544921875, -2.447719097137451171875), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -4.65322399139404296875), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -6.858726978302001953125), + osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -9.06423282623291015625), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -11.26973628997802734375), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -13.26497173309326171875), - osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -15.24860286712646484375), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -17.2322368621826171875), - osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -19.2158660888671875), + osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -15.24860477447509765625), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -17.23223876953125), + osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -19.215869903564453125), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -20.1338443756103515625), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -18.150211334228515625), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -18.1502132415771484375), osg::Vec3f(45.450958251953125, -45.450958251953125, -16.1665802001953125), - osg::Vec3f(65.48564910888671875, -65.48564910888671875, -14.18294811248779296875), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -12.19931507110595703125), - osg::Vec3f(105.55503082275390625, -105.55503082275390625, -10.08488559722900390625), - osg::Vec3f(125.5897216796875, -125.5897216796875, -7.879383563995361328125), - osg::Vec3f(145.6244049072265625, -145.6244049072265625, -5.673877239227294921875), - osg::Vec3f(165.659088134765625, -165.659088134765625, -3.4683735370635986328125), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -1.2628715038299560546875), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, 0.9426348209381103515625), + osg::Vec3f(65.48564910888671875, -65.48564910888671875, -14.18294620513916015625), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -12.199314117431640625), + osg::Vec3f(105.55503082275390625, -105.55503082275390625, -10.08488368988037109375), + osg::Vec3f(125.5897216796875, -125.5897216796875, -7.87938022613525390625), + osg::Vec3f(145.6244049072265625, -145.6244049072265625, -5.673875331878662109375), + osg::Vec3f(165.659088134765625, -165.659088134765625, -3.468370914459228515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -1.26286637783050537109375), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, 0.942641556262969970703125), osg::Vec3f(215, -215, 1.96328866481781005859375), })) << mPath; } @@ -399,26 +399,26 @@ namespace osg::Vec3f(-200.8159637451171875, 190.47265625, -0.639537751674652099609375), osg::Vec3f(-186.6319427490234375, 165.9453125, -3.2184507846832275390625), osg::Vec3f(-172.447906494140625, 141.41796875, -5.797363758087158203125), - osg::Vec3f(-158.263885498046875, 116.8906097412109375, -8.37627887725830078125), - osg::Vec3f(-144.079864501953125, 92.3632659912109375, -10.95519161224365234375), - osg::Vec3f(-129.89581298828125, 67.83591461181640625, -13.534107208251953125), + osg::Vec3f(-158.263885498046875, 116.8906097412109375, -8.37627696990966796875), + osg::Vec3f(-144.079864501953125, 92.3632659912109375, -10.9551906585693359375), + osg::Vec3f(-129.89581298828125, 67.83591461181640625, -13.53410625457763671875), osg::Vec3f(-115.7117919921875, 43.308563232421875, -16.1130199432373046875), osg::Vec3f(-101.5277557373046875, 18.7812137603759765625, -18.6919345855712890625), osg::Vec3f(-87.34372711181640625, -5.7461376190185546875, -20.4680538177490234375), osg::Vec3f(-67.02922821044921875, -25.4970550537109375, -20.514247894287109375), - osg::Vec3f(-46.714717864990234375, -45.2479705810546875, -20.5604457855224609375), + osg::Vec3f(-46.714717864990234375, -45.2479705810546875, -20.560443878173828125), osg::Vec3f(-26.40021514892578125, -64.99889373779296875, -20.6066417694091796875), osg::Vec3f(-6.085712432861328125, -84.74980926513671875, -20.652835845947265625), - osg::Vec3f(14.22879505157470703125, -104.50072479248046875, -18.151393890380859375), - osg::Vec3f(39.05098724365234375, -118.16222381591796875, -15.6674861907958984375), - osg::Vec3f(63.87317657470703125, -131.82373046875, -13.18357944488525390625), - osg::Vec3f(88.69537353515625, -145.4852142333984375, -10.69967365264892578125), - osg::Vec3f(113.51757049560546875, -159.146697998046875, -8.21576690673828125), - osg::Vec3f(138.3397674560546875, -172.808197021484375, -5.731858730316162109375), - osg::Vec3f(163.1619720458984375, -186.469696044921875, -3.2479503154754638671875), - osg::Vec3f(187.984161376953125, -200.1311798095703125, -0.764044582843780517578125), - osg::Vec3f(212.8063507080078125, -213.7926788330078125, 1.7198636531829833984375), - osg::Vec3f(215, -215, 1.93937528133392333984375), + osg::Vec3f(14.22879505157470703125, -104.50072479248046875, -18.151397705078125), + osg::Vec3f(39.05098724365234375, -118.16222381591796875, -15.66748714447021484375), + osg::Vec3f(63.87317657470703125, -131.82373046875, -13.18358135223388671875), + osg::Vec3f(88.69537353515625, -145.4852142333984375, -10.699672698974609375), + osg::Vec3f(113.51757049560546875, -159.146697998046875, -8.21576786041259765625), + osg::Vec3f(138.3397674560546875, -172.808197021484375, -5.731859683990478515625), + osg::Vec3f(163.1619720458984375, -186.469696044921875, -3.2479507923126220703125), + osg::Vec3f(187.984161376953125, -200.1311798095703125, -0.764044821262359619140625), + osg::Vec3f(212.8063507080078125, -213.7926788330078125, 1.719865322113037109375), + osg::Vec3f(215, -215, 1.9393787384033203125), })) << mPath; } @@ -507,10 +507,10 @@ namespace osg::Vec3f(0, -68.33331298828125, -143.3333587646484375), osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875), osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375), - osg::Vec3f(0, -153.33331298828125, -117.5942230224609375), - osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625), - osg::Vec3f(0, -209.999969482421875, -97.79712677001953125), - osg::Vec3f(0, -215, -94.753631591796875), + osg::Vec3f(0, -153.33331298828125, -117.59423065185546875), + osg::Vec3f(0, -181.6666412353515625, -107.73915863037109375), + osg::Vec3f(0, -209.999969482421875, -97.7971343994140625), + osg::Vec3f(0, -215, -94.75363922119140625), })) << mPath; } @@ -553,10 +553,10 @@ namespace osg::Vec3f(0, -68.33331298828125, -143.3333587646484375), osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875), osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375), - osg::Vec3f(0, -153.33331298828125, -117.5942230224609375), - osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625), - osg::Vec3f(0, -209.999969482421875, -97.79712677001953125), - osg::Vec3f(0, -215, -94.753631591796875), + osg::Vec3f(0, -153.33331298828125, -117.59423065185546875), + osg::Vec3f(0, -181.6666412353515625, -107.73915863037109375), + osg::Vec3f(0, -209.999969482421875, -97.7971343994140625), + osg::Vec3f(0, -215, -94.75363922119140625), })) << mPath; } @@ -587,8 +587,8 @@ namespace EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), - osg::Vec3f(9.8083515167236328125, 188.4185333251953125, -105.19994354248046875), - osg::Vec3f(19.6167049407958984375, 161.837066650390625, -114.25496673583984375), + osg::Vec3f(9.8083515167236328125, 188.4185333251953125, -105.199951171875), + osg::Vec3f(19.6167049407958984375, 161.837066650390625, -114.25495147705078125), osg::Vec3f(29.42505645751953125, 135.255615234375, -123.309967041015625), osg::Vec3f(39.23340606689453125, 108.674163818359375, -132.3649749755859375), osg::Vec3f(49.04175567626953125, 82.09270477294921875, -137.2874755859375), @@ -601,9 +601,9 @@ namespace osg::Vec3f(64.8477935791015625, -104.598602294921875, -137.840911865234375), osg::Vec3f(50.497714996337890625, -129.0291748046875, -131.45831298828125), osg::Vec3f(36.147632598876953125, -153.459747314453125, -121.42321014404296875), - osg::Vec3f(21.7975559234619140625, -177.8903350830078125, -111.38809967041015625), - osg::Vec3f(7.44747829437255859375, -202.3209075927734375, -101.1938323974609375), - osg::Vec3f(0, -215, -94.753631591796875), + osg::Vec3f(21.7975559234619140625, -177.8903350830078125, -111.38811492919921875), + osg::Vec3f(7.44747829437255859375, -202.3209075927734375, -101.19382476806640625), + osg::Vec3f(0, -215, -94.75363922119140625), })) << mPath; } @@ -636,27 +636,27 @@ namespace EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; } From a4f300f810e29a4809130abbb1d625ea9c83d502 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 14:58:03 +0300 Subject: [PATCH 269/410] Use player half extents only to find path in exterior cells --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwmechanics/aipackage.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.cpp | 9 ++++----- apps/openmw/mwworld/player.cpp | 6 ++++++ apps/openmw/mwworld/player.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 18 ++++++------------ apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++++++-- apps/openmw/mwworld/worldimp.hpp | 4 ++++ 8 files changed, 43 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 217e6d3677..4b9467e503 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -134,6 +134,7 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Ptr getPlayerPtr() = 0; + virtual MWWorld::ConstPtr getPlayerConstPtr() const = 0; virtual const MWWorld::ESMStore& getStore() const = 0; @@ -615,6 +616,9 @@ namespace MWBase virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0; virtual void setNavMeshNumberToRender(const std::size_t value) = 0; + + /// Return physical half extents of the given actor to be used in pathfinding + virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; }; } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 91449498da..0fa92c3016 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -135,9 +135,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - const osg::Vec3f playerHalfExtents = world->getHalfExtents(getPlayer()); // Using player half extents for better performance + const auto halfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), - playerHalfExtents, getNavigatorFlags(actor)); + halfExtents, getNavigatorFlags(actor)); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 05465c6b05..405f36767e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -155,9 +155,9 @@ namespace MWMechanics } else { - const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); // Using player half extents for better performance + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); } if (mPathFinder.isPathConstructed()) @@ -312,10 +312,9 @@ namespace MWMechanics if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || (isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) { - // Using player half extents for better performance - const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); mPathFinder.addPointToPath(mDestination); if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index f152b2cae3..9e2d9d6ff4 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -122,6 +122,12 @@ namespace MWWorld return ptr; } + MWWorld::ConstPtr Player::getConstPlayer() const + { + MWWorld::ConstPtr ptr (&mPlayer, mCellStore); + return ptr; + } + void Player::setBirthSign (const std::string &sign) { mSign = sign; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index e2632f2104..96ed20adfc 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -27,6 +27,7 @@ namespace Loading namespace MWWorld { class CellStore; + class ConstPtr; /// \brief NPC object representing the player and additional player data class Player @@ -81,6 +82,7 @@ namespace MWWorld void setCell (MWWorld::CellStore *cellStore); MWWorld::Ptr getPlayer(); + MWWorld::ConstPtr getConstPlayer() const; void setBirthSign(const std::string &sign); const std::string &getBirthSign() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1e84188935..d06034e1dc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,12 +172,9 @@ namespace ); } } - else if (const auto actor = physics.getActor(ptr)) + else if (physics.getActor(ptr)) { - const auto halfExtents = ptr.getCell()->isExterior() - ? physics.getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) - : actor->getHalfExtents(); - navigator.addAgent(halfExtents); + navigator.addAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } } @@ -337,15 +334,14 @@ namespace MWWorld ListAndResetObjectsVisitor visitor; (*iter)->forEach(visitor); - const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const auto playerHalfExtents = mPhysics->getHalfExtents(player); + const auto world = MWBase::Environment::get().getWorld(); for (const auto& ptr : visitor.mObjects) { if (const auto object = mPhysics->getObject(ptr)) navigator->removeObject(DetourNavigator::ObjectId(object)); else if (const auto actor = mPhysics->getActor(ptr)) { - navigator->removeAgent(ptr.getCell()->isExterior() ? playerHalfExtents : actor->getHalfExtents()); + navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); mRendering.removeActorPath(ptr); } mPhysics->remove(ptr); @@ -372,6 +368,7 @@ namespace MWWorld if ((*iter)->getCell()->hasWater()) navigator->removeWater(osg::Vec2i(cellX, cellY)); + const auto player = world->getPlayerPtr(); navigator->update(player.getRefData().getPosition().asVec3()); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -815,10 +812,7 @@ namespace MWWorld } else if (const auto actor = mPhysics->getActor(ptr)) { - const auto& halfExtents = ptr.getCell()->isExterior() - ? mPhysics->getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) - : actor->getHalfExtents(); - navigator->removeAgent(halfExtents); + navigator->removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } mPhysics->remove(ptr); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 502ff8843d..f619dfddba 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2408,7 +2408,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); - mNavigator->removeAgent(mPhysics->getHalfExtents(getPlayerPtr())); + mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr())); mPhysics->remove(getPlayerPtr()); mRendering->removePlayer(getPlayerPtr()); @@ -2443,7 +2443,7 @@ namespace MWWorld applyLoopingParticles(player); - mNavigator->addAgent(mPhysics->getHalfExtents(getPlayerPtr())); + mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); } World::RestPermitted World::canRest () const @@ -3418,6 +3418,11 @@ namespace MWWorld return mPlayer->getPlayer(); } + MWWorld::ConstPtr World::getPlayerConstPtr() const + { + return mPlayer->getConstPlayer(); + } + void World::updateDialogueGlobals() { MWWorld::Ptr player = getPlayerPtr(); @@ -3787,4 +3792,12 @@ namespace MWWorld mRendering->setNavMeshNumber(value); } + osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const + { + if (actor.getCell()->isExterior()) + return getHalfExtents(getPlayerConstPtr()); // Using player half extents for better performance + else + return getHalfExtents(actor); + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 98e82bb86d..71d6c5afdf 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -238,6 +238,7 @@ namespace MWWorld Player& getPlayer() override; MWWorld::Ptr getPlayerPtr() override; + MWWorld::ConstPtr getPlayerConstPtr() const override; const MWWorld::ESMStore& getStore() const override; @@ -717,6 +718,9 @@ namespace MWWorld void removeActorPath(const MWWorld::ConstPtr& actor) const override; void setNavMeshNumberToRender(const std::size_t value) override; + + /// Return physical half extents of the given actor to be used in pathfinding + osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; }; } From c066ee9dc5c124cb711c5c3242c5356f0cce0b01 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 14:45:36 +0300 Subject: [PATCH 270/410] Use not scaled player half extents as default to find path --- apps/openmw/mwphysics/actor.cpp | 5 +++++ apps/openmw/mwphysics/actor.hpp | 5 +++++ apps/openmw/mwphysics/physicssystem.cpp | 8 ++++++++ apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 3 ++- apps/openmw/mwworld/worldimp.hpp | 2 ++ 6 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 632d32c26d..0f8814aca4 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -201,6 +201,11 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } +osg::Vec3f Actor::getOriginalHalfExtents() const +{ + return mHalfExtents; +} + osg::Vec3f Actor::getRenderingHalfExtents() const { return osg::componentMultiply(mHalfExtents, mRenderingScale); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 31dd22a221..8752f7feee 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,6 +66,11 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; + /** + * Returns the half extents of the collision body (not scaled) + */ + osg::Vec3f getOriginalHalfExtents() const; + /** * Returns the position of the collision body * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d12f7fe6cb..e3884afad0 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -906,6 +906,14 @@ namespace MWPhysics return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getOriginalHalfExtents(const MWWorld::ConstPtr &actor) const + { + if (const Actor* physactor = getActor(actor)) + return physactor->getOriginalHalfExtents(); + else + return osg::Vec3f(); + } + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 76fbcf8c63..364a59ab1b 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -136,6 +136,9 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; + /// Get physical half extents (not scaled) of the given actor. + osg::Vec3f getOriginalHalfExtents(const MWWorld::ConstPtr& actor) const; + /// @see MWPhysics::Actor::getRenderingHalfExtents osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f619dfddba..1ae3f69b5d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2443,6 +2443,7 @@ namespace MWWorld applyLoopingParticles(player); + mDefaultHalfExtents = mPhysics->getOriginalHalfExtents(getPlayerPtr()); mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); } @@ -3795,7 +3796,7 @@ namespace MWWorld osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const { if (actor.getCell()->isExterior()) - return getHalfExtents(getPlayerConstPtr()); // Using player half extents for better performance + return mDefaultHalfExtents; // Using default half extents for better performance else return getHalfExtents(actor); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 71d6c5afdf..f0c28ea9e2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -111,6 +111,8 @@ namespace MWWorld std::string mUserDataPath; + osg::Vec3f mDefaultHalfExtents; + // not implemented World (const World&); World& operator= (const World&); From 1f41d5721d134557d648f8b6d8cd200c168e8a38 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 15:14:51 +0300 Subject: [PATCH 271/410] Update scaled agent half extents in navigator (bug #4763) --- apps/openmw/mwworld/worldimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1ae3f69b5d..63c1a760a7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1328,9 +1328,15 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { + if (mPhysics->getActor(ptr)) + mNavigator->removeAgent(getPathfindingHalfExtents(ptr)); + ptr.getCellRef().setScale(scale); mWorldScene->updateObjectScale(ptr); + + if (mPhysics->getActor(ptr)) + mNavigator->addAgent(getPathfindingHalfExtents(ptr)); } void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) From 133d7447f399e4fc1fae95ea373706d36e6b0f45 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 15:51:02 +0300 Subject: [PATCH 272/410] Update scaled objects in navigator --- apps/openmw/mwworld/worldimp.cpp | 13 ++++++++----- apps/openmw/mwworld/worldimp.hpp | 1 + .../detournavigator/recastmeshobject.cpp | 7 +++++++ components/detournavigator/recastmeshobject.cpp | 6 ++++++ components/detournavigator/recastmeshobject.hpp | 1 + 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 63c1a760a7..5b767f1b76 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1337,6 +1337,8 @@ namespace MWWorld if (mPhysics->getActor(ptr)) mNavigator->addAgent(getPathfindingHalfExtents(ptr)); + else if (const auto object = mPhysics->getObject(ptr)) + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; } void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) @@ -1570,19 +1572,20 @@ namespace MWWorld void World::updateNavigator() { - bool updated = false; - mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) { - updated = updateNavigatorObject(object) || updated; + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; }); for (const auto& door : mDoorStates) if (const auto object = mPhysics->getObject(door.first)) - updated = updateNavigatorObject(object) || updated; + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; - if (updated) + if (mShouldUpdateNavigator) + { mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); + mShouldUpdateNavigator = false; + } } bool World::updateNavigatorObject(const MWPhysics::Object* object) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f0c28ea9e2..45653ded2e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -112,6 +112,7 @@ namespace MWWorld std::string mUserDataPath; osg::Vec3f mDefaultHalfExtents; + bool mShouldUpdateNavigator = false; // not implemented World (const World&); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp index 9b30cadd7a..a3606f8273 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp @@ -69,4 +69,11 @@ namespace object.update(mTransform, AreaType_ground); EXPECT_FALSE(object.update(mTransform, AreaType_ground)); } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_changed_local_scaling_should_return_true) + { + RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); + mBoxShape.setLocalScaling(btVector3(2, 2, 2)); + EXPECT_TRUE(object.update(mTransform, AreaType_ground)); + } } diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index 24d3e6b5a8..aac0b4c3c8 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -13,6 +13,7 @@ namespace DetourNavigator : mShape(shape) , mTransform(transform) , mAreaType(areaType) + , mLocalScaling(shape.getLocalScaling()) , mChildren(makeChildrenObjects(shape, mAreaType)) { } @@ -30,6 +31,11 @@ namespace DetourNavigator mAreaType = areaType; result = true; } + if (!(mLocalScaling == mShape.get().getLocalScaling())) + { + mLocalScaling = mShape.get().getLocalScaling(); + result = true; + } if (mShape.get().isCompound()) result = updateCompoundObject(static_cast(mShape.get()), mAreaType, mChildren) || result; diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index aff4681222..f25647ae50 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -39,6 +39,7 @@ namespace DetourNavigator std::reference_wrapper mShape; btTransform mTransform; AreaType mAreaType; + btVector3 mLocalScaling; std::vector mChildren; static bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType, From f394ace4d5573d75d858d7c129b1dcc9b8f2f421 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 15:59:02 +0300 Subject: [PATCH 273/410] Update moved objects in navigator --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5b767f1b76..fe6a6be219 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1298,6 +1298,9 @@ namespace MWWorld { mPhysics->updatePosition(newPtr); mPhysics->updatePtr(ptr, newPtr); + + if (const auto object = mPhysics->getObject(newPtr)) + updateNavigatorObject(object); } } if (isPlayer) From b51a54e97682bbf51e5607ec531df86893ce8c0d Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 16:01:52 +0300 Subject: [PATCH 274/410] Update rotated objects in navigator --- apps/openmw/mwworld/worldimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fe6a6be219..cfec200b2c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1381,7 +1381,12 @@ namespace MWWorld ptr.getRefData().setPosition(pos); if(ptr.getRefData().getBaseNode() != 0) + { mWorldScene->updateObjectRotation(ptr, true); + + if (const auto object = mPhysics->getObject(ptr)) + updateNavigatorObject(object); + } } void World::adjustPosition(const Ptr &ptr, bool force) From 5505582a9733b6657ea9472313cedbf1fdfc37b5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 3 Mar 2019 20:53:05 +0400 Subject: [PATCH 275/410] Fix localized 'Invert Y axis' label cutoff --- files/mygui/openmw_settings_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 0e4f6e626e..58be98cca3 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -213,7 +213,7 @@ - + From 14c93b3df0f998163fd010c56c0a868831dc7b66 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Mon, 4 Mar 2019 11:06:15 +0100 Subject: [PATCH 276/410] Revert "Merge pull request #2204 from elsid/fix_navigator_update" This reverts commit 26fb0e7a0f0729e727c72c2eefe1475f6cc8e956, reversing changes made to 42b2391303b87a3fbe06cab17bc16079ae5a00f9. --- apps/openmw/mwbase/world.hpp | 4 -- apps/openmw/mwmechanics/aipackage.cpp | 4 +- apps/openmw/mwmechanics/aiwander.cpp | 9 ++-- apps/openmw/mwphysics/actor.cpp | 5 --- apps/openmw/mwphysics/actor.hpp | 5 --- apps/openmw/mwphysics/physicssystem.cpp | 8 ---- apps/openmw/mwphysics/physicssystem.hpp | 3 -- apps/openmw/mwworld/player.cpp | 6 --- apps/openmw/mwworld/player.hpp | 2 - apps/openmw/mwworld/scene.cpp | 18 +++++--- apps/openmw/mwworld/worldimp.cpp | 45 +++---------------- apps/openmw/mwworld/worldimp.hpp | 7 --- .../detournavigator/recastmeshobject.cpp | 7 --- .../detournavigator/recastmeshobject.cpp | 6 --- .../detournavigator/recastmeshobject.hpp | 1 - 15 files changed, 26 insertions(+), 104 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4b9467e503..217e6d3677 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -134,7 +134,6 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Ptr getPlayerPtr() = 0; - virtual MWWorld::ConstPtr getPlayerConstPtr() const = 0; virtual const MWWorld::ESMStore& getStore() const = 0; @@ -616,9 +615,6 @@ namespace MWBase virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0; virtual void setNavMeshNumberToRender(const std::size_t value) = 0; - - /// Return physical half extents of the given actor to be used in pathfinding - virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; }; } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 0fa92c3016..91449498da 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -135,9 +135,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - const auto halfExtents = world->getPathfindingHalfExtents(actor); + const osg::Vec3f playerHalfExtents = world->getHalfExtents(getPlayer()); // Using player half extents for better performance mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), - halfExtents, getNavigatorFlags(actor)); + playerHalfExtents, getNavigatorFlags(actor)); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 405f36767e..05465c6b05 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -155,9 +155,9 @@ namespace MWMechanics } else { - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); // Using player half extents for better performance mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); } if (mPathFinder.isPathConstructed()) @@ -312,9 +312,10 @@ namespace MWMechanics if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || (isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) { - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + // Using player half extents for better performance + const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); mPathFinder.addPointToPath(mDestination); if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 0f8814aca4..632d32c26d 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -201,11 +201,6 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } -osg::Vec3f Actor::getOriginalHalfExtents() const -{ - return mHalfExtents; -} - osg::Vec3f Actor::getRenderingHalfExtents() const { return osg::componentMultiply(mHalfExtents, mRenderingScale); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 8752f7feee..31dd22a221 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,11 +66,6 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; - /** - * Returns the half extents of the collision body (not scaled) - */ - osg::Vec3f getOriginalHalfExtents() const; - /** * Returns the position of the collision body * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e3884afad0..d12f7fe6cb 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -906,14 +906,6 @@ namespace MWPhysics return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getOriginalHalfExtents(const MWWorld::ConstPtr &actor) const - { - if (const Actor* physactor = getActor(actor)) - return physactor->getOriginalHalfExtents(); - else - return osg::Vec3f(); - } - osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 364a59ab1b..76fbcf8c63 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -136,9 +136,6 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; - /// Get physical half extents (not scaled) of the given actor. - osg::Vec3f getOriginalHalfExtents(const MWWorld::ConstPtr& actor) const; - /// @see MWPhysics::Actor::getRenderingHalfExtents osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 9e2d9d6ff4..f152b2cae3 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -122,12 +122,6 @@ namespace MWWorld return ptr; } - MWWorld::ConstPtr Player::getConstPlayer() const - { - MWWorld::ConstPtr ptr (&mPlayer, mCellStore); - return ptr; - } - void Player::setBirthSign (const std::string &sign) { mSign = sign; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 96ed20adfc..e2632f2104 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -27,7 +27,6 @@ namespace Loading namespace MWWorld { class CellStore; - class ConstPtr; /// \brief NPC object representing the player and additional player data class Player @@ -82,7 +81,6 @@ namespace MWWorld void setCell (MWWorld::CellStore *cellStore); MWWorld::Ptr getPlayer(); - MWWorld::ConstPtr getConstPlayer() const; void setBirthSign(const std::string &sign); const std::string &getBirthSign() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d06034e1dc..1e84188935 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,9 +172,12 @@ namespace ); } } - else if (physics.getActor(ptr)) + else if (const auto actor = physics.getActor(ptr)) { - navigator.addAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); + const auto halfExtents = ptr.getCell()->isExterior() + ? physics.getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) + : actor->getHalfExtents(); + navigator.addAgent(halfExtents); } } @@ -334,14 +337,15 @@ namespace MWWorld ListAndResetObjectsVisitor visitor; (*iter)->forEach(visitor); - const auto world = MWBase::Environment::get().getWorld(); + const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const auto playerHalfExtents = mPhysics->getHalfExtents(player); for (const auto& ptr : visitor.mObjects) { if (const auto object = mPhysics->getObject(ptr)) navigator->removeObject(DetourNavigator::ObjectId(object)); else if (const auto actor = mPhysics->getActor(ptr)) { - navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); + navigator->removeAgent(ptr.getCell()->isExterior() ? playerHalfExtents : actor->getHalfExtents()); mRendering.removeActorPath(ptr); } mPhysics->remove(ptr); @@ -368,7 +372,6 @@ namespace MWWorld if ((*iter)->getCell()->hasWater()) navigator->removeWater(osg::Vec2i(cellX, cellY)); - const auto player = world->getPlayerPtr(); navigator->update(player.getRefData().getPosition().asVec3()); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -812,7 +815,10 @@ namespace MWWorld } else if (const auto actor = mPhysics->getActor(ptr)) { - navigator->removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); + const auto& halfExtents = ptr.getCell()->isExterior() + ? mPhysics->getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) + : actor->getHalfExtents(); + navigator->removeAgent(halfExtents); } mPhysics->remove(ptr); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cfec200b2c..502ff8843d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1298,9 +1298,6 @@ namespace MWWorld { mPhysics->updatePosition(newPtr); mPhysics->updatePtr(ptr, newPtr); - - if (const auto object = mPhysics->getObject(newPtr)) - updateNavigatorObject(object); } } if (isPlayer) @@ -1331,17 +1328,9 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { - if (mPhysics->getActor(ptr)) - mNavigator->removeAgent(getPathfindingHalfExtents(ptr)); - ptr.getCellRef().setScale(scale); mWorldScene->updateObjectScale(ptr); - - if (mPhysics->getActor(ptr)) - mNavigator->addAgent(getPathfindingHalfExtents(ptr)); - else if (const auto object = mPhysics->getObject(ptr)) - mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; } void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) @@ -1381,12 +1370,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); if(ptr.getRefData().getBaseNode() != 0) - { mWorldScene->updateObjectRotation(ptr, true); - - if (const auto object = mPhysics->getObject(ptr)) - updateNavigatorObject(object); - } } void World::adjustPosition(const Ptr &ptr, bool force) @@ -1580,20 +1564,19 @@ namespace MWWorld void World::updateNavigator() { + bool updated = false; + mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) { - mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; + updated = updateNavigatorObject(object) || updated; }); for (const auto& door : mDoorStates) if (const auto object = mPhysics->getObject(door.first)) - mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; + updated = updateNavigatorObject(object) || updated; - if (mShouldUpdateNavigator) - { + if (updated) mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); - mShouldUpdateNavigator = false; - } } bool World::updateNavigatorObject(const MWPhysics::Object* object) @@ -2425,7 +2408,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); - mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr())); + mNavigator->removeAgent(mPhysics->getHalfExtents(getPlayerPtr())); mPhysics->remove(getPlayerPtr()); mRendering->removePlayer(getPlayerPtr()); @@ -2460,8 +2443,7 @@ namespace MWWorld applyLoopingParticles(player); - mDefaultHalfExtents = mPhysics->getOriginalHalfExtents(getPlayerPtr()); - mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); + mNavigator->addAgent(mPhysics->getHalfExtents(getPlayerPtr())); } World::RestPermitted World::canRest () const @@ -3436,11 +3418,6 @@ namespace MWWorld return mPlayer->getPlayer(); } - MWWorld::ConstPtr World::getPlayerConstPtr() const - { - return mPlayer->getConstPlayer(); - } - void World::updateDialogueGlobals() { MWWorld::Ptr player = getPlayerPtr(); @@ -3810,12 +3787,4 @@ namespace MWWorld mRendering->setNavMeshNumber(value); } - osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const - { - if (actor.getCell()->isExterior()) - return mDefaultHalfExtents; // Using default half extents for better performance - else - return getHalfExtents(actor); - } - } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 45653ded2e..98e82bb86d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -111,9 +111,6 @@ namespace MWWorld std::string mUserDataPath; - osg::Vec3f mDefaultHalfExtents; - bool mShouldUpdateNavigator = false; - // not implemented World (const World&); World& operator= (const World&); @@ -241,7 +238,6 @@ namespace MWWorld Player& getPlayer() override; MWWorld::Ptr getPlayerPtr() override; - MWWorld::ConstPtr getPlayerConstPtr() const override; const MWWorld::ESMStore& getStore() const override; @@ -721,9 +717,6 @@ namespace MWWorld void removeActorPath(const MWWorld::ConstPtr& actor) const override; void setNavMeshNumberToRender(const std::size_t value) override; - - /// Return physical half extents of the given actor to be used in pathfinding - osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; }; } diff --git a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp index a3606f8273..9b30cadd7a 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp @@ -69,11 +69,4 @@ namespace object.update(mTransform, AreaType_ground); EXPECT_FALSE(object.update(mTransform, AreaType_ground)); } - - TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_changed_local_scaling_should_return_true) - { - RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); - mBoxShape.setLocalScaling(btVector3(2, 2, 2)); - EXPECT_TRUE(object.update(mTransform, AreaType_ground)); - } } diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index aac0b4c3c8..24d3e6b5a8 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -13,7 +13,6 @@ namespace DetourNavigator : mShape(shape) , mTransform(transform) , mAreaType(areaType) - , mLocalScaling(shape.getLocalScaling()) , mChildren(makeChildrenObjects(shape, mAreaType)) { } @@ -31,11 +30,6 @@ namespace DetourNavigator mAreaType = areaType; result = true; } - if (!(mLocalScaling == mShape.get().getLocalScaling())) - { - mLocalScaling = mShape.get().getLocalScaling(); - result = true; - } if (mShape.get().isCompound()) result = updateCompoundObject(static_cast(mShape.get()), mAreaType, mChildren) || result; diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index f25647ae50..aff4681222 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -39,7 +39,6 @@ namespace DetourNavigator std::reference_wrapper mShape; btTransform mTransform; AreaType mAreaType; - btVector3 mLocalScaling; std::vector mChildren; static bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType, From 12bbecacfd2293729b0d34aeb3f69c6eb792247f Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Mon, 4 Mar 2019 16:23:57 +0000 Subject: [PATCH 277/410] Reuse a previously-saved value --- apps/openmw/mwclass/container.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 47dfa27b36..3a501a93f9 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -240,8 +240,8 @@ namespace MWClass std::string text; int lockLevel = ptr.getCellRef().getLockLevel(); if (lockLevel > 0 && lockLevel != ESM::UnbreakableLock) - text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ptr.getCellRef().getLockLevel()); - else if (ptr.getCellRef().getLockLevel() < 0) + text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(lockLevel); + else if (lockLevel < 0) text += "\n#{sUnlocked}"; if (ptr.getCellRef().getTrap() != "") text += "\n#{sTrapped}"; From 1218e4e15d778c91430e91afb4ff580180797950 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 14:58:03 +0300 Subject: [PATCH 278/410] Use player half extents only to find path in exterior cells --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwmechanics/aipackage.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.cpp | 9 ++++----- apps/openmw/mwworld/player.cpp | 6 ++++++ apps/openmw/mwworld/player.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 18 ++++++------------ apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++++++-- apps/openmw/mwworld/worldimp.hpp | 4 ++++ 8 files changed, 43 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 217e6d3677..4b9467e503 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -134,6 +134,7 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Ptr getPlayerPtr() = 0; + virtual MWWorld::ConstPtr getPlayerConstPtr() const = 0; virtual const MWWorld::ESMStore& getStore() const = 0; @@ -615,6 +616,9 @@ namespace MWBase virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0; virtual void setNavMeshNumberToRender(const std::size_t value) = 0; + + /// Return physical half extents of the given actor to be used in pathfinding + virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; }; } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 91449498da..0fa92c3016 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -135,9 +135,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - const osg::Vec3f playerHalfExtents = world->getHalfExtents(getPlayer()); // Using player half extents for better performance + const auto halfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), - playerHalfExtents, getNavigatorFlags(actor)); + halfExtents, getNavigatorFlags(actor)); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 05465c6b05..405f36767e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -155,9 +155,9 @@ namespace MWMechanics } else { - const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); // Using player half extents for better performance + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); } if (mPathFinder.isPathConstructed()) @@ -312,10 +312,9 @@ namespace MWMechanics if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || (isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) { - // Using player half extents for better performance - const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); mPathFinder.addPointToPath(mDestination); if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index f152b2cae3..9e2d9d6ff4 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -122,6 +122,12 @@ namespace MWWorld return ptr; } + MWWorld::ConstPtr Player::getConstPlayer() const + { + MWWorld::ConstPtr ptr (&mPlayer, mCellStore); + return ptr; + } + void Player::setBirthSign (const std::string &sign) { mSign = sign; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index e2632f2104..96ed20adfc 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -27,6 +27,7 @@ namespace Loading namespace MWWorld { class CellStore; + class ConstPtr; /// \brief NPC object representing the player and additional player data class Player @@ -81,6 +82,7 @@ namespace MWWorld void setCell (MWWorld::CellStore *cellStore); MWWorld::Ptr getPlayer(); + MWWorld::ConstPtr getConstPlayer() const; void setBirthSign(const std::string &sign); const std::string &getBirthSign() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1e84188935..d06034e1dc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,12 +172,9 @@ namespace ); } } - else if (const auto actor = physics.getActor(ptr)) + else if (physics.getActor(ptr)) { - const auto halfExtents = ptr.getCell()->isExterior() - ? physics.getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) - : actor->getHalfExtents(); - navigator.addAgent(halfExtents); + navigator.addAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } } @@ -337,15 +334,14 @@ namespace MWWorld ListAndResetObjectsVisitor visitor; (*iter)->forEach(visitor); - const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const auto playerHalfExtents = mPhysics->getHalfExtents(player); + const auto world = MWBase::Environment::get().getWorld(); for (const auto& ptr : visitor.mObjects) { if (const auto object = mPhysics->getObject(ptr)) navigator->removeObject(DetourNavigator::ObjectId(object)); else if (const auto actor = mPhysics->getActor(ptr)) { - navigator->removeAgent(ptr.getCell()->isExterior() ? playerHalfExtents : actor->getHalfExtents()); + navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); mRendering.removeActorPath(ptr); } mPhysics->remove(ptr); @@ -372,6 +368,7 @@ namespace MWWorld if ((*iter)->getCell()->hasWater()) navigator->removeWater(osg::Vec2i(cellX, cellY)); + const auto player = world->getPlayerPtr(); navigator->update(player.getRefData().getPosition().asVec3()); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -815,10 +812,7 @@ namespace MWWorld } else if (const auto actor = mPhysics->getActor(ptr)) { - const auto& halfExtents = ptr.getCell()->isExterior() - ? mPhysics->getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) - : actor->getHalfExtents(); - navigator->removeAgent(halfExtents); + navigator->removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } mPhysics->remove(ptr); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 502ff8843d..fa394cc106 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2408,7 +2408,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); - mNavigator->removeAgent(mPhysics->getHalfExtents(getPlayerPtr())); + mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr())); mPhysics->remove(getPlayerPtr()); mRendering->removePlayer(getPlayerPtr()); @@ -2443,7 +2443,7 @@ namespace MWWorld applyLoopingParticles(player); - mNavigator->addAgent(mPhysics->getHalfExtents(getPlayerPtr())); + mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); } World::RestPermitted World::canRest () const @@ -3418,6 +3418,11 @@ namespace MWWorld return mPlayer->getPlayer(); } + MWWorld::ConstPtr World::getPlayerConstPtr() const + { + return mPlayer->getConstPlayer(); + } + void World::updateDialogueGlobals() { MWWorld::Ptr player = getPlayerPtr(); @@ -3787,4 +3792,12 @@ namespace MWWorld mRendering->setNavMeshNumber(value); } + osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const + { + if (actor.isInCell() && actor.getCell()->isExterior()) + return getHalfExtents(getPlayerConstPtr()); // Using player half extents for better performance + else + return getHalfExtents(actor); + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 98e82bb86d..71d6c5afdf 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -238,6 +238,7 @@ namespace MWWorld Player& getPlayer() override; MWWorld::Ptr getPlayerPtr() override; + MWWorld::ConstPtr getPlayerConstPtr() const override; const MWWorld::ESMStore& getStore() const override; @@ -717,6 +718,9 @@ namespace MWWorld void removeActorPath(const MWWorld::ConstPtr& actor) const override; void setNavMeshNumberToRender(const std::size_t value) override; + + /// Return physical half extents of the given actor to be used in pathfinding + osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; }; } From 43b39e841816814e74cf49870439a4c5396c516c Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 14:45:36 +0300 Subject: [PATCH 279/410] Use not scaled player half extents as default to find path --- apps/openmw/mwphysics/actor.cpp | 5 +++++ apps/openmw/mwphysics/actor.hpp | 5 +++++ apps/openmw/mwphysics/physicssystem.cpp | 8 ++++++++ apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 3 ++- apps/openmw/mwworld/worldimp.hpp | 2 ++ 6 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 632d32c26d..0f8814aca4 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -201,6 +201,11 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } +osg::Vec3f Actor::getOriginalHalfExtents() const +{ + return mHalfExtents; +} + osg::Vec3f Actor::getRenderingHalfExtents() const { return osg::componentMultiply(mHalfExtents, mRenderingScale); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 31dd22a221..8752f7feee 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,6 +66,11 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; + /** + * Returns the half extents of the collision body (not scaled) + */ + osg::Vec3f getOriginalHalfExtents() const; + /** * Returns the position of the collision body * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d12f7fe6cb..e3884afad0 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -906,6 +906,14 @@ namespace MWPhysics return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getOriginalHalfExtents(const MWWorld::ConstPtr &actor) const + { + if (const Actor* physactor = getActor(actor)) + return physactor->getOriginalHalfExtents(); + else + return osg::Vec3f(); + } + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 76fbcf8c63..364a59ab1b 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -136,6 +136,9 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; + /// Get physical half extents (not scaled) of the given actor. + osg::Vec3f getOriginalHalfExtents(const MWWorld::ConstPtr& actor) const; + /// @see MWPhysics::Actor::getRenderingHalfExtents osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fa394cc106..eb401658e1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2443,6 +2443,7 @@ namespace MWWorld applyLoopingParticles(player); + mDefaultHalfExtents = mPhysics->getOriginalHalfExtents(getPlayerPtr()); mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); } @@ -3795,7 +3796,7 @@ namespace MWWorld osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const { if (actor.isInCell() && actor.getCell()->isExterior()) - return getHalfExtents(getPlayerConstPtr()); // Using player half extents for better performance + return mDefaultHalfExtents; // Using default half extents for better performance else return getHalfExtents(actor); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 71d6c5afdf..f0c28ea9e2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -111,6 +111,8 @@ namespace MWWorld std::string mUserDataPath; + osg::Vec3f mDefaultHalfExtents; + // not implemented World (const World&); World& operator= (const World&); From 2e063d59cef22c35cad3de5e70e568e270161ed3 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 15:14:51 +0300 Subject: [PATCH 280/410] Update scaled agent half extents in navigator (bug #4763) --- apps/openmw/mwworld/worldimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index eb401658e1..c0e79352f8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1328,9 +1328,15 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { + if (mPhysics->getActor(ptr)) + mNavigator->removeAgent(getPathfindingHalfExtents(ptr)); + ptr.getCellRef().setScale(scale); mWorldScene->updateObjectScale(ptr); + + if (mPhysics->getActor(ptr)) + mNavigator->addAgent(getPathfindingHalfExtents(ptr)); } void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) From 27d74522677ea3b95e37b5d44ce254c36c2835b0 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 15:51:02 +0300 Subject: [PATCH 281/410] Update scaled objects in navigator --- apps/openmw/mwworld/worldimp.cpp | 13 ++++++++----- apps/openmw/mwworld/worldimp.hpp | 1 + .../detournavigator/recastmeshobject.cpp | 7 +++++++ components/detournavigator/recastmeshobject.cpp | 6 ++++++ components/detournavigator/recastmeshobject.hpp | 1 + 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c0e79352f8..74d4d28383 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1337,6 +1337,8 @@ namespace MWWorld if (mPhysics->getActor(ptr)) mNavigator->addAgent(getPathfindingHalfExtents(ptr)); + else if (const auto object = mPhysics->getObject(ptr)) + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; } void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) @@ -1570,19 +1572,20 @@ namespace MWWorld void World::updateNavigator() { - bool updated = false; - mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) { - updated = updateNavigatorObject(object) || updated; + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; }); for (const auto& door : mDoorStates) if (const auto object = mPhysics->getObject(door.first)) - updated = updateNavigatorObject(object) || updated; + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; - if (updated) + if (mShouldUpdateNavigator) + { mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); + mShouldUpdateNavigator = false; + } } bool World::updateNavigatorObject(const MWPhysics::Object* object) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f0c28ea9e2..45653ded2e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -112,6 +112,7 @@ namespace MWWorld std::string mUserDataPath; osg::Vec3f mDefaultHalfExtents; + bool mShouldUpdateNavigator = false; // not implemented World (const World&); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp index 9b30cadd7a..a3606f8273 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp @@ -69,4 +69,11 @@ namespace object.update(mTransform, AreaType_ground); EXPECT_FALSE(object.update(mTransform, AreaType_ground)); } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_changed_local_scaling_should_return_true) + { + RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); + mBoxShape.setLocalScaling(btVector3(2, 2, 2)); + EXPECT_TRUE(object.update(mTransform, AreaType_ground)); + } } diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index 24d3e6b5a8..aac0b4c3c8 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -13,6 +13,7 @@ namespace DetourNavigator : mShape(shape) , mTransform(transform) , mAreaType(areaType) + , mLocalScaling(shape.getLocalScaling()) , mChildren(makeChildrenObjects(shape, mAreaType)) { } @@ -30,6 +31,11 @@ namespace DetourNavigator mAreaType = areaType; result = true; } + if (!(mLocalScaling == mShape.get().getLocalScaling())) + { + mLocalScaling = mShape.get().getLocalScaling(); + result = true; + } if (mShape.get().isCompound()) result = updateCompoundObject(static_cast(mShape.get()), mAreaType, mChildren) || result; diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index aff4681222..f25647ae50 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -39,6 +39,7 @@ namespace DetourNavigator std::reference_wrapper mShape; btTransform mTransform; AreaType mAreaType; + btVector3 mLocalScaling; std::vector mChildren; static bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType, From 8c08c3c7d6d6d75670554b91ff70614c8a581ea6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 15:59:02 +0300 Subject: [PATCH 282/410] Update moved objects in navigator --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 74d4d28383..895a6c198b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1298,6 +1298,9 @@ namespace MWWorld { mPhysics->updatePosition(newPtr); mPhysics->updatePtr(ptr, newPtr); + + if (const auto object = mPhysics->getObject(newPtr)) + updateNavigatorObject(object); } } if (isPlayer) From 80051db8f83b494583ba04988e2e91794e89de1a Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 3 Mar 2019 16:01:52 +0300 Subject: [PATCH 283/410] Update rotated objects in navigator --- apps/openmw/mwworld/worldimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 895a6c198b..72e1433583 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1381,7 +1381,12 @@ namespace MWWorld ptr.getRefData().setPosition(pos); if(ptr.getRefData().getBaseNode() != 0) + { mWorldScene->updateObjectRotation(ptr, true); + + if (const auto object = mPhysics->getObject(ptr)) + updateNavigatorObject(object); + } } void World::adjustPosition(const Ptr &ptr, bool force) From 84fbb486d3f534ef357a440a71ac9e3c8d0b4bde Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 4 Mar 2019 22:51:31 +0300 Subject: [PATCH 284/410] Fix switch from invalid navmesh number to valid --- apps/openmw/mwrender/navmesh.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/navmesh.cpp b/apps/openmw/mwrender/navmesh.cpp index 331f506abb..bfc80914a7 100644 --- a/apps/openmw/mwrender/navmesh.cpp +++ b/apps/openmw/mwrender/navmesh.cpp @@ -34,7 +34,7 @@ namespace MWRender void NavMesh::update(const dtNavMesh& navMesh, const std::size_t id, const std::size_t generation, const std::size_t revision, const DetourNavigator::Settings& settings) { - if (!mEnabled || (mId == id && mGeneration >= generation && mRevision >= revision)) + if (!mEnabled || (mGroup && mId == id && mGeneration >= generation && mRevision >= revision)) return; mId = id; @@ -53,7 +53,10 @@ namespace MWRender void NavMesh::reset() { if (mGroup) + { mRootNode->removeChild(mGroup); + mGroup = nullptr; + } } void NavMesh::enable() @@ -65,7 +68,8 @@ namespace MWRender void NavMesh::disable() { - reset(); + if (mGroup) + mRootNode->removeChild(mGroup); mEnabled = false; } } From bcf086d72dc9697515c38a763710a370cb464645 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 4 Mar 2019 22:43:44 +0400 Subject: [PATCH 285/410] Fix magic glow update for sheathing weapons --- apps/openmw/mwrender/actoranimation.cpp | 24 +++++++++++++----------- apps/openmw/mwrender/actoranimation.hpp | 1 + 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index afe8f5cd31..68b4c2ac85 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -194,15 +194,16 @@ void ActorAnimation::injectWeaponBones() } } -// To make sure we do not run morph controllers for weapons, i.e. bows -class EmptyCallback : public osg::NodeCallback +void ActorAnimation::resetControllers(osg::Node* node) { - public: + if (node == nullptr) + return; - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - } -}; + std::shared_ptr src; + src.reset(new NullAnimationTime); + SceneUtil::AssignControllerSourcesVisitor removeVisitor(src); + node->accept(removeVisitor); +} void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) { @@ -230,7 +231,9 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) if (mesh.empty() || boneName.empty()) return; - // If the scabbard is not found, use a weapon mesh as fallback + // If the scabbard is not found, use a weapon mesh as fallback. + // Note: it is unclear how to handle time for controllers attached to bodyparts, so disable them for now. + // We use the similar approach for other bodyparts. scabbardName = scabbardName.replace(scabbardName.size()-4, 4, "_sh.nif"); bool isEnchanted = !weapon->getClass().getEnchantment(*weapon).empty(); if(!mResourceSystem->getVFS()->exists(scabbardName)) @@ -239,8 +242,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) { osg::Vec4f glowColor = getEnchantmentColor(*weapon); mScabbard = getWeaponPart(mesh, boneName, isEnchanted, &glowColor); - if (mScabbard) - mScabbard->getNode()->setUpdateCallback(new EmptyCallback); + resetControllers(mScabbard->getNode()); } return; @@ -265,7 +267,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) if (!weaponNode->getNumChildren()) { osg::ref_ptr fallbackNode = mResourceSystem->getSceneManager()->getInstance(mesh, weaponNode); - fallbackNode->setUpdateCallback(new EmptyCallback); + resetControllers(fallbackNode); } if (isEnchanted) diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp index 7a8acd3a83..2146a0260d 100644 --- a/apps/openmw/mwrender/actoranimation.hpp +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -59,6 +59,7 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener private: void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight); void removeHiddenItemLight(const MWWorld::ConstPtr& item); + void resetControllers(osg::Node* node); typedef std::map > ItemLightMap; ItemLightMap mItemLights; From 59f7df187d5a4eb1e8bb36bf04a812b0f907c3d1 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 5 Mar 2019 20:47:05 +0300 Subject: [PATCH 286/410] Add explicit variant of Journal --- apps/openmw/mwscript/dialogueextensions.cpp | 1 + apps/openmw/mwscript/docs/vmformat.txt | 3 ++- components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 135cb787e3..200ddbb745 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -285,6 +285,7 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); + interpreter.installSegment5 (Compiler::Dialogue::opcodeJournalExplicit, new OpJournal); interpreter.installSegment5 (Compiler::Dialogue::opcodeSetJournalIndex, new OpSetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeAddTopic, new OpAddTopic); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index d346ab6e43..d97f2a134f 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -458,5 +458,6 @@ op 0x2000307: ToggleBorders, tb op 0x2000308: ToggleNavMesh op 0x2000309: ToggleActorsPaths op 0x200030a: SetNavMeshNumber +op 0x200030b: Journal, explicit -opcodes 0x200030b-0x3ffffff unused +opcodes 0x200030c-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 1b5558a3ab..fdb6707480 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -175,7 +175,7 @@ namespace Compiler { void registerExtensions (Extensions& extensions) { - extensions.registerInstruction ("journal", "cl", opcodeJournal); + extensions.registerInstruction ("journal", "cl", opcodeJournal, opcodeJournalExplicit); extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index a2d8a9467c..4aabe3f78a 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -150,6 +150,7 @@ namespace Compiler namespace Dialogue { const int opcodeJournal = 0x2000133; + const int opcodeJournalExplicit = 0x200030b; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; const int opcodeAddTopic = 0x200013a; From 44da71fdb34ff9e9bb1beaaebfff5778d1a76c21 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 5 Mar 2019 20:47:19 +0300 Subject: [PATCH 287/410] Restructure script verifier message --- apps/opencs/model/tools/scriptcheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d3d9d1503d..952127edf2 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -30,11 +30,11 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - stream << "line " << loc.mLine << ", column " << loc.mColumn << ": " << message << " (" << loc.mLiteral << ")"; + stream << message << " (" << loc.mLiteral << ")" << " @ line " << loc.mLine+1 << ", column " << loc.mColumn; std::ostringstream hintStream; - hintStream << "l:" << loc.mLine << " " << loc.mColumn; + hintStream << "l:" << loc.mLine+1 << " " << loc.mColumn; mMessages->add (id, stream.str(), hintStream.str(), getSeverity (type)); } From 5405efd3b543b19fde1a4ba44fd9aeadc81ec572 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 5 Mar 2019 09:49:56 +0300 Subject: [PATCH 288/410] Do not build path by navigator for pure water and flying creatures They don't need to move by surfaces and to open/close doors. --- apps/openmw/mwmechanics/pathfinding.cpp | 3 ++- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 8c7d6fce93..e31da94b15 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -286,7 +286,8 @@ namespace MWMechanics mPath.clear(); mCell = cell; - buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); + if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor)) + buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); if (mPath.empty()) buildPathByPathgridImpl(startPoint, endPoint, pathgridGraph, std::back_inserter(mPath)); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9786ed32b4..472db15c50 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -407,7 +407,7 @@ namespace MWWorld return false; } - bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const + bool Class::isPureWaterCreature(const ConstPtr& ptr) const { return canSwim(ptr) && !isBipedal(ptr) @@ -415,7 +415,7 @@ namespace MWWorld && !canWalk(ptr); } - bool Class::isPureFlyingCreature(const Ptr& ptr) const + bool Class::isPureFlyingCreature(const ConstPtr& ptr) const { return canFly(ptr) && !isBipedal(ptr) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index af88b0dcca..2be54e7bac 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -324,8 +324,8 @@ namespace MWWorld virtual bool canFly(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; virtual bool canWalk(const MWWorld::ConstPtr& ptr) const; - bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; - bool isPureFlyingCreature(const MWWorld::Ptr& ptr) const; + bool isPureWaterCreature(const MWWorld::ConstPtr& ptr) const; + bool isPureFlyingCreature(const MWWorld::ConstPtr& ptr) const; bool isPureLandCreature(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const; From eb45f9988058a33f02315cf574da7f980b81ae9b Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 5 Mar 2019 23:18:13 +0300 Subject: [PATCH 289/410] Remove unused code --- apps/openmw/mwmechanics/pathfinding.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 567056fa5d..56c7567c23 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -46,7 +46,6 @@ namespace MWMechanics } const float PATHFIND_Z_REACH = 50.0f; - //static const float sMaxSlope = 49.0f; // duplicate as in physicssystem // distance after which actor (failed previously to shortcut) will try again const float PATHFIND_SHORTCUT_RETRY_DIST = 300.0f; From cf1e1d9f4bcc6fc1dc79c132534b83d7256ed4ba Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 5 Mar 2019 23:15:15 +0300 Subject: [PATCH 290/410] Use min point tolerance to prevent face wrong direction (bug #4814) When next path point is too close to actor and it has speed 0, it can face direction not pointing to path target. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 0fa92c3016..698b2efce4 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -167,7 +167,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& mTimer = 0; } - const float pointTolerance = std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE); + const float pointTolerance = std::max(MIN_TOLERANCE, std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE)); mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 56c7567c23..8a5b8338ab 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -49,6 +49,7 @@ namespace MWMechanics // distance after which actor (failed previously to shortcut) will try again const float PATHFIND_SHORTCUT_RETRY_DIST = 300.0f; + const float MIN_TOLERANCE = 1.0f; const float DEFAULT_TOLERANCE = 32.0f; // cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target; From 0cdc46dfd6b17257859260211eed66ac22dc6389 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 291/410] Move forcePPL and clamp to global shader defines (bug #4869) --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- components/resource/scenemanager.cpp | 13 ------------- components/resource/scenemanager.hpp | 6 ------ components/shader/shadervisitor.cpp | 15 --------------- components/shader/shadervisitor.hpp | 9 --------- components/terrain/chunkmanager.cpp | 6 ++---- components/terrain/material.cpp | 6 ++---- components/terrain/material.hpp | 2 +- 8 files changed, 9 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 038438f326..f54e423f19 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -220,8 +220,8 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows")); // Shadows have problems with fixed-function mode + // FIXME: calling dummy method because terrain needs to know whether lighting is clamped resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); - resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders")); resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::Manager::getString("normal height map pattern", "Shaders")); @@ -253,6 +253,9 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; + globalDefines["forcePPL"] = Settings::Manager::getBool("force per pixel lighting", "Shaders") ? "1" : "0"; + globalDefines["clamp"] = Settings::Manager::getBool("clamp lighting", "Shaders") ? "1" : "0"; + // It is unnecessary to stop/start the viewer as no frames are being rendered yet. mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index d360e92b19..d371a8ce4c 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -218,7 +218,6 @@ namespace Resource , mShaderManager(new Shader::ShaderManager) , mForceShaders(false) , mClampLighting(true) - , mForcePerPixelLighting(false) , mAutoUseNormalMaps(false) , mAutoUseSpecularMaps(false) , mInstanceCache(new MultiObjectCache) @@ -260,16 +259,6 @@ namespace Resource return mClampLighting; } - void SceneManager::setForcePerPixelLighting(bool force) - { - mForcePerPixelLighting = force; - } - - bool SceneManager::getForcePerPixelLighting() const - { - return mForcePerPixelLighting; - } - void SceneManager::setAutoUseNormalMaps(bool use) { mAutoUseNormalMaps = use; @@ -749,8 +738,6 @@ namespace Resource { Shader::ShaderVisitor* shaderVisitor = new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl"); shaderVisitor->setForceShaders(mForceShaders); - shaderVisitor->setClampLighting(mClampLighting); - shaderVisitor->setForcePerPixelLighting(mForcePerPixelLighting); shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps); shaderVisitor->setNormalMapPattern(mNormalMapPattern); shaderVisitor->setNormalHeightMapPattern(mNormalHeightMapPattern); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 4f1523eced..1c1c60a58d 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -56,14 +56,9 @@ namespace Resource void setForceShaders(bool force); bool getForceShaders() const; - /// @see ShaderVisitor::setClampLighting void setClampLighting(bool clamp); bool getClampLighting() const; - /// @see ShaderVisitor::setForcePerPixelLighting - void setForcePerPixelLighting(bool force); - bool getForcePerPixelLighting() const; - /// @see ShaderVisitor::setAutoUseNormalMaps void setAutoUseNormalMaps(bool use); @@ -155,7 +150,6 @@ namespace Resource std::unique_ptr mShaderManager; bool mForceShaders; bool mClampLighting; - bool mForcePerPixelLighting; bool mAutoUseNormalMaps; std::string mNormalMapPattern; std::string mNormalHeightMapPattern; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 911a8cbbf1..63c6761188 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -37,8 +37,6 @@ namespace Shader ShaderVisitor::ShaderVisitor(ShaderManager& shaderManager, Resource::ImageManager& imageManager, const std::string &defaultVsTemplate, const std::string &defaultFsTemplate) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mForceShaders(false) - , mClampLighting(true) - , mForcePerPixelLighting(false) , mAllowedToModifyStateSets(true) , mAutoUseNormalMaps(false) , mAutoUseSpecularMaps(false) @@ -55,16 +53,6 @@ namespace Shader mForceShaders = force; } - void ShaderVisitor::setClampLighting(bool clamp) - { - mClampLighting = clamp; - } - - void ShaderVisitor::setForcePerPixelLighting(bool force) - { - mForcePerPixelLighting = force; - } - void ShaderVisitor::apply(osg::Node& node) { if (node.getStateSet()) @@ -297,9 +285,6 @@ namespace Shader defineMap[texIt->second + std::string("UV")] = std::to_string(texIt->first); } - defineMap["forcePPL"] = mForcePerPixelLighting ? "1" : "0"; - defineMap["clamp"] = mClampLighting ? "1" : "0"; - defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 8737baf599..ac0ecc6997 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -23,13 +23,6 @@ namespace Shader /// Setting force = true will cause all objects to render using shaders, regardless of having a bump map. void setForceShaders(bool force); - /// Set whether lighting is clamped for visual compatibility with the fixed function pipeline. - void setClampLighting(bool clamp); - - /// By default, only bump mapped objects use per-pixel lighting. - /// Setting force = true will cause all shaders to use per-pixel lighting, regardless of having a bump map. - void setForcePerPixelLighting(bool force); - /// Set if we are allowed to modify StateSets encountered in the graph (default true). /// @par If set to false, then instead of modifying, the StateSet will be cloned and this new StateSet will be assigned to the node. /// @par This option is useful when the ShaderVisitor is run on a "live" subgraph that may have already been submitted for rendering. @@ -57,8 +50,6 @@ namespace Shader private: bool mForceShaders; - bool mClampLighting; - bool mForcePerPixelLighting; bool mAllowedToModifyStateSets; bool mAutoUseNormalMaps; diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 27d87b0310..80f4145419 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -161,8 +161,7 @@ std::vector > ChunkManager::createPasses(float chunk float blendmapScale = mStorage->getBlendmapScale(chunkSize); - return ::Terrain::createPasses(useShaders, mSceneManager->getForcePerPixelLighting(), - mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); + return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); } osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, int lod, unsigned int lodFlags) @@ -217,8 +216,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve layer.mDiffuseMap = compositeMap->mTexture; layer.mParallax = false; layer.mSpecular = false; - geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager->getForcePerPixelLighting(), - mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector(1, layer), std::vector >(), 1.f, 1.f)); + geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector(1, layer), std::vector >(), 1.f, 1.f)); } else { diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index c61bdb455b..1c989cc2a7 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -153,7 +153,7 @@ namespace namespace Terrain { - std::vector > createPasses(bool useShaders, bool forcePerPixelLighting, bool clampLighting, Shader::ShaderManager* shaderManager, const std::vector &layers, + std::vector > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector &layers, const std::vector > &blendmaps, int blendmapScale, float layerTileSize) { std::vector > passes; @@ -211,8 +211,6 @@ namespace Terrain } Shader::ShaderManager::DefineMap defineMap; - defineMap["forcePPL"] = forcePerPixelLighting ? "1" : "0"; - defineMap["clamp"] = clampLighting ? "1" : "0"; defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; defineMap["blendMap"] = !firstLayer ? "1" : "0"; defineMap["specularMap"] = it->mSpecular ? "1" : "0"; @@ -223,7 +221,7 @@ namespace Terrain if (!vertexShader || !fragmentShader) { // Try again without shader. Error already logged by above - return createPasses(false, forcePerPixelLighting, clampLighting, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); + return createPasses(false, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 25aa695400..5f78af6a06 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -26,7 +26,7 @@ namespace Terrain bool mSpecular; }; - std::vector > createPasses(bool useShaders, bool forcePerPixelLighting, bool clampLighting, Shader::ShaderManager* shaderManager, + std::vector > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector& layers, const std::vector >& blendmaps, int blendmapScale, float layerTileSize); From 9d5fc7954f07d4b1d96592ba4e2da07912740cb6 Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Tue, 5 Mar 2019 22:50:27 +0000 Subject: [PATCH 292/410] DRY skill widget updates in stats window The skill widgets were configured in two places: initial creation, and updates. The former was redundant, and duplicated the functionality of the latter. To fix this redundancy, replace the duplicate code with a call to setValue. --- apps/openmw/mwgui/statswindow.cpp | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index fdc7bb6d20..c3f852c5b7 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -438,9 +438,6 @@ namespace MWGui if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; - int base = stat.getBase(); - int modified = stat.getModified(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -452,13 +449,9 @@ namespace MWGui const ESM::Attribute* attr = esmStore.get().find(skill->mData.mAttribute); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; std::pair widgets = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - MyGUI::utility::toString(static_cast(modified)), state, coord1, coord2); + "", "normal", coord1, coord2); + mSkillWidgetMap[skillId] = widgets; for (int i=0; i<2; ++i) { @@ -469,27 +462,9 @@ namespace MWGui mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - if (base < 100) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "false"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "true"); - - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "true"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "false"); - - setSkillProgress(mSkillWidgets[mSkillWidgets.size()-1-i], stat.getProgress(), skillId); - } - else - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "true"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "false"); - - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "false"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "true"); - } } - mSkillWidgetMap[skillId] = widgets; + setValue(static_cast(skillId), mSkillValues.find(skillId)->second); } } From be57da3b1ad5dd7b6606680a8eb3872fe04f7e90 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Feb 2019 23:44:01 +0300 Subject: [PATCH 293/410] Fix version of cached archives for appveyor --- appveyor.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 5f5657285a..90a9cb1bcf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,18 +33,18 @@ configuration: clone_depth: 1 cache: - - C:\projects\openmw\deps\Bullet-2.83.7-msvc2015-win32.7z - - C:\projects\openmw\deps\Bullet-2.83.7-msvc2015-win64.7z - - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2015-win64.7z - - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2015-win64.7z - - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2015-win64.7z - - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2015-win64.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-dev-win32.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-dev-win64.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-win32.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-win64.7z - - C:\projects\openmw\deps\OpenAL-Soft-1.17.2.zip - - C:\projects\openmw\deps\SDL2-2.0.4.zip + - C:\projects\openmw\deps\Bullet-2.86-msvc2015-win32.7z + - C:\projects\openmw\deps\Bullet-2.86-msvc2015-win64.7z + - C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win32.7z + - C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win64.7z + - C:\projects\openmw\deps\OSG-3.4.1-scrawl-msvc2015-win32.7z + - C:\projects\openmw\deps\OSG-3.4.1-scrawl-msvc2015-win64.7z + - C:\projects\openmw\deps\ffmpeg-3.2.4-dev-win32.zip + - C:\projects\openmw\deps\ffmpeg-3.2.4-dev-win64.zip + - C:\projects\openmw\deps\ffmpeg-3.2.4-win32.zip + - C:\projects\openmw\deps\ffmpeg-3.2.4-win64.zip + - C:\projects\openmw\deps\OpenAL-Soft-1.19.1.zip + - C:\projects\openmw\deps\SDL2-2.0.7.zip clone_folder: C:\projects\openmw From e99f783c65b3e12f5d2652c157d6b124f0160f41 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 7 Mar 2019 00:26:45 +0300 Subject: [PATCH 294/410] Remove white spaces and trailing spaces --- CI/before_script.msvc.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 77220cbb72..6b2502bc49 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -82,7 +82,7 @@ while [ $# -gt 0 ]; do t ) TEST_FRAMEWORK=true ;; - + h ) cat < Set the build platform, can also be set with environment variable PLATFORM. - -t - Build unit tests / Google test + -t + Build unit tests / Google test -u Configure for unity builds. -v <2013/2015/2017> @@ -402,7 +402,7 @@ if [ -z $SKIP_DOWNLOAD ]; then download "SDL 2.0.7" \ "https://www.libsdl.org/release/SDL2-devel-2.0.7-VC.zip" \ "SDL2-2.0.7.zip" - + # Google test and mock if [ ! -z $TEST_FRAMEWORK ]; then echo "Google test 1.8.1..." @@ -692,33 +692,33 @@ echo # Google Test and Google Mock if [ ! -z $TEST_FRAMEWORK ]; then printf "Google test 1.8.1 ..." - + cd googletest if [ ! -d build ]; then mkdir build fi - + cd build - + GOOGLE_INSTALL_ROOT="${DEPS_INSTALL}/GoogleTest" if [ $CONFIGURATION == "Debug" ]; then DEBUG_SUFFIX="d" else DEBUG_SUFFIX="" fi - + if [ ! -d $GOOGLE_INSTALL_ROOT ]; then - + cmake .. -DCMAKE_BUILD_TYPE="${CONFIGURATION}" -DCMAKE_INSTALL_PREFIX="${GOOGLE_INSTALL_ROOT}" -DCMAKE_USE_WIN32_THREADS_INIT=1 -G "${GENERATOR}" -DBUILD_SHARED_LIBS=1 cmake --build . --config "${CONFIGURATION}" cmake --build . --target install --config "${CONFIGURATION}" - + add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gtest_main${DEBUG_SUFFIX}.dll" add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gtest${DEBUG_SUFFIX}.dll" add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gmock_main${DEBUG_SUFFIX}.dll" add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gmock${DEBUG_SUFFIX}.dll" fi - + add_cmake_opts -DBUILD_UNITTESTS=yes # FindGTest and FindGMock do not work perfectly on Windows # but we can help them by telling them everything we know about installation @@ -730,7 +730,7 @@ if [ ! -z $TEST_FRAMEWORK ]; then add_cmake_opts -DGMOCK_MAIN_LIBRARY="$GOOGLE_INSTALL_ROOT/lib/gmock_main${DEBUG_SUFFIX}.lib" add_cmake_opts -DGTEST_LINKED_AS_SHARED_LIBRARY=True echo Done. - + fi echo From 7d2c741d1d46f01d2df7b7da9c0b48135c79a316 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 7 Mar 2019 00:18:40 +0300 Subject: [PATCH 295/410] Fix compare with empty value --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 6b2502bc49..5ed7283fd3 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -446,7 +446,7 @@ echo if [ -z $APPVEYOR ]; then printf "Boost 1.67.0... " else - if [ $MSVC_VER -eq 12.0 ]; then + if [ "${MSVC_VER}" -eq 12.0 ]; then printf "Boost 1.58.0 AppVeyor... " else printf "Boost 1.67.0 AppVeyor... " From dcec9df34511908a1ec52f8d38fc3771de076e30 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Mar 2019 08:08:13 +0400 Subject: [PATCH 296/410] Fix MSVC warning about variable re-declaration --- apps/openmw/mwmechanics/aipackage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 698b2efce4..9b01353c77 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -135,9 +135,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - const auto halfExtents = world->getPathfindingHalfExtents(actor); + const auto pathfindingHalfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), - halfExtents, getNavigatorFlags(actor)); + pathfindingHalfExtents, getNavigatorFlags(actor)); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity From 771a45174b048b91715d83455a50e5a53b916e70 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Mar 2019 08:56:46 +0400 Subject: [PATCH 297/410] Update AUTHORS.md --- AUTHORS.md | 88 +++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 0740818763..0c6a5388bc 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -26,17 +26,21 @@ Programmers Allofich Andrei Kortunov (akortunov) AnyOldName3 - Aussiemon - Austin Salgat (Salgat) + Ardekantur + Armin Preiml Artem Kotsynyak (greye) artemutin Arthur Moore (EmperorArthur) Assumeru athile + Aussiemon + Austin Salgat (Salgat) Ben Shealy (bentsherman) + Berulacks Bret Curtis (psi29a) Britt Mathis (galdor557) Capostrophic + Carl Maxwell cc9cii Cédric Mocquillon Chris Boyce (slothlife) @@ -47,6 +51,7 @@ Programmers DanielVukelich darkf David Cernat (davidcernat) + Declan Millar (declan-millar) devnexen Dieho Dmitry Shkurskiy (endorph) @@ -54,10 +59,11 @@ Programmers Douglas Mencken (dougmencken) dreamer-dead David Teviotdale (dteviot) + Diggory Hardy + Dmitry Marakasov (AMDmi3) Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 - elsid Emanuel Guével (potatoesmaster) eroen escondida @@ -67,13 +73,19 @@ Programmers Finbar Crago (finbar-crago) Florian Weber (Florianjw) Gašper Sedej + Gohan1989 gugus/gus + guidoj Hallfaer Tuilinn Haoda Wang (h313) hristoast Internecine - Jacob Essex (Yacoby) + Jackerty + Jacob Essex (Yacoby) Jake Westrip (16bitint) + James Carty (MrTopCat) + Jan-Peter Nilsson (peppe) + Jan Borsodi (am0s) Jason Hooks (jhooks) jeaye Jeffrey Haines (Jyby) @@ -84,6 +96,7 @@ Programmers John Blomberg (fstp) Jordan Ayers Jordan Milne + Josua Grawitter Jules Blok (Armada651) julianko Julien Voisin (jvoisin/ap0) @@ -95,9 +108,10 @@ Programmers lazydev Leon Krieg (lkrieg) Leon Saunders (emoose) - Łukasz Gołębiewski (lukago) logzero lohikaarme + Lordrea + Łukasz Gołębiewski (lukago) Lukasz Gromanowski (lgro) Manuel Edelmann (vorenon) Marc Bouvier (CramitDeFrog) @@ -112,6 +126,7 @@ Programmers Michael Hogan (Xethik) Michael Mc Donnell Michael Papageorgiou (werdanith) + Michał Ściubidło (mike-sc) Michał Bień (Glorf) Michał Moroz (dragonee) Miloslav Číž (drummyfish) @@ -123,15 +138,20 @@ Programmers Nathan Jeffords (blunted2night) NeveHanter Nialsy + Nicolay Korslund Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) Oleg Chkan (mrcheko) Paul Cercueil (pcercuei) Paul McElroy (Greendogo) + pchan3 + Perry Hugh + Phillip Andrews (PhillipAnd) Pi03k Pieter van der Kloet (pvdk) pkubik + PLkolek PlutonicOverkill Radu-Marius Popovici (rpopovici) Rafael Moura (dhustkoder) @@ -145,11 +165,12 @@ Programmers Roman Proskuryakov (kpp) Roman Siromakha (elsid) Sandy Carter (bwrsandman) - Scott Howard + Scott Howard (maqifrnswa) scrawl Sebastian Wick (swick) Sergey Fukanchik - Sergey Shambir + Sergey Shambir (sergey-shambir) + sergoz ShadowRadiance Siimacore sir_herrbatka @@ -158,24 +179,32 @@ Programmers spycrab Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) + Stanislaw Halik (sthalik) + Star-Demon stil-t + Stomy svaante Sylvain Thesnieres (Garvek) t6 terrorfisch thegriglat Thomas Luppi (Digmaster) + tlmullis tri4ng1e - unelsson - Will Herrmann (Thunderforge) + Thoronador Tom Mason (wheybags) Torben Leif Carrington (TorbenC) + unelsson + uramer viadanna Vincent Heuken + Vladimir Panteleev (CyberShadow) + Will Herrmann (Thunderforge) vocollapse + xyzz Yohaulticetl + Yuri Krupenin zelurker - James Carty (MrTopCat) Documentation ------------- @@ -184,11 +213,12 @@ Documentation Alejandro Sanchez (HiPhish) Bodillium Bret Curtis (psi29a) - David Walley (Loriel) Cramal + David Walley (Loriel) + Diego Crespo + Joakim Berg (lysol90) Ryan Tucker (Ravenwing) sir_herrbatka - Diego Crespo Packagers --------- @@ -207,13 +237,19 @@ Public Relations and Translations Artem Kotsynyak (greye) - Russian News Writer Dawid Lakomy (Vedyimyn) - Polish News Writer + ElderTroll - Release Manager Jim Clauwaert (Zedd) - Public Outreach + juanmnzsk8 - Spanish News Writer Julien Voisin (jvoisin/ap0) - French News Writer + Kingpix - Italian News Writer Lukasz Gromanowski (lgro) - English News Writer Martin Otto (Atahualpa) - Podcaster, Public Outreach, German Translator Mickey Lyle (raevol) - Release Manager + Nekochan - English News Writer + penguinroad - Indonesian News Writer Pithorn - Chinese News Writer sir_herrbatka - Polish News Writer + spyboot - German Translator Tom Koenderink (Okulo) - English News Writer Website @@ -243,34 +279,6 @@ Artwork Mickey Lyle (raevol) - Wordpress Theme Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel, Lamoot - OpenMW Editor Icons -Inactive Contributors ---------------------- - - Ardekantur - Armin Preiml - Berulacks - Carl Maxwell - Diggory Hardy - Dmitry Marakasov (AMDmi3) - ElderTroll - guidoj - Jan-Peter Nilsson (peppe) - Jan Borsodi - Josua Grawitter - juanmnzsk8 - Kingpix - Lordrea - Michal Sciubidlo - Nicolay Korslund - Nekochan - pchan3 - penguinroad - sergoz - spyboot - Star-Demon - Thoronador - Yuri Krupenin - Additional Credits ------------------ In this section we would like to thank people not part of OpenMW for their work. From 26dfa287f91d355dfa61b015a9b3308e55994206 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 29 Sep 2018 15:15:15 +0300 Subject: [PATCH 298/410] Use ccache for linux CI build --- .travis.yml | 6 +++++- CI/before_script.linux.sh | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 51b1720c46..d87b0f01c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,10 @@ env: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE=" +cache: + ccache: true + directories: + - ${HOME}/.ccache addons: apt: sources: @@ -17,7 +21,7 @@ addons: - llvm-toolchain-xenial-7 packages: [ # Dev - cmake, clang-7, clang-tools-7, gcc-8, g++-8, + cmake, clang-7, clang-tools-7, gcc-8, g++-8, ccache, # Boost libboost-filesystem-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-system-dev, # FFmpeg diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index 3ce0058747..250955e496 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -14,6 +14,10 @@ if [[ -z "${BUILD_OPENMW}" ]]; then export BUILD_OPENMW=ON; fi if [[ -z "${BUILD_OPENMW_CS}" ]]; then export BUILD_OPENMW_CS=ON; fi ${ANALYZE} cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_OPENMW=${BUILD_OPENMW} \ -DBUILD_OPENCS=${BUILD_OPENMW_CS} \ -DBUILD_LAUNCHER=${BUILD_OPENMW_CS} \ From d23a0ce2ae7e68becb1fb93c406321b10d938656 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Mar 2019 12:38:55 +0400 Subject: [PATCH 299/410] Use C++11-style loops in the game world instead of iterators --- apps/openmw/mwphysics/physicssystem.cpp | 16 +++---- apps/openmw/mwrender/animation.cpp | 3 +- apps/openmw/mwrender/globalmap.cpp | 12 ++--- apps/openmw/mwrender/localmap.cpp | 18 ++++---- apps/openmw/mwrender/pathgrid.cpp | 8 ++-- apps/openmw/mwrender/ripplesimulation.cpp | 15 ++++--- apps/openmw/mwrender/sky.cpp | 4 +- apps/openmw/mwworld/cellpreloader.cpp | 7 ++- apps/openmw/mwworld/globals.cpp | 5 +-- apps/openmw/mwworld/inventorystore.cpp | 44 ++++++++++--------- apps/openmw/mwworld/scene.cpp | 28 +++++------- apps/openmw/mwworld/store.cpp | 45 +++++++++---------- apps/openmw/mwworld/weather.cpp | 14 +++--- apps/openmw/mwworld/worldimp.cpp | 53 +++++++++++------------ 14 files changed, 133 insertions(+), 139 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e3884afad0..df6d299d0e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -707,11 +707,11 @@ namespace MWPhysics if (!targets.empty()) { - for (std::vector::const_iterator it = targets.begin(); it != targets.end(); ++it) + for (MWWorld::Ptr& target : targets) { - const Actor* physactor2 = getActor(*it); - if (physactor2) - targetCollisionObjects.push_back(physactor2->getCollisionObject()); + const Actor* targetActor = getActor(target); + if (targetActor) + targetCollisionObjects.push_back(targetActor->getCollisionObject()); } } @@ -811,9 +811,9 @@ namespace MWPhysics if (!targets.empty()) { - for (std::vector::const_iterator it = targets.begin(); it != targets.end(); ++it) + for (MWWorld::Ptr& target : targets) { - const Actor* actor = getActor(*it); + const Actor* actor = getActor(target); if (actor) targetCollisionObjects.push_back(actor->getCollisionObject()); } @@ -1320,8 +1320,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) - (*it)->animateCollisionShapes(mCollisionWorld); + for (Object* animatedObject : mAnimatedObjects) + animatedObject->animateCollisionShapes(mCollisionWorld); #ifndef BT_NO_PROFILE CProfileManager::Reset(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f6df24358d..bde7a53218 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -79,10 +79,9 @@ namespace void remove() { - for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + for (osg::Node* node : mToRemove) { // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index d1b6cd239f..5880396398 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -234,10 +234,10 @@ namespace MWRender GlobalMap::~GlobalMap() { - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); - for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) - removeCamera(*it); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); + for (auto& camera : mActiveCameras) + removeCamera(camera); if (mWorkItem) mWorkItem->waitTillDone(); @@ -581,8 +581,8 @@ namespace MWRender void GlobalMap::cleanupCameras() { - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); mCamerasPendingRemoval.clear(); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1060a5c0b2..1650dc92c6 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -92,10 +92,10 @@ LocalMap::LocalMap(osg::Group* root) LocalMap::~LocalMap() { - for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) - removeCamera(*it); - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); + for (auto& camera : mActiveCameras) + removeCamera(camera); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); } const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) @@ -259,16 +259,14 @@ bool needUpdate(std::set >& renderedGrid, std::set cells) { std::set > grid; - for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + for (const MWWorld::CellStore* cell : cells) { - const MWWorld::CellStore* cell = *it; if (cell->isExterior()) grid.insert(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); } - for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + for (const MWWorld::CellStore* cell : cells) { - const MWWorld::CellStore* cell = *it; if (cell->isExterior()) { int cellX = cell->getCell()->getGridX(); @@ -341,8 +339,8 @@ void LocalMap::cleanupCameras() if (mCamerasPendingRemoval.empty()) return; - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); mCamerasPendingRemoval.clear(); } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 8a7bc8b5ee..7977944570 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -76,17 +76,17 @@ void Pathgrid::togglePathgrid() mPathGridRoot->setNodeMask(Mask_Debug); mRootNode->addChild(mPathGridRoot); - for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) + for(const MWWorld::CellStore* cell : mActiveCells) { - enableCellPathgrid(*it); + enableCellPathgrid(cell); } } else { // remove path grid meshes from already loaded cells - for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) + for(const MWWorld::CellStore* cell : mActiveCells) { - disableCellPathgrid(*it); + disableCellPathgrid(cell); } if (mPathGridRoot) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 21bd48d9ae..a124870600 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -118,21 +118,22 @@ RippleSimulation::~RippleSimulation() void RippleSimulation::update(float dt) { const MWBase::World* world = MWBase::Environment::get().getWorld(); - for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) + for (Emitter& emitter : mEmitters) { - if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) + MWWorld::ConstPtr& ptr = emitter.mPtr; + if (ptr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) { // fetch a new ptr (to handle cell change etc) // for non-player actors this is done in updateObjectCell - it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); + osg::Vec3f currentPos (ptr.getRefData().getPosition().asVec3()); - bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr); - if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 ) + bool shouldEmit = (world->isUnderwater(ptr.getCell(), currentPos) && !world->isSubmerged(ptr)) || world->isWalkingOnWater(ptr); + if (shouldEmit && (currentPos - emitter.mLastEmitPosition).length() > 10) { - it->mLastEmitPosition = currentPos; + emitter.mLastEmitPosition = currentPos; currentPos.z() = mParticleNode->getPosition().z(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 194646f2aa..3b5f0a4fab 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1813,8 +1813,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? - for (std::vector >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it) - (*it)->setAlpha(weather.mEffectFade); + for (AlphaFader* fader : mParticleFaders) + fader->setAlpha(weather.mEffectFade); } void SkyManager::sunEnable() diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 96461c1178..65ba19b4ac 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -72,9 +72,9 @@ namespace MWWorld const std::vector& objectIds = cell->getPreloadedIds(); // could possibly build the model list in the worker thread if we manage to make the Store thread safe - for (std::vector::const_iterator it = objectIds.begin(); it != objectIds.end(); ++it) + for (const std::string& id : objectIds) { - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), *it); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id); std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); if (!model.empty()) mMeshes.push_back(model); @@ -102,14 +102,13 @@ namespace MWWorld } } - for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) + for (std::string& mesh: mMeshes) { if (mAbort) break; try { - std::string mesh = *it; mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); if (mPreloadInstances) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index acc06b28a9..69ec5563bc 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -37,10 +37,9 @@ namespace MWWorld const MWWorld::Store& globals = store.get(); - for (MWWorld::Store::iterator iter = globals.begin(); iter!=globals.end(); - ++iter) + for (const ESM::Global& esmGlobal : globals) { - mVariables.insert (std::make_pair (Misc::StringUtils::lowerCase (iter->mId), *iter)); + mVariables.insert (std::make_pair (Misc::StringUtils::lowerCase (esmGlobal.mId), esmGlobal)); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index a0895a1538..a8fa916802 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -462,14 +462,13 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& iter->getClass().getEquipmentSlots (*iter); // checking if current item pointed by iter can be equipped - for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); - iter2!=itemsSlots.first.end(); ++iter2) + for (int slot : itemsSlots.first) { // if true then it means slot is equipped already // check if slot may require swapping if current item is more valuable - if (slots_.at (*iter2)!=end()) + if (slots_.at (slot)!=end()) { - Ptr old = *slots_.at (*iter2); + Ptr old = *slots_.at (slot); if (iter.getType() == ContainerStore::Type_Armor) { @@ -490,7 +489,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& else if (iter.getType() == ContainerStore::Type_Clothing) { // if left ring is equipped - if (*iter2 == Slot_LeftRing) + if (slot == Slot_LeftRing) { // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) @@ -530,7 +529,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& } // if we are here it means item can be equipped or swapped - slots_[*iter2] = iter; + slots_[slot] = iter; break; } } @@ -645,10 +644,9 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Try resisting each effect int i=0; - for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt) + for (const ESM::ENAMstruct& effect : enchantment.mEffects.mList) { - params[i].mMultiplier = MWMechanics::getEffectMultiplier(effectIt->mEffectID, actor, actor); + params[i].mMultiplier = MWMechanics::getEffectMultiplier(effect.mEffectID, actor, actor); ++i; } @@ -662,18 +660,20 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()]; int i=0; - for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) + for (const ESM::ENAMstruct& effect : enchantment.mEffects.mList) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( - effectIt->mEffectID); + effect.mEffectID); // Fully resisted or can't be applied to target? - if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer())) + if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effect.mEffectID, actor, actor, actor == MWMechanics::getPlayer())) + { + i++; continue; + } - float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom; + float magnitude = effect.mMagnMin + (effect.mMagnMax - effect.mMagnMin) * params[i].mRandom; magnitude *= params[i].mMultiplier; if (!existed) @@ -685,7 +685,9 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) } if (magnitude) - mMagicEffects.add (*effectIt, magnitude); + mMagicEffects.add (effect, magnitude); + + i++; } } } @@ -949,17 +951,17 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito continue; int i=0; - for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) + for (const ESM::ENAMstruct& effect : enchantment.mEffects.mList) { + i++; // Don't get spell icon display information for enchantments that weren't actually applied - if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0) + if (mMagicEffects.get(MWMechanics::EffectKey(effect)).getMagnitude() == 0) continue; - const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; - float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; + const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i-1]; + float magnitude = effect.mMagnMin + (effect.mMagnMax - effect.mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; if (magnitude > 0) - visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); + visitor.visit(MWMechanics::EffectKey(effect), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); } } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d06034e1dc..6655bef4be 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -230,9 +230,8 @@ namespace template void InsertVisitor::insert(AddObject&& addObject) { - for (std::vector::iterator it = mToInsert.begin(); it != mToInsert.end(); ++it) + for (MWWorld::Ptr& ptr : mToInsert) { - MWWorld::Ptr ptr = *it; if (mRescale) { if (ptr.getCellRef().getScale()<0.5) @@ -905,24 +904,22 @@ namespace MWWorld void Scene::preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, std::vector& exteriorPositions) { std::vector teleportDoors; - for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); - iter!=mActiveCells.end(); ++iter) + for (const MWWorld::CellStore* cellStore : mActiveCells) { - const MWWorld::CellStore* cellStore = *iter; typedef MWWorld::CellRefList::List DoorList; const DoorList &doors = cellStore->getReadOnlyDoors().mList; - for (DoorList::const_iterator doorIt = doors.begin(); doorIt != doors.end(); ++doorIt) + for (auto& door : doors) { - if (!doorIt->mRef.getTeleport()) { + if (!door.mRef.getTeleport()) + { continue; } - teleportDoors.push_back(MWWorld::ConstPtr(&*doorIt, cellStore)); + teleportDoors.push_back(MWWorld::ConstPtr(&door, cellStore)); } } - for (std::vector::iterator it = teleportDoors.begin(); it != teleportDoors.end(); ++it) + for (const MWWorld::ConstPtr& door : teleportDoors) { - const MWWorld::ConstPtr& door = *it; float sqrDistToPlayer = (playerPos - door.getRefData().getPosition().asVec3()).length2(); sqrDistToPlayer = std::min(sqrDistToPlayer, (predictedPos - door.getRefData().getPosition().asVec3()).length2()); @@ -1046,20 +1043,19 @@ namespace MWWorld const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3()); - for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); iter!=mActiveCells.end(); ++iter) + for (MWWorld::CellStore* cellStore : mActiveCells) { - MWWorld::CellStore* cellStore = *iter; cellStore->forEachType(listVisitor); cellStore->forEachType(listVisitor); } - for (std::vector::const_iterator it = listVisitor.mList.begin(); it != listVisitor.mList.end(); ++it) + for (ESM::Transport::Dest& dest : listVisitor.mList) { - if (!it->mCellName.empty()) - preloadCell(MWBase::Environment::get().getWorld()->getInterior(it->mCellName)); + if (!dest.mCellName.empty()) + preloadCell(MWBase::Environment::get().getWorld()->getInterior(dest.mCellName)); else { - osg::Vec3f pos = it->mPos.asVec3(); + osg::Vec3f pos = dest.mPos.asVec3(); int x,y; MWBase::Environment::get().getWorld()->positionToIndex( pos.x(), pos.y(), x, y); preloadCell(MWBase::Environment::get().getWorld()->getExterior(x,y), true); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 631b6e0811..79d9174ed9 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -420,10 +420,9 @@ namespace MWWorld //========================================================================= Store::~Store() { - for (std::vector::const_iterator it = - mStatic.begin(); it != mStatic.end(); ++it) + for (const ESM::Land* staticLand : mStatic) { - delete *it; + delete staticLand; } } @@ -737,15 +736,16 @@ namespace MWWorld } const ESM::Cell *Store::searchExtByName(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mName, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + const ESM::Cell *cell = nullptr; + for (const ESM::Cell *sharedCell : mSharedExt) + { + if (Misc::StringUtils::ciEqual(sharedCell->mName, id)) + { + if (cell == 0 || + (sharedCell->mData.mX > cell->mData.mX) || + (sharedCell->mData.mX == cell->mData.mX && sharedCell->mData.mY > cell->mData.mY)) { - cell = *it; + cell = sharedCell; } } } @@ -753,15 +753,16 @@ namespace MWWorld } const ESM::Cell *Store::searchExtByRegion(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + const ESM::Cell *cell = nullptr; + for (const ESM::Cell *sharedCell : mSharedExt) + { + if (Misc::StringUtils::ciEqual(sharedCell->mRegion, id)) + { + if (cell == nullptr || + (sharedCell->mData.mX > cell->mData.mX) || + (sharedCell->mData.mX == cell->mData.mX && sharedCell->mData.mY > cell->mData.mY)) { - cell = *it; + cell = sharedCell; } } } @@ -775,9 +776,9 @@ namespace MWWorld { list.reserve(list.size() + mSharedInt.size()); - std::vector::const_iterator it = mSharedInt.begin(); - for (; it != mSharedInt.end(); ++it) { - list.push_back((*it)->mName); + for (const ESM::Cell *sharedCell : mSharedInt) + { + list.push_back(sharedCell->mName); } } ESM::Cell *Store::insert(const ESM::Cell &cell) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6ef9535e9f..c181b95cf6 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -298,10 +298,11 @@ void RegionWeather::setChances(const std::vector& chances) mChances.reserve(chances.size()); } - std::vector::const_iterator it = chances.begin(); - for(size_t i = 0; it != chances.end(); ++it, ++i) + int i = 0; + for(char chance : chances) { - mChances[i] = *it; + mChances[i] = chance; + i++; } // Regional weather no longer supports the current type, select a new weather pattern. @@ -936,11 +937,10 @@ inline void WeatherManager::addWeather(const std::string& name, inline void WeatherManager::importRegions() { - Store::iterator it = mStore.get().begin(); - for(; it != mStore.get().end(); ++it) + for(const ESM::Region& region : mStore.get()) { - std::string regionID = Misc::StringUtils::lowerCase(it->mId); - mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + std::string regionID = Misc::StringUtils::lowerCase(region.mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(region))); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 72e1433583..d8324476a2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1649,13 +1649,13 @@ namespace MWWorld /// \todo should use convexSweepTest here std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); - for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + for (MWWorld::Ptr& ptr : collisions) { - MWWorld::Ptr ptr = *cit; if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door - if(ptr != getPlayerPtr() ) { + if(ptr != getPlayerPtr() ) + { MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr); @@ -3606,18 +3606,17 @@ namespace MWWorld const std::string& id, const std::string& sourceName, const bool fromProjectile) { std::map > toApply; - for (std::vector::const_iterator effectIt = effects.mList.begin(); - effectIt != effects.mList.end(); ++effectIt) + for (const ESM::ENAMstruct& effectInfo : effects.mList) { - const ESM::MagicEffect* effect = mStore.get().find(effectIt->mEffectID); + const ESM::MagicEffect* effect = mStore.get().find(effectInfo.mEffectID); - if (effectIt->mRange != rangeType || (effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor())) + if (effectInfo.mRange != rangeType || (effectInfo.mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor())) continue; // Not right range type, or not area effect and hit an actor - if (fromProjectile && effectIt->mArea <= 0) + if (fromProjectile && effectInfo.mArea <= 0) continue; // Don't play explosion for projectiles with 0-area effects - if (!fromProjectile && effectIt->mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore))) + if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore))) continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from the projectile enchantment // Spawn the explosion orb effect @@ -3629,14 +3628,14 @@ namespace MWWorld std::string texture = effect->mParticle; - if (effectIt->mArea <= 0) + if (effectInfo.mArea <= 0) { - if (effectIt->mRange == ESM::RT_Target) + if (effectInfo.mRange == ESM::RT_Target) mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, 1.0f); continue; } else - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectIt->mArea * 2)); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectInfo.mArea * 2)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -3652,40 +3651,40 @@ namespace MWWorld // Get the actors in range of the effect std::vector objects; MWBase::Environment::get().getMechanicsManager()->getObjectsInRange( - origin, feetToGameUnits(static_cast(effectIt->mArea)), objects); + origin, feetToGameUnits(static_cast(effectInfo.mArea)), objects); for (const Ptr& affected : objects) { // Ignore actors without collisions here, otherwise it will be possible to hit actors outside processing range. if (affected.getClass().isActor() && !isActorCollisionEnabled(affected)) continue; - toApply[affected].push_back(*effectIt); + toApply[affected].push_back(effectInfo); } } // Now apply the appropriate effects to each actor in range - for (std::map >::iterator apply = toApply.begin(); apply != toApply.end(); ++apply) + for (auto& applyPair : toApply) { MWWorld::Ptr source = caster; // Vanilla-compatible behaviour of never applying the spell to the caster // (could be changed by mods later) - if (apply->first == caster) + if (applyPair.first == caster) continue; - if (apply->first == ignore) + if (applyPair.first == ignore) continue; if (source.isEmpty()) - source = apply->first; + source = applyPair.first; - MWMechanics::CastSpell cast(source, apply->first); + MWMechanics::CastSpell cast(source, applyPair.first); cast.mHitPosition = origin; cast.mId = id; cast.mSourceName = sourceName; cast.mStack = false; ESM::EffectList effectsToApply; - effectsToApply.mList = apply->second; - cast.inflict(apply->first, caster, effectsToApply, rangeType, false, true); + effectsToApply.mList = applyPair.second; + cast.inflict(applyPair.first, caster, effectsToApply, rangeType, false, true); } } @@ -3769,22 +3768,22 @@ namespace MWWorld void World::preloadEffects(const ESM::EffectList *effectList) { - for (std::vector::const_iterator it = effectList->mList.begin(); it != effectList->mList.end(); ++it) + for (const ESM::ENAMstruct& effectInfo : effectList->mList) { - const ESM::MagicEffect *effect = mStore.get().find(it->mEffectID); + const ESM::MagicEffect *effect = mStore.get().find(effectInfo.mEffectID); - if (MWMechanics::isSummoningEffect(it->mEffectID)) + if (MWMechanics::isSummoningEffect(effectInfo.mEffectID)) { preload(mWorldScene.get(), mStore, "VFX_Summon_Start"); - preload(mWorldScene.get(), mStore, MWMechanics::getSummonedCreature(it->mEffectID)); + preload(mWorldScene.get(), mStore, MWMechanics::getSummonedCreature(effectInfo.mEffectID)); } preload(mWorldScene.get(), mStore, effect->mCasting); preload(mWorldScene.get(), mStore, effect->mHit); - if (it->mArea > 0) + if (effectInfo.mArea > 0) preload(mWorldScene.get(), mStore, effect->mArea); - if (it->mRange == ESM::RT_Target) + if (effectInfo.mRange == ESM::RT_Target) preload(mWorldScene.get(), mStore, effect->mBolt); } } From 19092afa9418347937fd72e2b58519c07f10bb65 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Mar 2019 14:14:06 +0400 Subject: [PATCH 300/410] Add bzzt to the AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 0c6a5388bc..c3a27dea26 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -199,6 +199,7 @@ Programmers viadanna Vincent Heuken Vladimir Panteleev (CyberShadow) + Wang Ryu (bzzt) Will Herrmann (Thunderforge) vocollapse xyzz From b8b7568ce5810af2ddf9b40f2e0aabe323c2d93f Mon Sep 17 00:00:00 2001 From: Perry Hugh Date: Tue, 5 Mar 2019 14:39:40 -0800 Subject: [PATCH 301/410] Correct odd toggling menu behavior. --- apps/openmw/mwinput/inputmanagerimp.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b904dbcb71..e0c16166fd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1146,12 +1146,21 @@ namespace MWInput bool state = MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - if (mode == MWGui::GM_Settings || (!state && mode == MWGui::GM_MainMenu)) + if (mode == MWGui::GM_MainMenu) { if (MyGUI::InputManager::getInstance().isModalAny()) - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); + { + while (MyGUI::InputManager::getInstance().isModalAny()) + { + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + } + } + else if (!state) + MWBase::Environment::get().getWindowManager()->popGuiMode(); } + else if (mode == MWGui::GM_Settings) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + if(state || mode == MWGui::GM_MainMenu) return; From 72db11b56c16f0c3b2f291c01b51f944014d5673 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Mar 2019 14:50:29 +0400 Subject: [PATCH 302/410] Fix Clang warnings about hidden virtual methods --- components/terrain/quadtreenode.hpp | 2 +- components/terrain/quadtreeworld.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 9c925a4d92..618429c5c0 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -40,7 +40,7 @@ namespace Terrain inline unsigned int getNumChildren() const { return _children.size(); } // osg::Group::addChild() does a lot of unrelated stuff, but we just really want to add a child node. - void addChild(QuadTreeNode* child) + void addChildNode(QuadTreeNode* child) { // QuadTree node should not contain more than 4 child nodes. // Reserve enough space if this node is supposed to have child nodes. diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 141f7073c3..8d54f62ce2 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -165,7 +165,7 @@ public: if (child) { boundingBox.expandBy(child->getBoundingBox()); - parent->addChild(child); + parent->addChildNode(child); } } From b05531818ce0b023d7f04dde99ea6d59a19d294b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 7 Mar 2019 21:09:00 +0300 Subject: [PATCH 303/410] Fix raki creatures in Skyrim: Home of the Nords (bug #4810) Make bip01 have higher priority than 'root node' node when determining the movement accumulation root --- CHANGELOG.md | 1 + apps/openmw/mwrender/animation.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index beef1c79fe..c6c510fa16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change Bug #4803: Stray special characters before begin statement break script compilation Bug #4804: Particle system with the "Has Sizes = false" causes an exception + Bug #4810: Raki creature broken in OpenMW Bug #4813: Creatures with known file but no "Sound Gen Creature" assigned use default sounds Bug #4815: "Finished" journal entry with lower index doesn't close journal, SetJournalIndex closes journal Bug #4820: Spell absorption is broken diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f6df24358d..67e0e1d453 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -843,9 +843,9 @@ namespace MWRender if (!mAccumRoot) { - NodeMap::const_iterator found = nodeMap.find("root bone"); + NodeMap::const_iterator found = nodeMap.find("bip01"); if (found == nodeMap.end()) - found = nodeMap.find("bip01"); + found = nodeMap.find("root bone"); if (found != nodeMap.end()) mAccumRoot = found->second; From d34724a3c43be5786aabe535c9c56d128317c926 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 7 Mar 2019 20:46:10 +0000 Subject: [PATCH 304/410] Hopefully fix Clang warning about hiding overloaded virtual functions --- components/sceneutil/mwshadowtechnique.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 6210667990..74c8661b99 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -101,6 +101,8 @@ namespace SceneUtil { void apply(osg::Camera&); + using osg::NodeVisitor::apply; + void updateBound(const osg::BoundingBox& bb); void update(const osg::Vec3& v); From 47e87cc2bd9de1dfd31ac06e4dae4656ea9df31f Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 7 Mar 2019 23:49:20 +0300 Subject: [PATCH 305/410] Fix ODR violation for VDSMCameraCullCallback This class is also defined in OpenSceneGraph at global namespace. --- components/sceneutil/mwshadowtechnique.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 64c2e6e55f..4125ebe7d1 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -25,6 +25,8 @@ #include +namespace { + using namespace osgShadow; using namespace SceneUtil; @@ -331,6 +333,8 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) _projectionMatrix = cv->getProjectionMatrix(); } +} // namespace + MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { From de41c9802207e8dece6f1426907c9ffdfef0c210 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Mar 2019 13:36:44 +0400 Subject: [PATCH 306/410] Refactor menu toggling --- apps/openmw/mwinput/inputmanagerimp.cpp | 38 ++++++++++++++----------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e0c16166fd..32f79706d9 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1143,23 +1143,19 @@ namespace MWInput void InputManager::toggleMainMenu() { + if (MyGUI::InputManager::getInstance().isModalAny()) + { + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + return; + } + bool state = MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - if (mode == MWGui::GM_MainMenu) + if (mode == MWGui::GM_MainMenu || mode == MWGui::GM_Settings) { - if (MyGUI::InputManager::getInstance().isModalAny()) - { - while (MyGUI::InputManager::getInstance().isModalAny()) - { - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); - } - } - else if (!state) - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } - else if (mode == MWGui::GM_Settings) MWBase::Environment::get().getWindowManager()->popGuiMode(); + } if(state || mode == MWGui::GM_MainMenu) return; @@ -1169,20 +1165,25 @@ namespace MWInput void InputManager::toggleOptionsMenu() { + if (MyGUI::InputManager::getInstance().isModalAny()) + { + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + return; + } + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + bool state = MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; if (mode == MWGui::GM_Settings) { - if (MyGUI::InputManager::getInstance().isModalAny()) - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); MWBase::Environment::get().getWindowManager()->popGuiMode(); return; } - else if (mode == MWGui::GM_MainMenu && !(MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame)) + else if (mode == MWGui::GM_MainMenu && !state) { - if (MyGUI::InputManager::getInstance().isModalAny()) - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); MWBase::Environment::get().getWindowManager()->popGuiMode(); } + else if (mode == MWGui::GM_MainMenu) + return; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); } @@ -1626,6 +1627,7 @@ namespace MWInput descriptions[A_Journal] = "sJournal"; descriptions[A_Rest] = "sRestKey"; descriptions[A_Inventory] = "sInventory"; + descriptions[A_OptionsMenu] = "sPreferences"; descriptions[A_TogglePOV] = "sTogglePOVCmd"; descriptions[A_QuickKeysMenu] = "sQuickMenu"; descriptions[A_QuickKey1] = "sQuick1Cmd"; @@ -1763,6 +1765,7 @@ namespace MWInput ret.push_back(A_Inventory); ret.push_back(A_Journal); ret.push_back(A_Rest); + ret.push_back(A_OptionsMenu); ret.push_back(A_Console); ret.push_back(A_QuickSave); ret.push_back(A_QuickLoad); @@ -1795,6 +1798,7 @@ namespace MWInput ret.push_back(A_Inventory); ret.push_back(A_Journal); ret.push_back(A_Rest); + ret.push_back(A_OptionsMenu); ret.push_back(A_QuickSave); ret.push_back(A_QuickLoad); ret.push_back(A_Screenshot); From b6243e7d1fa1354f1eb19b731d61ce31c969ca12 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:02:49 +0300 Subject: [PATCH 307/410] Fix name styleguide --- components/detournavigator/navmeshtilescache.cpp | 14 +++++++------- components/detournavigator/navmeshtilescache.hpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 64edab0ad0..418e69e824 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -62,8 +62,8 @@ namespace DetourNavigator return Value(); // TODO: use different function to make key to avoid unnecessary std::string allocation - const auto tile = tileValues->second.Map.find(makeNavMeshKey(recastMesh, offMeshConnections)); - if (tile == tileValues->second.Map.end()) + const auto tile = tileValues->second.mMap.find(makeNavMeshKey(recastMesh, offMeshConnections)); + if (tile == tileValues->second.mMap.end()) return Value(); acquireItemUnsafe(tile->second); @@ -96,7 +96,7 @@ namespace DetourNavigator const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, navMeshKey); // TODO: use std::string_view or some alternative to avoid navMeshKey copy into both mFreeItems and mValues - const auto emplaced = mValues[agentHalfExtents][changedTile].Map.emplace(navMeshKey, iterator); + const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(navMeshKey, iterator); if (!emplaced.second) { @@ -125,16 +125,16 @@ namespace DetourNavigator if (tileValues == agentValues->second.end()) return; - const auto value = tileValues->second.Map.find(item.mNavMeshKey); - if (value == tileValues->second.Map.end()) + const auto value = tileValues->second.mMap.find(item.mNavMeshKey); + if (value == tileValues->second.mMap.end()) return; mUsedNavMeshDataSize -= getSize(item); mFreeNavMeshDataSize -= getSize(item); mFreeItems.pop_back(); - tileValues->second.Map.erase(value); - if (!tileValues->second.Map.empty()) + tileValues->second.mMap.erase(value); + if (!tileValues->second.mMap.empty()) return; agentValues->second.erase(tileValues); diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 7418c4d3a2..e244cda9d7 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -108,7 +108,7 @@ namespace DetourNavigator struct TileMap { - std::map Map; + std::map mMap; }; std::mutex mMutex; From 14c9190f490956ae86f01ff79c7fe488247d76cf Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:06:11 +0300 Subject: [PATCH 308/410] Move tile replacement into separate function --- components/detournavigator/makenavmesh.cpp | 84 ++++++++++++---------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index f1f6205c70..5b39230063 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -461,6 +461,49 @@ namespace ++power; return power; } + + dtStatus addTile(dtNavMesh& navMesh, const NavMeshData& navMeshData) + { + const dtTileRef lastRef = 0; + dtTileRef* const result = nullptr; + return navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize, + doNotTransferOwnership, lastRef, result); + } + + dtStatus addTile(dtNavMesh& navMesh, const NavMeshTilesCache::Value& cachedNavMeshData) + { + const dtTileRef lastRef = 0; + dtTileRef* const result = nullptr; + return navMesh.addTile(cachedNavMeshData.get().mValue, cachedNavMeshData.get().mSize, + doNotTransferOwnership, lastRef, result); + } + + template + UpdateNavMeshStatus replaceTile(const SharedNavMeshCacheItem& navMeshCacheItem, + const TilePosition& changedTile, T&& navMeshData) + { + const auto locked = navMeshCacheItem.lock(); + auto& navMesh = locked->getValue(); + const int layer = 0; + const auto tileRef = navMesh.getTileRefAt(changedTile.x(), changedTile.y(), layer); + unsigned char** const data = nullptr; + int* const dataSize = nullptr; + const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, data, dataSize)); + const auto addStatus = addTile(navMesh, navMeshData); + + if (dtStatusSucceed(addStatus)) + { + locked->setUsedTile(changedTile, std::forward(navMeshData)); + return makeUpdateNavMeshStatus(removed, true); + } + else + { + if (removed) + locked->removeUsedTile(changedTile); + log("failed to add tile with status=", WriteDtStatus {addStatus}); + return makeUpdateNavMeshStatus(removed, false); + } + } } namespace DetourNavigator @@ -583,47 +626,10 @@ namespace DetourNavigator if (!cachedNavMeshData) { log("cache overflow"); - - const auto locked = navMeshCacheItem.lock(); - auto& navMesh = locked->getValue(); - const auto tileRef = navMesh.getTileRefAt(x, y, 0); - const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); - const auto addStatus = navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize, - doNotTransferOwnership, 0, 0); - - if (dtStatusSucceed(addStatus)) - { - locked->setUsedTile(changedTile, std::move(navMeshData)); - return makeUpdateNavMeshStatus(removed, true); - } - else - { - if (removed) - locked->removeUsedTile(changedTile); - log("failed to add tile with status=", WriteDtStatus {addStatus}); - return makeUpdateNavMeshStatus(removed, false); - } + return replaceTile(navMeshCacheItem, changedTile, std::move(navMeshData)); } } - const auto locked = navMeshCacheItem.lock(); - auto& navMesh = locked->getValue(); - const auto tileRef = navMesh.getTileRefAt(x, y, 0); - const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); - const auto addStatus = navMesh.addTile(cachedNavMeshData.get().mValue, cachedNavMeshData.get().mSize, - doNotTransferOwnership, 0, 0); - - if (dtStatusSucceed(addStatus)) - { - locked->setUsedTile(changedTile, std::move(cachedNavMeshData)); - return makeUpdateNavMeshStatus(removed, true); - } - else - { - if (removed) - locked->removeUsedTile(changedTile); - log("failed to add tile with status=", WriteDtStatus {addStatus}); - return makeUpdateNavMeshStatus(removed, false); - } + return replaceTile(navMeshCacheItem, changedTile, std::move(cachedNavMeshData)); } } From 0c16fef285bdccee912887c9a027f2d4b773636c Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:06:47 +0300 Subject: [PATCH 309/410] Add navmesh update status builder --- .../detournavigator/asyncnavmeshupdater.cpp | 4 +- components/detournavigator/makenavmesh.cpp | 56 ++++++++++++++----- components/detournavigator/makenavmesh.hpp | 10 ++-- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 1e158667b0..fd240e4a0b 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -32,11 +32,11 @@ namespace DetourNavigator { switch (value) { - case UpdateNavMeshStatus::ignore: + case UpdateNavMeshStatus::ignored: return stream << "ignore"; case UpdateNavMeshStatus::removed: return stream << "removed"; - case UpdateNavMeshStatus::add: + case UpdateNavMeshStatus::added: return stream << "add"; case UpdateNavMeshStatus::replaced: return stream << "replaced"; diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 5b39230063..a03e9fd8d5 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -441,17 +441,47 @@ namespace return NavMeshData(navMeshData, navMeshDataSize); } - UpdateNavMeshStatus makeUpdateNavMeshStatus(bool removed, bool add) + class UpdateNavMeshStatusBuilder { - if (removed && add) - return UpdateNavMeshStatus::replaced; - else if (removed) - return UpdateNavMeshStatus::removed; - else if (add) - return UpdateNavMeshStatus::add; - else - return UpdateNavMeshStatus::ignore; - } + public: + UpdateNavMeshStatusBuilder() = default; + + UpdateNavMeshStatusBuilder removed(bool value) + { + if (value) + set(UpdateNavMeshStatus::removed); + else + unset(UpdateNavMeshStatus::removed); + return *this; + } + + UpdateNavMeshStatusBuilder added(bool value) + { + if (value) + set(UpdateNavMeshStatus::added); + else + unset(UpdateNavMeshStatus::added); + return *this; + } + + UpdateNavMeshStatus getResult() const + { + return mResult; + } + + private: + UpdateNavMeshStatus mResult = UpdateNavMeshStatus::ignored; + + void set(UpdateNavMeshStatus value) + { + mResult = static_cast(static_cast(mResult) | static_cast(value)); + } + + void unset(UpdateNavMeshStatus value) + { + mResult = static_cast(static_cast(mResult) & ~static_cast(value)); + } + }; template unsigned long getMinValuableBitsNumber(const T value) @@ -494,14 +524,14 @@ namespace if (dtStatusSucceed(addStatus)) { locked->setUsedTile(changedTile, std::forward(navMeshData)); - return makeUpdateNavMeshStatus(removed, true); + return UpdateNavMeshStatusBuilder().added(true).removed(removed).getResult(); } else { if (removed) locked->removeUsedTile(changedTile); log("failed to add tile with status=", WriteDtStatus {addStatus}); - return makeUpdateNavMeshStatus(removed, false); + return UpdateNavMeshStatusBuilder().removed(removed).getResult(); } } } @@ -565,7 +595,7 @@ namespace DetourNavigator const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); if (removed) locked->removeUsedTile(changedTile); - return makeUpdateNavMeshStatus(removed, false); + return UpdateNavMeshStatusBuilder().removed(removed).getResult(); }; if (!recastMesh) diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 55d3e261c5..20198047c3 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -20,12 +20,12 @@ namespace DetourNavigator class RecastMesh; struct Settings; - enum class UpdateNavMeshStatus + enum class UpdateNavMeshStatus : unsigned { - ignore, - removed, - add, - replaced + ignored = 0, + removed = 1 << 0, + added = 1 << 1, + replaced = removed | added, }; inline float getLength(const osg::Vec2i& value) From b9b8ed177c389e1d4d65e9664ed7a2931f9dd75b Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:23:36 +0300 Subject: [PATCH 310/410] Store priority values as named fields --- .../detournavigator/asyncnavmeshupdater.cpp | 24 +++++++++---------- .../detournavigator/asyncnavmeshupdater.hpp | 11 +++++++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index fd240e4a0b..ce52c1416c 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -14,16 +14,6 @@ namespace { return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y()); } - - std::tuple makePriority(const TilePosition& position, const ChangeType changeType, - const TilePosition& playerTile) - { - return std::make_tuple( - changeType, - getManhattanDistance(position, playerTile), - getManhattanDistance(position, TilePosition {0, 0}) - ); - } } namespace DetourNavigator @@ -81,8 +71,18 @@ namespace DetourNavigator for (const auto& changedTile : changedTiles) { if (mPushed[agentHalfExtents].insert(changedTile.first).second) - mJobs.push(Job {agentHalfExtents, navMeshCacheItem, changedTile.first, - makePriority(changedTile.first, changedTile.second, playerTile)}); + { + Job job; + + job.mAgentHalfExtents = agentHalfExtents; + job.mNavMeshCacheItem = navMeshCacheItem; + job.mChangedTile = changedTile.first; + job.mChangeType = changedTile.second; + job.mDistanceToPlayer = getManhattanDistance(changedTile.first, playerTile); + job.mDistanceToOrigin = getManhattanDistance(changedTile.first, TilePosition {0, 0}); + + mJobs.push(std::move(job)); + } } log("posted ", mJobs.size(), " jobs"); diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 39898e48e1..da97333627 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -50,11 +50,18 @@ namespace DetourNavigator osg::Vec3f mAgentHalfExtents; SharedNavMeshCacheItem mNavMeshCacheItem; TilePosition mChangedTile; - std::tuple mPriority; + ChangeType mChangeType; + int mDistanceToPlayer; + int mDistanceToOrigin; + + std::tuple getPriority() const + { + return std::make_tuple(mChangeType, mDistanceToPlayer, mDistanceToOrigin); + } friend inline bool operator <(const Job& lhs, const Job& rhs) { - return lhs.mPriority > rhs.mPriority; + return lhs.getPriority() > rhs.getPriority(); } }; From 82e2739bae198f5854629a1a3a93f2186513f783 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:27:16 +0300 Subject: [PATCH 311/410] Notify workers when only at least one job is posted --- components/detournavigator/asyncnavmeshupdater.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index ce52c1416c..6cfd75b27b 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -87,7 +87,8 @@ namespace DetourNavigator log("posted ", mJobs.size(), " jobs"); - mHasJob.notify_all(); + if (!mJobs.empty()) + mHasJob.notify_all(); } void AsyncNavMeshUpdater::wait() From ff47df4f2ccd8ff41d78db6a07ba31793ac7cc34 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:28:32 +0300 Subject: [PATCH 312/410] Repost navmesh update jobs when failed because of out of memory DT_OUT_OF_MEMORY error is returned when limit of tiles is reached. --- .../detournavigator/asyncnavmeshupdater.cpp | 45 ++++++++++++++----- .../detournavigator/asyncnavmeshupdater.hpp | 9 ++-- components/detournavigator/makenavmesh.cpp | 11 ++++- components/detournavigator/makenavmesh.hpp | 9 +++- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 6cfd75b27b..ee3b6d77ab 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -1,4 +1,4 @@ -#include "asyncnavmeshupdater.hpp" +#include "asyncnavmeshupdater.hpp" #include "debug.hpp" #include "makenavmesh.hpp" #include "settings.hpp" @@ -30,6 +30,10 @@ namespace DetourNavigator return stream << "add"; case UpdateNavMeshStatus::replaced: return stream << "replaced"; + case UpdateNavMeshStatus::failed: + return stream << "failed"; + case UpdateNavMeshStatus::lost: + return stream << "lost"; } return stream << "unknown"; } @@ -77,6 +81,7 @@ namespace DetourNavigator job.mAgentHalfExtents = agentHalfExtents; job.mNavMeshCacheItem = navMeshCacheItem; job.mChangedTile = changedTile.first; + job.mTryNumber = 0; job.mChangeType = changedTile.second; job.mDistanceToPlayer = getManhattanDistance(changedTile.first, playerTile); job.mDistanceToOrigin = getManhattanDistance(changedTile.first, TilePosition {0, 0}); @@ -104,8 +109,9 @@ namespace DetourNavigator { try { - if (const auto job = getNextJob()) - processJob(*job); + if (auto job = getNextJob()) + if (!processJob(*job)) + repost(std::move(*job)); } catch (const std::exception& e) { @@ -115,7 +121,7 @@ namespace DetourNavigator log("stop process jobs"); } - void AsyncNavMeshUpdater::processJob(const Job& job) + bool AsyncNavMeshUpdater::processJob(const Job& job) { log("process job for agent=", job.mAgentHalfExtents); @@ -136,12 +142,16 @@ namespace DetourNavigator using FloatMs = std::chrono::duration; - const auto locked = job.mNavMeshCacheItem.lockConst(); - log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, - " generation=", locked->getGeneration(), - " revision=", locked->getNavMeshRevision(), - " time=", std::chrono::duration_cast(finish - start).count(), "ms", - " total_time=", std::chrono::duration_cast(finish - firstStart).count(), "ms"); + { + const auto locked = job.mNavMeshCacheItem.lockConst(); + log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, + " generation=", locked->getGeneration(), + " revision=", locked->getNavMeshRevision(), + " time=", std::chrono::duration_cast(finish - start).count(), "ms", + " total_time=", std::chrono::duration_cast(finish - firstStart).count(), "ms"); + } + + return isSuccess(status); } boost::optional AsyncNavMeshUpdater::getNextJob() @@ -194,4 +204,19 @@ namespace DetourNavigator *locked = value; return *locked.get(); } + + void AsyncNavMeshUpdater::repost(Job&& job) + { + if (mShouldStop || job.mTryNumber > 2) + return; + + const std::lock_guard lock(mMutex); + + if (mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second) + { + ++job.mTryNumber; + mJobs.push(std::move(job)); + mHasJob.notify_all(); + } + } } diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index da97333627..98359964d1 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -50,13 +50,14 @@ namespace DetourNavigator osg::Vec3f mAgentHalfExtents; SharedNavMeshCacheItem mNavMeshCacheItem; TilePosition mChangedTile; + unsigned mTryNumber; ChangeType mChangeType; int mDistanceToPlayer; int mDistanceToOrigin; - std::tuple getPriority() const + std::tuple getPriority() const { - return std::make_tuple(mChangeType, mDistanceToPlayer, mDistanceToOrigin); + return std::make_tuple(mTryNumber, mChangeType, mDistanceToPlayer, mDistanceToOrigin); } friend inline bool operator <(const Job& lhs, const Job& rhs) @@ -83,13 +84,15 @@ namespace DetourNavigator void process() throw(); - void processJob(const Job& job); + bool processJob(const Job& job); boost::optional getNextJob(); void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const; std::chrono::steady_clock::time_point setFirstStart(const std::chrono::steady_clock::time_point& value); + + void repost(Job&& job); }; } diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index a03e9fd8d5..e62509940c 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -464,6 +464,15 @@ namespace return *this; } + UpdateNavMeshStatusBuilder failed(bool value) + { + if (value) + set(UpdateNavMeshStatus::failed); + else + unset(UpdateNavMeshStatus::failed); + return *this; + } + UpdateNavMeshStatus getResult() const { return mResult; @@ -531,7 +540,7 @@ namespace if (removed) locked->removeUsedTile(changedTile); log("failed to add tile with status=", WriteDtStatus {addStatus}); - return UpdateNavMeshStatusBuilder().removed(removed).getResult(); + return UpdateNavMeshStatusBuilder().removed(removed).failed((addStatus & DT_OUT_OF_MEMORY) != 0).getResult(); } } } diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 20198047c3..1dfa242eed 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -26,8 +26,15 @@ namespace DetourNavigator removed = 1 << 0, added = 1 << 1, replaced = removed | added, + failed = 1 << 2, + lost = removed | failed, }; + inline bool isSuccess(UpdateNavMeshStatus value) + { + return (static_cast(value) & static_cast(UpdateNavMeshStatus::failed)) == 0; + } + inline float getLength(const osg::Vec2i& value) { return std::sqrt(float(osg::square(value.x()) + osg::square(value.y()))); @@ -41,7 +48,7 @@ namespace DetourNavigator inline bool shouldAddTile(const TilePosition& changedTile, const TilePosition& playerTile, int maxTiles) { const auto expectedTilesCount = std::ceil(osg::PI * osg::square(getDistance(changedTile, playerTile))); - return expectedTilesCount * 3 <= maxTiles; + return expectedTilesCount <= maxTiles; } NavMeshPtr makeEmptyNavMesh(const Settings& settings); From f2e47d640d15dc5b1e96f34dd1ca18245ad8d0b0 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 22 Feb 2019 01:22:10 +0300 Subject: [PATCH 313/410] Add option to limit max number of navmesh tiles --- .../detournavigator/navigator.cpp | 1 + components/detournavigator/makenavmesh.cpp | 2 +- components/detournavigator/navmeshmanager.cpp | 2 +- components/detournavigator/settings.cpp | 1 + components/detournavigator/settings.hpp | 1 + .../reference/modding/settings/navigator.rst | 24 +++++++++++++++++++ files/settings-default.cfg | 3 +++ 7 files changed, 32 insertions(+), 2 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 42b69d7f91..9daef6f64e 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -61,6 +61,7 @@ namespace mSettings.mMaxSmoothPathSize = 1024; mSettings.mTrianglesPerChunk = 256; mSettings.mMaxPolys = 4096; + mSettings.mMaxTilesNumber = 512; mNavigator.reset(new NavigatorImpl(mSettings)); } }; diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index e62509940c..5ac28127ec 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -628,7 +628,7 @@ namespace DetourNavigator return removeTile(); } - if (!shouldAddTile(changedTile, playerTile, params.maxTiles)) + if (!shouldAddTile(changedTile, playerTile, std::min(settings.mMaxTilesNumber, params.maxTiles))) { log("ignore add tile: too far from player"); return removeTile(); diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 2a29d1dd4a..217c17e410 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -157,7 +157,7 @@ namespace DetourNavigator if (changedTiles->second.empty()) mChangedTiles.erase(changedTiles); } - const auto maxTiles = navMesh.getParams()->maxTiles; + const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles); mRecastMeshManager.forEachTilePosition([&] (const TilePosition& tile) { if (tilesToPost.count(tile)) diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index ddffd0d1f5..735194dbaf 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -24,6 +24,7 @@ namespace DetourNavigator navigatorSettings.mMaxEdgeLen = ::Settings::Manager::getInt("max edge len", "Navigator"); navigatorSettings.mMaxNavMeshQueryNodes = ::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"); navigatorSettings.mMaxPolys = ::Settings::Manager::getInt("max polygons per tile", "Navigator"); + navigatorSettings.mMaxTilesNumber = ::Settings::Manager::getInt("max tiles number", "Navigator"); navigatorSettings.mMaxVertsPerPoly = ::Settings::Manager::getInt("max verts per poly", "Navigator"); navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator"); navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min size", "Navigator"); diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index 0316092a0e..dc0e5dc5a0 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -26,6 +26,7 @@ namespace DetourNavigator int mMaxEdgeLen = 0; int mMaxNavMeshQueryNodes = 0; int mMaxPolys = 0; + int mMaxTilesNumber = 0; int mMaxVertsPerPoly = 0; int mRegionMergeSize = 0; int mRegionMinSize = 0; diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index 1b65c35a85..d9ddf5381a 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -24,6 +24,24 @@ 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. +max tiles number +---------------- + +:Type: integer +:Range: >= 0 +:Default: 512 + +Number of tiles at nav mesh. +Nav mesh covers circle area around player. +This option allows to set an explicit limit for nav mesh size, how many tiles should fit into circle. +If actor is inside this area it able to find path over nav mesh. +Increasing this value may decrease performance. + +.. note:: + Don't expect infinite nav mesh size increasing. + This condition is always true: ``max tiles number * max polygons per tile <= 4194304``. + It's a limitation of `Recastnavigation `_ library. + Advanced settings ***************** @@ -322,6 +340,12 @@ Maximum number of polygons per nav mesh tile. Maximum number of nav mesh tiles d this value. 22 bits is a limit to store both tile identifier and polygon identifier (tiles = 2^(22 - log2(polygons))). See `recastnavigation `_ for more details. +.. Warning:: + Lower value may lead to ignored world geometry on nav mesh. + Greater value will reduce number of nav mesh tiles. + This condition is always true: ``max tiles number * max polygons per tile <= 4194304``. + It's a limitation of `Recastnavigation `_ library. + max verts per poly ------------------ diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e3920a4bf9..e95646602d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -670,6 +670,9 @@ enable nav mesh render = false # Render agents paths (true, false) enable agents paths render = false +# Max number of navmesh tiles (value >= 0) +max tiles number = 512 + [Shadows] # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. From 4c21776b94cc5ba96bf343a956eeb696c5a55254 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 5 Mar 2019 13:33:58 +0400 Subject: [PATCH 314/410] Use relative animation time only for bows and crossbows (bug #3778) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 10 ++++++-- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwrender/npcanimation.hpp | 2 +- apps/openmw/mwrender/weaponanimation.cpp | 11 +++++--- apps/openmw/mwrender/weaponanimation.hpp | 5 ++-- apps/openmw/mwworld/projectilemanager.cpp | 29 +++++----------------- 9 files changed, 31 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index beef1c79fe..1fa78c8b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Bug #3623: Fix HiDPI on Windows Bug #3733: Normal maps are inverted on mirrored UVs Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable + Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4383: Bow model obscures crosshair when arrow is drawn Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 44a0f87ff4..d1f8562f4f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -917,7 +917,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) { mAnimation->showWeapons(true); - mAnimation->setWeaponGroup(mCurrentWeapon); + // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly, + // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example) + bool useRelativeDuration = mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Crossbow; + mAnimation->setWeaponGroup(mCurrentWeapon, useRelativeDuration); } mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType)); @@ -1375,7 +1378,10 @@ bool CharacterController::updateWeaponState(CharacterState& idle) mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype)); getWeaponGroup(weaptype, weapgroup); - mAnimation->setWeaponGroup(weapgroup); + // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly, + // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example) + bool useRelativeDuration = weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow; + mAnimation->setWeaponGroup(weapgroup, useRelativeDuration); if (!isStillWeapon) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 153f2ead95..f638a4db79 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -457,7 +457,7 @@ public: virtual void showWeapons(bool showWeapon) {} virtual void showCarriedLeft(bool show) {} - virtual void setWeaponGroup(const std::string& group) {} + virtual void setWeaponGroup(const std::string& group, bool relativeDuration) {} virtual void setVampire(bool vampire) {} /// A value < 1 makes the animation translucent, 1.f = fully opaque void setAlpha(float alpha); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index d0fd5bdb4f..5242725847 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -44,7 +44,7 @@ namespace MWRender virtual osg::Node* getWeaponNode(); virtual Resource::ResourceSystem* getResourceSystem(); virtual void showWeapon(bool show) { showWeapons(show); } - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void setWeaponGroup(const std::string& group, bool relativeDuration) { mWeaponAnimationTime->setGroup(group, relativeDuration); } virtual void addControllers(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a775f9391d..f1ebc80dfd 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1030,9 +1030,9 @@ void NpcAnimation::enableHeadAnimation(bool enable) mHeadAnimationTime->setEnabled(enable); } -void NpcAnimation::setWeaponGroup(const std::string &group) +void NpcAnimation::setWeaponGroup(const std::string &group, bool relativeDuration) { - mWeaponAnimationTime->setGroup(group); + mWeaponAnimationTime->setGroup(group, relativeDuration); } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1fbdd863cd..1ec0dfa591 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -117,7 +117,7 @@ public: /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands virtual void setAccurateAiming(bool enabled); - virtual void setWeaponGroup(const std::string& group); + virtual void setWeaponGroup(const std::string& group, bool relativeDuration); virtual osg::Vec3f runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index d5a8cb10d9..1b51f04623 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -33,15 +33,20 @@ float WeaponAnimationTime::getValue(osg::NodeVisitor*) return current - mStartTime; } -void WeaponAnimationTime::setGroup(const std::string &group) +void WeaponAnimationTime::setGroup(const std::string &group, bool relativeTime) { mWeaponGroup = group; - mStartTime = mAnimation->getStartTime(mWeaponGroup); + mRelativeTime = relativeTime; + + if (mRelativeTime) + mStartTime = mAnimation->getStartTime(mWeaponGroup); + else + mStartTime = 0; } void WeaponAnimationTime::updateStartTime() { - setGroup(mWeaponGroup); + setGroup(mWeaponGroup, mRelativeTime); } WeaponAnimation::WeaponAnimation() diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index d50729c622..ece0beaa6c 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -17,9 +17,10 @@ namespace MWRender Animation* mAnimation; std::string mWeaponGroup; float mStartTime; + bool mRelativeTime; public: - WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} - void setGroup(const std::string& group); + WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0), mRelativeTime(false) {} + void setGroup(const std::string& group, bool relativeTime); void updateStartTime(); virtual float getValue(osg::NodeVisitor* nv); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6e163b0d57..b13db3a3e5 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -204,12 +203,6 @@ namespace MWWorld osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); - osg::ref_ptr boundVisitor = new osg::ComputeBoundsVisitor(); - projectile->accept(*boundVisitor.get()); - osg::BoundingBox bb = boundVisitor->getBoundingBox(); - - state.mNode->setPivotPoint(bb.center()); - if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) { @@ -465,24 +458,14 @@ namespace MWWorld osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; - osg::Quat orient; - - if (it->mThrown) - orient.set( - osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) * - osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * - osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * - osg::Matrixd::inverse( - osg::Matrixd::lookAt( - osg::Vec3f(0,0,0), - it->mVelocity, - osg::Vec3f(0,0,1)) - ) - ); - else + // rotation does not work well for throwing projectiles - their roll angle will depend on shooting direction. + if (!it->mThrown) + { + osg::Quat orient; orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + it->mNode->setAttitude(orient); + } - it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); update(*it, duration); From 46e1ed660c6bb37517ed40e3425944aafd27f162 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 28 Feb 2019 22:10:13 +0400 Subject: [PATCH 315/410] Revert "Render default land texture for Wilderness cells with distant terrain" This reverts commit 888c2d9a33c27b764e55793ecc5cee7a4364d446. --- components/terrain/quadtreeworld.cpp | 37 +++++++++++++++++++--------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 8d54f62ce2..a97aba68c7 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -201,22 +201,35 @@ public: node->setLodCallback(parent->getLodCallback()); node->setViewDataMap(mViewDataMap); - if (node->getSize() > mMinSize) + if (center.x() - size > mMaxX + || center.x() + size < mMinX + || center.y() - size > mMaxY + || center.y() + size < mMinY ) + // Out of bounds of the actual terrain - this will happen because + // we rounded the size up to the next power of two + { + // Still create and return an empty node so as to not break the assumption that each QuadTreeNode has either 4 or 0 children. + return node; + } + + if (node->getSize() <= mMinSize) + { + // We arrived at a leaf + float minZ,maxZ; + if (mStorage->getMinMaxHeights(size, center, minZ, maxZ)) + { + float cellWorldSize = mStorage->getCellWorldSize(); + osg::BoundingBox boundingBox(osg::Vec3f((center.x()-size)*cellWorldSize, (center.y()-size)*cellWorldSize, minZ), + osg::Vec3f((center.x()+size)*cellWorldSize, (center.y()+size)*cellWorldSize, maxZ)); + node->setBoundingBox(boundingBox); + } + return node; + } + else { addChildren(node); return node; } - - // We arrived at a leaf - float minZ, maxZ; - mStorage->getMinMaxHeights(size, center, minZ, maxZ); - - float cellWorldSize = mStorage->getCellWorldSize(); - osg::BoundingBox boundingBox(osg::Vec3f((center.x()-halfSize)*cellWorldSize, (center.y()-halfSize)*cellWorldSize, minZ), - osg::Vec3f((center.x()+halfSize)*cellWorldSize, (center.y()+halfSize)*cellWorldSize, maxZ)); - node->setBoundingBox(boundingBox); - - return node; } osg::ref_ptr getRootNode() From a6fd077537bb8c114ae2b1ad5a1254ef6af1a87c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 28 Feb 2019 22:19:48 +0400 Subject: [PATCH 316/410] Render nearby default cells if the Distant Terrain is disabled --- components/terrain/quadtreeworld.cpp | 22 +++++++++++++++++++++- components/terrain/quadtreeworld.hpp | 7 ++++++- components/terrain/terraingrid.cpp | 5 +++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index a97aba68c7..6a4ad67031 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -249,7 +249,7 @@ private: }; QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize) - : World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) + : TerrainGrid(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) , mLodFactor(lodFactor) @@ -515,5 +515,25 @@ void QuadTreeWorld::setDefaultViewer(osg::Object *obj) mViewDataMap->setDefaultViewer(obj); } +void QuadTreeWorld::loadCell(int x, int y) +{ + // fallback behavior only for undefined cells (every other is already handled in quadtree) + float dummy; + if (!mStorage->getMinMaxHeights(1, osg::Vec2f(x+0.5, y+0.5), dummy, dummy)) + TerrainGrid::loadCell(x,y); + else + World::loadCell(x,y); +} + +void QuadTreeWorld::unloadCell(int x, int y) +{ + // fallback behavior only for undefined cells (every other is already handled in quadtree) + float dummy; + if (!mStorage->getMinMaxHeights(1, osg::Vec2f(x+0.5, y+0.5), dummy, dummy)) + TerrainGrid::unloadCell(x,y); + else + World::unloadCell(x,y); +} + } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index f724c44b1c..f02f5df4a3 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -2,6 +2,7 @@ #define COMPONENTS_TERRAIN_QUADTREEWORLD_H #include "world.hpp" +#include "terraingrid.hpp" #include @@ -16,7 +17,7 @@ namespace Terrain class ViewDataMap; /// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD. The entire world is displayed at all times. - class QuadTreeWorld : public Terrain::World + class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell) { public: QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize); @@ -28,6 +29,10 @@ namespace Terrain virtual void enable(bool enabled); void cacheCell(View *view, int x, int y); + /// @note Not thread safe. + virtual void loadCell(int x, int y); + /// @note Not thread safe. + virtual void unloadCell(int x, int y); View* createView(); void preload(View* view, const osg::Vec3f& eyePoint); diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 1888a02b34..a7d43f6730 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -5,6 +5,7 @@ #include #include "chunkmanager.hpp" +#include "compositemaprenderer.hpp" namespace Terrain { @@ -61,6 +62,10 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu if (parent) parent->addChild(node); + osg::UserDataContainer* udc = node->getUserDataContainer(); + if (udc && udc->getUserData()) + mCompositeMapRenderer->setImmediate(static_cast(udc->getUserData())); + return node; } } From e0cf460ba3288cb3cc0c43386da6453f6f63da9c Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 317/410] Do not load terrain beyond the viewing distance --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++ components/terrain/quadtreenode.cpp | 26 ++++++++++++- components/terrain/quadtreenode.hpp | 4 +- components/terrain/quadtreeworld.cpp | 45 ++++++----------------- components/terrain/quadtreeworld.hpp | 3 ++ components/terrain/world.hpp | 2 + 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f54e423f19..42bd0c69b0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1198,6 +1198,10 @@ namespace MWRender mUniformNear->set(mNearClip); mUniformFar->set(mViewDistance); + + // Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear. + float distanceMult = std::cos(osg::DegreesToRadians(mFieldOfView)/2.f); + mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f)); } void RenderingManager::updateTextureFiltering() diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index f8237306ea..0c157cd484 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -76,6 +76,30 @@ QuadTreeNode *QuadTreeNode::getNeighbour(Direction dir) return mNeighbours[dir]; } +float QuadTreeNode::distance(const osg::Vec3f& v) const +{ + const osg::BoundingBox& box = getBoundingBox(); + if (box.contains(v)) + return 0; + else + { + osg::Vec3f maxDist(0,0,0); + if (v.x() < box.xMin()) + maxDist.x() = box.xMin() - v.x(); + else if (v.x() > box.xMax()) + maxDist.x() = v.x() - box.xMax(); + if (v.y() < box.yMin()) + maxDist.y() = box.yMin() - v.y(); + else if (v.y() > box.yMax()) + maxDist.y() = v.y() - box.yMax(); + if (v.z() < box.zMin()) + maxDist.z() = box.zMin() - v.z(); + else if (v.z() > box.zMax()) + maxDist.z() = v.z() - box.zMax(); + return maxDist.length(); + } +} + void QuadTreeNode::initNeighbours() { for (int i=0; i<4; ++i) @@ -92,7 +116,7 @@ void QuadTreeNode::traverse(osg::NodeVisitor &nv) ViewData* vd = getView(nv); - if ((mLodCallback && mLodCallback->isSufficientDetail(this, vd->getEyePoint())) || !getNumChildren()) + if ((mLodCallback && mLodCallback->isSufficientDetail(this, distance(vd->getEyePoint()))) || !getNumChildren()) vd->add(this, true); else osg::Group::traverse(nv); diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 618429c5c0..336a257fb8 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -23,7 +23,7 @@ namespace Terrain public: virtual ~LodCallback() {} - virtual bool isSufficientDetail(QuadTreeNode *node, const osg::Vec3f& eyePoint) = 0; + virtual bool isSufficientDetail(QuadTreeNode *node, float dist) = 0; }; class ViewDataMap; @@ -49,6 +49,8 @@ namespace Terrain child->addParent(this); }; + float distance(const osg::Vec3f& v) const; + /// Returns our direction relative to the parent node, or Root if we are the root node. ChildDirection getDirection() { return mDirection; } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 6a4ad67031..5970732292 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -40,33 +40,6 @@ namespace return targetlevel; } - float distanceToBox(const osg::BoundingBox& box, const osg::Vec3f& v) - { - if (box.contains(v)) - return 0; - else - { - osg::Vec3f maxDist(0,0,0); - - if (v.x() < box.xMin()) - maxDist.x() = box.xMin() - v.x(); - else if (v.x() > box.xMax()) - maxDist.x() = v.x() - box.xMax(); - - if (v.y() < box.yMin()) - maxDist.y() = box.yMin() - v.y(); - else if (v.y() > box.yMax()) - maxDist.y() = v.y() - box.yMax(); - - if (v.z() < box.zMin()) - maxDist.z() = box.zMin() - v.z(); - else if (v.z() > box.zMax()) - maxDist.z() = v.z() - box.zMax(); - - return maxDist.length(); - } - } - } namespace Terrain @@ -81,9 +54,8 @@ public: { } - virtual bool isSufficientDetail(QuadTreeNode* node, const osg::Vec3f& eyePoint) + virtual bool isSufficientDetail(QuadTreeNode* node, float dist) { - float dist = distanceToBox(node->getBoundingBox(), eyePoint); int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize*mFactor))); @@ -254,6 +226,7 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour , mQuadTreeBuilt(false) , mLodFactor(lodFactor) , mVertexLodMod(vertexLodMod) + , mViewDistance(std::numeric_limits::max()) { // No need for culling on the Drawable / Transform level as the quad tree performs the culling already. mChunkManager->setCullingActive(false); @@ -269,7 +242,7 @@ QuadTreeWorld::~QuadTreeWorld() } -void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& eyePoint, bool visible) +void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& eyePoint, bool visible, float maxDist) { if (!node->hasValidBounds()) return; @@ -277,14 +250,18 @@ void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallbac if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) visible = visible && !static_cast(nv)->isCulled(node->getBoundingBox()); - bool stopTraversal = (lodCallback && lodCallback->isSufficientDetail(node, eyePoint)) || !node->getNumChildren(); + float dist = node->distance(eyePoint); + if (dist > maxDist) + return; + + bool stopTraversal = (lodCallback && lodCallback->isSufficientDetail(node, dist)) || !node->getNumChildren(); if (stopTraversal) vd->add(node, visible); else { for (unsigned int i=0; igetNumChildren(); ++i) - traverse(node->getChild(i), vd, nv, lodCallback, eyePoint, visible); + traverse(node->getChild(i), vd, nv, lodCallback, eyePoint, visible, maxDist); } } @@ -416,7 +393,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) traverseToCell(mRootNode.get(), vd, x,y); } else - traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true); + traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true, mViewDistance); } else mRootNode->traverse(nv); @@ -496,7 +473,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) ensureQuadTreeBuilt(); ViewData* vd = static_cast(view); - traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false); + traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false, mViewDistance); for (unsigned int i=0; igetNumEntries(); ++i) { diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index f02f5df4a3..bb09048c28 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -28,6 +28,8 @@ namespace Terrain virtual void enable(bool enabled); + virtual void setViewDistance(float distance) { mViewDistance = distance; } + void cacheCell(View *view, int x, int y); /// @note Not thread safe. virtual void loadCell(int x, int y); @@ -52,6 +54,7 @@ namespace Terrain bool mQuadTreeBuilt; float mLodFactor; int mVertexLodMod; + float mViewDistance; }; } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 4fb724ebbf..83a2655fdd 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -100,6 +100,8 @@ namespace Terrain /// Set the default viewer (usually a Camera), used as viewpoint for any viewers that don't use their own viewpoint. virtual void setDefaultViewer(osg::Object* obj) {} + virtual void setViewDistance(float distance) {} + Storage* getStorage() { return mStorage; } protected: From 8fd6b37e34d42a05602ecdfb74925b10f5f4a5f3 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 20:01:50 +0300 Subject: [PATCH 318/410] Make path point tolerance depending on actor half extents --- apps/openmw/mwmechanics/aipackage.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 9b01353c77..90da9d1609 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -167,7 +167,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& mTimer = 0; } - const float pointTolerance = std::max(MIN_TOLERANCE, std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE)); + const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration + + 1.2 * std::max(halfExtents.x(), halfExtents.y()); + const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance); mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE); From b9f21ec81a9c7e1d2403a14e8e937e10158de794 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 19:53:37 +0300 Subject: [PATCH 319/410] Use custom steps size to make smooth path depending on half extents --- apps/openmw/mwmechanics/pathfinding.cpp | 7 ++-- .../detournavigator/navigator.cpp | 34 ++++++++++--------- components/detournavigator/findsmoothpath.hpp | 11 +++--- components/detournavigator/navigator.hpp | 6 ++-- components/detournavigator/settingsutils.hpp | 5 +++ 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index e31da94b15..c4d3a8e96c 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -301,8 +301,11 @@ namespace MWMechanics { try { - const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); - navigator->findPath(halfExtents, startPoint, endPoint, flags, out); + const auto world = MWBase::Environment::get().getWorld(); + const auto realHalfExtents = world->getHalfExtents(actor); // This may differ from halfExtents argument + const auto stepSize = 2 * std::max(realHalfExtents.x(), realHalfExtents.y()); + const auto navigator = world->getNavigator(); + navigator->findPath(halfExtents, stepSize, startPoint, endPoint, flags, out); } catch (const DetourNavigator::NavigatorException& exception) { diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 42b69d7f91..3211ddf00a 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -27,6 +27,7 @@ namespace osg::Vec3f mEnd; std::deque mPath; std::back_insert_iterator> mOut; + float mStepSize; DetourNavigatorNavigatorTest() : mPlayerPosition(0, 0, 0) @@ -34,6 +35,7 @@ namespace , mStart(-215, 215, 1) , mEnd(215, -215, 1) , mOut(mPath) + , mStepSize(28.333332061767578125f) { mSettings.mEnableWriteRecastMeshToFile = false; mSettings.mEnableWriteNavMeshToFile = false; @@ -67,21 +69,21 @@ namespace TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) { - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque()); } TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception) { mNavigator->addAgent(mAgentHalfExtents); - EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException); + EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut), NavigatorException); } TEST_F(DetourNavigatorNavigatorTest, find_path_for_removed_agent_should_return_empty) { mNavigator->addAgent(mAgentHalfExtents); mNavigator->removeAgent(mAgentHalfExtents); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque()); } @@ -90,7 +92,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents); mNavigator->removeAgent(mAgentHalfExtents); - EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException); + EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut), NavigatorException); } TEST_F(DetourNavigatorNavigatorTest, update_then_find_path_should_return_path) @@ -110,7 +112,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), @@ -160,7 +162,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), @@ -193,7 +195,7 @@ namespace mNavigator->wait(); mPath.clear(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.87826788425445556640625), @@ -244,7 +246,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.87826788425445556640625), @@ -279,7 +281,7 @@ namespace mNavigator->wait(); mPath.clear(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), @@ -336,7 +338,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.96328866481781005859375), @@ -392,7 +394,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.9393787384033203125), @@ -445,7 +447,7 @@ namespace mEnd.x() = 0; mEnd.z() = 300; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, 185.33331298828125), @@ -491,7 +493,7 @@ namespace mStart.x() = 0; mEnd.x() = 0; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim | Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), @@ -537,7 +539,7 @@ namespace mStart.x() = 0; mEnd.x() = 0; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim | Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), @@ -583,7 +585,7 @@ namespace mStart.x() = 0; mEnd.x() = 0; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), @@ -632,7 +634,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), diff --git a/components/detournavigator/findsmoothpath.hpp b/components/detournavigator/findsmoothpath.hpp index ce5febebe0..e988dedb73 100644 --- a/components/detournavigator/findsmoothpath.hpp +++ b/components/detournavigator/findsmoothpath.hpp @@ -166,7 +166,7 @@ namespace DetourNavigator template OutputIterator makeSmoothPath(const dtNavMesh& navMesh, const dtNavMeshQuery& navMeshQuery, - const dtQueryFilter& filter, const osg::Vec3f& start, const osg::Vec3f& end, + const dtQueryFilter& filter, const osg::Vec3f& start, const osg::Vec3f& end, const float stepSize, std::vector polygonPath, std::size_t maxSmoothPathSize, OutputIterator out) { // Iterate over the path to find smooth path on the detail mesh surface. @@ -176,7 +176,6 @@ namespace DetourNavigator osg::Vec3f targetPos; navMeshQuery.closestPointOnPoly(polygonPath.back(), end.ptr(), targetPos.ptr(), 0); - const float STEP_SIZE = 0.5f; const float SLOP = 0.01f; *out++ = iterPos; @@ -200,10 +199,10 @@ namespace DetourNavigator const osg::Vec3f delta = steerTarget->steerPos - iterPos; float len = delta.length(); // If the steer target is end of path or off-mesh link, do not move past the location. - if ((endOfPath || offMeshConnection) && len < STEP_SIZE) + if ((endOfPath || offMeshConnection) && len < stepSize) len = 1; else - len = STEP_SIZE / len; + len = stepSize / len; const osg::Vec3f moveTgt = iterPos + delta * len; const auto result = moveAlongSurface(navMeshQuery, polygonPath.front(), iterPos, moveTgt, filter, 16); @@ -273,7 +272,7 @@ namespace DetourNavigator } template - OutputIterator findSmoothPath(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, + OutputIterator findSmoothPath(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, const float stepSize, const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings, OutputIterator out) { @@ -315,7 +314,7 @@ namespace DetourNavigator if (polygonPath.empty() || polygonPath.back() != endRef) return out; - makeSmoothPath(navMesh, navMeshQuery, queryFilter, start, end, std::move(polygonPath), + makeSmoothPath(navMesh, navMeshQuery, queryFilter, start, end, stepSize, std::move(polygonPath), settings.mMaxSmoothPathSize, OutputTransformIterator(out, settings)); return out; diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index a06d97c563..a146fe0fb9 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -160,7 +160,7 @@ namespace DetourNavigator * @throws InvalidArgument if there is no navmesh for given agentHalfExtents. */ template - OutputIterator findPath(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start, + OutputIterator findPath(const osg::Vec3f& agentHalfExtents, const float stepSize, const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, OutputIterator out) const { static_assert( @@ -175,8 +175,8 @@ namespace DetourNavigator return out; const auto settings = getSettings(); return findSmoothPath(navMesh.lock()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), - toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings, end), includeFlags, - settings, out); + toNavMeshCoordinates(settings, stepSize), toNavMeshCoordinates(settings, start), + toNavMeshCoordinates(settings, end), includeFlags, settings, out); } /** diff --git a/components/detournavigator/settingsutils.hpp b/components/detournavigator/settingsutils.hpp index d96ea53cc2..a22205b2aa 100644 --- a/components/detournavigator/settingsutils.hpp +++ b/components/detournavigator/settingsutils.hpp @@ -31,6 +31,11 @@ namespace DetourNavigator return agentHalfExtents.x() * settings.mRecastScaleFactor; } + inline float toNavMeshCoordinates(const Settings& settings, float value) + { + return value * settings.mRecastScaleFactor; + } + inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position) { std::swap(position.y(), position.z()); From ea80a81538fdd116177a0501e8909926a3084589 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 19:58:42 +0300 Subject: [PATCH 320/410] Drop path points while tolerance allows --- apps/openmw/mwmechanics/pathfinding.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index c4d3a8e96c..e0285be928 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -262,9 +262,10 @@ namespace MWMechanics if (mPath.empty()) return; - const auto tolerance = mPath.size() > 1 ? pointTolerance : destinationTolerance; + while (mPath.size() > 1 && sqrDistanceIgnoreZ(mPath.front(), position) < pointTolerance * pointTolerance) + mPath.pop_front(); - if (sqrDistanceIgnoreZ(mPath.front(), position) < tolerance * tolerance) + if (mPath.size() == 1 && sqrDistanceIgnoreZ(mPath.front(), position) < destinationTolerance * destinationTolerance) mPath.pop_front(); } From ca83b9ee9079fd24524fbdf4a62f174bd38d17f4 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 8 Mar 2019 22:57:25 +0300 Subject: [PATCH 321/410] Refactor main menu and settings toggling again --- apps/openmw/mwinput/inputmanagerimp.cpp | 31 ++++++++----------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 32f79706d9..6f615564cc 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1149,18 +1149,14 @@ namespace MWInput return; } - bool state = MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; + bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame; MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - if (mode == MWGui::GM_MainMenu || mode == MWGui::GM_Settings) - { + if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings) MWBase::Environment::get().getWindowManager()->popGuiMode(); - } - if(state || mode == MWGui::GM_MainMenu) - return; - - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); + if (inGame && mode != MWGui::GM_MainMenu) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); } void InputManager::toggleOptionsMenu() @@ -1172,20 +1168,13 @@ namespace MWInput } MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - bool state = MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; - if (mode == MWGui::GM_Settings) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - return; - } - else if (mode == MWGui::GM_MainMenu && !state) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } - else if (mode == MWGui::GM_MainMenu) - return; + bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame; - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); + if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + if (inGame && mode != MWGui::GM_Settings) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); } void InputManager::quickLoad() { From b214c54b3a9f9ee5a45ec13004f99732283d553f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Mar 2019 13:12:54 +0400 Subject: [PATCH 322/410] Calculate bounding volumes when preloading model instance --- components/resource/scenemanager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index d371a8ce4c..61a40ee4b3 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -531,6 +531,8 @@ namespace Resource if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); + else + loaded->getBound(); mCache->addEntryToObjectCache(normalized, loaded); return loaded; @@ -543,6 +545,12 @@ namespace Resource mVFS->normalizeFilename(normalized); osg::ref_ptr node = createInstance(normalized); + + // Note: osg::clone() does not calculate bound volumes. + // Do it immediately, otherwise we will need to update them for all objects + // during first update traversal, what may lead to stuttering during cell transitions + node->getBound(); + mInstanceCache->addEntryToObjectCache(normalized, node.get()); return node; } From 12f9184d003c1180cd2b75574dc5fc3319d224ab Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Mar 2019 13:13:39 +0400 Subject: [PATCH 323/410] Allow to interrupt terrain preloading --- apps/openmw/mwworld/cellpreloader.cpp | 2 +- components/terrain/quadtreeworld.cpp | 4 ++-- components/terrain/quadtreeworld.hpp | 2 +- components/terrain/world.hpp | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 65ba19b4ac..98e9c73684 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -381,7 +381,7 @@ namespace MWWorld { for (unsigned int i=0; ipreload(mTerrainViews[i], mPreloadPositions[i]); + mWorld->preload(mTerrainViews[i], mPreloadPositions[i], mAbort); mTerrainViews[i]->reset(0); } } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 8d54f62ce2..fa3972a34a 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -478,14 +478,14 @@ View* QuadTreeWorld::createView() return new ViewData; } -void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) +void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint, std::atomic &abort) { ensureQuadTreeBuilt(); ViewData* vd = static_cast(view); traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false); - for (unsigned int i=0; igetNumEntries(); ++i) + for (unsigned int i=0; igetNumEntries() && !abort; ++i) { ViewData::Entry& entry = vd->getEntry(i); loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index f724c44b1c..b2c0b4f14d 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -30,7 +30,7 @@ namespace Terrain void cacheCell(View *view, int x, int y); View* createView(); - void preload(View* view, const osg::Vec3f& eyePoint); + void preload(View* view, const osg::Vec3f& eyePoint, std::atomic& abort); void reportStats(unsigned int frameNumber, osg::Stats* stats); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 4fb724ebbf..d5d4e245ca 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -93,7 +94,7 @@ namespace Terrain virtual View* createView() { return nullptr; } /// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads. - virtual void preload(View* view, const osg::Vec3f& eyePoint) {} + virtual void preload(View* view, const osg::Vec3f& eyePoint, std::atomic& abort) {} virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) {} From bacaa1f7894ab87ffdf8de8ac68a7ea55be0fc92 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Mar 2019 13:52:03 +0400 Subject: [PATCH 324/410] Get rid of C-style limits in the shadows code --- components/sceneutil/mwshadowtechnique.cpp | 62 +++++++++++----------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 4125ebe7d1..b9d8e4bd33 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -30,6 +30,8 @@ namespace { using namespace osgShadow; using namespace SceneUtil; +#define dbl_max std::numeric_limits::max() + ////////////////////////////////////////////////////////////////// // fragment shader // @@ -928,7 +930,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) viewProjectionMatrix(2,3)==0.0; double minZNear = 0.0; - double maxZFar = DBL_MAX; + double maxZFar = dbl_max; if (cachedNearFarMode==osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) { @@ -1088,8 +1090,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double yRange = (clsb._bb.yMax()-clsb._bb.yMin()); osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); - double minZ = DBL_MAX; - double maxZ = -DBL_MAX; + double minZ = dbl_max; + double maxZ = -dbl_max; clsb._bb._max[2] = 1.0; for (unsigned int i = 0; i < 8; i++) { @@ -1777,7 +1779,7 @@ bool MWShadowTechnique::computeShadowCameraSettings(Frustum& frustum, LightData& } else { - double zMax=-DBL_MAX; + double zMax=-dbl_max; OSG_INFO<<"lightDir = "<getValue(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); + writeToFile(job.mNavMeshCacheItem->lockConst()->getValue(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); } std::chrono::steady_clock::time_point AsyncNavMeshUpdater::setFirstStart(const std::chrono::steady_clock::time_point& value) diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 5ac28127ec..5d2de481e1 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -521,7 +521,7 @@ namespace UpdateNavMeshStatus replaceTile(const SharedNavMeshCacheItem& navMeshCacheItem, const TilePosition& changedTile, T&& navMeshData) { - const auto locked = navMeshCacheItem.lock(); + const auto locked = navMeshCacheItem->lock(); auto& navMesh = locked->getValue(); const int layer = 0; const auto tileRef = navMesh.getTileRefAt(changedTile.x(), changedTile.y(), layer); @@ -591,14 +591,14 @@ namespace DetourNavigator " playerTile=", playerTile, " changedTileDistance=", getDistance(changedTile, playerTile)); - const auto params = *navMeshCacheItem.lockConst()->getValue().getParams(); + const auto params = *navMeshCacheItem->lockConst()->getValue().getParams(); const osg::Vec3f origin(params.orig[0], params.orig[1], params.orig[2]); const auto x = changedTile.x(); const auto y = changedTile.y(); const auto removeTile = [&] { - const auto locked = navMeshCacheItem.lock(); + const auto locked = navMeshCacheItem->lock(); auto& navMesh = locked->getValue(); const auto tileRef = navMesh.getTileRefAt(x, y, 0); const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index a146fe0fb9..cc62d61640 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -174,7 +174,7 @@ namespace DetourNavigator if (!navMesh) return out; const auto settings = getSettings(); - return findSmoothPath(navMesh.lock()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), + return findSmoothPath(navMesh->lockConst()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, stepSize), toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings, end), includeFlags, settings, out); } diff --git a/components/detournavigator/navmeshcacheitem.hpp b/components/detournavigator/navmeshcacheitem.hpp index e64b9d1383..e6ca60ef73 100644 --- a/components/detournavigator/navmeshcacheitem.hpp +++ b/components/detournavigator/navmeshcacheitem.hpp @@ -64,7 +64,8 @@ namespace DetourNavigator std::map> mUsedTiles; }; - using SharedNavMeshCacheItem = Misc::SharedGuarded; + using GuardedNavMeshCacheItem = Misc::ScopeGuarded; + using SharedNavMeshCacheItem = std::shared_ptr; } #endif diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 3e26915657..03a8b055fd 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -93,7 +93,7 @@ namespace DetourNavigator if (cached != mCache.end()) return; mCache.insert(std::make_pair(agentHalfExtents, - std::make_shared(makeEmptyNavMesh(mSettings), ++mGenerationCounter))); + std::make_shared(makeEmptyNavMesh(mSettings), ++mGenerationCounter))); log("cache add for agent=", agentHalfExtents); } @@ -159,7 +159,7 @@ namespace DetourNavigator } const auto changedTiles = mChangedTiles.find(agentHalfExtents); { - const auto locked = cached.lock(); + const auto locked = cached->lockConst(); const auto& navMesh = locked->getValue(); if (changedTiles != mChangedTiles.end()) { diff --git a/components/misc/guarded.hpp b/components/misc/guarded.hpp index 114a77b106..559476867a 100644 --- a/components/misc/guarded.hpp +++ b/components/misc/guarded.hpp @@ -83,38 +83,6 @@ namespace Misc std::mutex mMutex; T mValue; }; - - template - class SharedGuarded - { - public: - SharedGuarded() - : mMutex(std::make_shared()), mValue() - {} - - SharedGuarded(std::shared_ptr value) - : mMutex(std::make_shared()), mValue(std::move(value)) - {} - - Locked lock() const - { - return Locked(*mMutex, *mValue); - } - - Locked lockConst() const - { - return Locked(*mMutex, *mValue); - } - - operator bool() const - { - return static_cast(mValue); - } - - private: - std::shared_ptr mMutex; - std::shared_ptr mValue; - }; } #endif From f6a1d3cecfac2291c3ff6f9c9a5213c57c218550 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 10 Mar 2019 16:04:44 +0300 Subject: [PATCH 334/410] Store weak pointers to navmesh in jobs queue To avoid useless processing for removed navmeshes. --- components/detournavigator/asyncnavmeshupdater.cpp | 12 +++++++++--- components/detournavigator/asyncnavmeshupdater.hpp | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 667fff88ec..e9172f041b 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -129,12 +129,17 @@ namespace DetourNavigator const auto firstStart = setFirstStart(start); + const auto navMeshCacheItem = job.mNavMeshCacheItem.lock(); + + if (!navMeshCacheItem) + return true; + const auto recastMesh = mRecastMeshManager.get().getMesh(job.mChangedTile); const auto playerTile = *mPlayerTile.lockConst(); const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile); const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile, - offMeshConnections, mSettings, job.mNavMeshCacheItem, mNavMeshTilesCache); + offMeshConnections, mSettings, navMeshCacheItem, mNavMeshTilesCache); const auto finish = std::chrono::steady_clock::now(); @@ -143,7 +148,7 @@ namespace DetourNavigator using FloatMs = std::chrono::duration; { - const auto locked = job.mNavMeshCacheItem->lockConst(); + const auto locked = navMeshCacheItem->lockConst(); log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, " generation=", locked->getGeneration(), " revision=", locked->getNavMeshRevision(), @@ -194,7 +199,8 @@ namespace DetourNavigator writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix + std::to_string(job.mChangedTile.x()) + "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision); if (mSettings.get().mEnableWriteNavMeshToFile) - writeToFile(job.mNavMeshCacheItem->lockConst()->getValue(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); + if (const auto shared = job.mNavMeshCacheItem.lock()) + writeToFile(shared->lockConst()->getValue(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); } std::chrono::steady_clock::time_point AsyncNavMeshUpdater::setFirstStart(const std::chrono::steady_clock::time_point& value) diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 98359964d1..55e502b453 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -48,7 +48,7 @@ namespace DetourNavigator struct Job { osg::Vec3f mAgentHalfExtents; - SharedNavMeshCacheItem mNavMeshCacheItem; + std::weak_ptr mNavMeshCacheItem; TilePosition mChangedTile; unsigned mTryNumber; ChangeType mChangeType; From 578beb630575f6785fdd1eebe71392e548fdce11 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 10 Mar 2019 17:05:56 +0300 Subject: [PATCH 335/410] Use selected object local variables in console (feature #3893) --- CHANGELOG.md | 1 + apps/openmw/mwgui/console.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d14b45e905..534ab22706 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis + Feature #3893: Implicit target for "set" function in console Feature #3980: In-game option to disable controller Feature #4209: Editor: Faction rank sub-table Feature #4673: Weapon sheathing diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 929dffe48c..899bc0d902 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -11,10 +11,12 @@ #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" namespace MWGui { @@ -173,6 +175,12 @@ namespace MWGui print("> " + command + "\n"); Compiler::Locals locals; + if (!mPtr.isEmpty()) + { + std::string script = mPtr.getClass().getScript(mPtr); + if (!script.empty()) + locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + } Compiler::Output output (locals); if (compile (command + "\n", output)) From dd952c3ddbbe7d69079a21da0dcdeb7db076f98c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 10 Mar 2019 17:12:43 +0300 Subject: [PATCH 336/410] Fix extra space in "no script" showvars output --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index c480cfec89..a10dc00d20 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -951,7 +951,7 @@ namespace MWScript const std::string script = ptr.getClass().getScript(ptr); if(script.empty()) - str<< ptr.getCellRef().getRefId()<<" does not have a script."; + str<< ptr.getCellRef().getRefId()<<" does not have a script."; else { str<< "Local variables for "< Date: Sun, 4 Nov 2018 22:57:10 +0300 Subject: [PATCH 337/410] Use std::make_shared --- components/nif/data.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index d19c8321e1..0860219305 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -120,7 +120,7 @@ void NiRotatingParticlesData::read(NIFStream *nif) void NiPosData::read(NIFStream *nif) { - mKeyList.reset(new Vector3KeyMap); + mKeyList = std::make_shared(); mKeyList->read(nif); } @@ -128,14 +128,14 @@ void NiUVData::read(NIFStream *nif) { for(int i = 0;i < 4;i++) { - mKeyList[i].reset(new FloatKeyMap); + mKeyList[i] = std::make_shared(); mKeyList[i]->read(nif); } } void NiFloatData::read(NIFStream *nif) { - mKeyList.reset(new FloatKeyMap); + mKeyList = std::make_shared(); mKeyList->read(nif); } @@ -177,7 +177,7 @@ void NiPixelData::read(NIFStream *nif) void NiColorData::read(NIFStream *nif) { - mKeyMap.reset(new Vector4KeyMap); + mKeyMap = std::make_shared(); mKeyMap->read(nif); } @@ -231,7 +231,7 @@ void NiMorphData::read(NIFStream *nif) mMorphs.resize(morphCount); for(int i = 0;i < morphCount;i++) { - mMorphs[i].mKeyFrames.reset(new FloatKeyMap); + mMorphs[i].mKeyFrames = std::make_shared(); mMorphs[i].mKeyFrames->read(nif, true); nif->getVector3s(mMorphs[i].mVertices, vertCount); } @@ -239,22 +239,22 @@ void NiMorphData::read(NIFStream *nif) void NiKeyframeData::read(NIFStream *nif) { - mRotations.reset(new QuaternionKeyMap); + mRotations = std::make_shared(); mRotations->read(nif); if(mRotations->mInterpolationType == Vector3KeyMap::sXYZInterpolation) { //Chomp unused float nif->getFloat(); - mXRotations.reset(new FloatKeyMap); - mYRotations.reset(new FloatKeyMap); - mZRotations.reset(new FloatKeyMap); + mXRotations = std::make_shared(); + mYRotations = std::make_shared(); + mZRotations = std::make_shared(); mXRotations->read(nif, true); mYRotations->read(nif, true); mZRotations->read(nif, true); } - mTranslations.reset(new Vector3KeyMap); + mTranslations = std::make_shared(); mTranslations->read(nif); - mScales.reset(new FloatKeyMap); + mScales = std::make_shared(); mScales->read(nif); } From 614d5243c35aada206dcfd26a449e40f34dccca6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 10 Mar 2019 15:48:12 +0300 Subject: [PATCH 338/410] Make NavMeshCacheItem consistent Move all logic related to this type into its methods. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- .../detournavigator/asyncnavmeshupdater.cpp | 2 +- components/detournavigator/makenavmesh.cpp | 121 +------------- components/detournavigator/makenavmesh.hpp | 15 -- components/detournavigator/navigator.hpp | 2 +- .../detournavigator/navmeshcacheitem.hpp | 155 ++++++++++++++++-- components/detournavigator/navmeshmanager.cpp | 2 +- 7 files changed, 152 insertions(+), 147 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c937073749..c17914b36e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1447,7 +1447,7 @@ namespace MWRender try { const auto locked = it->second->lockConst(); - mNavMesh->update(locked->getValue(), mNavMeshNumber, locked->getGeneration(), + mNavMesh->update(locked->getImpl(), mNavMeshNumber, locked->getGeneration(), locked->getNavMeshRevision(), mNavigator.getSettings()); } catch (const std::exception& e) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index e9172f041b..13600fe06f 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -200,7 +200,7 @@ namespace DetourNavigator + "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision); if (mSettings.get().mEnableWriteNavMeshToFile) if (const auto shared = job.mNavMeshCacheItem.lock()) - writeToFile(shared->lockConst()->getValue(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); + writeToFile(shared->lockConst()->getImpl(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); } std::chrono::steady_clock::time_point AsyncNavMeshUpdater::setFirstStart(const std::chrono::steady_clock::time_point& value) diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 5d2de481e1..7caad9ec66 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -25,8 +25,6 @@ namespace { using namespace DetourNavigator; - static const int doNotTransferOwnership = 0; - void initPolyMeshDetail(rcPolyMeshDetail& value) { value.meshes = nullptr; @@ -441,56 +439,7 @@ namespace return NavMeshData(navMeshData, navMeshDataSize); } - class UpdateNavMeshStatusBuilder - { - public: - UpdateNavMeshStatusBuilder() = default; - UpdateNavMeshStatusBuilder removed(bool value) - { - if (value) - set(UpdateNavMeshStatus::removed); - else - unset(UpdateNavMeshStatus::removed); - return *this; - } - - UpdateNavMeshStatusBuilder added(bool value) - { - if (value) - set(UpdateNavMeshStatus::added); - else - unset(UpdateNavMeshStatus::added); - return *this; - } - - UpdateNavMeshStatusBuilder failed(bool value) - { - if (value) - set(UpdateNavMeshStatus::failed); - else - unset(UpdateNavMeshStatus::failed); - return *this; - } - - UpdateNavMeshStatus getResult() const - { - return mResult; - } - - private: - UpdateNavMeshStatus mResult = UpdateNavMeshStatus::ignored; - - void set(UpdateNavMeshStatus value) - { - mResult = static_cast(static_cast(mResult) | static_cast(value)); - } - - void unset(UpdateNavMeshStatus value) - { - mResult = static_cast(static_cast(mResult) & ~static_cast(value)); - } - }; template unsigned long getMinValuableBitsNumber(const T value) @@ -500,49 +449,6 @@ namespace ++power; return power; } - - dtStatus addTile(dtNavMesh& navMesh, const NavMeshData& navMeshData) - { - const dtTileRef lastRef = 0; - dtTileRef* const result = nullptr; - return navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize, - doNotTransferOwnership, lastRef, result); - } - - dtStatus addTile(dtNavMesh& navMesh, const NavMeshTilesCache::Value& cachedNavMeshData) - { - const dtTileRef lastRef = 0; - dtTileRef* const result = nullptr; - return navMesh.addTile(cachedNavMeshData.get().mValue, cachedNavMeshData.get().mSize, - doNotTransferOwnership, lastRef, result); - } - - template - UpdateNavMeshStatus replaceTile(const SharedNavMeshCacheItem& navMeshCacheItem, - const TilePosition& changedTile, T&& navMeshData) - { - const auto locked = navMeshCacheItem->lock(); - auto& navMesh = locked->getValue(); - const int layer = 0; - const auto tileRef = navMesh.getTileRefAt(changedTile.x(), changedTile.y(), layer); - unsigned char** const data = nullptr; - int* const dataSize = nullptr; - const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, data, dataSize)); - const auto addStatus = addTile(navMesh, navMeshData); - - if (dtStatusSucceed(addStatus)) - { - locked->setUsedTile(changedTile, std::forward(navMeshData)); - return UpdateNavMeshStatusBuilder().added(true).removed(removed).getResult(); - } - else - { - if (removed) - locked->removeUsedTile(changedTile); - log("failed to add tile with status=", WriteDtStatus {addStatus}); - return UpdateNavMeshStatusBuilder().removed(removed).failed((addStatus & DT_OUT_OF_MEMORY) != 0).getResult(); - } - } } namespace DetourNavigator @@ -591,26 +497,13 @@ namespace DetourNavigator " playerTile=", playerTile, " changedTileDistance=", getDistance(changedTile, playerTile)); - const auto params = *navMeshCacheItem->lockConst()->getValue().getParams(); + const auto params = *navMeshCacheItem->lockConst()->getImpl().getParams(); const osg::Vec3f origin(params.orig[0], params.orig[1], params.orig[2]); - const auto x = changedTile.x(); - const auto y = changedTile.y(); - - const auto removeTile = [&] { - const auto locked = navMeshCacheItem->lock(); - auto& navMesh = locked->getValue(); - const auto tileRef = navMesh.getTileRefAt(x, y, 0); - const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); - if (removed) - locked->removeUsedTile(changedTile); - return UpdateNavMeshStatusBuilder().removed(removed).getResult(); - }; - if (!recastMesh) { log("ignore add tile: recastMesh is null"); - return removeTile(); + return navMeshCacheItem->lock()->removeTile(changedTile); } auto recastMeshBounds = recastMesh->getBounds(); @@ -625,13 +518,13 @@ namespace DetourNavigator if (isEmpty(recastMeshBounds)) { log("ignore add tile: recastMesh is empty"); - return removeTile(); + return navMeshCacheItem->lock()->removeTile(changedTile); } if (!shouldAddTile(changedTile, playerTile, std::min(settings.mMaxTilesNumber, params.maxTiles))) { log("ignore add tile: too far from player"); - return removeTile(); + return navMeshCacheItem->lock()->removeTile(changedTile); } auto cachedNavMeshData = navMeshTilesCache.get(agentHalfExtents, changedTile, *recastMesh, offMeshConnections); @@ -648,7 +541,7 @@ namespace DetourNavigator if (!navMeshData.mValue) { log("ignore add tile: NavMeshData is null"); - return removeTile(); + return navMeshCacheItem->lock()->removeTile(changedTile); } try @@ -665,10 +558,10 @@ namespace DetourNavigator if (!cachedNavMeshData) { log("cache overflow"); - return replaceTile(navMeshCacheItem, changedTile, std::move(navMeshData)); + return navMeshCacheItem->lock()->updateTile(changedTile, std::move(navMeshData)); } } - return replaceTile(navMeshCacheItem, changedTile, std::move(cachedNavMeshData)); + return navMeshCacheItem->lock()->updateTile(changedTile, std::move(cachedNavMeshData)); } } diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 1dfa242eed..f9cf68a736 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -20,21 +20,6 @@ namespace DetourNavigator class RecastMesh; struct Settings; - enum class UpdateNavMeshStatus : unsigned - { - ignored = 0, - removed = 1 << 0, - added = 1 << 1, - replaced = removed | added, - failed = 1 << 2, - lost = removed | failed, - }; - - inline bool isSuccess(UpdateNavMeshStatus value) - { - return (static_cast(value) & static_cast(UpdateNavMeshStatus::failed)) == 0; - } - inline float getLength(const osg::Vec2i& value) { return std::sqrt(float(osg::square(value.x()) + osg::square(value.y()))); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index cc62d61640..d277fa49ed 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -174,7 +174,7 @@ namespace DetourNavigator if (!navMesh) return out; const auto settings = getSettings(); - return findSmoothPath(navMesh->lockConst()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), + return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, stepSize), toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings, end), includeFlags, settings, out); } diff --git a/components/detournavigator/navmeshcacheitem.hpp b/components/detournavigator/navmeshcacheitem.hpp index e6ca60ef73..f133413971 100644 --- a/components/detournavigator/navmeshcacheitem.hpp +++ b/components/detournavigator/navmeshcacheitem.hpp @@ -4,29 +4,113 @@ #include "sharednavmesh.hpp" #include "tileposition.hpp" #include "navmeshtilescache.hpp" +#include "dtstatus.hpp" #include +#include + #include namespace DetourNavigator { + enum class UpdateNavMeshStatus : unsigned + { + ignored = 0, + removed = 1 << 0, + added = 1 << 1, + replaced = removed | added, + failed = 1 << 2, + lost = removed | failed, + }; + + inline bool isSuccess(UpdateNavMeshStatus value) + { + return (static_cast(value) & static_cast(UpdateNavMeshStatus::failed)) == 0; + } + + class UpdateNavMeshStatusBuilder + { + public: + UpdateNavMeshStatusBuilder() = default; + + UpdateNavMeshStatusBuilder removed(bool value) + { + if (value) + set(UpdateNavMeshStatus::removed); + else + unset(UpdateNavMeshStatus::removed); + return *this; + } + + UpdateNavMeshStatusBuilder added(bool value) + { + if (value) + set(UpdateNavMeshStatus::added); + else + unset(UpdateNavMeshStatus::added); + return *this; + } + + UpdateNavMeshStatusBuilder failed(bool value) + { + if (value) + set(UpdateNavMeshStatus::failed); + else + unset(UpdateNavMeshStatus::failed); + return *this; + } + + UpdateNavMeshStatus getResult() const + { + return mResult; + } + + private: + UpdateNavMeshStatus mResult = UpdateNavMeshStatus::ignored; + + void set(UpdateNavMeshStatus value) + { + mResult = static_cast(static_cast(mResult) | static_cast(value)); + } + + void unset(UpdateNavMeshStatus value) + { + mResult = static_cast(static_cast(mResult) & ~static_cast(value)); + } + }; + + inline unsigned char* getRawData(NavMeshData& navMeshData) + { + return navMeshData.mValue.get(); + } + + inline unsigned char* getRawData(NavMeshTilesCache::Value& cachedNavMeshData) + { + return cachedNavMeshData.get().mValue; + } + + inline int getSize(const NavMeshData& navMeshData) + { + return navMeshData.mSize; + } + + inline int getSize(const NavMeshTilesCache::Value& cachedNavMeshData) + { + return cachedNavMeshData.get().mSize; + } + class NavMeshCacheItem { public: - NavMeshCacheItem(const NavMeshPtr& value, std::size_t generation) - : mValue(value), mGeneration(generation), mNavMeshRevision(0) + NavMeshCacheItem(const NavMeshPtr& impl, std::size_t generation) + : mImpl(impl), mGeneration(generation), mNavMeshRevision(0) { } - const dtNavMesh& getValue() const + const dtNavMesh& getImpl() const { - return *mValue; - } - - dtNavMesh& getValue() - { - return *mValue; + return *mImpl; } std::size_t getGeneration() const @@ -39,6 +123,38 @@ namespace DetourNavigator return mNavMeshRevision; } + template + UpdateNavMeshStatus updateTile(const TilePosition& position, T&& navMeshData) + { + const auto removed = removeTileImpl(position); + const auto addStatus = addTileImpl(getRawData(navMeshData), getSize(navMeshData)); + if (dtStatusSucceed(addStatus)) + { + setUsedTile(position, std::forward(navMeshData)); + return UpdateNavMeshStatusBuilder().added(true).removed(removed).getResult(); + } + else + { + if (removed) + removeUsedTile(position); + return UpdateNavMeshStatusBuilder().removed(removed).failed((addStatus & DT_OUT_OF_MEMORY) != 0).getResult(); + } + } + + UpdateNavMeshStatus removeTile(const TilePosition& position) + { + const auto removed = dtStatusSucceed(removeTileImpl(position)); + if (removed) + removeUsedTile(position); + return UpdateNavMeshStatusBuilder().removed(removed).getResult(); + } + + private: + NavMeshPtr mImpl; + std::size_t mGeneration; + std::size_t mNavMeshRevision; + std::map> mUsedTiles; + void setUsedTile(const TilePosition& tilePosition, NavMeshTilesCache::Value value) { mUsedTiles[tilePosition] = std::make_pair(std::move(value), NavMeshData()); @@ -57,11 +173,22 @@ namespace DetourNavigator ++mNavMeshRevision; } - private: - NavMeshPtr mValue; - std::size_t mGeneration; - std::size_t mNavMeshRevision; - std::map> mUsedTiles; + dtStatus addTileImpl(unsigned char* data, int size) + { + const int doNotTransferOwnership = 0; + const dtTileRef lastRef = 0; + dtTileRef* const result = nullptr; + return mImpl->addTile(data, size, doNotTransferOwnership, lastRef, result); + } + + dtStatus removeTileImpl(const TilePosition& position) + { + const int layer = 0; + const auto tileRef = mImpl->getTileRefAt(position.x(), position.y(), layer); + unsigned char** const data = nullptr; + int* const dataSize = nullptr; + return mImpl->removeTile(tileRef, data, dataSize); + } }; using GuardedNavMeshCacheItem = Misc::ScopeGuarded; diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 03a8b055fd..aca1594015 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -160,7 +160,7 @@ namespace DetourNavigator const auto changedTiles = mChangedTiles.find(agentHalfExtents); { const auto locked = cached->lockConst(); - const auto& navMesh = locked->getValue(); + const auto& navMesh = locked->getImpl(); if (changedTiles != mChangedTiles.end()) { for (const auto& tile : changedTiles->second) From 9d61c494789749f1b3cda43f008920af6bf2177a Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 10 Mar 2019 20:28:33 +0300 Subject: [PATCH 339/410] Store key by reference in tiles map --- components/detournavigator/navmeshtilescache.cpp | 10 +++++----- components/detournavigator/navmeshtilescache.hpp | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 418e69e824..51450cdbd1 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -85,7 +85,7 @@ namespace DetourNavigator if (navMeshSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) return Value(); - const auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections); + auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections); const auto itemSize = navMeshSize + 2 * navMeshKey.size(); if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) @@ -94,9 +94,8 @@ namespace DetourNavigator while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) removeLeastRecentlyUsed(); - const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, navMeshKey); - // TODO: use std::string_view or some alternative to avoid navMeshKey copy into both mFreeItems and mValues - const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(navMeshKey, iterator); + const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey)); + const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(iterator->mNavMeshKey, iterator); if (!emplaced.second) { @@ -131,9 +130,10 @@ namespace DetourNavigator mUsedNavMeshDataSize -= getSize(item); mFreeNavMeshDataSize -= getSize(item); - mFreeItems.pop_back(); tileValues->second.mMap.erase(value); + mFreeItems.pop_back(); + if (!tileValues->second.mMap.empty()) return; diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index e244cda9d7..6c57f7563c 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -105,10 +105,24 @@ namespace DetourNavigator NavMeshData&& value); private: + class KeyView + { + public: + KeyView(const std::string& value) + : mValue(value) {} + + friend bool operator <(const KeyView& lhs, const KeyView& rhs) + { + return lhs.mValue.get() < rhs.mValue.get(); + } + + private: + std::reference_wrapper mValue; + }; struct TileMap { - std::map mMap; + std::map mMap; }; std::mutex mMutex; From 518e34b403bb907410579fd136106787b4b25597 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 10 Mar 2019 14:24:03 +0300 Subject: [PATCH 340/410] Remove useless variables --- apps/openmw/mwworld/scene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6655bef4be..8cccb2fc5a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -338,7 +338,7 @@ namespace MWWorld { if (const auto object = mPhysics->getObject(ptr)) navigator->removeObject(DetourNavigator::ObjectId(object)); - else if (const auto actor = mPhysics->getActor(ptr)) + else if (mPhysics->getActor(ptr)) { navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); mRendering.removeActorPath(ptr); @@ -809,7 +809,7 @@ namespace MWWorld const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); navigator->update(player.getRefData().getPosition().asVec3()); } - else if (const auto actor = mPhysics->getActor(ptr)) + else if (mPhysics->getActor(ptr)) { navigator->removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } From ce9aebcba14965ddca14801488e83810a89f3a0e Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Feb 2019 00:52:20 +0300 Subject: [PATCH 341/410] Clear all changed tiles after post --- components/detournavigator/navmeshmanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 03a8b055fd..c9af545932 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -172,10 +172,6 @@ namespace DetourNavigator else tileToPost->second = addChangeType(tileToPost->second, tile.second); } - for (const auto& tile : tilesToPost) - changedTiles->second.erase(tile.first); - if (changedTiles->second.empty()) - mChangedTiles.erase(changedTiles); } const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles); mRecastMeshManager.forEachTilePosition([&] (const TilePosition& tile) @@ -191,6 +187,8 @@ namespace DetourNavigator }); } mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, tilesToPost); + if (changedTiles != mChangedTiles.end()) + changedTiles->second.clear(); log("cache update posted for agent=", agentHalfExtents, " playerTile=", lastPlayerTile->second, " recastMeshManagerRevision=", lastRevision); From c05fc9e054dbf2cae27993aef421a03150ac0605 Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 18 Feb 2019 01:29:11 +0300 Subject: [PATCH 342/410] Add missing cleanup --- components/detournavigator/navmeshmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index c9af545932..9723366f95 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -105,6 +105,9 @@ namespace DetourNavigator if (!resetIfUnique(it->second)) return false; mCache.erase(agentHalfExtents); + mChangedTiles.erase(agentHalfExtents); + mPlayerTile.erase(agentHalfExtents); + mLastRecastMeshManagerRevision.erase(agentHalfExtents); return true; } From ece111d05a238b4b49d810eef878298d6665156d Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 19 Feb 2019 03:05:15 +0300 Subject: [PATCH 343/410] Check for jobs using predicate --- components/detournavigator/asyncnavmeshupdater.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index e9172f041b..bb2605a5ba 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -162,9 +162,7 @@ namespace DetourNavigator boost::optional AsyncNavMeshUpdater::getNextJob() { std::unique_lock lock(mMutex); - if (mJobs.empty()) - mHasJob.wait_for(lock, std::chrono::milliseconds(10)); - if (mJobs.empty()) + if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), [&] { return !mJobs.empty(); })) { mFirstStart.lock()->reset(); mDone.notify_all(); From 8d2af94b75fb9c893270ef9df27f6a29ecf6e23b Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 19 Feb 2019 11:46:00 +0300 Subject: [PATCH 344/410] Use default objects for NavigatorStub methods result --- components/detournavigator/navigator.hpp | 2 +- components/detournavigator/navigatorimpl.cpp | 2 +- components/detournavigator/navigatorimpl.hpp | 2 +- components/detournavigator/navigatorstub.hpp | 13 +++++++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index cc62d61640..baf56145bb 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -191,7 +191,7 @@ namespace DetourNavigator */ virtual std::map getNavMeshes() const = 0; - virtual Settings getSettings() const = 0; + virtual const Settings& getSettings() const = 0; }; } diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 2e16b6d04d..a62220e555 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -133,7 +133,7 @@ namespace DetourNavigator return mNavMeshManager.getNavMeshes(); } - Settings NavigatorImpl::getSettings() const + const Settings& NavigatorImpl::getSettings() const { return mSettings; } diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index 8156f6655e..d2ff8a57bd 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -46,7 +46,7 @@ namespace DetourNavigator std::map getNavMeshes() const override; - Settings getSettings() const override; + const Settings& getSettings() const override; private: Settings mSettings; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 5d82d2f59f..cab93b1052 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -5,8 +5,9 @@ namespace DetourNavigator { - struct NavigatorStub final : public Navigator + class NavigatorStub final : public Navigator { + public: NavigatorStub() = default; void addAgent(const osg::Vec3f& /*agentHalfExtents*/) override {} @@ -65,7 +66,7 @@ namespace DetourNavigator SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override { - return SharedNavMeshCacheItem(); + return mEmptyNavMeshCacheItem; } std::map getNavMeshes() const override @@ -73,10 +74,14 @@ namespace DetourNavigator return std::map(); } - Settings getSettings() const override + const Settings& getSettings() const override { - return Settings {}; + return mDefaultSettings; } + + private: + Settings mDefaultSettings {}; + SharedNavMeshCacheItem mEmptyNavMeshCacheItem; }; } From 849f2078c134f670fce9a95318f508fe7bcc380e Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 22 Feb 2019 23:52:00 +0300 Subject: [PATCH 345/410] Swap outside critical section --- components/detournavigator/tilecachedrecastmeshmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index b878c2d3e4..0cb1cfb807 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -61,8 +61,8 @@ namespace DetourNavigator for (const auto& tile : currentTiles) if (!newTiles.count(tile) && removeTile(id, tile, tiles.get())) changedTiles.push_back(tile); - std::swap(currentTiles, newTiles); } + std::swap(currentTiles, newTiles); if (!changedTiles.empty()) ++mRevision; return changedTiles; From 4395a92c354cf9ff2a1516df1ab4545588f78e12 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 10 Mar 2019 19:08:30 +0300 Subject: [PATCH 346/410] Use display list to render navmesh Slightly improves performance of massive navmesh rendering. --- components/sceneutil/detourdebugdraw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/detourdebugdraw.cpp b/components/sceneutil/detourdebugdraw.cpp index a0ae67dc29..046bbb08cf 100644 --- a/components/sceneutil/detourdebugdraw.cpp +++ b/components/sceneutil/detourdebugdraw.cpp @@ -102,7 +102,7 @@ namespace SceneUtil osg::ref_ptr geometry(new osg::Geometry); geometry->setStateSet(stateSet); - geometry->setUseDisplayList(false); + geometry->setUseDisplayList(true); geometry->setVertexArray(mVertices); geometry->setColorArray(mColors, osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawArrays(mMode, 0, static_cast(mVertices->size()))); From 68948bc847f51a314b873bc41c60a731e7fe61b5 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 10 Mar 2019 22:04:41 +0300 Subject: [PATCH 347/410] Avoid key allocation to find tile in cache --- .../detournavigator/navmeshtilescache.cpp | 59 ++++++++++++++++++- .../detournavigator/navmeshtilescache.hpp | 45 +++++++++++++- 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 51450cdbd1..76060981f4 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -1,6 +1,8 @@ #include "navmeshtilescache.hpp" #include "exceptions.hpp" +#include + namespace DetourNavigator { namespace @@ -61,8 +63,7 @@ namespace DetourNavigator if (tileValues == agentValues->second.end()) return Value(); - // TODO: use different function to make key to avoid unnecessary std::string allocation - const auto tile = tileValues->second.mMap.find(makeNavMeshKey(recastMesh, offMeshConnections)); + const auto tile = tileValues->second.mMap.find(RecastMeshKeyView(recastMesh, offMeshConnections)); if (tile == tileValues->second.mMap.end()) return Value(); @@ -163,4 +164,58 @@ namespace DetourNavigator mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator); mFreeNavMeshDataSize += getSize(*iterator); } + + namespace + { + struct CompareBytes + { + const char* mRhsIt; + const char* mRhsEnd; + + template + int operator ()(const std::vector& lhs) + { + const auto lhsBegin = reinterpret_cast(lhs.data()); + const auto lhsEnd = reinterpret_cast(lhs.data() + lhs.size()); + const auto lhsSize = static_cast(lhsEnd - lhsBegin); + const auto rhsSize = static_cast(mRhsEnd - mRhsIt); + const auto size = std::min(lhsSize, rhsSize); + + if (const auto result = std::memcmp(lhsBegin, mRhsIt, size)) + return result; + + if (lhsSize > rhsSize) + return 1; + + mRhsIt += size; + + return 0; + } + }; + } + + int NavMeshTilesCache::RecastMeshKeyView::compare(const std::string& other) const + { + CompareBytes compareBytes {other.data(), other.data() + other.size()}; + + if (const auto result = compareBytes(mRecastMesh.get().getIndices())) + return result; + + if (const auto result = compareBytes(mRecastMesh.get().getVertices())) + return result; + + if (const auto result = compareBytes(mRecastMesh.get().getAreaTypes())) + return result; + + if (const auto result = compareBytes(mRecastMesh.get().getWater())) + return result; + + if (const auto result = compareBytes(mOffMeshConnections.get())) + return result; + + if (compareBytes.mRhsIt < compareBytes.mRhsEnd) + return -1; + + return 0; + } } diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 6c57f7563c..3f2e0cc019 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace DetourNavigator { @@ -108,16 +109,54 @@ namespace DetourNavigator class KeyView { public: + KeyView() = default; + KeyView(const std::string& value) - : mValue(value) {} + : mValue(&value) {} + + const std::string& getValue() const + { + assert(mValue); + return *mValue; + } + + virtual int compare(const std::string& other) const + { + assert(mValue); + return mValue->compare(other); + } + + virtual bool isLess(const KeyView& other) const + { + assert(mValue); + return other.compare(*mValue) > 0; + } friend bool operator <(const KeyView& lhs, const KeyView& rhs) { - return lhs.mValue.get() < rhs.mValue.get(); + return lhs.isLess(rhs); } private: - std::reference_wrapper mValue; + const std::string* mValue = nullptr; + }; + + class RecastMeshKeyView : public KeyView + { + public: + RecastMeshKeyView(const RecastMesh& recastMesh, const std::vector& offMeshConnections) + : mRecastMesh(recastMesh), mOffMeshConnections(offMeshConnections) {} + + int compare(const std::string& other) const override; + + bool isLess(const KeyView& other) const override + { + return compare(other.getValue()) < 0; + } + + private: + std::reference_wrapper mRecastMesh; + std::reference_wrapper> mOffMeshConnections; }; struct TileMap From 943279abbbcd31c111af1bb8963a2c212bbbd340 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 11 Mar 2019 15:05:43 +0400 Subject: [PATCH 348/410] Consider land texture with given ID and index as override for base texture with the same ID and index (bug #4736) --- CHANGELOG.md | 1 + apps/openmw/mwworld/store.cpp | 15 +++++++++++++++ components/esm/loadltex.hpp | 15 +++------------ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d14b45e905..3a1a3396e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Bug #4720: Inventory avatar has shield with two-handed weapon during [un]equipping animation Bug #4723: ResetActors command works incorrectly Bug #4745: Editor: Interior cell lighting field values are not displayed as colors + Bug #4736: LandTexture records overrides do not work Bug #4746: Non-solid player can't run or sneak Bug #4747: Bones are not read from X.NIF file for NPC animation Bug #4750: Sneaking doesn't work in first person view if the player is in attack ready state diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 79d9174ed9..2a0c394664 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -387,6 +387,21 @@ namespace MWWorld assert(plugin < mStatic.size()); + // Replace texture for records with given ID and index from all plugins. + for (unsigned int i=0; i(search(lt.mIndex, i)); + if (tex) + { + const std::string texId = Misc::StringUtils::lowerCase(tex->mId); + const std::string ltId = Misc::StringUtils::lowerCase(lt.mId); + if (texId == ltId) + { + tex->mTexture = lt.mTexture; + } + } + } + LandTextureList <exl = mStatic[plugin]; if(lt.mIndex + 1 > (int)ltexl.size()) ltexl.resize(lt.mIndex+1); diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 1604e9281c..e3e2582462 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -11,18 +11,9 @@ class ESMWriter; /* * Texture used for texturing landscape. - * - * They are probably indexed by 'num', not 'id', but I don't know for - * sure. And num is not unique between files, so one option is to keep - * a separate list for each input file (that has LTEX records, of - * course.) We also need to resolve references to already existing - * land textures to save space. - - * I'm not sure if it is even possible to override existing land - * textures, probably not. I'll have to try it, and have to mimic the - * behaviour of morrowind. First, check what you are allowed to do in - * the editor. Then make an esp which changes a commonly used land - * texture, and see if it affects the game. + * They are indexed by 'num', but still use 'id' to override base records. + * Original editor even does not allow to create new records with existing ID's. + * TODO: currently OpenMW-CS does not allow to override LTEX records at all. */ struct LandTexture From 8e09468f45d45a77787096151ee81b43f4ae1999 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 12 Mar 2019 00:05:55 +0300 Subject: [PATCH 349/410] Don't set display list usage for navmesh --- components/sceneutil/detourdebugdraw.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sceneutil/detourdebugdraw.cpp b/components/sceneutil/detourdebugdraw.cpp index 046bbb08cf..ea8a4c2f6a 100644 --- a/components/sceneutil/detourdebugdraw.cpp +++ b/components/sceneutil/detourdebugdraw.cpp @@ -102,7 +102,6 @@ namespace SceneUtil osg::ref_ptr geometry(new osg::Geometry); geometry->setStateSet(stateSet); - geometry->setUseDisplayList(true); geometry->setVertexArray(mVertices); geometry->setColorArray(mColors, osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawArrays(mMode, 0, static_cast(mVertices->size()))); From 4aa21b908811f18d0924e5de08f4028e1e5d0f46 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Mar 2019 14:25:55 +0400 Subject: [PATCH 350/410] Do not swap buffers for non-exposed windows (bug #4911) --- CHANGELOG.md | 1 + extern/osgQt/GraphicsWindowQt.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a1a3396e6..bbdcd2e638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Bug #4876: AI ratings handling inconsistencies Bug #4877: Startup script executes only on a new game start Bug #4888: Global variable stray explicit reference calls break script compilation + Bug #4911: Editor: QOpenGLContext::swapBuffers() warning with Qt5 Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis diff --git a/extern/osgQt/GraphicsWindowQt.cpp b/extern/osgQt/GraphicsWindowQt.cpp index 9e5f6e55ea..e46cbba2d3 100644 --- a/extern/osgQt/GraphicsWindowQt.cpp +++ b/extern/osgQt/GraphicsWindowQt.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0)) # define USE_GESTURES @@ -518,6 +519,12 @@ bool GraphicsWindowQt::releaseContextImplementation() void GraphicsWindowQt::swapBuffersImplementation() { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + // QOpenGLContext complains if we swap on an non-exposed QWindow + if (!_widget || !_widget->windowHandle()->isExposed()) + return; +#endif + _widget->swapBuffers(); // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but From 46fee678a78a933a985a00fea3448f0d8bedda5d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Mar 2019 20:00:06 +0400 Subject: [PATCH 351/410] Place QWindow include under Qt version check --- extern/osgQt/GraphicsWindowQt.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extern/osgQt/GraphicsWindowQt.cpp b/extern/osgQt/GraphicsWindowQt.cpp index e46cbba2d3..0135a1784b 100644 --- a/extern/osgQt/GraphicsWindowQt.cpp +++ b/extern/osgQt/GraphicsWindowQt.cpp @@ -17,7 +17,10 @@ #include #include #include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include +#endif #if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0)) # define USE_GESTURES From 2ed05a519571fd046261f2ccf4cefe68b03b5373 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Mar 2019 11:15:58 +0400 Subject: [PATCH 352/410] Implement generic caching system --- apps/openmw/mwrender/landmanager.cpp | 9 +- apps/openmw/mwrender/landmanager.hpp | 3 +- components/resource/objectcache.cpp | 165 ------------------------ components/resource/objectcache.hpp | 130 ++++++++++++++++--- components/resource/resourcemanager.cpp | 46 ------- components/resource/resourcemanager.hpp | 52 ++++++-- components/resource/resourcesystem.cpp | 16 +-- components/resource/resourcesystem.hpp | 8 +- components/terrain/chunkmanager.cpp | 15 +-- components/terrain/chunkmanager.hpp | 10 +- 10 files changed, 186 insertions(+), 268 deletions(-) delete mode 100644 components/resource/objectcache.cpp delete mode 100644 components/resource/resourcemanager.cpp diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index e3b19ca474..560c1ba720 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -12,16 +12,15 @@ namespace MWRender { LandManager::LandManager(int loadFlags) - : ResourceManager(nullptr) + : GenericResourceManager >(nullptr) , mLoadFlags(loadFlags) { + mCache = new CacheType; } osg::ref_ptr LandManager::getLand(int x, int y) { - std::string idstr = std::to_string(x) + " " + std::to_string(y); - - osg::ref_ptr obj = mCache->getRefFromObjectCache(idstr); + osg::ref_ptr obj = mCache->getRefFromObjectCache(std::make_pair(x,y)); if (obj) return static_cast(obj.get()); else @@ -30,7 +29,7 @@ osg::ref_ptr LandManager::getLand(int x, int y) if (!land) return nullptr; osg::ref_ptr landObj (new ESMTerrain::LandObject(land, mLoadFlags)); - mCache->addEntryToObjectCache(idstr, landObj.get()); + mCache->addEntryToObjectCache(std::make_pair(x,y), landObj.get()); return landObj; } } diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 81253bba35..0d37097d8b 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -14,7 +15,7 @@ namespace ESM namespace MWRender { - class LandManager : public Resource::ResourceManager + class LandManager : public Resource::GenericResourceManager > { public: LandManager(int loadFlags); diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp deleted file mode 100644 index ffe150c74e..0000000000 --- a/components/resource/objectcache.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * OpenSceneGraph Public License for more details. -*/ - -#include "objectcache.hpp" - -#include -#include - -namespace Resource -{ - -//////////////////////////////////////////////////////////////////////////////////////////// -// -// ObjectCache -// -ObjectCache::ObjectCache(): - osg::Referenced(true) -{ -} - -ObjectCache::~ObjectCache() -{ -} - -void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) -{ - if (!object) - { - OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl; - return; - } - OpenThreads::ScopedLock lock(_objectCacheMutex); - _objectCache[filename]=ObjectTimeStampPair(object,timestamp); -} - -osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) - { - return itr->second.first; - } - else return 0; -} - -bool ObjectCache::checkInObjectCache(const std::string &fileName, double timeStamp) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) - { - itr->second.second = timeStamp; - return true; - } - else return false; -} - -void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - - // look for objects with external references and update their time stamp. - for(ObjectCacheMap::iterator itr=_objectCache.begin(); - itr!=_objectCache.end(); - ++itr) - { - // If ref count is greater than 1, the object has an external reference. - // If the timestamp is yet to be initialized, it needs to be updated too. - if (itr->second.first->referenceCount()>1 || itr->second.second == 0.0) - { - // So update it. - itr->second.second = referenceTime; - } - } -} - -void ObjectCache::removeExpiredObjectsInCache(double expiryTime) -{ - std::vector > objectsToRemove; - - { - OpenThreads::ScopedLock lock(_objectCacheMutex); - - // Remove expired entries from object cache - ObjectCacheMap::iterator oitr = _objectCache.begin(); - while(oitr != _objectCache.end()) - { - if (oitr->second.second<=expiryTime) - { - objectsToRemove.push_back(oitr->second.first); - _objectCache.erase(oitr++); - } - else - { - ++oitr; - } - } - } - - // note, actual unref happens outside of the lock - objectsToRemove.clear(); -} - -void ObjectCache::removeFromObjectCache(const std::string& fileName) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) _objectCache.erase(itr); -} - -void ObjectCache::clear() -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - _objectCache.clear(); -} - -void ObjectCache::releaseGLObjects(osg::State* state) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - - for(ObjectCacheMap::iterator itr = _objectCache.begin(); - itr != _objectCache.end(); - ++itr) - { - osg::Object* object = itr->second.first.get(); - object->releaseGLObjects(state); - } -} - -void ObjectCache::accept(osg::NodeVisitor &nv) -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - - for(ObjectCacheMap::iterator itr = _objectCache.begin(); - itr != _objectCache.end(); - ++itr) - { - osg::Object* object = itr->second.first.get(); - if (object) - { - osg::Node* node = dynamic_cast(object); - if (node) - node->accept(nv); - } - } -} - -unsigned int ObjectCache::getCacheSize() const -{ - OpenThreads::ScopedLock lock(_objectCacheMutex); - return _objectCache.size(); -} - -} diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index 72db835e89..cfd41f19cf 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -1,5 +1,8 @@ // Resource ObjectCache for OpenMW, forked from osgDB ObjectCache by Robert Osfield, see copyright notice below. -// The main change from the upstream version is that removeExpiredObjectsInCache no longer keeps a lock while the unref happens. +// Changes: +// - removeExpiredObjectsInCache no longer keeps a lock while the unref happens. +// - template allows customized KeyType. +// - objects with uninitialized time stamp are not removed. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * @@ -19,6 +22,7 @@ #include #include +#include #include #include @@ -32,11 +36,13 @@ namespace osg namespace Resource { -class ObjectCache : public osg::Referenced +template +class GenericObjectCache : public osg::Referenced { public: - ObjectCache(); + GenericObjectCache() + : osg::Referenced(true) {} /** For each object in the cache which has an reference count greater than 1 * (and therefore referenced by elsewhere in the application) set the time stamp @@ -44,59 +50,149 @@ class ObjectCache : public osg::Referenced * This would typically be called once per frame by applications which are doing database paging, * and need to prune objects that are no longer required. * The time used should be taken from the FrameStamp::getReferenceTime().*/ - void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime); + void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) + { + // look for objects with external references and update their time stamp. + OpenThreads::ScopedLock lock(_objectCacheMutex); + for(typename ObjectCacheMap::iterator itr=_objectCache.begin(); itr!=_objectCache.end(); ++itr) + { + // If ref count is greater than 1, the object has an external reference. + // If the timestamp is yet to be initialized, it needs to be updated too. + if (itr->second.first->referenceCount()>1 || itr->second.second == 0.0) + itr->second.second = referenceTime; + } + } /** Removed object in the cache which have a time stamp at or before the specified expiry time. * This would typically be called once per frame by applications which are doing database paging, * and need to prune objects that are no longer required, and called after the a called * after the call to updateTimeStampOfObjectsInCacheWithExternalReferences(expirtyTime).*/ - void removeExpiredObjectsInCache(double expiryTime); + void removeExpiredObjectsInCache(double expiryTime) + { + std::vector > objectsToRemove; + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + // Remove expired entries from object cache + typename ObjectCacheMap::iterator oitr = _objectCache.begin(); + while(oitr != _objectCache.end()) + { + if (oitr->second.second<=expiryTime) + { + objectsToRemove.push_back(oitr->second.first); + _objectCache.erase(oitr++); + } + else + ++oitr; + } + } + // note, actual unref happens outside of the lock + objectsToRemove.clear(); + } /** Remove all objects in the cache regardless of having external references or expiry times.*/ - void clear(); + void clear() + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.clear(); + } - /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ - void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); + /** Add a key,object,timestamp triple to the Registry::ObjectCache.*/ + void addEntryToObjectCache(const KeyType& key, osg::Object* object, double timestamp = 0.0) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache[key]=ObjectTimeStampPair(object,timestamp); + } /** Remove Object from cache.*/ - void removeFromObjectCache(const std::string& fileName); + void removeFromObjectCache(const KeyType& key) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + typename ObjectCacheMap::iterator itr = _objectCache.find(key); + if (itr!=_objectCache.end()) _objectCache.erase(itr); + } /** Get an ref_ptr from the object cache*/ - osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + osg::ref_ptr getRefFromObjectCache(const KeyType& key) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + typename ObjectCacheMap::iterator itr = _objectCache.find(key); + if (itr!=_objectCache.end()) + return itr->second.first; + else return 0; + } /** Check if an object is in the cache, and if it is, update its usage time stamp. */ - bool checkInObjectCache(const std::string& fileName, double timeStamp); + bool checkInObjectCache(const KeyType& key, double timeStamp) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + typename ObjectCacheMap::iterator itr = _objectCache.find(key); + if (itr!=_objectCache.end()) + { + itr->second.second = timeStamp; + return true; + } + else return false; + } /** call releaseGLObjects on all objects attached to the object cache.*/ - void releaseGLObjects(osg::State* state); + void releaseGLObjects(osg::State* state) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + for(typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr) + { + osg::Object* object = itr->second.first.get(); + object->releaseGLObjects(state); + } + } /** call node->accept(nv); for all nodes in the objectCache. */ - void accept(osg::NodeVisitor& nv); + void accept(osg::NodeVisitor& nv) + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + for(typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr) + { + osg::Object* object = itr->second.first.get(); + if (object) + { + osg::Node* node = dynamic_cast(object); + if (node) + node->accept(nv); + } + } + } /** call operator()(osg::Object*) for each object in the cache. */ template void call(Functor& f) { OpenThreads::ScopedLock lock(_objectCacheMutex); - for (ObjectCacheMap::iterator it = _objectCache.begin(); it != _objectCache.end(); ++it) + for (typename ObjectCacheMap::iterator it = _objectCache.begin(); it != _objectCache.end(); ++it) f(it->second.first.get()); } /** Get the number of objects in the cache. */ - unsigned int getCacheSize() const; + unsigned int getCacheSize() const + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + return _objectCache.size(); + } protected: - virtual ~ObjectCache(); + virtual ~GenericObjectCache() {} typedef std::pair, double > ObjectTimeStampPair; - typedef std::map ObjectCacheMap; + typedef std::map ObjectCacheMap; ObjectCacheMap _objectCache; mutable OpenThreads::Mutex _objectCacheMutex; }; +class ObjectCache : public GenericObjectCache +{ +}; + } #endif diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp deleted file mode 100644 index c0e99674ec..0000000000 --- a/components/resource/resourcemanager.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "resourcemanager.hpp" - -#include "objectcache.hpp" - -namespace Resource -{ - - ResourceManager::ResourceManager(const VFS::Manager *vfs) - : mVFS(vfs) - , mCache(new Resource::ObjectCache) - , mExpiryDelay(0.0) - { - - } - - ResourceManager::~ResourceManager() - { - } - - void ResourceManager::updateCache(double referenceTime) - { - mCache->updateTimeStampOfObjectsInCacheWithExternalReferences(referenceTime); - mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); - } - - void ResourceManager::clearCache() - { - mCache->clear(); - } - - void ResourceManager::setExpiryDelay(double expiryDelay) - { - mExpiryDelay = expiryDelay; - } - - const VFS::Manager* ResourceManager::getVFS() const - { - return mVFS; - } - - void ResourceManager::releaseGLObjects(osg::State *state) - { - mCache->releaseGLObjects(state); - } - -} diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index 6031ecc01d..a5ae27c6a5 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -3,6 +3,8 @@ #include +#include "objectcache.hpp" + namespace VFS { class Manager; @@ -16,37 +18,67 @@ namespace osg namespace Resource { - class ObjectCache; + + class BaseResourceManager + { + public: + virtual ~BaseResourceManager() {} + virtual void updateCache(double referenceTime) {} + virtual void clearCache() {} + virtual void setExpiryDelay(double expiryDelay) {} + virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const {} + virtual void releaseGLObjects(osg::State* state) {} + }; /// @brief Base class for managers that require a virtual file system and object cache. /// @par This base class implements clearing of the cache, but populating it and what it's used for is up to the individual sub classes. - class ResourceManager + template + class GenericResourceManager : public BaseResourceManager { public: - ResourceManager(const VFS::Manager* vfs); - virtual ~ResourceManager(); + typedef GenericObjectCache CacheType; + + GenericResourceManager(const VFS::Manager* vfs) + : mVFS(vfs) + , mCache(new CacheType) + , mExpiryDelay(0.0) + { + } + + virtual ~GenericResourceManager() {} /// Clear cache entries that have not been referenced for longer than expiryDelay. - virtual void updateCache(double referenceTime); + virtual void updateCache(double referenceTime) + { + mCache->updateTimeStampOfObjectsInCacheWithExternalReferences(referenceTime); + mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); + } /// Clear all cache entries. - virtual void clearCache(); + virtual void clearCache() { mCache->clear(); } /// How long to keep objects in cache after no longer being referenced. - void setExpiryDelay (double expiryDelay); + void setExpiryDelay (double expiryDelay) { mExpiryDelay = expiryDelay; } - const VFS::Manager* getVFS() const; + const VFS::Manager* getVFS() const { return mVFS; } virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const {} - virtual void releaseGLObjects(osg::State* state); + virtual void releaseGLObjects(osg::State* state) { mCache->releaseGLObjects(state); } protected: const VFS::Manager* mVFS; - osg::ref_ptr mCache; + osg::ref_ptr mCache; double mExpiryDelay; }; + + class ResourceManager : public GenericResourceManager + { + public: + ResourceManager(const VFS::Manager* vfs) : GenericResourceManager(vfs) {} + }; + } #endif diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 4d61dce692..2015ba874d 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -54,7 +54,7 @@ namespace Resource void ResourceSystem::setExpiryDelay(double expiryDelay) { - for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->setExpiryDelay(expiryDelay); // NIF files aren't needed any more once the converted objects are cached in SceneManager / BulletShapeManager, @@ -64,24 +64,24 @@ namespace Resource void ResourceSystem::updateCache(double referenceTime) { - for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->updateCache(referenceTime); } void ResourceSystem::clearCache() { - for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->clearCache(); } - void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) + void ResourceSystem::addResourceManager(BaseResourceManager *resourceMgr) { mResourceManagers.push_back(resourceMgr); } - void ResourceSystem::removeResourceManager(ResourceManager *resourceMgr) + void ResourceSystem::removeResourceManager(BaseResourceManager *resourceMgr) { - std::vector::iterator found = std::find(mResourceManagers.begin(), mResourceManagers.end(), resourceMgr); + std::vector::iterator found = std::find(mResourceManagers.begin(), mResourceManagers.end(), resourceMgr); if (found != mResourceManagers.end()) mResourceManagers.erase(found); } @@ -93,13 +93,13 @@ namespace Resource void ResourceSystem::reportStats(unsigned int frameNumber, osg::Stats *stats) const { - for (std::vector::const_iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + for (std::vector::const_iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->reportStats(frameNumber, stats); } void ResourceSystem::releaseGLObjects(osg::State *state) { - for (std::vector::const_iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + for (std::vector::const_iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->releaseGLObjects(state); } diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 396bdb8fa5..db8bbafc96 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -22,7 +22,7 @@ namespace Resource class ImageManager; class NifFileManager; class KeyframeManager; - class ResourceManager; + class BaseResourceManager; /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems. /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but @@ -48,10 +48,10 @@ namespace Resource /// Add this ResourceManager to be handled by the ResourceSystem. /// @note Does not transfer ownership. - void addResourceManager(ResourceManager* resourceMgr); + void addResourceManager(BaseResourceManager* resourceMgr); /// @note Do nothing if resourceMgr does not exist. /// @note Does not delete resourceMgr. - void removeResourceManager(ResourceManager* resourceMgr); + void removeResourceManager(BaseResourceManager* resourceMgr); /// How long to keep objects in cache after no longer being referenced. void setExpiryDelay(double expiryDelay); @@ -72,7 +72,7 @@ namespace Resource // Store the base classes separately to get convenient access to the common interface // Here users can register their own resourcemanager as well - std::vector mResourceManagers; + std::vector mResourceManagers; const VFS::Manager* mVFS; diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 80f4145419..4b2bee89a6 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -22,7 +22,7 @@ namespace Terrain { ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, TextureManager* textureManager, CompositeMapRenderer* renderer) - : ResourceManager(nullptr) + : GenericResourceManager(nullptr) , mStorage(storage) , mSceneManager(sceneMgr) , mTextureManager(textureManager) @@ -35,12 +35,9 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T } -osg::ref_ptr ChunkManager::getChunk(float size, const osg::Vec2f ¢er, int lod, unsigned int lodFlags) +osg::ref_ptr ChunkManager::getChunk(float size, const osg::Vec2f ¢er, unsigned char lod, unsigned int lodFlags) { - std::ostringstream stream; - stream << size << " " << center.x() << " " << center.y() << " " << lod << " " << lodFlags; - std::string id = stream.str(); - + ChunkId id = std::make_tuple(center, lod, lodFlags); osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) return obj->asNode(); @@ -59,14 +56,14 @@ void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats) cons void ChunkManager::clearCache() { - ResourceManager::clearCache(); + GenericResourceManager::clearCache(); mBufferCache.clearCache(); } void ChunkManager::releaseGLObjects(osg::State *state) { - ResourceManager::releaseGLObjects(state); + GenericResourceManager::releaseGLObjects(state); mBufferCache.releaseGLObjects(state); } @@ -164,7 +161,7 @@ std::vector > ChunkManager::createPasses(float chunk return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); } -osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, int lod, unsigned int lodFlags) +osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags) { osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); osg::ref_ptr transform (new SceneUtil::PositionAttitudeTransform); diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 27201864f7..2dea1cf92e 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_TERRAIN_CHUNKMANAGER_H #define OPENMW_COMPONENTS_TERRAIN_CHUNKMANAGER_H +#include + #include #include "buffercache.hpp" @@ -24,13 +26,15 @@ namespace Terrain class Storage; class CompositeMap; + typedef std::tuple ChunkId; // Center, Lod, Lod Flags + /// @brief Handles loading and caching of terrain chunks - class ChunkManager : public Resource::ResourceManager + class ChunkManager : public Resource::GenericResourceManager { public: ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager, CompositeMapRenderer* renderer); - osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); + osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags); void setCullingActive(bool active) { mCullingActive = active; } void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; } @@ -44,7 +48,7 @@ namespace Terrain void releaseGLObjects(osg::State* state) override; private: - osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); + osg::ref_ptr createChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags); osg::ref_ptr createCompositeMapRTT(); From 4ab93aeffe030993d10a5a1e4dd3cbb4bca7f152 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 353/410] Do not allocate empty callbacks in the RigGeometry --- components/sceneutil/riggeometry.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 0c81980553..97c8e1d391 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -40,8 +40,8 @@ RigGeometry::RigGeometry() , mLastFrameNumber(0) , mBoundsFirstFrame(true) { - setUpdateCallback(new osg::Callback); // dummy to make sure getNumChildrenRequiringUpdateTraversal() is correct - // update done in accept(NodeVisitor&) + setNumChildrenRequiringUpdateTraversal(1); + // update done in accept(NodeVisitor&) } RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) @@ -54,6 +54,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mBoundsFirstFrame(true) { setSourceGeometry(copy.mSourceGeometry); + setNumChildrenRequiringUpdateTraversal(1); } void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) From dd0b45ede66934d904831ee7e979349497b5d5a3 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 14 Mar 2019 22:15:57 +0300 Subject: [PATCH 354/410] Do not pass nullptr to std::memcmp --- components/detournavigator/navmeshtilescache.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 76060981f4..8dd14f04c3 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -179,6 +179,17 @@ namespace DetourNavigator const auto lhsEnd = reinterpret_cast(lhs.data() + lhs.size()); const auto lhsSize = static_cast(lhsEnd - lhsBegin); const auto rhsSize = static_cast(mRhsEnd - mRhsIt); + + if (lhsBegin == nullptr || mRhsIt == nullptr) + { + if (lhsSize < rhsSize) + return -1; + else if (lhsSize > rhsSize) + return 1; + else + return 0; + } + const auto size = std::min(lhsSize, rhsSize); if (const auto result = std::memcmp(lhsBegin, mRhsIt, size)) From dd03d3b2318ddb93dcbc7569cdf7963ea68959ed Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 15 Mar 2019 19:04:47 +0300 Subject: [PATCH 355/410] Print SDL version at startup --- apps/openmw/engine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a68bf4c369..4fae3061a7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -651,6 +651,9 @@ void OMW::Engine::go() assert (!mContentFiles.empty()); Log(Debug::Info) << "OSG version: " << osgGetVersion(); + SDL_version sdlVersion; + SDL_GetVersion(&sdlVersion); + Log(Debug::Info) << "SDL version: " << (int)sdlVersion.major << "." << (int)sdlVersion.minor << "." << (int)sdlVersion.patch; Misc::Rng::init(mRandomSeed); From 5b2691e7447dc8f5f82a0a14332b3452273669b3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 15 Mar 2019 17:44:52 +0000 Subject: [PATCH 356/410] Actually use specular shininess parameter instead of hardcoded value. --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 90d849472b..6de34bc075 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -78,5 +78,5 @@ vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matS if (NdotL < 0.0) return vec3(0.,0.,0.); vec3 halfVec = normalize(lightDir - viewDirection); - return pow(max(dot(viewNormal, halfVec), 0.0), 128.) * gl_LightSource[0].specular.xyz * matSpec; + return pow(max(dot(viewNormal, halfVec), 0.0), shininess) * gl_LightSource[0].specular.xyz * matSpec; } From a92690d43393946953f14785c35f3099a3103cee Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 15 Mar 2019 21:30:57 +0000 Subject: [PATCH 357/410] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c0f476b86..2f3fcc3291 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Bug #4877: Startup script executes only on a new game start Bug #4888: Global variable stray explicit reference calls break script compilation Bug #4911: Editor: QOpenGLContext::swapBuffers() warning with Qt5 + Bug #4916: Specular power (shininess) material parameter is ignored when shaders are used. Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis From c91deaf7affb5bd43a105c3bc802c98b65ad7520 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 Mar 2019 00:08:24 +0300 Subject: [PATCH 358/410] Use std::vector::data method to avoid reference binding to null pointer --- components/esm/loadscpt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 808b416d7b..b41dc496fa 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -104,7 +104,7 @@ namespace ESM } mScriptData.resize(subSize); - esm.getExact(&mScriptData[0], mScriptData.size()); + esm.getExact(mScriptData.data(), mScriptData.size()); break; } case ESM::FourCC<'S','C','T','X'>::value: @@ -156,7 +156,7 @@ namespace ESM } esm.startSubRecord("SCDT"); - esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); + esm.write(reinterpret_cast(mScriptData.data()), mData.mScriptDataSize); esm.endRecord("SCDT"); esm.writeHNOString("SCTX", mScriptText); From 2b674cedaad6261594418689bbd5bc1ae7bc04f7 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 16 Mar 2019 14:38:51 +0200 Subject: [PATCH 359/410] Implement view cell from r-type hint --- .../view/render/pagedworldspacewidget.cpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ff69656a29..7f31373ee8 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -615,7 +616,39 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) } else if (hint[0]=='r') { - /// \todo implement 'r' type hints + // syntax r:ref#number (e.g. r:ref#100) + char ignore; + + std::istringstream stream (hint.c_str()); + if (stream >> ignore) // ignore r + { + char ignore1; // : or ; + + std::string refCode; // ref#number (e.g. ref#100) + + while (stream >> ignore1 >> refCode) {} + + //Find out cell coordinate + CSMWorld::IdTable& references = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References)); + int cellColumn = references.findColumnIndex(CSMWorld::Columns::ColumnId_Cell); + QVariant cell = references.data(references.getModelIndex(refCode, cellColumn)).value(); + QString cellqs = cell.toString(); + std::istringstream streamCellCoord (cellqs.toStdString().c_str()); + + if (streamCellCoord >> ignore) //ignore # + { + // Current coordinate + int x, y; + + // Loop through all the coordinates to add them to selection + while (streamCellCoord >> x >> y) + selection.add (CSMWorld::CellCoordinates (x, y)); + + // Mark that camera needs setup + mCamPositionSet=false; + } + } } setCellSelection (selection); From 5f86933dc6e7361f3a4a16e97f9ade81786fbb97 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 11 Mar 2019 16:31:16 +0300 Subject: [PATCH 360/410] Merge upstream osgQt changes --- extern/osgQt/GraphicsWindowQt | 2 -- extern/osgQt/GraphicsWindowQt.cpp | 17 ++++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/extern/osgQt/GraphicsWindowQt b/extern/osgQt/GraphicsWindowQt index 1e34fc9db6..274f0a149f 100644 --- a/extern/osgQt/GraphicsWindowQt +++ b/extern/osgQt/GraphicsWindowQt @@ -14,8 +14,6 @@ #ifndef OSGVIEWER_GRAPHICSWINDOWQT #define OSGVIEWER_GRAPHICSWINDOWQT -#include - #include #include diff --git a/extern/osgQt/GraphicsWindowQt.cpp b/extern/osgQt/GraphicsWindowQt.cpp index 0135a1784b..af963c04b5 100644 --- a/extern/osgQt/GraphicsWindowQt.cpp +++ b/extern/osgQt/GraphicsWindowQt.cpp @@ -22,12 +22,6 @@ #include #endif -#if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0)) -# define USE_GESTURES -# include -# include -#endif - using namespace osgQt; #if (QT_VERSION < QT_VERSION_CHECK(5, 2, 0)) @@ -132,6 +126,8 @@ bool GLWidget::event( QEvent* event ) void GLWidget::resizeEvent( QResizeEvent* event ) { + if (_gw == nullptr || !_gw->valid()) + return; const QSize& size = event->size(); int scaled_width = static_cast(size.width()*_devicePixelRatio); @@ -143,6 +139,8 @@ void GLWidget::resizeEvent( QResizeEvent* event ) void GLWidget::moveEvent( QMoveEvent* event ) { + if (_gw == nullptr || !_gw->valid()) + return; const QPoint& pos = event->pos(); int scaled_width = static_cast(width()*_devicePixelRatio); int scaled_height = static_cast(height()*_devicePixelRatio); @@ -527,9 +525,6 @@ void GraphicsWindowQt::swapBuffersImplementation() if (!_widget || !_widget->windowHandle()->isExposed()) return; #endif - - _widget->swapBuffers(); - // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but // I couln't find any reliable way to do this. For now, lets hope non of *GUI thread only operations* will // be executed in a QGLWidget::event handler. On the other hand, calling GUI only operations in the @@ -539,8 +534,8 @@ void GraphicsWindowQt::swapBuffersImplementation() // We need to call makeCurrent here to restore our previously current context // which may be changed by the processDeferredEvents function. - if (QGLContext::currentContext() != _widget->context()) - _widget->makeCurrent(); + _widget->makeCurrent(); + _widget->swapBuffers(); } void GraphicsWindowQt::requestWarpPointer( float x, float y ) From 168e758921933fcc857067312cf9864f2711ccd8 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 17 Mar 2019 06:37:20 +0300 Subject: [PATCH 361/410] Correct look and behavior of some setting sliders --- apps/openmw/mwgui/settingswindow.cpp | 11 ++++++--- files/mygui/openmw_settings_window.layout | 29 +++++++++++++---------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 98bbe859c0..deb1116d0d 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -126,7 +126,8 @@ namespace MWGui { MyGUI::ScrollBar* scroll = current->castType(); std::string valueStr; - if (getSettingValueType(current) == "Float") + std::string valueType = getSettingValueType(current); + if (valueType == "Float" || valueType == "Integer") { // TODO: ScrollBar isn't meant for this. should probably use a dedicated FloatSlider widget float min,max; @@ -423,14 +424,18 @@ namespace MWGui if (getSettingType(scroller) == "Slider") { std::string valueStr; - if (getSettingValueType(scroller) == "Float") + std::string valueType = getSettingValueType(scroller); + if (valueType == "Float" || valueType == "Integer") { float value = pos / float(scroller->getScrollRange()-1); float min,max; getSettingMinMax(scroller, min, max); value = min + (max-min) * value; - Settings::Manager::setFloat(getSettingName(scroller), getSettingCategory(scroller), value); + if (valueType == "Float") + Settings::Manager::setFloat(getSettingName(scroller), getSettingCategory(scroller), value); + else + Settings::Manager::setInt(getSettingName(scroller), getSettingCategory(scroller), (int)value); valueStr = MyGUI::utility::toString(int(value)); } else diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 58be98cca3..2341bfa198 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -53,12 +53,12 @@ - - + + - + @@ -83,11 +83,11 @@ - + - + @@ -309,12 +309,12 @@ - - + + - + @@ -353,18 +353,19 @@ - + - + + @@ -372,18 +373,20 @@ - + - + - + + + From e131e6699c91d2c3478209346c2ac05faff595b2 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 362/410] Match vertex colors data type to source --- components/esmterrain/storage.cpp | 28 ++++++++++++++-------------- components/esmterrain/storage.hpp | 4 ++-- components/terrain/chunkmanager.cpp | 3 ++- components/terrain/storage.hpp | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 567d93bbd2..6c7d6130e7 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -158,7 +158,7 @@ namespace ESMTerrain normal.normalize(); } - void Storage::fixColour (osg::Vec4f& color, int cellX, int cellY, int col, int row, LandCache& cache) + void Storage::fixColour (osg::Vec4ub& color, int cellX, int cellY, int col, int row, LandCache& cache) { if (col == ESM::Land::LAND_SIZE-1) { @@ -175,22 +175,22 @@ namespace ESMTerrain const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VCLR) : 0; if (data) { - color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3]; + color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1]; + color.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2]; } else { - color.r() = 1; - color.g() = 1; - color.b() = 1; + color.r() = 255; + color.g() = 255; + color.b() = 255; } } void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, osg::ref_ptr positions, osg::ref_ptr normals, - osg::ref_ptr colours) + osg::ref_ptr colours) { // LOD level n means every 2^n-th vertex is kept size_t increment = static_cast(1) << lodLevel; @@ -207,7 +207,7 @@ namespace ESMTerrain colours->resize(numVerts*numVerts); osg::Vec3f normal; - osg::Vec4f color; + osg::Vec4ub color; float vertY = 0; float vertX = 0; @@ -295,20 +295,20 @@ namespace ESMTerrain if (colourData) { for (int i=0; i<3; ++i) - color[i] = colourData->mColours[srcArrayIndex+i] / 255.f; + color[i] = colourData->mColours[srcArrayIndex+i]; } else { - color.r() = 1; - color.g() = 1; - color.b() = 1; + color.r() = 255; + color.g() = 255; + color.b() = 255; } // Unlike normals, colors mostly connect seamlessly between cells, but not always... if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) fixColour(color, cellX, cellY, col, row, cache); - color.a() = 1; + color.a() = 255; (*colours)[static_cast(vertX*numVerts + vertY)] = color; diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index f3300f7485..58c937e89b 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -75,7 +75,7 @@ namespace ESMTerrain virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, osg::ref_ptr positions, osg::ref_ptr normals, - osg::ref_ptr colours); + osg::ref_ptr colours); /// Create textures holding layer blend values for a terrain chunk. /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might @@ -106,7 +106,7 @@ namespace ESMTerrain const VFS::Manager* mVFS; void fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row, LandCache& cache); - void fixColour (osg::Vec4f& colour, int cellX, int cellY, int col, int row, LandCache& cache); + void fixColour (osg::Vec4ub& colour, int cellX, int cellY, int col, int row, LandCache& cache); void averageNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row, LandCache& cache); float getVertexHeight (const ESM::Land::LandData* data, int x, int y); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 80f4145419..1b297d11b6 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -172,7 +172,8 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve osg::ref_ptr positions (new osg::Vec3Array); osg::ref_ptr normals (new osg::Vec3Array); - osg::ref_ptr colors (new osg::Vec4Array); + osg::ref_ptr colors (new osg::Vec4ubArray); + colors->setNormalize(true); osg::ref_ptr vbo (new osg::VertexBufferObject); positions->setVertexBufferObject(vbo); diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index ebac1148cf..0cc4a315d1 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -52,7 +52,7 @@ namespace Terrain virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, osg::ref_ptr positions, osg::ref_ptr normals, - osg::ref_ptr colours) = 0; + osg::ref_ptr colours) = 0; typedef std::vector > ImageVector; /// Create textures holding layer blend values for a terrain chunk. From b42ad0f610e8d5567f076c20b6fe7acdfe87d362 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 363/410] Inline certain terrain storage functions --- components/esmterrain/storage.cpp | 13 ------------- components/esmterrain/storage.hpp | 26 +++++++++++++++++--------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 6c7d6130e7..3d6e521d10 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -46,19 +46,6 @@ namespace ESMTerrain { } - const ESM::Land::LandData *LandObject::getData(int flags) const - { - if ((mData.mDataLoaded & flags) != flags) - return nullptr; - return &mData; - } - - int LandObject::getPlugin() const - { - return mLand->mPlugin; - } - - const float defaultHeight = ESM::Land::DEFAULT_HEIGHT; Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 58c937e89b..27d6232eb7 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -29,8 +29,17 @@ namespace ESMTerrain META_Object(ESMTerrain, LandObject) - const ESM::Land::LandData* getData(int flags) const; - int getPlugin() const; + inline const ESM::Land::LandData* getData(int flags) const + { + if ((mData.mDataLoaded & flags) != flags) + return nullptr; + return &mData; + } + + inline int getPlugin() const + { + return mLand->mPlugin; + } private: const ESM::Land* mLand; @@ -105,21 +114,20 @@ namespace ESMTerrain private: const VFS::Manager* mVFS; - void fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row, LandCache& cache); - void fixColour (osg::Vec4ub& colour, int cellX, int cellY, int col, int row, LandCache& cache); - void averageNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row, LandCache& cache); + inline void fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row, LandCache& cache); + inline void fixColour (osg::Vec4ub& colour, int cellX, int cellY, int col, int row, LandCache& cache); + inline void averageNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row, LandCache& cache); - float getVertexHeight (const ESM::Land::LandData* data, int x, int y); + inline float getVertexHeight (const ESM::Land::LandData* data, int x, int y); - const LandObject* getLand(int cellX, int cellY, LandCache& cache); + inline const LandObject* getLand(int cellX, int cellY, LandCache& cache); // Since plugins can define new texture palettes, we need to know the plugin index too // in order to retrieve the correct texture name. // pair typedef std::pair UniqueTextureId; - UniqueTextureId getVtexIndexAt(int cellX, int cellY, - int x, int y, LandCache&); + inline UniqueTextureId getVtexIndexAt(int cellX, int cellY, int x, int y, LandCache&); std::string getTextureName (UniqueTextureId id); std::map mLayerInfoMap; From de572226e4ce536624313974a4618d363b7633e1 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 17 Mar 2019 07:59:16 +0300 Subject: [PATCH 364/410] Update optimizer with upstream improvements --- components/sceneutil/optimizer.cpp | 206 ++++++++++------------------- 1 file changed, 70 insertions(+), 136 deletions(-) diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index aaff38797b..7c568ff9d7 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -422,7 +422,7 @@ void CollectLowestTransformsVisitor::disableObject(ObjectMap::iterator itr) if (itr->second._canBeApplied) { - // we havn't been disabled yet so we need to disable, + // we haven't been disabled yet so we need to disable, itr->second._canBeApplied = false; // and then inform everybody we have been disabled. @@ -446,7 +446,7 @@ void CollectLowestTransformsVisitor::disableTransform(osg::Transform* transform) if (itr->second._canBeApplied) { - // we havn't been disabled yet so we need to disable, + // we haven't been disabled yet so we need to disable, itr->second._canBeApplied = false; // and then inform everybody we have been disabled. for(TransformStruct::ObjectSet::iterator oitr = itr->second._objectSet.begin(); @@ -905,7 +905,7 @@ void Optimizer::RemoveRedundantNodesVisitor::removeRedundantNodes() struct LessGeometry { - bool operator() (const osg::Geometry* lhs,const osg::Geometry* rhs) const + bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) const { if (lhs->getStateSet()getStateSet()) return true; if (rhs->getStateSet()getStateSet()) return false; @@ -1001,7 +1001,7 @@ struct LessGeometry struct LessGeometryPrimitiveType { - bool operator() (const osg::Geometry* lhs,const osg::Geometry* rhs) const + bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) const { for(unsigned int i=0; igetNumPrimitiveSets() && igetNumPrimitiveSets(); @@ -1115,45 +1115,39 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group) if (group.getNumChildren()>=2) { - typedef std::vector DuplicateList; - typedef std::vector< osg::ref_ptr > DrawableList; - typedef std::map GeometryDuplicateMap; + typedef std::vector< osg::ref_ptr > DuplicateList; + typedef std::vector< osg::ref_ptr > Nodes; + typedef std::map< osg::ref_ptr ,DuplicateList,LessGeometry> GeometryDuplicateMap; typedef std::vector MergeList; GeometryDuplicateMap geometryDuplicateMap; - DrawableList standardDrawables; + Nodes standardChildren; unsigned int i; for(i=0;iasDrawable(); - if (drawable) + osg::Node* child = group.getChild(i); + osg::Geometry* geom = child->asGeometry(); + if (geom) { - osg::Geometry* geom = drawable->asGeometry(); - if (geom) + if (!geometryContainsSharedArrays(*geom) && + geom->getDataVariance()!=osg::Object::DYNAMIC && + isOperationPermissibleForObject(geom)) { - //geom->computeCorrectBindingsAndArraySizes(); - - if (!geometryContainsSharedArrays(*geom) && - geom->getDataVariance()!=osg::Object::DYNAMIC && - isOperationPermissibleForObject(geom)) - { - geometryDuplicateMap[geom].push_back(geom); - } - else - { - standardDrawables.push_back(drawable); - } + geometryDuplicateMap[geom].push_back(geom); } else { - standardDrawables.push_back(drawable); + standardChildren.push_back(geom); } } + else + { + standardChildren.push_back(child); + } } -#if 1 // first try to group geometries with the same properties // (i.e. array types) to avoid loss of data during merging MergeList mergeListChecked; // List of drawables just before merging, grouped by "compatibility" and vertex limit @@ -1183,7 +1177,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group) dupItr!=itr->second.end(); ++dupItr) { - osg::Geometry* geomToPush = *dupItr; + osg::Geometry* geomToPush = dupItr->get(); // try to group geomToPush with another geometry MergeList::iterator eachMergeList=mergeListTmp.begin(); @@ -1216,126 +1210,74 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group) // then build merge list using _targetMaximumNumberOfVertices bool needToDoMerge = false; // dequeue each DuplicateList when vertices limit is reached or when all elements has been checked - for(;!mergeListChecked.empty();) + for(MergeList::iterator itr=mergeListChecked.begin(); itr!=mergeListChecked.end(); ++itr) { - MergeList::iterator itr=mergeListChecked.begin(); DuplicateList& duplicateList(*itr); if (duplicateList.size()==0) { - mergeListChecked.erase(itr); continue; } if (duplicateList.size()==1) { mergeList.push_back(duplicateList); - mergeListChecked.erase(itr); continue; } - unsigned int numVertices(duplicateList.front()->getVertexArray() ? duplicateList.front()->getVertexArray()->getNumElements() : 0); - DuplicateList::iterator eachGeom(duplicateList.begin()+1); - // until all geometries have been checked or _targetMaximumNumberOfVertices is reached - for(;eachGeom!=duplicateList.end(); ++eachGeom) + unsigned int totalNumberVertices = 0; + DuplicateList subset; + for(DuplicateList::iterator ditr = duplicateList.begin(); + ditr != duplicateList.end(); + ++ditr) { - unsigned int numAddVertices((*eachGeom)->getVertexArray() ? (*eachGeom)->getVertexArray()->getNumElements() : 0); - if ((numVertices+numAddVertices)>_targetMaximumNumberOfVertices) + osg::Geometry* geometry = ditr->get(); + unsigned int numVertices = (geometry->getVertexArray() ? geometry->getVertexArray()->getNumElements() : 0); + if ((totalNumberVertices+numVertices)>_targetMaximumNumberOfVertices && !subset.empty()) { - break; - } - else - { - numVertices += numAddVertices; + mergeList.push_back(subset); + subset.clear(); + totalNumberVertices = 0; } + totalNumberVertices += numVertices; + subset.push_back(geometry); + if (subset.size()>1) needToDoMerge = true; } - - // push back if bellow the limit - if (eachGeom==duplicateList.end()) - { - if (duplicateList.size()>1) needToDoMerge = true; - mergeList.push_back(duplicateList); - mergeListChecked.erase(itr); - } - // else split the list to store what is below the limit and retry on what is above - else - { - mergeList.push_back(DuplicateList()); - DuplicateList* duplicateListResult = &mergeList.back(); - duplicateListResult->insert(duplicateListResult->end(),duplicateList.begin(),eachGeom); - duplicateList.erase(duplicateList.begin(),eachGeom); - if (duplicateListResult->size()>1) needToDoMerge = true; - } + if (!subset.empty()) mergeList.push_back(subset); } if (needToDoMerge) { + // to avoid performance issues associated with incrementally removing a large number children, we remove them all and add back the ones we need. + group.removeChildren(0, group.getNumChildren()); + + for(Nodes::iterator itr = standardChildren.begin(); + itr != standardChildren.end(); + ++itr) + { + group.addChild(*itr); + } + // now do the merging of geometries for(MergeList::iterator mitr = mergeList.begin(); mitr != mergeList.end(); ++mitr) { DuplicateList& duplicateList = *mitr; - if (duplicateList.size()>1) + if (!duplicateList.empty()) { - osg::Geometry* lhs = duplicateList.front(); - for(DuplicateList::iterator ditr = duplicateList.begin()+1; + DuplicateList::iterator ditr = duplicateList.begin(); + osg::ref_ptr lhs = *ditr++; + group.addChild(lhs.get()); + for(; ditr != duplicateList.end(); ++ditr) { - mergeGeometry(*lhs,**ditr); - - group.removeChild(*ditr); + mergeGeometry(*lhs, **ditr); } } } } -#else - // don't merge geometry if its above a maximum number of vertices. - for(GeometryDuplicateMap::iterator itr=geometryDuplicateMap.begin(); - itr!=geometryDuplicateMap.end(); - ++itr) - { - if (itr->second.size()>1) - { - std::sort(itr->second.begin(),itr->second.end(),LessGeometryPrimitiveType()); - osg::Geometry* lhs = itr->second[0]; - for(DuplicateList::iterator dupItr=itr->second.begin()+1; - dupItr!=itr->second.end(); - ++dupItr) - { - - osg::Geometry* rhs = *dupItr; - - if (lhs->getVertexArray() && lhs->getVertexArray()->getNumElements()>=_targetMaximumNumberOfVertices) - { - lhs = rhs; - continue; - } - - if (rhs->getVertexArray() && rhs->getVertexArray()->getNumElements()>=_targetMaximumNumberOfVertices) - { - continue; - } - - if (lhs->getVertexArray() && rhs->getVertexArray() && - (lhs->getVertexArray()->getNumElements()+rhs->getVertexArray()->getNumElements())>=_targetMaximumNumberOfVertices) - { - continue; - } - - if (mergeGeometry(*lhs,*rhs)) - { - geode.removeDrawable(rhs); - - static int co = 0; - OSG_INFO<<"merged and removed Geometry "<<++co<getType()!=rhs->getType()) return false; _lhs = lhs; - _offset = offset; rhs->accept(*this); return true; @@ -1607,30 +1546,24 @@ class MergeArrayVisitor : public osg::ArrayVisitor lhs->insert(lhs->end(),rhs.begin(),rhs.end()); } - template - void _mergeAndOffset(T& rhs) - { - T* lhs = static_cast(_lhs); - - typename T::iterator itr; - for(itr = rhs.begin(); - itr != rhs.end(); - ++itr) - { - lhs->push_back(*itr + _offset); - } - } - virtual void apply(osg::Array&) { OSG_WARN << "Warning: Optimizer's MergeArrayVisitor cannot merge Array type." << std::endl; } - virtual void apply(osg::ByteArray& rhs) { if (_offset) _mergeAndOffset(rhs); else _merge(rhs); } - virtual void apply(osg::ShortArray& rhs) { if (_offset) _mergeAndOffset(rhs); else _merge(rhs); } - virtual void apply(osg::IntArray& rhs) { if (_offset) _mergeAndOffset(rhs); else _merge(rhs); } - virtual void apply(osg::UByteArray& rhs) { if (_offset) _mergeAndOffset(rhs); else _merge(rhs); } - virtual void apply(osg::UShortArray& rhs) { if (_offset) _mergeAndOffset(rhs); else _merge(rhs); } - virtual void apply(osg::UIntArray& rhs) { if (_offset) _mergeAndOffset(rhs); else _merge(rhs); } + + virtual void apply(osg::ByteArray& rhs) { _merge(rhs); } + virtual void apply(osg::ShortArray& rhs) { _merge(rhs); } + virtual void apply(osg::IntArray& rhs) { _merge(rhs); } + virtual void apply(osg::UByteArray& rhs) { _merge(rhs); } + virtual void apply(osg::UShortArray& rhs) { _merge(rhs); } + virtual void apply(osg::UIntArray& rhs) { _merge(rhs); } virtual void apply(osg::Vec4ubArray& rhs) { _merge(rhs); } + virtual void apply(osg::Vec3ubArray& rhs) { _merge(rhs); } + virtual void apply(osg::Vec2ubArray& rhs) { _merge(rhs); } + + virtual void apply(osg::Vec4usArray& rhs) { _merge(rhs); } + virtual void apply(osg::Vec3usArray& rhs) { _merge(rhs); } + virtual void apply(osg::Vec2usArray& rhs) { _merge(rhs); } + virtual void apply(osg::FloatArray& rhs) { _merge(rhs); } virtual void apply(osg::Vec2Array& rhs) { _merge(rhs); } virtual void apply(osg::Vec3Array& rhs) { _merge(rhs); } @@ -1644,6 +1577,7 @@ class MergeArrayVisitor : public osg::ArrayVisitor virtual void apply(osg::Vec2bArray& rhs) { _merge(rhs); } virtual void apply(osg::Vec3bArray& rhs) { _merge(rhs); } virtual void apply(osg::Vec4bArray& rhs) { _merge(rhs); } + virtual void apply(osg::Vec2sArray& rhs) { _merge(rhs); } virtual void apply(osg::Vec3sArray& rhs) { _merge(rhs); } virtual void apply(osg::Vec4sArray& rhs) { _merge(rhs); } From 2c78d530a273e20e3e8e57e53145caaabe25f2c6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Mar 2019 19:45:54 +0300 Subject: [PATCH 365/410] Use static vector to store stat names --- components/resource/stats.cpp | 47 +++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index 0a70d75ab6..b23558e99b 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -197,14 +197,14 @@ class ResourceStatsTextDrawCallback : public osg::Drawable::DrawCallback { public: ResourceStatsTextDrawCallback(osg::Stats* stats, const std::vector& statNames) - : _stats(stats) - , _statNames(statNames) + : mStats(stats) + , mStatNames(statNames) { } virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { - if (!_stats) return; + if (!mStats) return; osgText::Text* text = (osgText::Text*)(drawable); @@ -218,14 +218,14 @@ public: unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber()-1; - for (std::vector::const_iterator it = _statNames.begin(); it != _statNames.end(); ++it) + for (const auto& statName : mStatNames.get()) { - if (it->empty()) + if (statName.empty()) viewStr << std::endl; else { double value = 0.0; - if (_stats->getAttribute(frameNumber, *it, value)) + if (mStats->getAttribute(frameNumber, statName, value)) viewStr << std::setw(8) << value << std::endl; else viewStr << std::setw(8) << "." << std::endl; @@ -237,8 +237,8 @@ public: text->drawImplementation(renderInfo); } - osg::ref_ptr _stats; - std::vector _statNames; + osg::ref_ptr mStats; + std::reference_wrapper> mStatNames; }; void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) @@ -269,9 +269,30 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) _resourceStatsChildNum = _switch->getNumChildren(); _switch->addChild(group, false); - const char* statNames[] = {"Compiling", "WorkQueue", "WorkThread", "", "Texture", "StateSet", "Node", "Node Instance", "Shape", "Shape Instance", "Image", "Nif", "Keyframe", "", "Terrain Chunk", "Terrain Texture", "Land", "Composite", "", "UnrefQueue"}; + static const std::vector statNames({ + "Compiling", + "WorkQueue", + "WorkThread", + "", + "Texture", + "StateSet", + "Node", + "Node Instance", + "Shape", + "Shape Instance", + "Image", + "Nif", + "Keyframe", + "", + "Terrain Chunk", + "Terrain Texture", + "Land", + "Composite", + "", + "UnrefQueue", + }); - int numLines = sizeof(statNames) / sizeof(statNames[0]); + const int numLines = statNames.size(); group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), 10 * _characterSize + 2 * backgroundMargin, @@ -289,9 +310,9 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) viewStr.clear(); viewStr.setf(std::ios::left, std::ios::adjustfield); viewStr.width(14); - for (size_t i = 0; isetText(viewStr.str()); @@ -311,7 +332,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) statsText->setCharacterSize(_characterSize); statsText->setPosition(pos); statsText->setText(""); - statsText->setDrawCallback(new ResourceStatsTextDrawCallback(viewer->getViewerStats(), std::vector(statNames, statNames + numLines))); + statsText->setDrawCallback(new ResourceStatsTextDrawCallback(viewer->getViewerStats(), statNames)); } } From abae35e88bc3fa87317b6652217314a937e604f0 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 4 Mar 2019 01:31:51 +0300 Subject: [PATCH 366/410] Loop title screen music (bug #4896) --- CHANGELOG.md | 1 + apps/openmw/engine.cpp | 14 ++++------- apps/openmw/mwbase/soundmanager.hpp | 3 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 32 ++++++++++++++++++++++++- apps/openmw/mwsound/soundmanagerimp.hpp | 3 +++ 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f3fcc3291..c9f23a26c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Bug #4876: AI ratings handling inconsistencies Bug #4877: Startup script executes only on a new game start Bug #4888: Global variable stray explicit reference calls break script compilation + Bug #4896: Title screen music doesn't loop Bug #4911: Editor: QOpenGLContext::swapBuffers() warning with Qt5 Bug #4916: Specular power (shininess) material parameter is ignored when shaders are used. Feature #2229: Improve pathfinding AI diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4fae3061a7..b317c8b405 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -706,16 +706,10 @@ void OMW::Engine::go() { // start in main menu mEnvironment.getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); - try - { - // Is there an ini setting for this filename or something? - mEnvironment.getSoundManager()->streamMusic("Special/morrowind title.mp3"); - - std::string logo = mFallbackMap["Movies_Morrowind_Logo"]; - if (!logo.empty()) - mEnvironment.getWindowManager()->playVideo(logo, true); - } - catch (...) {} + mEnvironment.getSoundManager()->playTitleMusic(); + std::string logo = mFallbackMap["Movies_Morrowind_Logo"]; + if (!logo.empty()) + mEnvironment.getWindowManager()->playVideo(logo, true); } else { diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 2b3cf1f0df..bad80d6bd3 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -89,6 +89,9 @@ namespace MWBase ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist + virtual void playTitleMusic() = 0; + ///< Start playing title music + virtual void say(const MWWorld::ConstPtr &reference, const std::string& filename) = 0; ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7b722a8352..ae2c25eade 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -471,6 +471,36 @@ namespace MWSound startRandomTitle(); } + void SoundManager::playTitleMusic() + { + if (mCurrentPlaylist == "Title") + return; + + if (mMusicFiles.find("Title") == mMusicFiles.end()) + { + std::vector filelist; + const std::map& index = mVFS->getIndex(); + // Is there an ini setting for this filename or something? + std::string filename = "music/special/morrowind title.mp3"; + auto found = index.find(filename); + if (found != index.end()) + { + filelist.emplace_back(found->first); + mMusicFiles["Title"] = filelist; + } + else + { + Log(Debug::Warning) << "Title music not found"; + return; + } + } + + if (mMusicFiles["Title"].empty()) + return; + + mCurrentPlaylist = "Title"; + startRandomTitle(); + } void SoundManager::say(const MWWorld::ConstPtr &ptr, const std::string &filename) { @@ -1122,10 +1152,10 @@ namespace MWSound if(!mOutput->isInitialized()) return; + updateSounds(duration); if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - updateSounds(duration); updateRegionSound(duration); updateWaterSound(duration); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d8a4cfc8cc..9878e924ab 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -168,6 +168,9 @@ namespace MWSound ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist + virtual void playTitleMusic(); + ///< Start playing title music + virtual void say(const MWWorld::ConstPtr &reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. From 8adc83f6e2d240f372cf7bdc6dffabcbd0391d8d Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Mar 2019 21:24:49 +0300 Subject: [PATCH 367/410] Fix clean unused navmeshes weak_ptr doesn't have constructor for shared_ptr&& type, so ptr wasn't moved, just copied. --- components/detournavigator/navmeshmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index fc3563acee..871bb6e593 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -22,7 +22,8 @@ namespace template bool resetIfUnique(std::shared_ptr& ptr) { - const std::weak_ptr weak = std::move(ptr); + const std::weak_ptr weak(ptr); + ptr.reset(); if (auto shared = weak.lock()) { ptr = std::move(shared); From 4624f3178801b38288aa8b031d89def24d58ee4b Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Mar 2019 20:18:53 +0300 Subject: [PATCH 368/410] Report navigator stats --- apps/openmw/engine.cpp | 4 ++++ .../detournavigator/asyncnavmeshupdater.cpp | 16 +++++++++++++++ .../detournavigator/asyncnavmeshupdater.hpp | 4 +++- components/detournavigator/navigator.hpp | 2 ++ components/detournavigator/navigatorimpl.cpp | 5 +++++ components/detournavigator/navigatorimpl.hpp | 2 ++ components/detournavigator/navigatorstub.hpp | 2 ++ components/detournavigator/navmeshmanager.cpp | 5 +++++ components/detournavigator/navmeshmanager.hpp | 2 ++ .../detournavigator/navmeshtilescache.cpp | 20 +++++++++++++++++++ .../detournavigator/navmeshtilescache.hpp | 9 ++++++++- components/resource/stats.cpp | 19 +++++++++++++----- 12 files changed, 83 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4fae3061a7..98869703f9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -32,6 +32,8 @@ #include +#include + #include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" @@ -198,6 +200,8 @@ bool OMW::Engine::frame(float frametime) stats->setAttribute(frameNumber, "WorkQueue", mWorkQueue->getNumItems()); stats->setAttribute(frameNumber, "WorkThread", mWorkQueue->getNumActiveThreads()); + + mEnvironment.getWorld()->getNavigator()->reportStats(frameNumber, *stats); } } diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 2013931edf..6bd4f01c9e 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -5,6 +5,8 @@ #include +#include + namespace { using DetourNavigator::ChangeType; @@ -102,6 +104,20 @@ namespace DetourNavigator mDone.wait(lock, [&] { return mJobs.empty(); }); } + void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + std::size_t jobs = 0; + + { + const std::lock_guard lock(mMutex); + jobs = mJobs.size(); + } + + stats.setAttribute(frameNumber, "NavMesh UpdateJobs", jobs); + + mNavMeshTilesCache.reportStats(frameNumber, stats); + } + void AsyncNavMeshUpdater::process() throw() { log("start process jobs"); diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 55e502b453..3493ba02f6 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -44,6 +44,8 @@ namespace DetourNavigator void wait(); + void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + private: struct Job { @@ -72,7 +74,7 @@ namespace DetourNavigator std::reference_wrapper mRecastMeshManager; std::reference_wrapper mOffMeshConnectionsManager; std::atomic_bool mShouldStop; - std::mutex mMutex; + mutable std::mutex mMutex; std::condition_variable mHasJob; std::condition_variable mDone; Jobs mJobs; diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index d9c5ebe0b5..561b7f02b5 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -192,6 +192,8 @@ namespace DetourNavigator virtual std::map getNavMeshes() const = 0; virtual const Settings& getSettings() const = 0; + + virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; }; } diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index a62220e555..b743f26b21 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -138,6 +138,11 @@ namespace DetourNavigator return mSettings; } + void NavigatorImpl::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + mNavMeshManager.reportStats(frameNumber, stats); + } + void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId) { updateId(id, avoidId, mWaterIds); diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index d2ff8a57bd..b6b3b1b7f5 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -48,6 +48,8 @@ namespace DetourNavigator const Settings& getSettings() const override; + void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; + private: Settings mSettings; NavMeshManager mNavMeshManager; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index cab93b1052..885482a453 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -79,6 +79,8 @@ namespace DetourNavigator return mDefaultSettings; } + void reportStats(unsigned int /*frameNumber*/, osg::Stats& /*stats*/) const override {} + private: Settings mDefaultSettings {}; SharedNavMeshCacheItem mEmptyNavMeshCacheItem; diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index fc3563acee..c3e13ad7fb 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -212,6 +212,11 @@ namespace DetourNavigator return mCache; } + void NavMeshManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + mAsyncNavMeshUpdater.reportStats(frameNumber, stats); + } + void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType) { diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index cee33c63df..3ef898b050 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -50,6 +50,8 @@ namespace DetourNavigator std::map getNavMeshes() const; + void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + private: const Settings& mSettings; TileCachedRecastMeshManager mRecastMeshManager; diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 8dd14f04c3..466d2e708d 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -1,6 +1,8 @@ #include "navmeshtilescache.hpp" #include "exceptions.hpp" +#include + #include namespace DetourNavigator @@ -113,6 +115,24 @@ namespace DetourNavigator return Value(*this, iterator); } + void NavMeshTilesCache::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + std::size_t navMeshCacheSize = 0; + std::size_t usedNavMeshTiles = 0; + std::size_t cachedNavMeshTiles = 0; + + { + const std::lock_guard lock(mMutex); + navMeshCacheSize = mUsedNavMeshDataSize; + usedNavMeshTiles = mBusyItems.size(); + cachedNavMeshTiles = mFreeItems.size(); + } + + stats.setAttribute(frameNumber, "NavMesh CacheSize", navMeshCacheSize); + stats.setAttribute(frameNumber, "NavMesh UsedTiles", usedNavMeshTiles); + stats.setAttribute(frameNumber, "NavMesh CachedTiles", cachedNavMeshTiles); + } + void NavMeshTilesCache::removeLeastRecentlyUsed() { const auto& item = mFreeItems.back(); diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 3f2e0cc019..5d5db47a8f 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -12,6 +12,11 @@ #include #include +namespace osg +{ + class Stats; +} + namespace DetourNavigator { struct NavMeshDataRef @@ -105,6 +110,8 @@ namespace DetourNavigator const RecastMesh& recastMesh, const std::vector& offMeshConnections, NavMeshData&& value); + void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + private: class KeyView { @@ -164,7 +171,7 @@ namespace DetourNavigator std::map mMap; }; - std::mutex mMutex; + mutable std::mutex mMutex; std::size_t mMaxNavMeshDataSize; std::size_t mUsedNavMeshDataSize; std::size_t mFreeNavMeshDataSize; diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index b23558e99b..51497cd279 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -255,7 +256,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED); #endif - osg::Vec3 pos(_statsWidth-300.f, _statsHeight-500.0f,0.0f); + osg::Vec3 pos(_statsWidth-420.f, _statsHeight-500.0f,0.0f); osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3); osg::Vec4 staticTextColor(1.0, 1.0, 0.0f, 1.0); osg::Vec4 dynamicTextColor(1.0, 1.0, 1.0f, 1.0); @@ -290,12 +291,20 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) "Composite", "", "UnrefQueue", + "", + "NavMesh UpdateJobs", + "NavMesh CacheSize", + "NavMesh UsedTiles", + "NavMesh CachedTiles", }); + static const auto longest = std::max_element(statNames.begin(), statNames.end(), + [] (const std::string& lhs, const std::string& rhs) { return lhs.size() < rhs.size(); }); const int numLines = statNames.size(); + const float statNamesWidth = 13 * _characterSize + 2 * backgroundMargin; group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), - 10 * _characterSize + 2 * backgroundMargin, + statNamesWidth, numLines * _characterSize + 2 * backgroundMargin, backgroundColor)); @@ -309,7 +318,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) std::ostringstream viewStr; viewStr.clear(); viewStr.setf(std::ios::left, std::ios::adjustfield); - viewStr.width(14); + viewStr.width(longest->size()); for (const auto& statName : statNames) { viewStr << statName << std::endl; @@ -317,10 +326,10 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) staticText->setText(viewStr.str()); - pos.x() += 10 * _characterSize + 2 * backgroundMargin + backgroundSpacing; + pos.x() += statNamesWidth + backgroundSpacing; group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), - 5 * _characterSize + 2 * backgroundMargin, + 7 * _characterSize + 2 * backgroundMargin, numLines * _characterSize + 2 * backgroundMargin, backgroundColor)); From 80e0fbdd887063d91c26bb034f1d069922393577 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Mar 2019 08:47:46 +0400 Subject: [PATCH 369/410] Fix missing \n characters on the active effects tooltips --- apps/openmw/mwgui/spellicons.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c1bd421dba..51508cd06b 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -79,14 +79,11 @@ namespace MWGui static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get().find("fMagicStartIconBlink")->mValue.getFloat(); std::vector& effectInfos = effectInfoPair.second; - bool addNewLine = true; + bool addNewLine = false; for (const MagicEffectInfo& effectInfo : effectInfos) { if (addNewLine) - { sourcesDescription += "\n"; - addNewLine = false; - } // if at least one of the effect sources is permanent, the effect will never wear off if (effectInfo.mPermanent) @@ -161,6 +158,8 @@ namespace MWGui sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; } } + + addNewLine = true; } if (remainingDuration > 0.f) From 36fa51b6ad8a947d70bea2e726bfca87976c2c4a Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 370/410] Fix bounding box calculation for terrain shapes --- components/terrain/chunkmanager.cpp | 2 +- components/terrain/quadtreeworld.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 80f4145419..1cdfcf2432 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -188,7 +188,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve geometry->setUseDisplayList(false); geometry->setUseVertexBufferObjects(true); - if (chunkSize <= 2.f) + if (chunkSize <= 1.f) geometry->setLightListCallback(new SceneUtil::LightListCallback); unsigned int numVerts = (mStorage->getCellVertices()-1) * chunkSize / (1 << lod) + 1; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 5970732292..efe0dd58a0 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -173,10 +173,10 @@ public: node->setLodCallback(parent->getLodCallback()); node->setViewDataMap(mViewDataMap); - if (center.x() - size > mMaxX - || center.x() + size < mMinX - || center.y() - size > mMaxY - || center.y() + size < mMinY ) + if (center.x() - halfSize > mMaxX + || center.x() + halfSize < mMinX + || center.y() - halfSize > mMaxY + || center.y() + halfSize < mMinY ) // Out of bounds of the actual terrain - this will happen because // we rounded the size up to the next power of two { @@ -191,8 +191,8 @@ public: if (mStorage->getMinMaxHeights(size, center, minZ, maxZ)) { float cellWorldSize = mStorage->getCellWorldSize(); - osg::BoundingBox boundingBox(osg::Vec3f((center.x()-size)*cellWorldSize, (center.y()-size)*cellWorldSize, minZ), - osg::Vec3f((center.x()+size)*cellWorldSize, (center.y()+size)*cellWorldSize, maxZ)); + osg::BoundingBox boundingBox(osg::Vec3f((center.x()-halfSize)*cellWorldSize, (center.y()-halfSize)*cellWorldSize, minZ), + osg::Vec3f((center.x()+halfSize)*cellWorldSize, (center.y()+halfSize)*cellWorldSize, maxZ)); node->setBoundingBox(boundingBox); } return node; From 6029ed4eccd7adc97faa7718c582064c1f316119 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 371/410] Reject empty quad tree nodes at the cell level without land data --- apps/openmw/mwrender/terrainstorage.cpp | 9 +++++++++ apps/openmw/mwrender/terrainstorage.hpp | 2 ++ components/terrain/quadtreeworld.cpp | 5 +++++ components/terrain/storage.hpp | 8 ++++++++ 4 files changed, 24 insertions(+) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 7894a8393f..528ce70ea3 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -22,6 +22,15 @@ namespace MWRender mResourceSystem->removeResourceManager(mLandManager.get()); } + bool TerrainStorage::hasData(int cellX, int cellY) + { + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Land* land = esmStore.get().search(cellX, cellY); + return land != nullptr; + } + void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY) { minX = 0, minY = 0, maxX = 0, maxY = 0; diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index 6f716e752e..cae56d3aa4 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -23,6 +23,8 @@ namespace MWRender virtual osg::ref_ptr getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); + virtual bool hasData(int cellX, int cellY) override; + /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index efe0dd58a0..cf877142a4 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -184,6 +184,11 @@ public: return node; } + // Do not add child nodes for default cells without data. + // size = 1 means that the single shape covers the whole cell. + if (node->getSize() == 1 && !mStorage->hasData(center.x()-0.5, center.y()-0.5)) + return node; + if (node->getSize() <= mMinSize) { // We arrived at a leaf diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index ebac1148cf..3bc20aa595 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -28,6 +28,14 @@ namespace Terrain /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0; + /// Return true if there is land data for this cell + /// May be overriden for a faster implementation + virtual bool hasData(int cellX, int cellY) + { + float dummy; + return getMinMaxHeights(1, osg::Vec2f(cellX+0.5, cellY+0.5), dummy, dummy); + } + /// Get the minimum and maximum heights of a terrain region. /// @note Will only be called for chunks with size = minBatchSize, i.e. leafs of the quad tree. /// Larger chunks can simply merge AABB of children. From 540709fdae4147462430875cc7f37c6e2ef11a68 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 2 Mar 2019 19:01:25 +0400 Subject: [PATCH 372/410] Add a changelog entry for terrain optimization --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c510fa16..92b2fa9cad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Feature #4887: Add openmw command option to set initial random seed Feature #4890: Make Distant Terrain configurable Task #4686: Upgrade media decoder to a more current FFmpeg API + Task #4695: Optimize Distant Terrain memory consumption 0.45.0 ------ From c6cb91ce614eefb32153b496e736edf9e419fb75 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 3 Mar 2019 21:29:51 +0400 Subject: [PATCH 373/410] Limit maximum FOV value --- apps/openmw/mwrender/renderingmanager.cpp | 10 +++++++--- docs/source/reference/modding/settings/camera.rst | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 42bd0c69b0..5f35b401e5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -371,8 +371,10 @@ namespace MWRender mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); - mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); + float fov = Settings::Manager::getFloat("field of view", "Camera"); + mFieldOfView = std::min(std::max(1.f, fov), 179.f); + float firstPersonFov = Settings::Manager::getFloat("first person field of view", "Camera"); + mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f); mStateUpdater->setFogEnd(mViewDistance); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); @@ -1200,7 +1202,9 @@ namespace MWRender mUniformFar->set(mViewDistance); // Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear. - float distanceMult = std::cos(osg::DegreesToRadians(mFieldOfView)/2.f); + // Limit FOV here just for sure, otherwise viewing distance can be too high. + fov = std::min(mFieldOfView, 140.f); + float distanceMult = std::cos(osg::DegreesToRadians(fov)/2.f); mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f)); } diff --git a/docs/source/reference/modding/settings/camera.rst b/docs/source/reference/modding/settings/camera.rst index aed68658f2..6f13e33050 100644 --- a/docs/source/reference/modding/settings/camera.rst +++ b/docs/source/reference/modding/settings/camera.rst @@ -94,7 +94,7 @@ field of view ------------- :Type: floating point -:Range: 0-360 +:Range: 1-179 :Default: 55.0 Sets the camera field of view in degrees. Recommended values range from 30 degrees to 110 degrees. @@ -109,7 +109,7 @@ first person field of view -------------------------- :Type: floating point -:Range: 0-360 +:Range: 1-179 :Default: 55.0 This setting controls the field of view for first person meshes such as the player's hands and held objects. From 5ec28e09c9707f586812bd7d1b1823028f866e07 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 374/410] Do not recreate shaders to update transparency --- apps/openmw/mwrender/animation.cpp | 6 +----- apps/openmw/mwrender/npcanimation.cpp | 12 ------------ 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c21cab6c96..8ec75b1ce8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1798,17 +1798,13 @@ namespace MWRender material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - + stateset->addUniform(new osg::Uniform("colorMode", 0), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); mObjectRoot->setStateSet(stateset); - - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } } else { mObjectRoot->setStateSet(nullptr); - - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } setRenderBin(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f1ebc80dfd..0b421a7533 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -649,9 +649,6 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); - - if (mAlpha != 1.f) - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } @@ -918,9 +915,6 @@ void NpcAnimation::showWeapons(bool showWeapon) attachArrow(); } } - // Note: we will need to recreate shaders later if we use weapon sheathing anyway, so there is no point to update them here - if (mAlpha != 1.f && !mWeaponSheathing) - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } else { @@ -932,10 +926,6 @@ void NpcAnimation::showWeapons(bool showWeapon) updateHolsteredWeapon(!mShowWeapons); updateQuiver(); - - // Recreate shaders for invisible actors, otherwise sheath nodes will be visible - if (mAlpha != 1.f && mWeaponSheathing) - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } void NpcAnimation::showCarriedLeft(bool show) @@ -953,8 +943,6 @@ void NpcAnimation::showCarriedLeft(bool show) if (iter->getTypeName() == typeid(ESM::Light).name() && mObjectParts[ESM::PRT_Shield]) addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), iter->get()->mBase); } - if (mAlpha != 1.f) - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } else removeIndividualPart(ESM::PRT_Shield); From aa5a071aef59d4aa4a3f4b8f664d0a322d28f130 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 375/410] Delete composite map layers in the background thread --- apps/openmw/mwrender/renderingmanager.cpp | 1 + components/terrain/compositemaprenderer.cpp | 21 +++++++++++++++++++++ components/terrain/compositemaprenderer.hpp | 13 +++++++++++++ components/terrain/quadtreeworld.hpp | 2 +- components/terrain/world.cpp | 5 +++++ components/terrain/world.hpp | 8 ++++++++ 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5f35b401e5..7333a4c2ca 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -314,6 +314,7 @@ namespace MWRender mTerrain->setDefaultViewer(mViewer->getCamera()); mTerrain->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); + mTerrain->setWorkQueue(mWorkQueue.get()); mCamera.reset(new Camera(mViewer->getCamera())); diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 0ef6491977..39d00db361 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include + #include namespace Terrain @@ -20,9 +23,20 @@ CompositeMapRenderer::CompositeMapRenderer() mFBO = new osg::FrameBufferObject; + mUnrefQueue = new SceneUtil::UnrefQueue; + getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); } +CompositeMapRenderer::~CompositeMapRenderer() +{ +} + +void CompositeMapRenderer::setWorkQueue(SceneUtil::WorkQueue* workQueue) +{ + mWorkQueue = workQueue; +} + void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const { double dt = mTimer.time_s(); @@ -35,6 +49,9 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const mCompiled.clear(); + if (mWorkQueue) + mUnrefQueue->flush(mWorkQueue.get()); + OpenThreads::ScopedLock lock(mMutex); if (mImmediateCompileSet.empty() && mCompileSet.empty()) @@ -122,6 +139,10 @@ void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo & ++compositeMap.mCompiled; + if (mWorkQueue) + { + mUnrefQueue->push(compositeMap.mDrawables[i]); + } compositeMap.mDrawables[i] = nullptr; if (timeLeft) diff --git a/components/terrain/compositemaprenderer.hpp b/components/terrain/compositemaprenderer.hpp index 54e158ed46..5c81fdca65 100644 --- a/components/terrain/compositemaprenderer.hpp +++ b/components/terrain/compositemaprenderer.hpp @@ -14,6 +14,12 @@ namespace osg class Texture2D; } +namespace SceneUtil +{ + class UnrefQueue; + class WorkQueue; +} + namespace Terrain { @@ -34,11 +40,15 @@ namespace Terrain { public: CompositeMapRenderer(); + ~CompositeMapRenderer(); virtual void drawImplementation(osg::RenderInfo& renderInfo) const; void compile(CompositeMap& compositeMap, osg::RenderInfo& renderInfo, double* timeLeft) const; + /// Set a WorkQueue to delete compiled composite map layers in the background thread + void setWorkQueue(SceneUtil::WorkQueue* workQueue); + /// Set the available time in seconds for compiling (non-immediate) composite maps each frame void setMinimumTimeAvailableForCompile(double time); @@ -58,6 +68,9 @@ namespace Terrain double mMinimumTimeAvailable; mutable osg::Timer mTimer; + osg::ref_ptr mUnrefQueue; + osg::ref_ptr mWorkQueue; + typedef std::set > CompileSet; mutable CompileSet mCompileSet; diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index bb09048c28..3e4055671f 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -16,7 +16,7 @@ namespace Terrain class RootNode; class ViewDataMap; - /// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD. The entire world is displayed at all times. + /// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD. class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell) { public: diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 6a8322bb54..da3bdb5c22 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -66,6 +66,11 @@ World::~World() delete mStorage; } +void World::setWorkQueue(SceneUtil::WorkQueue* workQueue) +{ + mCompositeMapRenderer->setWorkQueue(workQueue); +} + void World::setBordersVisible(bool visible) { mBorderVisible = visible; diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 83a2655fdd..ba5cf67885 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -24,6 +24,11 @@ namespace Resource class ResourceSystem; } +namespace SceneUtil +{ + class WorkQueue; +} + namespace Terrain { class Storage; @@ -59,6 +64,9 @@ namespace Terrain World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask); virtual ~World(); + /// Set a WorkQueue to delete objects in the background thread. + void setWorkQueue(SceneUtil::WorkQueue* workQueue); + /// See CompositeMapRenderer::setTargetFrameRate void setTargetFrameRate(float rate); From 02242ce66b0bd5b9e8df64d67284117b5925919d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 18 Mar 2019 17:07:27 +0300 Subject: [PATCH 376/410] Fix shader specular lighting (again) --- files/shaders/lighting.glsl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 6de34bc075..782d17d4e4 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -74,9 +74,10 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec) { vec3 lightDir = normalize(gl_LightSource[0].position.xyz); - float NdotL = max(dot(viewNormal, lightDir), 0.0); - if (NdotL < 0.0) + float NdotL = dot(viewNormal, lightDir); + if (NdotL <= 0.0) return vec3(0.,0.,0.); vec3 halfVec = normalize(lightDir - viewDirection); - return pow(max(dot(viewNormal, halfVec), 0.0), shininess) * gl_LightSource[0].specular.xyz * matSpec; + float NdotH = dot(viewNormal, halfVec); + return pow(max(NdotH, 0.0), max(1e-4, shininess)) * gl_LightSource[0].specular.xyz * matSpec; } From 9b65f0dbca5ecb467221e926a9630ce80bb7aaab Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 18 Mar 2019 19:21:07 +0300 Subject: [PATCH 377/410] Vsync tweaks Try to use adaptive vsync if available Don't use vsync if unavailable --- components/sdlutil/sdlgraphicswindow.cpp | 24 ++++++++++++++++++++++-- components/sdlutil/sdlgraphicswindow.hpp | 3 +++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index dc6129e43f..3b76e6887c 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -113,7 +113,7 @@ void GraphicsWindowSDL2::init() return; } - SDL_GL_SetSwapInterval(_traits->vsync ? 1 : 0); + setSwapInterval(_traits->vsync); SDL_GL_MakeCurrent(oldWin, oldCtx); @@ -194,11 +194,31 @@ void GraphicsWindowSDL2::setSyncToVBlank(bool on) SDL_GL_MakeCurrent(mWindow, mContext); - SDL_GL_SetSwapInterval(on ? 1 : 0); + setSwapInterval(on); SDL_GL_MakeCurrent(oldWin, oldCtx); } +void GraphicsWindowSDL2::setSwapInterval(bool enable) +{ + if (enable) + { + if (SDL_GL_SetSwapInterval(-1) == -1) + { + OSG_NOTICE << "Adaptive vsync unsupported" << std::endl; + if (SDL_GL_SetSwapInterval(1) == -1) + { + OSG_NOTICE << "Vertical synchronization unsupported, disabling" << std::endl; + SDL_GL_SetSwapInterval(0); + } + } + } + else + { + SDL_GL_SetSwapInterval(0); + } +} + void GraphicsWindowSDL2::raiseWindow() { SDL_RaiseWindow(mWindow); diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index 4b48b40732..dd8076776d 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -80,6 +80,9 @@ public: SDL_Window *mWindow; }; + +private: + void setSwapInterval(bool enable); }; } From fd5e9cf27176c3b7a120b46cfd9d63424e9476ef Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 19 Mar 2019 09:11:14 +0400 Subject: [PATCH 378/410] Catch possible boost::bad_any_cast exception --- apps/niftest/niftest.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index e3f2b89f8b..f848ae330e 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -102,6 +102,17 @@ bool parseOptions (int argc, char** argv, std::vector& files) bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv). options(desc).positional(p).run(); bpo::store(valid_opts, variables); + bpo::notify(variables); + if (variables.count ("help")) + { + std::cout << desc << std::endl; + return false; + } + if (variables.count("input-file")) + { + files = variables["input-file"].as< std::vector >(); + return true; + } } catch(std::exception &e) { @@ -110,18 +121,6 @@ bool parseOptions (int argc, char** argv, std::vector& files) return false; } - bpo::notify(variables); - if (variables.count ("help")) - { - std::cout << desc << std::endl; - return false; - } - if (variables.count("input-file")) - { - files = variables["input-file"].as< std::vector >(); - return true; - } - std::cout << "No input files or directories specified!" << std::endl; std::cout << desc << std::endl; return false; From 7995a9267291a785f024a10f43710f5e625fb09e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 19 Mar 2019 09:12:31 +0400 Subject: [PATCH 379/410] Initialize missing variables --- apps/openmw/engine.cpp | 1 + components/nifosg/controller.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fb7be22b24..181ebd822f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -226,6 +226,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mActivationDistanceOverride(-1) , mGrab(true) , mExportFonts(false) + , mRandomSeed(0) , mScriptContext (0) , mFSStrict (false) , mScriptBlacklistUse (true) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 934b3b914e..4029e9b158 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -311,10 +311,11 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) RollController::RollController(const Nif::NiFloatData *data) : mData(data->mKeyList, 1.f) + , mStartingTime(0) { } -RollController::RollController() +RollController::RollController() : mStartingTime(0) { } From b2fca46206765553d719702fdddafde0a9333e48 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 19 Mar 2019 09:14:07 +0400 Subject: [PATCH 380/410] Fix a couple of minor issues in shadows --- components/sceneutil/mwshadowtechnique.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index b9d8e4bd33..92bf44ec15 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -777,6 +777,7 @@ MWShadowTechnique::MWShadowTechnique(const MWShadowTechnique& vdsm, const osg::C ShadowTechnique(vdsm,copyop) { _shadowRecievingPlaceholderStateSet = new osg::StateSet; + _enableShadows = vdsm._enableShadows; } MWShadowTechnique::~MWShadowTechnique() @@ -2011,18 +2012,20 @@ struct ConvexHull Vertices unwantedEdgeEnds = findInternalEdges(vertex, connectedVertices); for (auto edgeEnd : unwantedEdgeEnds) { - for (auto itr = _edges.begin(); itr != _edges.end(); ++itr) + for (auto itr = _edges.begin(); itr != _edges.end();) { if (*itr == Edge(vertex, edgeEnd)) { - _edges.erase(itr); + itr = _edges.erase(itr); break; } else if (*itr == Edge(edgeEnd, vertex)) { - _edges.erase(itr); + itr = _edges.erase(itr); break; } + else + ++itr; } } } From 7501f18d212f7cbd9dc1e7bd4b348290b0f2a651 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 19 Mar 2019 09:16:03 +0400 Subject: [PATCH 381/410] Avoid the 'structurally dead code' warning --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6f615564cc..b7014c99dd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -196,8 +196,6 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { - // Temporary shut-down of this function until deemed necessary. - return; if (SDL_IsTextInputActive()) return; @@ -402,7 +400,8 @@ namespace MWInput case A_MoveRight: case A_MoveForward: case A_MoveBackward: - handleGuiArrowKey(action); + // Temporary shut-down of this function until deemed necessary. + //handleGuiArrowKey(action); break; case A_Journal: toggleJournal (); From ccb325c663bea1e5a8f687cade18168a7d17fae1 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 00:19:26 +0300 Subject: [PATCH 382/410] Add override to fix warnings --- apps/opencs/view/render/terrainstorage.hpp | 6 +++--- apps/openmw/mwrender/terrainstorage.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.hpp b/apps/opencs/view/render/terrainstorage.hpp index 949311248a..6c3151e8d3 100644 --- a/apps/opencs/view/render/terrainstorage.hpp +++ b/apps/opencs/view/render/terrainstorage.hpp @@ -18,10 +18,10 @@ namespace CSVRender private: const CSMWorld::Data& mData; - virtual osg::ref_ptr getLand (int cellX, int cellY); - virtual const ESM::LandTexture* getLandTexture(int index, short plugin); + virtual osg::ref_ptr getLand (int cellX, int cellY) override; + virtual const ESM::LandTexture* getLandTexture(int index, short plugin) override; - virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); + virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) override; }; } diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index cae56d3aa4..14bed7b7ba 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -20,13 +20,13 @@ namespace MWRender TerrainStorage(Resource::ResourceSystem* resourceSystem, const std::string& normalMapPattern = "", const std::string& normalHeightMapPatteern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false); ~TerrainStorage(); - virtual osg::ref_ptr getLand (int cellX, int cellY); - virtual const ESM::LandTexture* getLandTexture(int index, short plugin); + virtual osg::ref_ptr getLand (int cellX, int cellY) override; + virtual const ESM::LandTexture* getLandTexture(int index, short plugin) override; virtual bool hasData(int cellX, int cellY) override; /// Get bounds of the whole terrain in cell units - virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); + virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) override; LandManager* getLandManager() const; From e171d34192b9ffca36a6d7842363fa2c4f6f14c3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Mar 2019 11:52:47 +0400 Subject: [PATCH 383/410] Init NPC type properly in the NpcAnimation --- apps/openmw/mwrender/npcanimation.cpp | 30 ++++++++++++++++----------- apps/openmw/mwrender/npcanimation.hpp | 2 ++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f1ebc80dfd..877c0d99b1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -238,6 +238,18 @@ void HeadAnimationTime::setBlinkStop(float value) // ---------------------------------------------------- +NpcAnimation::NpcType NpcAnimation::getNpcType() +{ + const MWWorld::Class &cls = mPtr.getClass(); + NpcAnimation::NpcType curType = Type_Normal; + if (cls.getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0) + curType = Type_Vampire; + if (cls.getNpcStats(mPtr).isWerewolf()) + curType = Type_Werewolf; + + return curType; +} + static NpcAnimation::PartBoneMap createPartListMap() { NpcAnimation::PartBoneMap result; @@ -283,7 +295,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), - mNpcType(Type_Normal), + mNpcType(getNpcType()), mFirstPersonFieldOfView(firstPersonFieldOfView), mSoundsDisabled(disableSounds), mAccurateAiming(false), @@ -431,8 +443,9 @@ void NpcAnimation::updateNpcBase() const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); - bool isWerewolf = (mNpcType == Type_Werewolf); - bool isVampire = (mNpcType == Type_Vampire); + NpcType curType = getNpcType(); + bool isWerewolf = (curType == Type_Werewolf); + bool isVampire = (curType == Type_Vampire); bool isFemale = !mNpc->isMale(); if (isWerewolf) @@ -517,14 +530,7 @@ void NpcAnimation::updateParts() if (!mObjectRoot.get()) return; - const MWWorld::Class &cls = mPtr.getClass(); - - NpcType curType = Type_Normal; - if (cls.getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0) - curType = Type_Vampire; - if (cls.getNpcStats(mPtr).isWerewolf()) - curType = Type_Werewolf; - + NpcType curType = getNpcType(); if (curType != mNpcType) { mNpcType = curType; @@ -632,7 +638,7 @@ void NpcAnimation::updateParts() showWeapons(mShowWeapons); showCarriedLeft(mShowCarriedLeft); - bool isWerewolf = (mNpcType == Type_Werewolf); + bool isWerewolf = (getNpcType() == Type_Werewolf); std::string race = (isWerewolf ? "werewolf" : Misc::StringUtils::lowerCase(mNpc->mRace)); const std::vector &parts = getBodyParts(race, !mNpc->isMale(), mViewMode == VM_FirstPerson, isWerewolf); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1ec0dfa591..bed07dcdc2 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -74,6 +74,8 @@ private: void updateNpcBase(); + NpcType getNpcType(); + PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=nullptr); From be12d241da2aeeba92298e05e321cae1b78fb3d9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Mar 2019 12:19:35 +0400 Subject: [PATCH 384/410] Reset current attack during force update (bug #4922) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e56632db7f..86eb3712eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Bug #4896: Title screen music doesn't loop Bug #4911: Editor: QOpenGLContext::swapBuffers() warning with Qt5 Bug #4916: Specular power (shininess) material parameter is ignored when shaders are used. + Bug #4922: Werewolves can not attack if the transformation happens during attack Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d1f8562f4f..ffbf5dd097 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2554,6 +2554,13 @@ void CharacterController::forceStateUpdate() return; clearAnimQueue(); + // Make sure we canceled the current attack or spellcasting, + // because we disabled attack animations anyway. + mCastingManualSpell = false; + mAttackingOrSpell = false; + if (mUpperBodyState != UpperCharState_Nothing) + mUpperBodyState = UpperCharState_WeapEquiped; + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); if(mDeathState != CharState_None) From 695cd5bb49d12b552fa9c125a6576cd5a602f410 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 20 Mar 2019 00:50:05 +0300 Subject: [PATCH 385/410] Minor NpcAnimation cleanup --- apps/openmw/mwrender/npcanimation.cpp | 169 ++++++++++++-------------- 1 file changed, 79 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 877c0d99b1..6baf99e560 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -54,10 +54,8 @@ std::string getVampireHead(const std::string& race, bool female) if (sVampireMapping.find(thisCombination) == sVampireMapping.end()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const MWWorld::Store &partStore = store.get(); - for(MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) + for (const ESM::BodyPart& bodypart : store.get()) { - const ESM::BodyPart& bodypart = *it; if (!bodypart.mData.mVampire) continue; if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) @@ -68,12 +66,11 @@ std::string getVampireHead(const std::string& race, bool female) continue; if (!Misc::StringUtils::ciEqual(bodypart.mRace, race)) continue; - sVampireMapping[thisCombination] = &*it; + sVampireMapping[thisCombination] = &bodypart; } } - if (sVampireMapping.find(thisCombination) == sVampireMapping.end()) - sVampireMapping[thisCombination] = nullptr; + sVampireMapping.emplace(thisCombination, nullptr); const ESM::BodyPart* bodyPart = sVampireMapping[thisCombination]; if (!bodyPart) @@ -448,37 +445,34 @@ void NpcAnimation::updateNpcBase() bool isVampire = (curType == Type_Vampire); bool isFemale = !mNpc->isMale(); - if (isWerewolf) - { - mHeadModel = "meshes\\" + store.get().find("WerewolfHead")->mModel; - mHairModel = "meshes\\" + store.get().find("WerewolfHair")->mModel; - } - else - { - mHeadModel = ""; - const std::string& vampireHead = getVampireHead(mNpc->mRace, isFemale); - if (isVampire && !vampireHead.empty()) - mHeadModel = vampireHead; - else if (!mNpc->mHead.empty()) - { - const ESM::BodyPart* bp = store.get().search(mNpc->mHead); - if (bp) - mHeadModel = "meshes\\" + bp->mModel; - else - Log(Debug::Warning) << "Warning: Failed to load body part '" << mNpc->mHead << "'"; - } + mHeadModel.clear(); + mHairModel.clear(); - mHairModel = ""; - if (!mNpc->mHair.empty()) - { - const ESM::BodyPart* bp = store.get().search(mNpc->mHair); - if (bp) - mHairModel = "meshes\\" + bp->mModel; - else - Log(Debug::Warning) << "Warning: Failed to load body part '" << mNpc->mHair << "'"; - } + std::string headName = isWerewolf ? "WerewolfHead" : mNpc->mHead; + std::string hairName = isWerewolf ? "WerewolfHair" : mNpc->mHair; + + if (!headName.empty()) + { + const ESM::BodyPart* bp = store.get().search(headName); + if (bp) + mHeadModel = "meshes\\" + bp->mModel; + else + Log(Debug::Warning) << "Warning: Failed to load body part '" << headName << "'"; } + if (!hairName.empty()) + { + const ESM::BodyPart* bp = store.get().search(hairName); + if (bp) + mHairModel = "meshes\\" + bp->mModel; + else + Log(Debug::Warning) << "Warning: Failed to load body part '" << hairName << "'"; + } + + const std::string& vampireHead = getVampireHead(mNpc->mRace, isFemale); + if (!isWerewolf && isVampire && !vampireHead.empty()) + mHeadModel = vampireHead; + bool is1stPerson = mViewMode == VM_FirstPerson; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; @@ -486,7 +480,7 @@ void NpcAnimation::updateNpcBase() defaultSkeleton = Misc::ResourceHelpers::correctActorModelPath(defaultSkeleton, mResourceSystem->getVFS()); std::string smodel = defaultSkeleton; - if (!is1stPerson && !isWerewolf & !mNpc->mModel.empty()) + if (!is1stPerson && !isWerewolf && !mNpc->mModel.empty()) smodel = Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()); setObjectRoot(smodel, true, true, false); @@ -736,10 +730,7 @@ void NpcAnimation::removePartGroup(int group) bool NpcAnimation::isFirstPersonPart(const ESM::BodyPart* bodypart) { - return (bodypart->mId.size() >= 3) - && bodypart->mId[bodypart->mId.size()-3] == '1' - && bodypart->mId[bodypart->mId.size()-2] == 's' - && bodypart->mId[bodypart->mId.size()-1] == 't'; + return bodypart->mId.size() >= 3 && bodypart->mId.substr(bodypart->mId.size()-3, 3) == "1st"; } bool NpcAnimation::isFemalePart(const ESM::BodyPart* bodypart) @@ -799,16 +790,16 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g osg::Object* obj = node->getUserDataContainer()->getUserObject(i); if (NifOsg::TextKeyMapHolder* keys = dynamic_cast(obj)) { - for (NifOsg::TextKeyMap::const_iterator it = keys->mTextKeys.begin(); it != keys->mTextKeys.end(); ++it) + for (const std::pair &key : keys->mTextKeys) { - if (Misc::StringUtils::ciEqual(it->second, "talk: start")) - mHeadAnimationTime->setTalkStart(it->first); - if (Misc::StringUtils::ciEqual(it->second, "talk: stop")) - mHeadAnimationTime->setTalkStop(it->first); - if (Misc::StringUtils::ciEqual(it->second, "blink: start")) - mHeadAnimationTime->setBlinkStart(it->first); - if (Misc::StringUtils::ciEqual(it->second, "blink: stop")) - mHeadAnimationTime->setBlinkStop(it->first); + if (Misc::StringUtils::ciEqual(key.second, "talk: start")) + mHeadAnimationTime->setTalkStart(key.first); + if (Misc::StringUtils::ciEqual(key.second, "talk: stop")) + mHeadAnimationTime->setTalkStop(key.first); + if (Misc::StringUtils::ciEqual(key.second, "blink: start")) + mHeadAnimationTime->setBlinkStart(key.first); + if (Misc::StringUtils::ciEqual(key.second, "blink: stop")) + mHeadAnimationTime->setBlinkStop(key.first); } break; @@ -834,16 +825,15 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector &partStore = store.get(); const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; - std::vector::const_iterator part(parts.begin()); - for(;part != parts.end();++part) + for(const ESM::PartReference& part : parts) { - const ESM::BodyPart *bodypart = 0; - if(!mNpc->isMale() && !part->mFemale.empty()) + const ESM::BodyPart *bodypart = nullptr; + if(!mNpc->isMale() && !part.mFemale.empty()) { - bodypart = partStore.search(part->mFemale+ext); + bodypart = partStore.search(part.mFemale+ext); if(!bodypart && mViewMode == VM_FirstPerson) { - bodypart = partStore.search(part->mFemale); + bodypart = partStore.search(part.mFemale); if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand || bodypart->mData.mPart == ESM::BodyPart::MP_Wrist || bodypart->mData.mPart == ESM::BodyPart::MP_Forearm || @@ -851,14 +841,14 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormFemale << "'"; + Log(Debug::Warning) << "Warning: Failed to find body part '" << part.mFemale << "'"; } - if(!bodypart && !part->mMale.empty()) + if(!bodypart && !part.mMale.empty()) { - bodypart = partStore.search(part->mMale+ext); + bodypart = partStore.search(part.mMale+ext); if(!bodypart && mViewMode == VM_FirstPerson) { - bodypart = partStore.search(part->mMale); + bodypart = partStore.search(part.mMale); if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand || bodypart->mData.mPart == ESM::BodyPart::MP_Wrist || bodypart->mData.mPart == ESM::BodyPart::MP_Forearm || @@ -866,13 +856,13 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormMale << "'"; + Log(Debug::Warning) << "Warning: Failed to find body part '" << part.mMale << "'"; } if(bodypart) - addOrReplaceIndividualPart((ESM::PartReferenceType)part->mPart, group, priority, "meshes\\"+bodypart->mModel, enchantedGlow, glowColor); + addOrReplaceIndividualPart((ESM::PartReferenceType)part.mPart, group, priority, "meshes\\"+bodypart->mModel, enchantedGlow, glowColor); else - reserveIndividualPart((ESM::PartReferenceType)part->mPart, group, priority); + reserveIndividualPart((ESM::PartReferenceType)part.mPart, group, priority); } } @@ -891,7 +881,7 @@ void NpcAnimation::addControllers() osg::MatrixTransform* node = found->second.get(); mFirstPersonNeckController = new NeckController(mObjectRoot.get()); node->addUpdateCallback(mFirstPersonNeckController); - mActiveControllers.insert(std::make_pair(node, mFirstPersonNeckController)); + mActiveControllers.emplace(node, mFirstPersonNeckController); } } else if (mViewMode == VM_Normal) @@ -1093,40 +1083,39 @@ const std::vector& NpcAnimation::getBodyParts(const std:: std::vector& parts = sRaceMapping[std::make_pair(race, flags)]; typedef std::multimap BodyPartMapType; - static BodyPartMapType sBodyPartMap; - if(sBodyPartMap.empty()) + static const BodyPartMapType sBodyPartMap = { - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg)); - sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail)); - } + {ESM::BodyPart::MP_Neck, ESM::PRT_Neck}, + {ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass}, + {ESM::BodyPart::MP_Groin, ESM::PRT_Groin}, + {ESM::BodyPart::MP_Hand, ESM::PRT_RHand}, + {ESM::BodyPart::MP_Hand, ESM::PRT_LHand}, + {ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist}, + {ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist}, + {ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm}, + {ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm}, + {ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm}, + {ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm}, + {ESM::BodyPart::MP_Foot, ESM::PRT_RFoot}, + {ESM::BodyPart::MP_Foot, ESM::PRT_LFoot}, + {ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle}, + {ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle}, + {ESM::BodyPart::MP_Knee, ESM::PRT_RKnee}, + {ESM::BodyPart::MP_Knee, ESM::PRT_LKnee}, + {ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg}, + {ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg}, + {ESM::BodyPart::MP_Tail, ESM::PRT_Tail} + }; parts.resize(ESM::PRT_Count, nullptr); + if (werewolf) + return parts; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const MWWorld::Store &partStore = store.get(); - for(MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) + + for(const ESM::BodyPart& bodypart : store.get()) { - if(werewolf) - break; - const ESM::BodyPart& bodypart = *it; if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) continue; if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) From c2986b3bd72457c0e3f035c973fa2db06beb19b7 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 386/410] Do not block the loading thread while compiling composite maps in the draw thread --- components/terrain/compositemaprenderer.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 39d00db361..3fc56a8821 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -59,26 +59,29 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const while (!mImmediateCompileSet.empty()) { - CompositeMap* node = *mImmediateCompileSet.begin(); + osg::ref_ptr node = *mImmediateCompileSet.begin(); mCompiled.insert(node); + mImmediateCompileSet.erase(node); + mMutex.unlock(); compile(*node, renderInfo, nullptr); - - mImmediateCompileSet.erase(mImmediateCompileSet.begin()); + mMutex.lock(); } double timeLeft = availableTime; while (!mCompileSet.empty() && timeLeft > 0) { - CompositeMap* node = *mCompileSet.begin(); + osg::ref_ptr node = *mCompileSet.begin(); + mMutex.unlock(); compile(*node, renderInfo, &timeLeft); + mMutex.lock(); if (node->mCompiled >= node->mDrawables.size()) { mCompiled.insert(node); - mCompileSet.erase(mCompileSet.begin()); + mCompileSet.erase(node); } } mTimer.setStartTick(); From 32da9a8ab10fb04895b74a113509e22d793c9615 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Mar 2019 23:32:01 +0000 Subject: [PATCH 387/410] Use irreflexive, asymmetric comparator as required by the spec. --- apps/opencs/model/prefs/shortcuteventhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index e42cb5da1f..07c48fcaa8 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -195,7 +195,7 @@ namespace CSMPrefs // Only activate the best match; in exact conflicts, this will favor the first shortcut added. if (!potentials.empty()) { - std::sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort); + std::stable_sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort); Shortcut* shortcut = potentials.front().second; if (shortcut->getModifierStatus() && shortcut->getSecondaryMode() == Shortcut::SM_Replace) @@ -325,7 +325,7 @@ namespace CSMPrefs if (left.first == Matches_WithMod && right.first == Matches_NoMod) return true; else - return left.second->getPosition() >= right.second->getPosition(); + return left.second->getPosition() > right.second->getPosition(); } void ShortcutEventHandler::widgetDestroyed() From cad45e96ac4b9f66448b5a8ebde23433e0487957 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Mar 2019 08:42:48 +0400 Subject: [PATCH 388/410] Remove redundant mCompile set - we do not use data from it anyway --- components/terrain/compositemaprenderer.cpp | 4 ---- components/terrain/compositemaprenderer.hpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 3fc56a8821..355ef6c16f 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -47,8 +47,6 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const double availableTime = std::max((targetFrameTime - dt)*conservativeTimeRatio, mMinimumTimeAvailable); - mCompiled.clear(); - if (mWorkQueue) mUnrefQueue->flush(mWorkQueue.get()); @@ -60,7 +58,6 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const while (!mImmediateCompileSet.empty()) { osg::ref_ptr node = *mImmediateCompileSet.begin(); - mCompiled.insert(node); mImmediateCompileSet.erase(node); mMutex.unlock(); @@ -80,7 +77,6 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const if (node->mCompiled >= node->mDrawables.size()) { - mCompiled.insert(node); mCompileSet.erase(node); } } diff --git a/components/terrain/compositemaprenderer.hpp b/components/terrain/compositemaprenderer.hpp index 5c81fdca65..201130e303 100644 --- a/components/terrain/compositemaprenderer.hpp +++ b/components/terrain/compositemaprenderer.hpp @@ -76,8 +76,6 @@ namespace Terrain mutable CompileSet mCompileSet; mutable CompileSet mImmediateCompileSet; - mutable CompileSet mCompiled; - mutable OpenThreads::Mutex mMutex; osg::ref_ptr mFBO; From 0e1f5f68b6947eb11d713208ca2a6b0281ba9bcb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Mar 2019 08:52:13 +0400 Subject: [PATCH 389/410] Do not allow different threads to compile the same composite map --- components/terrain/compositemaprenderer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 355ef6c16f..ee4a66fcde 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -70,14 +70,17 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const while (!mCompileSet.empty() && timeLeft > 0) { osg::ref_ptr node = *mCompileSet.begin(); + mCompileSet.erase(node); mMutex.unlock(); compile(*node, renderInfo, &timeLeft); mMutex.lock(); - if (node->mCompiled >= node->mDrawables.size()) + if (node->mCompiled < node->mDrawables.size()) { - mCompileSet.erase(node); + // We did not compile the map fully. + // Place it back to queue to continue work in the next time. + mCompileSet.insert(node); } } mTimer.setStartTick(); From b466bfee40068dba7c26c2d466d8e3236b07ab46 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Mar 2019 10:27:50 +0400 Subject: [PATCH 390/410] Enable light sources directly to avoid virtual calls --- components/sceneutil/lightmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index f0fd0ef9f3..c657e66fd7 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -245,7 +245,8 @@ namespace SceneUtil osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); // don't use setAttributeAndModes, that does not support light indices! stateset->setAttribute(attr, osg::StateAttribute::ON); - stateset->setAssociatedModes(attr, osg::StateAttribute::ON); + for (unsigned int i=0; isetMode(GL_LIGHT0 + mStartLight + i, osg::StateAttribute::ON); // need to push some dummy attributes to ensure proper state tracking // lights need to reset to their default when the StateSet is popped From af47ec7756ff29542aa29078ae5d1fa5deeb3b93 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 21 Feb 2019 20:01:40 +0300 Subject: [PATCH 391/410] Skip extra text after variable declaration (bug #4867) --- CHANGELOG.md | 1 + components/compiler/declarationparser.cpp | 38 ++++++++++++++++------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86eb3712eb..312cb7b5df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Bug #4860: Actors outside of processing range visible for one frame after spawning + Bug #4867: Arbitrary text after local variable declarations breaks script compilation Bug #4876: AI ratings handling inconsistencies Bug #4877: Startup script executes only on a new game start Bug #4888: Global variable stray explicit reference calls break script compilation diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index e85c8c3ec2..1e3bc05857 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -22,20 +22,20 @@ bool Compiler::DeclarationParser::parseName (const std::string& name, const Toke char type = mLocals.getType (name2); if (type!=' ') - { - /// \todo add option to make re-declared local variables an error - getErrorHandler().warning ("ignoring local variable re-declaration", - loc); - - mState = State_End; - return true; - } - - mLocals.declare (mType, name2); + getErrorHandler().warning ("ignoring local variable re-declaration", loc); + else + mLocals.declare (mType, name2); mState = State_End; return true; } + else if (mState==State_End) + { + getErrorHandler().warning ("Ignoring extra text after local variable declaration", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return false; + } return Parser::parseName (name, loc, scanner); } @@ -61,17 +61,31 @@ bool Compiler::DeclarationParser::parseKeyword (int keyword, const TokenLoc& loc else if (mState==State_Name) { // allow keywords to be used as local variable names. MW script compiler, you suck! - /// \todo option to disable this atrocity. return parseName (loc.mLiteral, loc, scanner); } + else if (mState==State_End) + { + getErrorHandler().warning ("Ignoring extra text after local variable declaration", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return false; + } return Parser::parseKeyword (keyword, loc, scanner); } bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { - if (code==Scanner::S_newline && mState==State_End) + if (mState==State_End) + { + if (code!=Scanner::S_newline) + { + getErrorHandler().warning ("Ignoring extra text after local variable declaration", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + } return false; + } return Parser::parseSpecial (code, loc, scanner); } From fa7b304e78595d34365eb049007f97e01892839b Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 21 Mar 2019 23:08:35 +0300 Subject: [PATCH 392/410] Use auto for map value_type in range-based for loops To avoid implicit call of copy constructor for pair to pair conversion. --- apps/esmtool/record.cpp | 2 +- apps/opencs/model/world/data.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index cfd658fc94..c5153dadb8 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -739,7 +739,7 @@ void Record::print() std::cout << " Faction Reaction: " << mData.mData.mRankData[i].mFactReaction << std::endl; } - for (const std::pair &reaction : mData.mReactions) + for (const auto &reaction : mData.mReactions) std::cout << " Reaction: " << reaction.second << " = " << reaction.first << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index da46ea876a..8fa449b8f4 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1006,7 +1006,7 @@ void CSMWorld::Data::loadFallbackEntries() std::make_pair("PrisonMarker", "marker_prison.nif") }; - for (const std::pair &marker : staticMarkers) + for (const auto &marker : staticMarkers) { if (mReferenceables.searchId (marker.first)==-1) { @@ -1020,7 +1020,7 @@ void CSMWorld::Data::loadFallbackEntries() } } - for (const std::pair &marker : doorMarkers) + for (const auto &marker : doorMarkers) { if (mReferenceables.searchId (marker.first)==-1) { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6baf99e560..5fad40a9ab 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -790,7 +790,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g osg::Object* obj = node->getUserDataContainer()->getUserObject(i); if (NifOsg::TextKeyMapHolder* keys = dynamic_cast(obj)) { - for (const std::pair &key : keys->mTextKeys) + for (const auto &key : keys->mTextKeys) { if (Misc::StringUtils::ciEqual(key.second, "talk: start")) mHeadAnimationTime->setTalkStart(key.first); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d8576800d6..24e8cb43c8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -470,7 +470,7 @@ namespace MWWorld gmst["iWereWolfBounty"] = ESM::Variant(1000); gmst["fCombatDistanceWerewolfMod"] = ESM::Variant(0.3f); - for (const std::pair ¶ms : gmst) + for (const auto ¶ms : gmst) { if (!mStore.get().search(params.first)) { @@ -500,7 +500,7 @@ namespace MWWorld globals["crimegoldturnin"] = ESM::Variant(0); globals["pchasturnin"] = ESM::Variant(0); - for (const std::pair ¶ms : globals) + for (const auto ¶ms : globals) { if (!mStore.get().search(params.first)) { @@ -519,7 +519,7 @@ namespace MWWorld statics["templemarker"] = "marker_temple.nif"; statics["travelmarker"] = "marker_travel.nif"; - for (const std::pair ¶ms : statics) + for (const auto ¶ms : statics) { if (!mStore.get().search(params.first)) { @@ -533,7 +533,7 @@ namespace MWWorld std::map doors; doors["prisonmarker"] = "marker_prison.nif"; - for (const std::pair ¶ms : doors) + for (const auto ¶ms : doors) { if (!mStore.get().search(params.first)) { From e82d65a2c79aa61cdf242856a69f03d1f6b866ee Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:02:59 +0300 Subject: [PATCH 393/410] Use if-continue to skip build path --- apps/openmw/mwmechanics/aiwander.cpp | 31 +++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 405f36767e..6b7d6bf162 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -309,22 +309,25 @@ namespace MWMechanics mDestination = osg::Vec3f(destinationX, destinationY, destinationZ); // Check if land creature will walk onto water or if water creature will swim onto land - if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || - (isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) - { - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); - mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); - mPathFinder.addPointToPath(mDestination); + if (!isWaterCreature && destinationIsAtWater(actor, mDestination)) + continue; - if (mPathFinder.isPathConstructed()) - { - storage.setState(AiWanderStorage::Wander_Walking, true); - mHasDestination = true; - mUsePathgrid = false; - } - return; + if (isWaterCreature && destinationThroughGround(currentPosition, mDestination)) + continue; + + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); + mPathFinder.addPointToPath(mDestination); + + if (mPathFinder.isPathConstructed()) + { + storage.setState(AiWanderStorage::Wander_Walking, true); + mHasDestination = true; + mUsePathgrid = false; } + + break; } while (--attempts); } From e033b0c565849b80c0f92def1e11fc6fdea292ec Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:04:07 +0300 Subject: [PATCH 394/410] Avoid build path through the ground for flying wandering creatures --- apps/openmw/mwmechanics/aiwander.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6b7d6bf162..8c01c7b968 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -298,7 +298,8 @@ namespace MWMechanics const auto currentPosition = actor.getRefData().getPosition().asVec3(); std::size_t attempts = 10; // If a unit can't wander out of water, don't want to hang here - bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); + const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); + const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor); do { // Determine a random location within radius of original position const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; @@ -312,7 +313,7 @@ namespace MWMechanics if (!isWaterCreature && destinationIsAtWater(actor, mDestination)) continue; - if (isWaterCreature && destinationThroughGround(currentPosition, mDestination)) + if ((isWaterCreature || isFlyingCreature) && destinationThroughGround(currentPosition, mDestination)) continue; const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); From ebdff5d96e32fa6d8672d544e0741050892c45b0 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:05:13 +0300 Subject: [PATCH 395/410] Check for height map when cast ray for AiWander path --- apps/openmw/mwmechanics/aiwander.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8c01c7b968..8ed9cf8d20 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -13,6 +13,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwphysics/collisiontype.hpp" + #include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" @@ -346,8 +348,10 @@ namespace MWMechanics * Returns true if the start to end point travels through a collision point (land). */ bool AiWander::destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination) { + const int mask = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Door; return MWBase::Environment::get().getWorld()->castRay(startPoint.x(), startPoint.y(), startPoint.z(), - destination.x(), destination.y(), destination.z()); + destination.x(), destination.y(), destination.z(), + mask); } void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { From ff67a9e2333fbbee8144dcba1c70d2f3d3743098 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:08:06 +0300 Subject: [PATCH 396/410] Build straight path for wandering flying and water creatures --- apps/openmw/mwmechanics/aiwander.cpp | 15 +++++++++++---- apps/openmw/mwmechanics/pathfinding.cpp | 7 +++++++ apps/openmw/mwmechanics/pathfinding.hpp | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8ed9cf8d20..e334f72daf 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -318,10 +318,17 @@ namespace MWMechanics if ((isWaterCreature || isFlyingCreature) && destinationThroughGround(currentPosition, mDestination)) continue; - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); - mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); - mPathFinder.addPointToPath(mDestination); + if (isWaterCreature || isFlyingCreature) + { + mPathFinder.buildStraightPath(mDestination); + } + else + { + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); + mPathFinder.addPointToPath(mDestination); + } if (mPathFinder.isPathConstructed()) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index e0285be928..13c2180081 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -269,6 +269,13 @@ namespace MWMechanics mPath.pop_front(); } + void PathFinder::buildStraightPath(const osg::Vec3f& endPoint) + { + mPath.clear(); + mPath.push_back(endPoint); + mConstructed = true; + } + void PathFinder::buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph) { diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 8a5b8338ab..b59af44fd8 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -72,6 +72,8 @@ namespace MWMechanics mCell = nullptr; } + void buildStraightPath(const osg::Vec3f& endPoint); + void buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); From a65f60e1f1bc1f8bf35cddbdd2f809fb37a8cab9 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:10:46 +0300 Subject: [PATCH 397/410] Build path only by navmesh for wandering near spawn --- apps/openmw/mwmechanics/aiwander.cpp | 5 ++--- apps/openmw/mwmechanics/pathfinding.cpp | 10 ++++++++++ apps/openmw/mwmechanics/pathfinding.hpp | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e334f72daf..3537866770 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -325,9 +325,8 @@ namespace MWMechanics else { const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); - mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); - mPathFinder.addPointToPath(mDestination); + mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, halfExtents, + getNavigatorFlags(actor)); } if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 13c2180081..db6b8d686e 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -287,6 +287,16 @@ namespace MWMechanics mConstructed = true; } + void PathFinder::buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, + const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags) + { + mPath.clear(); + + buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); + + mConstructed = true; + } + void PathFinder::buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index b59af44fd8..1dc85c5e52 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -77,6 +77,9 @@ namespace MWMechanics void buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); + void buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, + const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags); + void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags); From 287433efa8ab146db98f31dc6dcbc58edd681813 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:58:22 +0300 Subject: [PATCH 398/410] Stop walking for water and flying creatures after single stuck --- apps/openmw/mwmechanics/aiwander.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3537866770..db2057df30 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -47,6 +47,16 @@ namespace MWMechanics std::string("idle9"), }; + namespace + { + inline int getCountBeforeReset(const MWWorld::ConstPtr& actor) + { + if (actor.getClass().isPureWaterCreature(actor) || actor.getClass().isPureFlyingCreature(actor)) + return 1; + return COUNT_BEFORE_RESET; + } + } + AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), @@ -493,7 +503,7 @@ namespace MWMechanics } // if stuck for sufficiently long, act like current location was the destination - if (storage.mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset + if (storage.mStuckCount >= getCountBeforeReset(actor)) // something has gone wrong, reset { mObstacleCheck.clear(); stopWalking(actor, storage); From 1e8bf3846e7b61a1b5265894e1cb7e7250de0586 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:59:09 +0300 Subject: [PATCH 399/410] Remove unused argument --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- apps/openmw/mwmechanics/obstacle.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3d8fe7919c..c8b548bad9 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -121,13 +121,13 @@ namespace MWMechanics * u = how long to move sideways * */ - void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance) + void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration) { const MWWorld::Class& cls = actor.getClass(); ESM::Position pos = actor.getRefData().getPosition(); if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor) * scaleMinimumDistance; + mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); float distSameSpot = mDistSameSpot * duration; diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index d7e582f8c5..46c1bc83de 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -30,7 +30,7 @@ namespace MWMechanics bool isEvading() const; // Updates internal state, call each frame for moving actor - void update(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance = 1.0f); + void update(const MWWorld::Ptr& actor, float duration); // change direction to try to fix "stuck" actor void takeEvasiveAction(MWMechanics::Movement& actorMovement) const; From 5434e924375ae878124aaab1b3353a1781b4ed8a Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 02:00:08 +0300 Subject: [PATCH 400/410] Take in account actor half extents for obstacle check --- apps/openmw/mwmechanics/obstacle.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index c8b548bad9..63167e302f 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -2,6 +2,8 @@ #include +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -123,15 +125,17 @@ namespace MWMechanics */ void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration) { - const MWWorld::Class& cls = actor.getClass(); - ESM::Position pos = actor.getRefData().getPosition(); + const ESM::Position pos = actor.getRefData().getPosition(); - if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); + if (mDistSameSpot == -1) + { + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor); + mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) + 1.2 * std::max(halfExtents.x(), halfExtents.y()); + } - float distSameSpot = mDistSameSpot * duration; - - bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot; + const float distSameSpot = mDistSameSpot * duration; + const float squaredMovedDistance = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2(); + const bool samePosition = squaredMovedDistance < distSameSpot * distSameSpot; // update position mPrevX = pos.pos[0]; From c2176945bd8cdfe8b5c34563e05bac68584585c4 Mon Sep 17 00:00:00 2001 From: bzzt Date: Thu, 28 Feb 2019 09:10:22 +0400 Subject: [PATCH 401/410] Do not use the delayed map cells update --- apps/openmw/mwgui/mapwindow.cpp | 13 ++----------- apps/openmw/mwgui/mapwindow.hpp | 4 ---- apps/openmw/mwgui/windowmanagerimp.cpp | 3 --- apps/openmw/mwrender/globalmap.cpp | 2 +- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index f3bdd4c7d0..a6e9c98188 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -837,22 +837,13 @@ namespace MWGui void MapWindow::cellExplored(int x, int y) { - mQueuedToExplore.push_back(std::make_pair(x,y)); + mGlobalMapRender->cleanupCameras(); + mGlobalMapRender->exploreCell(x, y, mLocalMapRender->getMapTexture(x, y)); } void MapWindow::onFrame(float dt) { LocalMapBase::onFrame(dt); - - mGlobalMapRender->cleanupCameras(); - - for (CellId& cellId : mQueuedToExplore) - { - mGlobalMapRender->exploreCell(cellId.first, cellId.second, mLocalMapRender->getMapTexture(cellId.first, cellId.second)); - } - - mQueuedToExplore.clear(); - NoDrop::onFrame(dt); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 3d9ca23d83..033672c7f2 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -261,10 +261,6 @@ namespace MWGui typedef std::pair CellId; std::set mMarkers; - // Cells that should be explored in the next frame (i.e. their map revealed on the global map) - // We can't do this immediately, because the map update is not immediate either (see mNeedMapUpdate in scene.cpp) - std::vector mQueuedToExplore; - MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index badfa2f3c6..abd483a729 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1027,9 +1027,6 @@ namespace MWGui updateMap(); - if (!mMap->isVisible()) - mMap->onFrame(frameDuration); - mHud->onFrame(frameDuration); mDebugWindow->onFrame(frameDuration); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 5880396398..57137d4157 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -293,7 +293,7 @@ namespace MWRender camera->setViewMatrix(osg::Matrix::identity()); camera->setProjectionMatrix(osg::Matrix::identity()); camera->setProjectionResizePolicy(osg::Camera::FIXED); - camera->setRenderOrder(osg::Camera::PRE_RENDER); + camera->setRenderOrder(osg::Camera::PRE_RENDER, 1); // Make sure the global map is rendered after the local map y = mHeight - y - height; // convert top-left origin to bottom-left camera->setViewport(x, y, width, height); From 786f3e5fc31bac7db5a179fab2fb9b07f0c6c36b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 22 Mar 2019 21:59:27 +0300 Subject: [PATCH 402/410] Remove unused and unfinished blendmap packing feature --- components/esmterrain/storage.cpp | 26 +++++++++----------------- components/esmterrain/storage.hpp | 8 ++------ components/terrain/chunkmanager.cpp | 2 +- components/terrain/storage.hpp | 8 ++------ 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 3d6e521d10..1e23569b52 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -375,8 +375,7 @@ namespace ESMTerrain return texture; } - void Storage::getBlendmaps(float chunkSize, const osg::Vec2f &chunkCenter, - bool pack, ImageVector &blendmaps, std::vector &layerList) + void Storage::getBlendmaps(float chunkSize, const osg::Vec2f &chunkCenter, ImageVector &blendmaps, std::vector &layerList) { osg::Vec2f origin = chunkCenter - osg::Vec2f(chunkSize/2.f, chunkSize/2.f); int cellX = static_cast(std::floor(origin.x())); @@ -416,11 +415,8 @@ namespace ESMTerrain layerList.push_back(getLayerInfo(getTextureName(*it))); } - int numTextures = textureIndices.size(); - // numTextures-1 since the base layer doesn't need blending - int numBlendmaps = pack ? static_cast(std::ceil((numTextures - 1) / 4.f)) : (numTextures - 1); - - int channels = pack ? 4 : 1; + // size-1 since the base layer doesn't need blending + int numBlendmaps = textureIndices.size() - 1; // Second iteration - create and fill in the blend maps const int blendmapSize = (realTextureSize-1) * chunkSize + 1; @@ -430,10 +426,8 @@ namespace ESMTerrain for (int i=0; i image (new osg::Image); - image->allocateImage(blendmapImageSize, blendmapImageSize, 1, format, GL_UNSIGNED_BYTE); + image->allocateImage(blendmapImageSize, blendmapImageSize, 1, GL_ALPHA, GL_UNSIGNED_BYTE); unsigned char* pData = image->data(); for (int y=0; ysecond; - int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); - int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; - int alpha = (blendIndex == i) ? 255 : 0; + int alpha = (layerIndex == i+1) ? 255 : 0; int realY = (blendmapSize - y - 1)*imageScaleFactor; int realX = x*imageScaleFactor; - pData[((realY+0)*blendmapImageSize + realX + 0)*channels + channel] = alpha; - pData[((realY+1)*blendmapImageSize + realX + 0)*channels + channel] = alpha; - pData[((realY+0)*blendmapImageSize + realX + 1)*channels + channel] = alpha; - pData[((realY+1)*blendmapImageSize + realX + 1)*channels + channel] = alpha; + pData[(realY+0)*blendmapImageSize + realX + 0] = alpha; + pData[(realY+1)*blendmapImageSize + realX + 0] = alpha; + pData[(realY+0)*blendmapImageSize + realX + 1] = alpha; + pData[(realY+1)*blendmapImageSize + realX + 1] = alpha; } } blendmaps.push_back(image); diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 27d6232eb7..613d2e2185 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -92,14 +92,10 @@ namespace ESMTerrain /// @note May be called from background threads. /// @param chunkSize size of the terrain chunk in cell units /// @param chunkCenter center of the chunk in cell units - /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - - /// otherwise, each texture contains blend values for one layer only. Shader-based rendering - /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, bool pack, - ImageVector& blendmaps, - std::vector& layerList); + virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, ImageVector& blendmaps, + std::vector& layerList); virtual float getHeightAt (const osg::Vec3f& worldPos); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 8cfccabceb..a22d43d744 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -119,7 +119,7 @@ std::vector > ChunkManager::createPasses(float chunk { std::vector layerList; std::vector > blendmaps; - mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList); + mStorage->getBlendmaps(chunkSize, chunkCenter, blendmaps, layerList); bool useShaders = mSceneManager->getForceShaders(); if (!mSceneManager->getClampLighting()) diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index 8a59c104c6..cdde06e47d 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -69,14 +69,10 @@ namespace Terrain /// @note May be called from background threads. Make sure to only call thread-safe functions from here! /// @param chunkSize size of the terrain chunk in cell units /// @param chunkCenter center of the chunk in cell units - /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - - /// otherwise, each texture contains blend values for one layer only. Shader-based rendering - /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, bool pack, - ImageVector& blendmaps, - std::vector& layerList) = 0; + virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, ImageVector& blendmaps, + std::vector& layerList) = 0; virtual float getHeightAt (const osg::Vec3f& worldPos) = 0; From 231e629e66f70dfcf59c9bdd8bb09fcab1ee82e4 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 403/410] Store map widgets and textures in one vector instead of 4 different ones --- apps/openmw/mwgui/mapwindow.cpp | 37 +++++++++++++++++---------------- apps/openmw/mwgui/mapwindow.hpp | 15 ++++++++----- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index a6e9c98188..5f4c9971c9 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -213,8 +213,7 @@ namespace MWGui map->setNeedMouseFocus(false); fog->setNeedMouseFocus(false); - mMapWidgets.push_back(map); - mFogWidgets.push_back(fog); + mMaps.emplace_back(map, fog); } } } @@ -234,36 +233,37 @@ namespace MWGui void LocalMapBase::applyFogOfWar() { - TextureVector fogTextures; for (int mx=0; mxsetImageTexture(""); + entry.mFogTexture.reset(); continue; } osg::ref_ptr tex = mLocalMapRender->getFogOfWarTexture(x, y); if (tex) { - std::shared_ptr myguitex (new osgMyGUI::OSGTexture(tex)); - fog->setRenderItemTexture(myguitex.get()); + entry.mFogTexture.reset(new osgMyGUI::OSGTexture(tex)); + fog->setRenderItemTexture(entry.mFogTexture.get()); fog->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); - fogTextures.push_back(myguitex); } else + { fog->setImageTexture("black"); + entry.mFogTexture.reset(); + } } } - // Move the textures we just set into mFogTextures, and move the previous textures into fogTextures, for deletion when this function ends. - // Note, above we need to ensure that all widgets are getting a new texture set, lest we delete textures that are still in use. - mFogTextures.swap(fogTextures); redraw(); } @@ -369,7 +369,6 @@ namespace MWGui applyFogOfWar(); // Update the map textures - TextureVector textures; for (int mx=0; mx texture = mLocalMapRender->getMapTexture(mapX, mapY); if (texture) { - std::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); - textures.push_back(guiTex); - box->setRenderItemTexture(guiTex.get()); + entry.mMapTexture.reset(new osgMyGUI::OSGTexture(texture)); + box->setRenderItemTexture(entry.mMapTexture.get()); box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } else + { box->setRenderItemTexture(nullptr); + entry.mMapTexture.reset(); + } } } - mMapTextures.swap(textures); // Delay the door markers update until scripts have been given a chance to run. // If we don't do this, door markers that should be disabled will still appear on the map. @@ -1046,8 +1047,8 @@ namespace MWGui NoDrop::setAlpha(alpha); // can't allow showing map with partial transparency, as the fog of war will also go transparent // and reveal parts of the map you shouldn't be able to see - for (MyGUI::ImageBox* widget : mMapWidgets) - widget->setVisible(alpha == 1); + for (MapEntry& entry : mMaps) + entry.mMapWidget->setVisible(alpha == 1); } void MapWindow::customMarkerCreated(MyGUI::Widget *marker) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 033672c7f2..4104a7824b 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -126,12 +126,17 @@ namespace MWGui // Stores markers that were placed by a player. May be shared between multiple map views. CustomMarkerCollection& mCustomMarkers; - std::vector mMapWidgets; - std::vector mFogWidgets; + struct MapEntry + { + MapEntry(MyGUI::ImageBox* mapWidget, MyGUI::ImageBox* fogWidget) + : mMapWidget(mapWidget), mFogWidget(fogWidget) {} - typedef std::vector > TextureVector; - TextureVector mMapTextures; - TextureVector mFogTextures; + MyGUI::ImageBox* mMapWidget; + MyGUI::ImageBox* mFogWidget; + std::shared_ptr mMapTexture; + std::shared_ptr mFogTexture; + }; + std::vector mMaps; // Keep track of created marker widgets, just to easily remove them later. std::vector mDoorMarkerWidgets; From bbb1fdd92f378e0d995e8a4c9403d6bd4e8dea6e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 23 Mar 2019 14:25:44 +0400 Subject: [PATCH 404/410] Reduce default composite map distance to decrease GPU loading --- docs/source/reference/modding/settings/terrain.rst | 2 +- files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index e15a0035dd..c8ae2a2276 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -68,7 +68,7 @@ composite map level :Type: integer :Range: >= -3 -:Default: 0 +:Default: -2 Controls at which minimum size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures. With value -3 composite maps are used everywhere. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e95646602d..353a3ac3d9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -98,7 +98,7 @@ vertex lod mod = 0 # Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3. # Higher value is more detailed textures. -composite map level = 0 +composite map level = -2 # Controls the resolution of composite maps. composite map resolution = 512 From 1143985bc7559e5f19d996eeac7a04c4a3edd30d Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 405/410] Do not update map texture if it did not change --- apps/openmw/mwrender/localmap.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1650dc92c6..6c8dfec602 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -613,7 +613,8 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient if (!segment.mFogOfWarImage || !segment.mMapTexture) continue; - unsigned char* data = segment.mFogOfWarImage->data(); + uint32_t* data = (uint32_t*)segment.mFogOfWarImage->data(); + bool changed = false; for (int texV = 0; texV> 24); alpha = std::min( alpha, (uint8_t) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); - *(uint32_t*)data = (uint32_t) (alpha << 24); + uint32_t val = (uint32_t) (alpha << 24); + if ( *data != val) + { + *data = val; + changed = true; + } - data += 4; + ++data; } } - segment.mHasFogState = true; - segment.mFogOfWarImage->dirty(); + if (changed) + { + segment.mHasFogState = true; + segment.mFogOfWarImage->dirty(); + } } } } From 6dbd875f75ce3597d1e8a7484b516c57f9f07d2f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 23 Mar 2019 22:56:30 +0300 Subject: [PATCH 406/410] Disallow binding some reserved keys (bug #3282) --- CHANGELOG.md | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86eb3712eb..8a00f4d724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Bug #2969: Scripted items can stack Bug #2987: Editor: some chance and AI data fields can overflow + Bug #3282: Unintended behaviour when assigning F3 and Windows keys Bug #3623: Fix HiDPI on Windows Bug #3733: Normal maps are inverted on mirrored UVs Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b7014c99dd..a5cb662208 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1834,6 +1834,17 @@ namespace MWInput MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); return; } + + // Disallow binding reserved keys + if (key == SDL_SCANCODE_F3 || key == SDL_SCANCODE_F4 || key == SDL_SCANCODE_F10 || key == SDL_SCANCODE_F11) + return; + + #ifndef __APPLE__ + // Disallow binding Windows/Meta keys + if (key == SDL_SCANCODE_LGUI || key == SDL_SCANCODE_RGUI) + return; + #endif + if(!mDetectingKeyboard) return; From cbce1a1b7c10e315f51163c5b75ae2f5e5f598e3 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 19 Sep 2018 22:44:09 +0300 Subject: [PATCH 407/410] Ignore the rest of the line after else (bug #3006) --- CHANGELOG.md | 1 + components/compiler/controlparser.cpp | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a00f4d724..6f6586511b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Bug #2969: Scripted items can stack Bug #2987: Editor: some chance and AI data fields can overflow + Bug #3006: 'else if' operator breaks script compilation Bug #3282: Unintended behaviour when assigning F3 and Windows keys Bug #3623: Fix HiDPI on Windows Bug #3733: Normal maps are inverted on mirrored UVs diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index b202467db8..6f9fad35f0 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -179,6 +179,14 @@ namespace Compiler scanner.scan (mLineParser); return true; } + else if (mState==IfElseJunkState) + { + getErrorHandler().warning ("Ignoring extra text after else", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = IfElseBodyState; + return true; + } return Parser::parseName (name, loc, scanner); } @@ -207,8 +215,7 @@ namespace Compiler return true; } } - else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState || - mState==IfElseJunkState) + else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState) { if (parseIfBody (keyword, loc, scanner)) return true; @@ -218,6 +225,14 @@ namespace Compiler if ( parseWhileBody (keyword, loc, scanner)) return true; } + else if (mState==IfElseJunkState) + { + getErrorHandler().warning ("Ignoring extra text after else", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = IfElseBodyState; + return true; + } return Parser::parseKeyword (keyword, loc, scanner); } @@ -250,8 +265,9 @@ namespace Compiler default: ; } } - else if (code==Scanner::S_open && mState==IfElseJunkState) + else if (mState==IfElseJunkState) { + getErrorHandler().warning ("Ignoring extra text after else", loc); SkipParser skip (getErrorHandler(), getContext()); scanner.scan (skip); mState = IfElseBodyState; From 93f78aad60346d5a4369074e99b743be67ebcbbe Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 24 Mar 2019 22:53:22 +0300 Subject: [PATCH 408/410] Avoid menu button texture vertical cutoff --- apps/openmw/mwgui/mainmenu.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 8c06859e44..2c2bd84dfd 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -287,11 +287,10 @@ namespace MWGui MyGUI::IntSize requested = button->getRequestedSize(); + button->setImageCoord(MyGUI::IntCoord(0, 0, requested.width, requested.height)); // Trim off some of the excessive padding // TODO: perhaps do this within ImageButton? - int trim = 8; - button->setImageCoord(MyGUI::IntCoord(0, trim, requested.width, requested.height-trim)); - int height = requested.height-trim*2; + int height = requested.height-16; button->setImageTile(MyGUI::IntSize(requested.width, height)); button->setCoord((maxwidth-requested.width) / 2, curH, requested.width, height); curH += height; From 6c0837259c3779fac14ae349b6523655c3d118b7 Mon Sep 17 00:00:00 2001 From: Alex Kokkinos Date: Mon, 25 Mar 2019 21:11:00 -0500 Subject: [PATCH 409/410] Update paths.rst - Windows paths, shell friendly paths - Adds path expansion based paths for Windows for easier copying and pasting - Escapes Application Support in Mac to make the paths terminal and Finder Go menu friendly - Places paths in tables --- docs/source/reference/modding/paths.rst | 48 ++++++++++++++++++++----- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/docs/source/reference/modding/paths.rst b/docs/source/reference/modding/paths.rst index 23e33190dc..0851681892 100644 --- a/docs/source/reference/modding/paths.rst +++ b/docs/source/reference/modding/paths.rst @@ -9,20 +9,50 @@ The following describes the locations for the various OpenMW file paths for diff Configuration files and log files --------------------------------- -:Linux: ``$HOME/.config/openmw`` -:Mac: ``$HOME/Library/Preferences/openmw`` -:Windows: ``C:\Users\Username\Documents\my games\openmw`` ++--------------+------------------------------------------------------------------+ +| OS | Location | ++==============+==================================================================+ +| Linux | ``$HOME/.config/openmw`` | ++--------------+------------------------------------------------------------------+ +| Mac | ``$HOME/Library/Preferences/openmw`` | ++--------------+---------------+--------------------------------------------------+ +| Windows | File Explorer | ``%USERPROFILE%\Documents\My Games\OpenMW`` | +| | | | +| | PowerShell | ``"$env:USERPROFILE\Documents\My Games\OpenMW"`` | +| | | | +| | Example | ``C:\Users\Username\Documents\My Games\OpenMW`` | ++--------------+---------------+--------------------------------------------------+ Savegames --------- -:Linux: ``$HOME/.local/share/openmw/saves`` -:Mac: ``$HOME/Library/Application Support/openmw/saves`` -:Windows: ``C:\Users\Username\Documents\my games\openmw\saves`` ++--------------+------------------------------------------------------------------------+ +| OS | Location | ++==============+========================================================================+ +| Linux | ``$HOME/.config/openmw/saves`` | ++--------------+------------------------------------------------------------------------+ +| Mac | ``$HOME/Library/Application\ Support/openmw/saves`` | ++--------------+---------------+--------------------------------------------------------+ +| Windows | File Explorer | ``%USERPROFILE%\Documents\My Games\OpenMW\saves`` | +| | | | +| | PowerShell | ``"$env:USERPROFILE\Documents\My Games\OpenMW\saves"`` | +| | | | +| | Example | ``C:\Users\Username\Documents\My Games\OpenMW\saves`` | ++--------------+---------------+--------------------------------------------------------+ Screenshots ----------- -:Linux: ``$HOME/.local/share/openmw`` -:Mac: ``$HOME/Library/Application Support/openmw`` -:Windows: ``C:\Users\Username\Documents\my games\openmw`` ++--------------+-------------------------------------------------------------------------+ +| OS | Location | ++==============+=========================================================================+ +| Linux | ``$HOME/.local/share/openmw`` | ++--------------+-------------------------------------------------------------------------+ +| Mac | ``$HOME/Library/Application\ Support/openmw`` | ++--------------+---------------+---------------------------------------------------------+ +| Windows | File Explorer | ``%USERPROFILE%\Documents\My Games\OpenMW\OpenMW`` | +| | | | +| | PowerShell | ``"$env:USERPROFILE\Documents\My Games\OpenMW\OpenMW"`` | +| | | | +| | Example | ``C:\Users\Username\Documents\My Games\OpenMW\OpenMW`` | ++--------------+---------------+---------------------------------------------------------+ From 6363cc883960c876acb6871797211f8484e44342 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 28 Mar 2019 20:48:54 +0100 Subject: [PATCH 410/410] Relax CMake version requirements on macOS --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbebe99e77..bf489d99c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -796,8 +796,8 @@ endif() # Apple bundling if (OPENMW_OSX_DEPLOYMENT AND APPLE AND DESIRED_QT_VERSION MATCHES 5) - if (${CMAKE_MAJOR_VERSION} STREQUAL "3" AND ${CMAKE_MINOR_VERSION} STREQUAL "13") - message(FATAL_ERROR "macOS packaging is broken in CMake 3.13.*, see https://gitlab.com/OpenMW/openmw/issues/4767. Please use an older version like 3.12.4") + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13 AND CMAKE_VERSION VERSION_LESS 3.13.4) + message(FATAL_ERROR "macOS packaging is broken in early CMake 3.13 releases, see https://gitlab.com/OpenMW/openmw/issues/4767. Please use at least 3.13.4 or an older version like 3.12.4") endif () get_property(QT_COCOA_PLUGIN_PATH TARGET Qt5::QCocoaIntegrationPlugin PROPERTY LOCATION_RELEASE)