From 04edb1c817d81c0a8559bcd88ea4e376f6df5832 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 30 Apr 2021 19:39:26 +0200 Subject: [PATCH 001/101] Trim down some internal includes --- apps/openmw/mwclass/creature.cpp | 1 - apps/openmw/mwclass/npc.cpp | 1 - apps/openmw/mwdialogue/journalimp.hpp | 1 - apps/openmw/mwgui/itemmodel.cpp | 1 - apps/openmw/mwgui/levelupdialog.cpp | 1 - apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/pickpocketitemmodel.cpp | 1 - apps/openmw/mwgui/quickkeysmenu.hpp | 2 -- apps/openmw/mwgui/recharge.cpp | 1 - apps/openmw/mwgui/spellwindow.hpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 1 - 11 files changed, 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5ce9a66ab..acf969bd3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -25,7 +25,6 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/localscripts.hpp" diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c5b352cb4..933ba5cd3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -35,7 +35,6 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" -#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/localscripts.hpp" diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index a6501e54e..0c778d2ba 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -3,7 +3,6 @@ #include "../mwbase/journal.hpp" -#include "journalentry.hpp" #include "quest.hpp" namespace MWDialogue diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index cf88efaae..4e4d77da4 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -2,7 +2,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 86f92db6f..14de3fd27 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/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index aeaacaa63..65d49ffc9 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -25,8 +25,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" -#include "../mwrender/vismask.hpp" - #include "backgroundimage.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index b4de5cb50..5daea8f3f 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -7,7 +7,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/pickpocket.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d0e950979..b2742df79 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_QUICKKEYS_H #define MWGUI_QUICKKEYS_H -#include "../mwworld/ptr.hpp" - #include "windowbase.hpp" #include "spellmodel.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index f8d89c0cb..1bf3b24ee 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -15,7 +15,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/recharge.hpp" diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index cf5e88f8e..786a7d877 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -2,7 +2,6 @@ #define MWGUI_SPELLWINDOW_H #include "windowpinnablebase.hpp" -#include "../mwworld/ptr.hpp" #include "spellmodel.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81d6a8ab3..19ea38348 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -26,7 +26,6 @@ #include "containeritemmodel.hpp" #include "tradeitemmodel.hpp" #include "countdialog.hpp" -#include "controllers.hpp" #include "tooltips.hpp" namespace From ee2446d5c4c244864afc96c2a4a8fdc4d5444102 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 30 Apr 2021 20:11:41 +0200 Subject: [PATCH 002/101] Trim even more --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 - apps/openmw/mwinput/keyboardmanager.hpp | 1 - apps/openmw/mwmechanics/activespells.hpp | 1 - apps/openmw/mwmechanics/actors.cpp | 1 - apps/openmw/mwmechanics/aicombat.hpp | 1 - apps/openmw/mwmechanics/aicombataction.hpp | 2 -- apps/openmw/mwmechanics/aifollow.hpp | 2 -- apps/openmw/mwmechanics/aipackage.cpp | 3 --- apps/openmw/mwmechanics/aipursue.cpp | 1 - apps/openmw/mwmechanics/aiwander.cpp | 1 - apps/openmw/mwmechanics/aiwander.hpp | 2 -- apps/openmw/mwmechanics/alchemy.cpp | 1 - apps/openmw/mwmechanics/character.hpp | 2 -- 13 files changed, 19 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 690183c57..436eab7ad 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwinput/keyboardmanager.hpp b/apps/openmw/mwinput/keyboardmanager.hpp index f97f6b9e6..ca58461a2 100644 --- a/apps/openmw/mwinput/keyboardmanager.hpp +++ b/apps/openmw/mwinput/keyboardmanager.hpp @@ -1,7 +1,6 @@ #ifndef MWINPUT_MWKEYBOARDMANAGER_H #define MWINPUT_MWKEYBOARDMANAGER_H -#include #include namespace MWInput diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 4d36c717e..54f662fc2 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "../mwworld/timestamp.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e9467a679..95633bd00 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -40,7 +40,6 @@ #include "aiwander.hpp" #include "actor.hpp" #include "summoning.hpp" -#include "combat.hpp" #include "actorutil.hpp" #include "tickableeffects.hpp" diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 0f42c6e2d..5425f1af0 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -9,7 +9,6 @@ #include "pathfinding.hpp" #include "movement.hpp" -#include "obstacle.hpp" #include "aitimer.hpp" namespace ESM diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index 77a19f804..d17d5a313 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -3,8 +3,6 @@ #include -#include - #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index e6aeebb24..c4ac5eb3f 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -9,8 +9,6 @@ #include "../mwworld/ptr.hpp" -#include "pathfinding.hpp" - namespace ESM { namespace AiSequence diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 204cf2f3f..a7e8e74b0 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -15,8 +14,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwphysics/collisiontype.hpp" - #include "pathgrid.hpp" #include "creaturestats.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 5af73887c..05605529a 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -8,7 +8,6 @@ #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/action.hpp" #include "movement.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 72b8757bf..01088d967 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -11,7 +11,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 52a926d14..db8701c74 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -5,8 +5,6 @@ #include -#include "../mwworld/timestamp.hpp" - #include "pathfinding.hpp" #include "obstacle.hpp" #include "aistate.hpp" diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 6d06724f0..61fec3b54 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -21,7 +21,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/manualref.hpp" #include "magiceffects.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0821b3225..3f7fa4e1b 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -3,8 +3,6 @@ #include -#include - #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" From be371ccd9f8f6aeec7b9fc2e4bcead3929bca7a0 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 30 Apr 2021 20:27:33 +0200 Subject: [PATCH 003/101] An another pass --- apps/openmw/mwmechanics/creaturestats.cpp | 1 - apps/openmw/mwmechanics/pathfinding.cpp | 1 - apps/openmw/mwmechanics/spellcasting.hpp | 1 - apps/openmw/mwmechanics/spelllist.cpp | 1 - apps/openmw/mwmechanics/spellpriority.cpp | 1 - apps/openmw/mwmechanics/weaponpriority.cpp | 1 - apps/openmw/mwmechanics/weapontype.hpp | 2 -- apps/openmw/mwphysics/actorconvexcallback.cpp | 1 - apps/openmw/mwphysics/physicssystem.cpp | 2 -- apps/openmw/mwphysics/projectile.cpp | 3 --- apps/openmw/mwphysics/projectile.hpp | 2 -- 11 files changed, 16 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 1d5fe8347..4bc0b9a58 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -11,7 +11,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 781b897a7..3f113802f 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 45431bbc6..cc525d2db 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -2,7 +2,6 @@ #define MWMECHANICS_SPELLCASTING_H #include -#include #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwmechanics/spelllist.cpp b/apps/openmw/mwmechanics/spelllist.cpp index d8fbcf25a..24a04788e 100644 --- a/apps/openmw/mwmechanics/spelllist.cpp +++ b/apps/openmw/mwmechanics/spelllist.cpp @@ -3,7 +3,6 @@ #include #include -#include #include "spells.hpp" diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 81658193d..bd9c5f7cb 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -17,7 +17,6 @@ #include "creaturestats.hpp" #include "spellresistance.hpp" #include "weapontype.hpp" -#include "combat.hpp" #include "summoning.hpp" #include "spellutil.hpp" diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 13ce30927..8480dc208 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -9,7 +9,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "npcstats.hpp" #include "combat.hpp" #include "aicombataction.hpp" #include "spellpriority.hpp" diff --git a/apps/openmw/mwmechanics/weapontype.hpp b/apps/openmw/mwmechanics/weapontype.hpp index 056a1dbfd..09fa73c06 100644 --- a/apps/openmw/mwmechanics/weapontype.hpp +++ b/apps/openmw/mwmechanics/weapontype.hpp @@ -3,8 +3,6 @@ #include "../mwworld/inventorystore.hpp" -#include "creaturestats.hpp" - namespace MWMechanics { static std::map sWeaponTypeList = diff --git a/apps/openmw/mwphysics/actorconvexcallback.cpp b/apps/openmw/mwphysics/actorconvexcallback.cpp index f99b706d7..cdd432289 100644 --- a/apps/openmw/mwphysics/actorconvexcallback.cpp +++ b/apps/openmw/mwphysics/actorconvexcallback.cpp @@ -7,7 +7,6 @@ #include #include -#include "collisiontype.hpp" #include "projectile.hpp" namespace MWPhysics diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c5ba902fc..7c9961f2a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -56,7 +55,6 @@ #include "closestnotmerayresultcallback.hpp" #include "contacttestresultcallback.hpp" #include "projectileconvexcallback.hpp" -#include "constants.hpp" #include "movementsolver.hpp" #include "mtphysics.hpp" diff --git a/apps/openmw/mwphysics/projectile.cpp b/apps/openmw/mwphysics/projectile.cpp index a93121997..252da0a68 100644 --- a/apps/openmw/mwphysics/projectile.cpp +++ b/apps/openmw/mwphysics/projectile.cpp @@ -5,10 +5,7 @@ #include -#include #include -#include -#include #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwphysics/projectile.hpp b/apps/openmw/mwphysics/projectile.hpp index fb50eebde..81c33d2a5 100644 --- a/apps/openmw/mwphysics/projectile.hpp +++ b/apps/openmw/mwphysics/projectile.hpp @@ -6,8 +6,6 @@ #include #include -#include "components/misc/convert.hpp" - #include "ptrholder.hpp" class btCollisionObject; From 998cc97a4fddbd7f669790d49cc0dc0d14eed623 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 30 Apr 2021 20:49:22 +0200 Subject: [PATCH 004/101] And done! --- apps/openmw/mwrender/actoranimation.cpp | 1 - apps/openmw/mwrender/actoranimation.hpp | 1 - apps/openmw/mwrender/characterpreview.cpp | 1 - apps/openmw/mwrender/globalmap.cpp | 1 - apps/openmw/mwrender/landmanager.hpp | 1 - apps/openmw/mwrender/localmap.cpp | 1 - apps/openmw/mwrender/recastmesh.cpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 3 --- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwscript/cellextensions.cpp | 1 - apps/openmw/mwscript/controlextensions.cpp | 3 --- apps/openmw/mwscript/globalscripts.cpp | 2 -- apps/openmw/mwscript/interpretercontext.cpp | 2 -- apps/openmw/mwstate/quicksavemanager.hpp | 1 - apps/openmw/mwworld/cellpreloader.cpp | 4 ---- apps/openmw/mwworld/failedaction.cpp | 1 - apps/openmw/mwworld/globals.hpp | 1 - apps/openmw/mwworld/projectilemanager.cpp | 1 - apps/openmw/mwworld/scene.cpp | 2 -- apps/openmw/mwworld/worldimp.hpp | 1 - 20 files changed, 30 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 845e917fb..59bc32765 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp index 86929a18a..e149e4414 100644 --- a/apps/openmw/mwrender/actoranimation.hpp +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -6,7 +6,6 @@ #include #include "../mwworld/containerstore.hpp" -#include "../mwworld/inventorystore.hpp" #include "animation.hpp" diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b75e45906..e88c4cee3 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -23,7 +23,6 @@ #include #include -#include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 366da6439..8784eb501 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -9,7 +9,6 @@ #include -#include #include #include diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 1694bd243..f3cc86085 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -3,7 +3,6 @@ #include -#include #include #include diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index ec2bf54a7..686078879 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwrender/recastmesh.cpp b/apps/openmw/mwrender/recastmesh.cpp index d07e7d37b..7c7c6b8eb 100644 --- a/apps/openmw/mwrender/recastmesh.cpp +++ b/apps/openmw/mwrender/recastmesh.cpp @@ -1,7 +1,6 @@ #include "recastmesh.hpp" #include -#include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5d5a349d4..7093c2b98 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -43,14 +43,12 @@ #include #include -#include #include #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwgui/loadingscreen.hpp" -#include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/actorutil.hpp" @@ -63,7 +61,6 @@ #include "viewovershoulder.hpp" #include "water.hpp" #include "terrainstorage.hpp" -#include "util.hpp" #include "navmesh.hpp" #include "actorspaths.hpp" #include "recastmesh.hpp" diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f0e876470..1bf6be0d9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -46,7 +46,6 @@ #include #include -#include #include diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 356428156..b0977984f 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -13,7 +13,6 @@ #include "../mwworld/actionteleport.hpp" #include "../mwworld/cellstore.hpp" #include "../mwbase/environment.hpp" -#include "../mwworld/player.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 5362759e1..2716630d7 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -1,6 +1,5 @@ #include "controlextensions.hpp" -#include #include #include @@ -15,8 +14,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "interpretercontext.hpp" #include "ref.hpp" diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 0d579abdc..b287d33b3 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -12,8 +12,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/scriptmanager.hpp" -#include "../mwmechanics/creaturestats.hpp" - #include "interpretercontext.hpp" namespace diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index f3895c8b6..d8fd287d7 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -5,8 +5,6 @@ #include -#include - #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp index cdeff42c2..3272b24b5 100644 --- a/apps/openmw/mwstate/quicksavemanager.hpp +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -4,7 +4,6 @@ #include #include "character.hpp" -#include "../mwbase/statemanager.hpp" namespace MWState{ class QuickSaveManager{ diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 6bc60968c..d3322cefe 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -15,13 +15,9 @@ #include #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - #include "../mwrender/landmanager.hpp" #include "cellstore.hpp" -#include "manualref.hpp" #include "class.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 45df75a32..ec8314712 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -1,5 +1,4 @@ #include "failedaction.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 3468c2e71..ae5e412c7 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -7,7 +7,6 @@ #include -#include #include namespace ESM diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index b463fc09e..53b1b364b 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -44,7 +44,6 @@ #include "../mwsound/sound.hpp" -#include "../mwphysics/collisiontype.hpp" #include "../mwphysics/physicssystem.hpp" #include "../mwphysics/projectile.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index dae703c8c..3fdf4503a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -26,8 +26,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/actorutil.hpp" - #include "../mwrender/renderingmanager.hpp" #include "../mwrender/landmanager.hpp" diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5447e20c3..314f38607 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -4,7 +4,6 @@ #include #include -#include #include "../mwbase/world.hpp" From 1626762d5c7e113a34f2a864dec3ff3560a64d64 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 1 May 2021 22:20:51 +0000 Subject: [PATCH 005/101] Maybe fix #5551 If we were doing this properly, we'd migrate to https://cmake.org/cmake/help/latest/module/InstallRequiredSystemLibraries.html but this should hopefully remove a blocker for 0.47 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f930772a..7f9b4d590 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -830,13 +830,13 @@ elseif(NOT APPLE) SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe") if(EXISTS ${VCREDIST32}) INSTALL(FILES ${VCREDIST32} DESTINATION "redist") - SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q'" ) + SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q /norestart'" ) endif(EXISTS ${VCREDIST32}) SET(VCREDIST64 "${OpenMW_BINARY_DIR}/vcredist_x64.exe") if(EXISTS ${VCREDIST64}) INSTALL(FILES ${VCREDIST64} DESTINATION "redist") - SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q'" ) + SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q /norestart'" ) endif(EXISTS ${VCREDIST64}) SET(OALREDIST "${OpenMW_BINARY_DIR}/oalinst.exe") From f169f8e6f0325bfb1f9e2c1cb337cde53abd0ce6 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 5 May 2021 18:13:17 +0200 Subject: [PATCH 006/101] Wait until navmesh is generated for interior cells Add special loading progress bar. It should be fast enough to not keep loading screen for noticably long but will provide better pathfinding for actors inside interior cells. --- apps/openmw/mwworld/scene.cpp | 2 + .../detournavigator/navigator.cpp | 46 ++++++++++--------- .../detournavigator/asyncnavmeshupdater.cpp | 46 +++++++++++++++++-- .../detournavigator/asyncnavmeshupdater.hpp | 11 ++++- components/detournavigator/navigator.hpp | 7 ++- components/detournavigator/navigatorimpl.cpp | 4 +- components/detournavigator/navigatorimpl.hpp | 2 +- components/detournavigator/navigatorstub.hpp | 7 ++- components/detournavigator/navmeshmanager.cpp | 4 +- components/detournavigator/navmeshmanager.hpp | 2 +- components/misc/guarded.hpp | 4 +- 11 files changed, 98 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index dae703c8c..0cfca3be2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -847,6 +847,8 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); + + mNavigator.wait(*loadingListener); } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 619276588..8d92b48e0 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,7 @@ namespace std::back_insert_iterator> mOut; float mStepSize; AreaCosts mAreaCosts; + Loading::Listener mListener; DetourNavigatorNavigatorTest() : mPlayerPosition(0, 0, 0) @@ -124,7 +126,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -174,7 +176,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -206,7 +208,7 @@ namespace mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mPath.clear(); mOut = std::back_inserter(mPath); @@ -259,7 +261,7 @@ namespace mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -293,7 +295,7 @@ namespace mNavigator->updateObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mPath.clear(); mOut = std::back_inserter(mPath); @@ -352,7 +354,7 @@ namespace mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape2), shape2, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -408,7 +410,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), ObjectShapes {shape, &shapeAvoid}, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -456,7 +458,7 @@ namespace mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mStart.x() = 0; mStart.z() = 300; @@ -504,7 +506,7 @@ namespace mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mStart.x() = 0; mEnd.x() = 0; @@ -551,7 +553,7 @@ namespace mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits::max(), -25, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mStart.x() = 0; mEnd.x() = 0; @@ -598,7 +600,7 @@ namespace mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mStart.x() = 0; mEnd.x() = 0; @@ -642,15 +644,15 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mNavigator->removeObject(ObjectId(&shape)); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -696,7 +698,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); Misc::Rng::init(42); @@ -745,7 +747,7 @@ namespace } mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -788,7 +790,7 @@ namespace mNavigator->addObject(ObjectId(&shapes[i]), shapes[i], transform); } mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); const auto start = std::chrono::steady_clock::now(); for (std::size_t i = 0; i < shapes.size(); ++i) @@ -797,7 +799,7 @@ namespace mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); } mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); for (std::size_t i = 0; i < shapes.size(); ++i) { @@ -805,7 +807,7 @@ namespace mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); } mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); const auto duration = std::chrono::steady_clock::now() - start; @@ -828,7 +830,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); const auto result = mNavigator->raycast(mAgentHalfExtents, mStart, mEnd, Flag_walk); @@ -859,7 +861,7 @@ namespace mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape, btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); const auto navMeshes = mNavigator->getNavMeshes(); ASSERT_EQ(navMeshes.size(), 1); @@ -875,7 +877,7 @@ namespace oscillatingBoxShapePosition); mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform); mNavigator->update(mPlayerPosition); - mNavigator->wait(); + mNavigator->wait(mListener); } ASSERT_EQ(navMeshes.size(), 1); diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 7248850a6..124d3c4e0 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -111,13 +112,44 @@ namespace DetourNavigator mHasJob.notify_all(); } - void AsyncNavMeshUpdater::wait() + void AsyncNavMeshUpdater::wait(Loading::Listener& listener) { + listener.setLabel("Building navigation mesh"); + const std::size_t initialJobsLeft = getTotalJobs(); + std::size_t maxProgress = initialJobsLeft + mThreads.size(); + listener.setProgressRange(maxProgress); + waitUntilJobsDone(initialJobsLeft, maxProgress, listener); + mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); + listener.setProgress(maxProgress); + } + + void AsyncNavMeshUpdater::waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener) + { + std::size_t prevJobsLeft = initialJobsLeft; + std::size_t jobsDone = 0; + std::size_t jobsLeft = 0; + const auto isDone = [&] { - std::unique_lock lock(mMutex); - mDone.wait(lock, [&] { return mJobs.empty() && getTotalThreadJobsUnsafe() == 0; }); + jobsLeft = mJobs.size() + getTotalThreadJobsUnsafe(); + return jobsLeft == 0; + }; + std::unique_lock lock(mMutex); + while (!mDone.wait_for(lock, std::chrono::milliseconds(250), isDone)) + { + if (maxProgress < jobsLeft) + { + maxProgress = jobsLeft + mThreads.size(); + listener.setProgressRange(maxProgress); + listener.setProgress(jobsDone); + } + else if (jobsLeft < prevJobsLeft) + { + const std::size_t newJobsDone = prevJobsLeft - jobsLeft; + jobsDone += newJobsDone; + prevJobsLeft = jobsLeft; + listener.increaseProgress(newJobsDone); + } } - mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); } void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const @@ -381,6 +413,12 @@ namespace DetourNavigator mProcessed.notify_all(); } + std::size_t AsyncNavMeshUpdater::getTotalJobs() const + { + const std::scoped_lock lock(mMutex); + return mJobs.size() + getTotalThreadJobsUnsafe(); + } + std::size_t AsyncNavMeshUpdater::getTotalThreadJobsUnsafe() const { return std::accumulate(mThreadsQueues.begin(), mThreadsQueues.end(), std::size_t(0), diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 53e7fd7c1..fcf57d683 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -20,6 +20,11 @@ class dtNavMesh; +namespace Loading +{ + class Listener; +} + namespace DetourNavigator { enum class ChangeType @@ -55,7 +60,7 @@ namespace DetourNavigator void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& mNavMeshCacheItem, const TilePosition& playerTile, const std::map& changedTiles); - void wait(); + void wait(Loading::Listener& listener); void reportStats(unsigned int frameNumber, osg::Stats& stats) const; @@ -131,9 +136,13 @@ namespace DetourNavigator void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile); + inline std::size_t getTotalJobs() const; + inline std::size_t getTotalThreadJobsUnsafe() const; void cleanupLastUpdates(); + + void waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener); }; } diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index edf597348..3ec5e5acc 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -14,6 +14,11 @@ namespace ESM struct Pathgrid; } +namespace Loading +{ + class Listener; +} + namespace DetourNavigator { struct ObjectShapes @@ -162,7 +167,7 @@ namespace DetourNavigator /** * @brief wait locks thread until all tiles are updated from last update call. */ - virtual void wait() = 0; + virtual void wait(Loading::Listener& listener) = 0; /** * @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through. diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index abfb20ba8..d1e75b864 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -153,9 +153,9 @@ namespace DetourNavigator mUpdatesEnabled = enabled; } - void NavigatorImpl::wait() + void NavigatorImpl::wait(Loading::Listener& listener) { - mNavMeshManager.wait(); + mNavMeshManager.wait(listener); } SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index 74fff0dea..a53c9608d 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -48,7 +48,7 @@ namespace DetourNavigator void setUpdatesEnabled(bool enabled) override; - void wait() override; + void wait(Loading::Listener& listener) override; SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index f6892bf1b..c21db2bf8 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -3,6 +3,11 @@ #include "navigator.hpp" +namespace Loading +{ + class Listener; +} + namespace DetourNavigator { class NavigatorStub final : public Navigator @@ -68,7 +73,7 @@ namespace DetourNavigator void setUpdatesEnabled(bool /*enabled*/) override {} - void wait() override {} + void wait(Loading::Listener& /*listener*/) override {} SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 43d330648..21022d60b 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -188,9 +188,9 @@ namespace DetourNavigator " recastMeshManagerRevision=" << lastRevision; } - void NavMeshManager::wait() + void NavMeshManager::wait(Loading::Listener& listener) { - mAsyncNavMeshUpdater.wait(); + mAsyncNavMeshUpdater.wait(listener); } SharedNavMeshCacheItem NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index f3861f8f2..ce90aafc5 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -45,7 +45,7 @@ namespace DetourNavigator void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents); - void wait(); + void wait(Loading::Listener& listener); SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const; diff --git a/components/misc/guarded.hpp b/components/misc/guarded.hpp index 55a2c670c..7f1005fc3 100644 --- a/components/misc/guarded.hpp +++ b/components/misc/guarded.hpp @@ -75,7 +75,7 @@ namespace Misc return Locked(mMutex, mValue); } - Locked lockConst() + Locked lockConst() const { return Locked(mMutex, mValue); } @@ -88,7 +88,7 @@ namespace Misc } private: - std::mutex mMutex; + mutable std::mutex mMutex; T mValue; }; } From 7a51d0db1886d549e81e3ad8e2f21110e4ac881e Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 5 May 2021 19:23:07 +0200 Subject: [PATCH 007/101] Wait until navmesh is generated within given distance around player Add a setting to change this distance. To prevent situations when there is not enough navmesh generated and actors can't find path correctly. --- CHANGELOG.md | 1 + apps/openmw/mwworld/scene.cpp | 2 + .../detournavigator/navigator.cpp | 1 + .../detournavigator/asyncnavmeshupdater.cpp | 37 ++++++++++++++++--- .../detournavigator/asyncnavmeshupdater.hpp | 2 +- components/detournavigator/settings.cpp | 1 + components/detournavigator/settings.hpp | 1 + .../reference/modding/settings/navigator.rst | 12 ++++++ files/settings-default.cfg | 4 ++ 9 files changed, 55 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba8081dae..867ae0412 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -141,6 +141,7 @@ Feature #5456: Basic collada animation support Feature #5457: Realistic diagonal movement Feature #5486: Fixes trainers to choose their training skills based on their base skill points + Feature #5500: Prepare enough navmesh tiles before scene loading ends Feature #5511: Add in game option to toggle HRTF support in OpenMW Feature #5519: Code Patch tab in launcher Feature #5524: Resume failed script execution after reload diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0cfca3be2..c2d96788c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -620,6 +620,8 @@ namespace MWWorld if (changeEvent) mCellChanged = true; + + mNavigator.wait(*loadingListener); } void Scene::testExteriorCells() diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 8d92b48e0..cb8ae4152 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -66,6 +66,7 @@ namespace mSettings.mRegionMergeSize = 20; mSettings.mRegionMinSize = 8; mSettings.mTileSize = 64; + mSettings.mWaitUntilMinDistanceToPlayer = std::numeric_limits::max(); mSettings.mAsyncNavMeshUpdaterThreads = 1; mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024; mSettings.mMaxPolygonPathSize = 1024; diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 124d3c4e0..ff51e39aa 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -21,6 +21,16 @@ namespace { return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y()); } + + int getMinDistanceTo(const TilePosition& position, int maxDistance, + const std::map>& tilesPerHalfExtents) + { + int result = maxDistance; + for (const auto& [halfExtents, tiles] : tilesPerHalfExtents) + for (const TilePosition& tile : tiles) + result = std::min(result, getManhattanDistance(position, tile)); + return result; + } } namespace DetourNavigator @@ -114,24 +124,40 @@ namespace DetourNavigator void AsyncNavMeshUpdater::wait(Loading::Listener& listener) { + if (mSettings.get().mWaitUntilMinDistanceToPlayer == 0) + return; listener.setLabel("Building navigation mesh"); const std::size_t initialJobsLeft = getTotalJobs(); std::size_t maxProgress = initialJobsLeft + mThreads.size(); listener.setProgressRange(maxProgress); - waitUntilJobsDone(initialJobsLeft, maxProgress, listener); - mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); - listener.setProgress(maxProgress); + const int minDistanceToPlayer = waitUntilJobsDone(initialJobsLeft, maxProgress, listener); + if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer) + { + mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); + listener.setProgress(maxProgress); + } } - void AsyncNavMeshUpdater::waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener) + int AsyncNavMeshUpdater::waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener) { std::size_t prevJobsLeft = initialJobsLeft; std::size_t jobsDone = 0; std::size_t jobsLeft = 0; + const int maxDistanceToPlayer = mSettings.get().mWaitUntilMinDistanceToPlayer; + const TilePosition playerPosition = *mPlayerTile.lockConst(); + int minDistanceToPlayer = 0; const auto isDone = [&] { jobsLeft = mJobs.size() + getTotalThreadJobsUnsafe(); - return jobsLeft == 0; + if (jobsLeft == 0) + { + minDistanceToPlayer = 0; + return true; + } + minDistanceToPlayer = getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed); + for (const auto& [threadId, queue] : mThreadsQueues) + minDistanceToPlayer = getMinDistanceTo(playerPosition, minDistanceToPlayer, queue.mPushed); + return minDistanceToPlayer >= maxDistanceToPlayer; }; std::unique_lock lock(mMutex); while (!mDone.wait_for(lock, std::chrono::milliseconds(250), isDone)) @@ -150,6 +176,7 @@ namespace DetourNavigator listener.increaseProgress(newJobsDone); } } + return minDistanceToPlayer; } void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index fcf57d683..c28d8f21d 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -142,7 +142,7 @@ namespace DetourNavigator void cleanupLastUpdates(); - void waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener); + int waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener); }; } diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index 0c4d0f838..ff99fae20 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -29,6 +29,7 @@ namespace DetourNavigator 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.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "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")); diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index ece16e35a..39f5815b8 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -31,6 +31,7 @@ namespace DetourNavigator int mRegionMergeSize = 0; int mRegionMinSize = 0; int mTileSize = 0; + int mWaitUntilMinDistanceToPlayer = 0; std::size_t mAsyncNavMeshUpdaterThreads = 0; std::size_t mMaxNavMeshTilesCacheSize = 0; std::size_t mMaxPolygonPathSize = 0; diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index b9485c3e9..fee4b2626 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -42,6 +42,18 @@ Increasing this value may decrease performance. This condition is always true: ``max tiles number * max polygons per tile <= 4194304``. It's a limitation of `Recastnavigation `_ library. +wait until min distance to player +------------------------------ + +:Type: integer +:Range: >= 0 +:Default: 5 + +Distance in navmesh tiles around the player to keep loading screen until navigation mesh is generated. +Allows to complete cell loading only when minimal navigation mesh area is generated to correctly find path for actors +nearby the player. Increasing this value will keep loading screen longer but will slightly increase nav mesh generation +speed on systems bound by CPU. Zero means no waiting. + Advanced settings ***************** diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ea678c70f..584fe5951 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -908,6 +908,10 @@ max tiles number = 512 # Min time duration for the same tile update in milliseconds (value >= 0) min update interval ms = 250 +# Keep loading screen until navmesh is generated around the player for all tiles within manhattan distance (value >= 0). +# Distance is measured in the number of tiles and can be only an integer value. +wait until min distance to player = 5 + [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 57c372a50e481518e93aba40fc2f80f7ae2eab48 Mon Sep 17 00:00:00 2001 From: Dobrohotov Alexei Date: Wed, 5 May 2021 22:23:06 +0300 Subject: [PATCH 008/101] ESM code cleanup --- components/esm/esmreader.cpp | 21 +-------------------- components/esm/esmreader.hpp | 5 ----- components/esm/globalscript.cpp | 3 +-- components/esm/loadtes3.cpp | 13 ++++++------- components/esm/weatherstate.cpp | 8 ++++---- 5 files changed, 12 insertions(+), 38 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 4e7dce876..7aa8add48 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -97,13 +97,6 @@ void ESMReader::open(const std::string &file) open (Files::openConstrainedFileStream (file.c_str ()), file); } -int64_t ESMReader::getHNLong(const char *name) -{ - int64_t val; - getHNT(val, name); - return val; -} - std::string ESMReader::getHNOString(const char* name) { if (isNextSub(name)) @@ -215,18 +208,6 @@ void ESMReader::getSubName() mCtx.leftRec -= subNameSize; } -bool ESMReader::isEmptyOrGetName() -{ - if (mCtx.leftRec) - { - const size_t subNameSize = mCtx.subName.data_size(); - getExact(mCtx.subName.rw_data(), subNameSize); - mCtx.leftRec -= subNameSize; - return false; - } - return true; -} - void ESMReader::skipHSub() { getSubHeader(); @@ -343,7 +324,7 @@ std::string ESMReader::getString(int size) mBuffer[s] = 0; // read ESM data - char *ptr = &mBuffer[0]; + char *ptr = mBuffer.data(); getExact(ptr, size); size = strnlen(ptr, size); diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 761756e8f..ba24c79f8 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -128,8 +128,6 @@ public: getHT(x); } - int64_t getHNLong(const char *name); - // Get data of a given type/size, including subrecord header template void getHT(X &x) @@ -193,9 +191,6 @@ public: // slightly. void getSubName(); - // This is specially optimized for LoadINFO. - bool isEmptyOrGetName(); - // Skip current sub record, including header (but not including // name.) void skipHSub(); diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 239d162f2..016ea4f0c 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -13,8 +13,7 @@ void ESM::GlobalScript::load (ESMReader &esm) esm.getHNOT (mRunning, "RUN_"); mTargetRef.unset(); - if (esm.peekNextSub("TARG")) - mTargetId = esm.getHNString ("TARG"); + mTargetId = esm.getHNOString ("TARG"); if (esm.peekNextSub("FRMR")) mTargetRef.load(esm, true, "FRMR"); } diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index d953f1dc2..f5cbcd62f 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -41,7 +41,7 @@ void ESM::Header::load (ESMReader &esm) { MasterData m; m.name = esm.getHString(); - m.size = esm.getHNLong ("DATA"); + esm.getHNT(m.size, "DATA"); mMaster.push_back (m); } @@ -54,14 +54,14 @@ void ESM::Header::load (ESMReader &esm) esm.getSubHeader(); mSCRD.resize(esm.getSubSize()); if (!mSCRD.empty()) - esm.getExact(&mSCRD[0], mSCRD.size()); + esm.getExact(mSCRD.data(), mSCRD.size()); } if (esm.isNextSub("SCRS")) { esm.getSubHeader(); mSCRS.resize(esm.getSubSize()); if (!mSCRS.empty()) - esm.getExact(&mSCRS[0], mSCRS.size()); + esm.getExact(mSCRS.data(), mSCRS.size()); } } @@ -78,10 +78,9 @@ void ESM::Header::save (ESMWriter &esm) esm.writeT(mData.records); esm.endRecord("HEDR"); - for (std::vector::iterator iter = mMaster.begin(); - iter != mMaster.end(); ++iter) + for (const Header::MasterData& data : mMaster) { - esm.writeHNCString ("MAST", iter->name); - esm.writeHNT ("DATA", iter->size); + esm.writeHNCString ("MAST", data.name); + esm.writeHNT ("DATA", data.size); } } diff --git a/components/esm/weatherstate.cpp b/components/esm/weatherstate.cpp index ff2528e58..3d94a445b 100644 --- a/components/esm/weatherstate.cpp +++ b/components/esm/weatherstate.cpp @@ -31,15 +31,15 @@ namespace ESM esm.getHNT(mNextWeather, nextWeatherRecord); esm.getHNT(mQueuedWeather, queuedWeatherRecord); - while(esm.peekNextSub(regionNameRecord)) + while (esm.isNextSub(regionNameRecord)) { - std::string regionID = esm.getHNString(regionNameRecord); + std::string regionID = esm.getHString(); RegionWeatherState region; esm.getHNT(region.mWeather, regionWeatherRecord); - while(esm.peekNextSub(regionChanceRecord)) + while (esm.isNextSub(regionChanceRecord)) { char chance; - esm.getHNT(chance, regionChanceRecord); + esm.getHT(chance); region.mChances.push_back(chance); } From 813b8ee0d18e66bb5e029ff5aa687bdab1c6cf95 Mon Sep 17 00:00:00 2001 From: CedricMocquillon Date: Wed, 5 May 2021 23:19:08 +0200 Subject: [PATCH 009/101] Search only in the niffilemanager for nif files --- components/resource/scenemanager.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index a3c751f7a..64128ae30 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -378,7 +378,7 @@ namespace Resource Resource::ImageManager* mImageManager; }; - osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) + osg::ref_ptr load (const std::string& normalizedFilename, const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) { std::string ext = Resource::getFileExtension(normalizedFilename); if (ext == "nif") @@ -400,7 +400,7 @@ namespace Resource options->setReadFileCallback(new ImageReadCallback(imageManager)); if (ext == "dae") options->setOptionString("daeUseSequencedTextureUnits"); - osgDB::ReaderWriter::ReadResult result = reader->readNode(*file, options); + osgDB::ReaderWriter::ReadResult result = reader->readNode(*vfs->get(normalizedFilename), options); if (!result.success()) { std::stringstream errormsg; @@ -527,9 +527,7 @@ namespace Resource osg::ref_ptr loaded; try { - Files::IStreamPtr file = mVFS->get(normalized); - - loaded = load(file, normalized, mImageManager, mNifFileManager); + loaded = load(normalized, mVFS, mImageManager, mNifFileManager); } catch (std::exception& e) { @@ -542,7 +540,7 @@ namespace Resource { Log(Debug::Error) << "Failed to load '" << name << "': " << e.what() << ", using marker_error." << sMeshTypes[i] << " instead"; Files::IStreamPtr file = mVFS->get(normalized); - loaded = load(file, normalized, mImageManager, mNifFileManager); + loaded = load(normalized, mVFS, mImageManager, mNifFileManager); break; } } From 626e0329315e6ec3037210dc0fa00cdd0755754c Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 5 May 2021 23:25:13 +0200 Subject: [PATCH 010/101] Do not store callback inside Misc::Barrier The only wait method can be provided with it so pass it as a template parameter there. --- apps/openmw/mwphysics/mtphysics.cpp | 82 ++++++++++++++++------------- apps/openmw/mwphysics/mtphysics.hpp | 3 ++ components/misc/barrier.hpp | 13 ++--- 3 files changed, 52 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 95a741825..82214b628 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -177,43 +177,11 @@ namespace MWPhysics mDeferAabbUpdate = false; } - mPreStepBarrier = std::make_unique(mNumThreads, [&]() - { - if (mDeferAabbUpdate) - updateAabbs(); - if (!mRemainingSteps) - return; - for (auto& data : mActorsFrameData) - if (data.mActor.lock()) - { - std::unique_lock lock(mCollisionWorldMutex); - MovementSolver::unstuck(data, mCollisionWorld); - } - }); + mPreStepBarrier = std::make_unique(mNumThreads); - mPostStepBarrier = std::make_unique(mNumThreads, [&]() - { - if (mRemainingSteps) - { - --mRemainingSteps; - updateActorsPositions(); - } - mNextJob.store(0, std::memory_order_release); - }); + mPostStepBarrier = std::make_unique(mNumThreads); - mPostSimBarrier = std::make_unique(mNumThreads, [&]() - { - mNewFrame = false; - if (mLOSCacheExpiry >= 0) - { - std::unique_lock lock(mLOSCacheMutex); - mLOSCache.erase( - std::remove_if(mLOSCache.begin(), mLOSCache.end(), - [](const LOSRequest& req) { return req.mStale; }), - mLOSCache.end()); - } - mTimeEnd = mTimer->tick(); - }); + mPostSimBarrier = std::make_unique(mNumThreads); } PhysicsTaskScheduler::~PhysicsTaskScheduler() @@ -525,7 +493,7 @@ namespace MWPhysics if (!mNewFrame) mHasJob.wait(lock, [&]() { return mQuit || mNewFrame; }); - mPreStepBarrier->wait(); + mPreStepBarrier->wait([this] { afterPreStep(); }); int job = 0; while (mRemainingSteps && (job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs) @@ -537,7 +505,7 @@ namespace MWPhysics } } - mPostStepBarrier->wait(); + mPostStepBarrier->wait([this] { afterPostStep(); }); if (!mRemainingSteps) { @@ -552,7 +520,7 @@ namespace MWPhysics if (mLOSCacheExpiry >= 0) refreshLOSCache(); - mPostSimBarrier->wait(); + mPostSimBarrier->wait([this] { afterPostSim(); }); } } } @@ -633,4 +601,42 @@ namespace MWPhysics std::shared_lock lock(mCollisionWorldMutex); mDebugDrawer->step(); } + + void PhysicsTaskScheduler::afterPreStep() + { + if (mDeferAabbUpdate) + updateAabbs(); + if (!mRemainingSteps) + return; + for (auto& data : mActorsFrameData) + if (data.mActor.lock()) + { + std::unique_lock lock(mCollisionWorldMutex); + MovementSolver::unstuck(data, mCollisionWorld); + } + } + + void PhysicsTaskScheduler::afterPostStep() + { + if (mRemainingSteps) + { + --mRemainingSteps; + updateActorsPositions(); + } + mNextJob.store(0, std::memory_order_release); + } + + void PhysicsTaskScheduler::afterPostSim() + { + mNewFrame = false; + if (mLOSCacheExpiry >= 0) + { + std::unique_lock lock(mLOSCacheMutex); + mLOSCache.erase( + std::remove_if(mLOSCache.begin(), mLOSCache.end(), + [](const LOSRequest& req) { return req.mStale; }), + mLOSCache.end()); + } + mTimeEnd = mTimer->tick(); + } } diff --git a/apps/openmw/mwphysics/mtphysics.hpp b/apps/openmw/mwphysics/mtphysics.hpp index 6d2c392c0..3fd4d5a69 100644 --- a/apps/openmw/mwphysics/mtphysics.hpp +++ b/apps/openmw/mwphysics/mtphysics.hpp @@ -66,6 +66,9 @@ namespace MWPhysics void updatePtrAabb(const std::weak_ptr& ptr); void updateStats(osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats); std::tuple calculateStepConfig(float timeAccum) const; + void afterPreStep(); + void afterPostStep(); + void afterPostSim(); std::unique_ptr mWorldFrameData; std::vector mActorsFrameData; diff --git a/components/misc/barrier.hpp b/components/misc/barrier.hpp index a5af9f565..b3fe944b0 100644 --- a/components/misc/barrier.hpp +++ b/components/misc/barrier.hpp @@ -2,7 +2,6 @@ #define OPENMW_BARRIER_H #include -#include #include namespace Misc @@ -11,15 +10,14 @@ namespace Misc class Barrier { public: - using BarrierCallback = std::function; /// @param count number of threads to wait on - /// @param func callable to be executed once after all threads have met - Barrier(int count, BarrierCallback&& func) : mThreadCount(count), mRendezvousCount(0), mGeneration(0) - , mFunc(std::forward(func)) + explicit Barrier(int count) : mThreadCount(count), mRendezvousCount(0), mGeneration(0) {} /// @brief stop execution of threads until count distinct threads reach this point - void wait() + /// @param func callable to be executed once after all threads have met + template + void wait(Callback&& func) { std::unique_lock lock(mMutex); @@ -29,7 +27,7 @@ namespace Misc { ++mGeneration; mRendezvousCount = 0; - mFunc(); + func(); mRendezvous.notify_all(); } else @@ -44,7 +42,6 @@ namespace Misc int mGeneration; mutable std::mutex mMutex; std::condition_variable mRendezvous; - BarrierCallback mFunc; }; } From b78bed90c5a437020ed3ec50c80408d9a41fa95d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 5 May 2021 23:51:07 +0100 Subject: [PATCH 011/101] Add CMake-based base64 port --- cmake/base64.cmake | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 cmake/base64.cmake diff --git a/cmake/base64.cmake b/cmake/base64.cmake new file mode 100644 index 000000000..7931758bb --- /dev/null +++ b/cmake/base64.cmake @@ -0,0 +1,74 @@ +# math(EXPR "...") can't parse hex until 3.13 +cmake_minimum_required(VERSION 3.13) + +if (NOT DEFINED INPUT_FILE) + message(STATUS "Usage: cmake -DINPUT_FILE=\"infile.ext\" -DOUTPUT_FILE=\"out.txt\" -P base64.cmake") + message(FATAL_ERROR "INPUT_FILE not specified") +endif() + +if (NOT DEFINED OUTPUT_FILE) + message(STATUS "Usage: cmake -DINPUT_FILE=\"infile.ext\" -DOUTPUT_FILE=\"out.txt\" -P base64.cmake") + message(FATAL_ERROR "OUTPUT_FILE not specified") +endif() + +if (NOT EXISTS ${INPUT_FILE}) + message(FATAL_ERROR "INPUT_FILE ${INPUT_FILE} does not exist") +endif() + +set(lut "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + +file(READ "${INPUT_FILE}" hexContent HEX) + +set(base64Content "") +while(TRUE) + string(LENGTH "${hexContent}" tailLength) + if (tailLength LESS 1) + break() + endif() + + string(SUBSTRING "${hexContent}" 0 6 head) + # base64 works on three-byte chunks. Pad. + string(LENGTH "${head}" headLength) + if (headLength LESS 6) + set(hexContent "") + math(EXPR padSize "6 - ${headLength}") + set(pad "") + foreach(i RANGE 1 ${padSize}) + string(APPEND pad "0") + endforeach() + string(APPEND head "${pad}") + else() + string(SUBSTRING "${hexContent}" 6 -1 hexContent) + set(padSize 0) + endif() + + # get six-bit slices + math(EXPR first "0x${head} >> 18") + math(EXPR second "(0x${head} & 0x3F000) >> 12") + math(EXPR third "(0x${head} & 0xFC0) >> 6") + math(EXPR fourth "0x${head} & 0x3F") + + # first two characters are always needed to represent the first byte + string(SUBSTRING "${lut}" ${first} 1 char) + string(APPEND base64Content "${char}") + string(SUBSTRING "${lut}" ${second} 1 char) + string(APPEND base64Content "${char}") + + # if there's no second byte, pad with = + if (NOT padSize EQUAL 4) + string(SUBSTRING "${lut}" ${third} 1 char) + string(APPEND base64Content "${char}") + else() + string(APPEND base64Content "=") + endif() + + # if there's no third byte, pad with = + if (padSize EQUAL 0) + string(SUBSTRING "${lut}" ${fourth} 1 char) + string(APPEND base64Content "${char}") + else() + string(APPEND base64Content "=") + endif() +endwhile() + +file(WRITE "${OUTPUT_FILE}" "${base64Content}") \ No newline at end of file From a88513486844fddf14f116e0c95668de2e39f9b3 Mon Sep 17 00:00:00 2001 From: CedricMocquillon Date: Thu, 6 May 2021 13:28:06 +0200 Subject: [PATCH 012/101] Do not search if it is not used --- components/resource/scenemanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 64128ae30..8ca6c8214 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -539,7 +539,6 @@ namespace Resource if (mVFS->exists(normalized)) { Log(Debug::Error) << "Failed to load '" << name << "': " << e.what() << ", using marker_error." << sMeshTypes[i] << " instead"; - Files::IStreamPtr file = mVFS->get(normalized); loaded = load(normalized, mVFS, mImageManager, mNifFileManager); break; } From e97e4d07ddd91bedf7ad10eea3dfd5eccc46ba38 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Thu, 6 May 2021 22:41:20 +0200 Subject: [PATCH 013/101] Teensy optimisation for esmtool - Use an unordered_set instead of a list to keep track of skipped records. - Reduce the number of conditions when parsing 4-letters records by using a switch-case instead of cascading conditions. - Add a const --- apps/esmtool/esmtool.cpp | 9 +++++---- apps/esmtool/record.cpp | 2 +- components/esm/esmcommon.hpp | 17 ++++++++--------- components/esm/esmreader.cpp | 2 +- components/esm/esmreader.hpp | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 579f5f67d..60483f981 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -322,7 +323,7 @@ int load(Arguments& info) std::string filename = info.filename; std::cout << "Loading file: " << filename << std::endl; - std::list skipped; + std::unordered_set skipped; try { @@ -364,17 +365,17 @@ int load(Arguments& info) // Loop through all records while(esm.hasMoreRecs()) { - ESM::NAME n = esm.getRecName(); + const ESM::NAME n = esm.getRecName(); uint32_t flags; esm.getRecHeader(flags); EsmTool::RecordBase *record = EsmTool::RecordBase::create(n); if (record == nullptr) { - if (std::find(skipped.begin(), skipped.end(), n.intval) == skipped.end()) + if (skipped.count(n.intval) == 0) { std::cout << "Skipping " << n.toString() << " records." << std::endl; - skipped.push_back(n.intval); + skipped.emplace(n.intval); } esm.skipRecord(); diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 3679184a6..55170e232 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -172,7 +172,7 @@ void printTransport(const std::vector& transport) namespace EsmTool { RecordBase * -RecordBase::create(ESM::NAME type) +RecordBase::create(const ESM::NAME type) { RecordBase *record = nullptr; diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 232a24fcf..6087de83d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -110,15 +110,14 @@ struct FIXED_STRING<4> : public FIXED_STRING_BASE void assign(const std::string& value) { intval = 0; - size_t length = value.size(); - if (length == 0) return; - data[0] = value[0]; - if (length == 1) return; - data[1] = value[1]; - if (length == 2) return; - data[2] = value[2]; - if (length == 3) return; - data[3] = value[3]; + switch(value.size()) { + case 4: data[3] = value[3]; + case 3: data[2] = value[2]; + case 2: data[1] = value[1]; + case 1: data[0] = value[0]; + default: break; + } + } char const* ro_data() const { return data; } diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 4e7dce876..0ee47cab6 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -373,7 +373,7 @@ void ESMReader::setEncoder(ToUTF8::Utf8Encoder* encoder) mEncoder = encoder; } -size_t ESMReader::getFileOffset() +size_t ESMReader::getFileOffset() const { return mEsm->tellg(); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 761756e8f..721c91802 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -73,7 +73,7 @@ public: void openRaw(const std::string &filename); /// Get the current position in the file. Make sure that the file has been opened! - size_t getFileOffset(); + size_t getFileOffset() const; // This is a quick hack for multiple esm/esp files. Each plugin introduces its own // terrain palette, but ESMReader does not pass a reference to the correct plugin From a0582caa262b36b058ee8c4d2aadf92ffc1a3c9f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 7 May 2021 10:41:14 +0400 Subject: [PATCH 014/101] Fix uninitialized variable --- apps/openmw/mwphysics/physicssystem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c52ecc68f..f910a7fd9 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -937,7 +937,7 @@ namespace MWPhysics ActorFrameData::ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr standingOn, bool waterCollision, osg::Vec3f movement, float slowFall, float waterlevel) : mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn), - mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision), + mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision), mSkipCollisionDetection(actor->skipCollisions()), mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos() { const MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -954,7 +954,6 @@ namespace MWPhysics void ActorFrameData::updatePosition(btCollisionWorld* world) { mActorRaw->updateWorldPosition(); - mSkipCollisionDetection = mActorRaw->skipCollisions(); mActorRaw->applyOffsetChange(); mPosition = mActorRaw->getPosition(); if (mWaterCollision && mPosition.z() < mWaterlevel && canMoveToWaterSurface(mActorRaw, mWaterlevel, world)) From e8ed66767b2935068d11652a56f02f3336a9edb1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 7 May 2021 11:04:49 +0400 Subject: [PATCH 015/101] Fix AppVeyor CI --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index ed6f727be..e2c13ed94 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -50,7 +50,7 @@ install: before_build: - cmd: git submodule update --init --recursive - - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -c %configuration% -p %PLATFORM% -v %msvc% -V -i %APPVEYOR_BUILD_FOLDER%\install -D + - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -c %configuration% -p %PLATFORM% -v %msvc% -V -i %APPVEYOR_BUILD_FOLDER%\install build_script: - cmd: if %PLATFORM%==Win32 set build=MSVC%msvc%_32 From 8d4a374516f6cfa0ad8350474c45a6749e6b4485 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 7 May 2021 11:30:10 +0400 Subject: [PATCH 016/101] Add missing include for std::inserter --- components/detournavigator/navmeshmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 43d330648..2692f016e 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -10,6 +10,8 @@ #include +#include + namespace { using DetourNavigator::ChangeType; From fbeccc2908d82fb646fb0beb8ed31b5a4396b9aa Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 7 May 2021 09:28:47 +0000 Subject: [PATCH 017/101] Apply 1 suggestion(s) to 1 file(s) --- components/esm/esmcommon.hpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 6087de83d..e4f3b636d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -110,13 +110,7 @@ struct FIXED_STRING<4> : public FIXED_STRING_BASE void assign(const std::string& value) { intval = 0; - switch(value.size()) { - case 4: data[3] = value[3]; - case 3: data[2] = value[2]; - case 2: data[1] = value[1]; - case 1: data[0] = value[0]; - default: break; - } + std::memcpy(data, value.data(), std::min(value.size(), 4)); } From 8a56ba6aaaabfe6a553b37c1e6d518187c2e0ffb Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 7 May 2021 13:58:30 +0200 Subject: [PATCH 018/101] Fix compilation --- components/esm/esmcommon.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index e4f3b636d..bb4069d26 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -110,7 +110,7 @@ struct FIXED_STRING<4> : public FIXED_STRING_BASE void assign(const std::string& value) { intval = 0; - std::memcpy(data, value.data(), std::min(value.size(), 4)); + std::memcpy(data, value.data(), (value.size() < 4)? value.size(): 4); } From 60649792baa4c989267b157c0538a279028f6813 Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Fri, 7 May 2021 12:29:06 +0000 Subject: [PATCH 019/101] Add information about DX format being used in normal maps --- .../reference/modding/texture-modding/texture-basics.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/texture-modding/texture-basics.rst b/docs/source/reference/modding/texture-modding/texture-basics.rst index 65e71834c..78ae00770 100644 --- a/docs/source/reference/modding/texture-modding/texture-basics.rst +++ b/docs/source/reference/modding/texture-modding/texture-basics.rst @@ -19,8 +19,10 @@ OpenMW automatically uses shaders for objects with these mapping techniques. Normal Mapping ############## -To plug in a normal map, you name the normal map as the diffuse texture but with a specified suffix after. -OpenMW will then recognise the file and load it as a normal map, provided you have set up your settings file correctly. +To plug in a normal map, you name the normal map as the diffuse texture but with a specified suffix after. OpenMW will then recognise the file and load it as a normal map, provided you have set up your settings file correctly. + +Content creators need to know that OpenMW uses the DX format for normal maps, and not the OpenGL format as one otherwise might expect. See an example of the difference between the two formats `here `_. Make sure your normal maps are created according to the DX style. + See the section `Automatic use`_ further down below for detailed information. Specular Mapping From 2e8873af514fb93630e83626f8f733ad6ebd1108 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 7 May 2021 19:20:14 +0400 Subject: [PATCH 020/101] Add new scene nodes to scene graph serializer blacklist --- components/sceneutil/serialize.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 7e176be3d..1b5c1feed 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -131,9 +131,11 @@ void registerSerializers() "SceneUtil::StateSetUpdater", "SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", + "SceneUtil::TextKeyMapHolder", + "Shader::RemovedAlphaFunc", + "NifOsg::LightManagerStateAttribute", "NifOsg::FlipController", "NifOsg::KeyframeController", - "NifOsg::TextKeyMapHolder", "NifOsg::Emitter", "NifOsg::ParticleColorAffector", "NifOsg::ParticleSystem", @@ -147,6 +149,7 @@ void registerSerializers() "NifOsg::VisController", "osgMyGUI::Drawable", "osg::DrawCallback", + "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback", "osgOQ::RetrieveQueriesCallback", "osg::DummyObject" From b86356fe1386cf664bf771fd2d2192cf8468040e Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 8 May 2021 19:57:11 -0500 Subject: [PATCH 021/101] [Launcher] Removing extra box surrounding all main content Previously, all main content was in a single box, separated from the bottom containing the version and Help/Close/Play buttons. For pages that already had boxes, that meant there were were boxes within boxes and this looked visually cluttered. I've removed the box to reduce the amount of visual clutter and added a horizontal line so that the content is still separated from the bottom content. --- files/ui/mainwindow.ui | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/files/ui/mainwindow.ui b/files/ui/mainwindow.ui index 13e8593e0..54a2d16a1 100644 --- a/files/ui/mainwindow.ui +++ b/files/ui/mainwindow.ui @@ -52,27 +52,13 @@ - - - + + + + + + Qt::Horizontal - - - 0 - - - 0 - - - 0 - - - 0 - - - - - From ead51784dc2cc19f6644166eb356c4c7ea199461 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 8 May 2021 23:28:29 -0500 Subject: [PATCH 022/101] [Launcher] Replacing static method access through instances This addresses the Clang Tidy check [readability-static-accessed-through-instance](https://clang.llvm.org/extra/clang-tidy/checks/readability-static-accessed-through-instance.html). It also simplifies the code by reducing the number of parameters we're passing around. --- apps/launcher/advancedpage.cpp | 94 ++++++++++++----------- apps/launcher/advancedpage.hpp | 4 +- apps/launcher/graphicspage.cpp | 133 ++++++++++++++++----------------- apps/launcher/graphicspage.hpp | 4 +- apps/launcher/maindialog.cpp | 4 +- 5 files changed, 116 insertions(+), 123 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 4ba732234..5199be07e 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -13,11 +13,9 @@ #include "utils/openalutil.hpp" -Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings, - Settings::Manager &engineSettings, QWidget *parent) +Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings, QWidget *parent) : QWidget(parent) , mGameSettings(gameSettings) - , mEngineSettings(engineSettings) { setObjectName ("AdvancedPage"); setupUi(this); @@ -100,12 +98,12 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game"); loadSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game"); loadSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game"); - int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game"); + int unarmedFactorsStrengthIndex = Settings::Manager::getInt("strength influences hand to hand", "Game"); if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2) unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex); loadSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game"); loadSettingBool(enableNavigatorCheckBox, "enable", "Navigator"); - int numPhysicsThreads = mEngineSettings.getInt("async num threads", "Physics"); + int numPhysicsThreads = Settings::Manager::getInt("async num threads", "Physics"); if (numPhysicsThreads >= 0) physicsThreadsSpinBox->setValue(numPhysicsThreads); loadSettingBool(allowNPCToFollowOverWaterSurfaceCheckBox, "allow actors to follow over water surface", "Game"); @@ -130,26 +128,26 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game"); loadSettingBool(smoothMovementCheckBox, "smooth movement", "Game"); - const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain"); - const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain"); + const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); + const bool objectPaging = Settings::Manager::getBool("object paging", "Terrain"); if (distantTerrain && objectPaging) { distantLandCheckBox->setCheckState(Qt::Checked); } loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain"); - viewingDistanceComboBox->setValue(convertToCells(mEngineSettings.getInt("viewing distance", "Camera"))); + viewingDistanceComboBox->setValue(convertToCells(Settings::Manager::getInt("viewing distance", "Camera"))); int lightingMethod = 1; - if (mEngineSettings.getString("lighting method", "Shaders") == "legacy") + if (Settings::Manager::getString("lighting method", "Shaders") == "legacy") lightingMethod = 0; - else if (mEngineSettings.getString("lighting method", "Shaders") == "shaders") + else if (Settings::Manager::getString("lighting method", "Shaders") == "shaders") lightingMethod = 2; lightingMethodComboBox->setCurrentIndex(lightingMethod); } // Audio { - std::string selectedAudioDevice = mEngineSettings.getString("device", "Sound"); + std::string selectedAudioDevice = Settings::Manager::getString("device", "Sound"); if (selectedAudioDevice.empty() == false) { int audioDeviceIndex = audioDeviceSelectorComboBox->findData(QString::fromStdString(selectedAudioDevice)); @@ -158,12 +156,12 @@ bool Launcher::AdvancedPage::loadSettings() audioDeviceSelectorComboBox->setCurrentIndex(audioDeviceIndex); } } - int hrtfEnabledIndex = mEngineSettings.getInt("hrtf enable", "Sound"); + int hrtfEnabledIndex = Settings::Manager::getInt("hrtf enable", "Sound"); if (hrtfEnabledIndex >= -1 && hrtfEnabledIndex <= 1) { enableHRTFComboBox->setCurrentIndex(hrtfEnabledIndex + 1); } - std::string selectedHRTFProfile = mEngineSettings.getString("hrtf", "Sound"); + std::string selectedHRTFProfile = Settings::Manager::getString("hrtf", "Sound"); if (selectedHRTFProfile.empty() == false) { int hrtfProfileIndex = hrtfProfileSelectorComboBox->findData(QString::fromStdString(selectedHRTFProfile)); @@ -185,7 +183,7 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera"); loadSettingBool(headBobbingCheckBox, "head bobbing", "Camera"); defaultShoulderComboBox->setCurrentIndex( - mEngineSettings.getVector2("view over shoulder offset", "Camera").x() >= 0 ? 0 : 1); + Settings::Manager::getVector2("view over shoulder offset", "Camera").x() >= 0 ? 0 : 1); } // Interface Changes @@ -195,13 +193,13 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game"); loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); loadSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI"); - int showOwnedIndex = mEngineSettings.getInt("show owned", "Game"); + int showOwnedIndex = Settings::Manager::getInt("show owned", "Game"); // Match the index with the option (only 0, 1, 2, or 3 are valid). Will default to 0 if invalid. if (showOwnedIndex >= 0 && showOwnedIndex <= 3) showOwnedComboBox->setCurrentIndex(showOwnedIndex); loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI"); loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game"); - scalingSpinBox->setValue(mEngineSettings.getFloat("scaling factor", "GUI")); + scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI")); } // Bug fixes @@ -214,10 +212,10 @@ bool Launcher::AdvancedPage::loadSettings() { // Saves loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); - maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves")); + maximumQuicksavesComboBox->setValue(Settings::Manager::getInt("max quicksaves", "Saves")); // Other Settings - QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper(); + QString screenshotFormatString = QString::fromStdString(Settings::Manager::getString("screenshot format", "General")).toUpper(); if (screenshotFormatComboBox->findText(screenshotFormatString) == -1) screenshotFormatComboBox->addItem(screenshotFormatString); screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString)); @@ -258,13 +256,13 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game"); saveSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game"); int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex(); - if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game")) - mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex); + if (unarmedFactorsStrengthIndex != Settings::Manager::getInt("strength influences hand to hand", "Game")) + Settings::Manager::setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex); saveSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game"); saveSettingBool(enableNavigatorCheckBox, "enable", "Navigator"); int numPhysicsThreads = physicsThreadsSpinBox->value(); - if (numPhysicsThreads != mEngineSettings.getInt("async num threads", "Physics")) - mEngineSettings.setInt("async num threads", "Physics", numPhysicsThreads); + if (numPhysicsThreads != Settings::Manager::getInt("async num threads", "Physics")) + Settings::Manager::setInt("async num threads", "Physics", numPhysicsThreads); } // Visuals @@ -282,23 +280,23 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game"); saveSettingBool(smoothMovementCheckBox, "smooth movement", "Game"); - const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain"); - const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain"); + const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); + const bool objectPaging = Settings::Manager::getBool("object paging", "Terrain"); const bool wantDistantLand = distantLandCheckBox->checkState(); if (wantDistantLand != (distantTerrain && objectPaging)) { - mEngineSettings.setBool("distant terrain", "Terrain", wantDistantLand); - mEngineSettings.setBool("object paging", "Terrain", wantDistantLand); + Settings::Manager::setBool("distant terrain", "Terrain", wantDistantLand); + Settings::Manager::setBool("object paging", "Terrain", wantDistantLand); } saveSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain"); double viewingDistance = viewingDistanceComboBox->value(); - if (viewingDistance != convertToCells(mEngineSettings.getInt("viewing distance", "Camera"))) + if (viewingDistance != convertToCells(Settings::Manager::getInt("viewing distance", "Camera"))) { - mEngineSettings.setInt("viewing distance", "Camera", convertToUnits(viewingDistance)); + Settings::Manager::setInt("viewing distance", "Camera", convertToUnits(viewingDistance)); } static std::array lightingMethodMap = {"legacy", "shaders compatibility", "shaders"}; - mEngineSettings.setString("lighting method", "Shaders", lightingMethodMap[lightingMethodComboBox->currentIndex()]); + Settings::Manager::setString("lighting method", "Shaders", lightingMethodMap[lightingMethodComboBox->currentIndex()]); } // Audio @@ -306,25 +304,25 @@ void Launcher::AdvancedPage::saveSettings() int audioDeviceIndex = audioDeviceSelectorComboBox->currentIndex(); if (audioDeviceIndex != 0) { - mEngineSettings.setString("device", "Sound", audioDeviceSelectorComboBox->currentText().toUtf8().constData()); + Settings::Manager::setString("device", "Sound", audioDeviceSelectorComboBox->currentText().toUtf8().constData()); } else { - mEngineSettings.setString("device", "Sound", ""); + Settings::Manager::setString("device", "Sound", ""); } int hrtfEnabledIndex = enableHRTFComboBox->currentIndex() - 1; - if (hrtfEnabledIndex != mEngineSettings.getInt("hrtf enable", "Sound")) + if (hrtfEnabledIndex != Settings::Manager::getInt("hrtf enable", "Sound")) { - mEngineSettings.setInt("hrtf enable", "Sound", hrtfEnabledIndex); + Settings::Manager::setInt("hrtf enable", "Sound", hrtfEnabledIndex); } int selectedHRTFProfileIndex = hrtfProfileSelectorComboBox->currentIndex(); if (selectedHRTFProfileIndex != 0) { - mEngineSettings.setString("hrtf", "Sound", hrtfProfileSelectorComboBox->currentText().toUtf8().constData()); + Settings::Manager::setString("hrtf", "Sound", hrtfProfileSelectorComboBox->currentText().toUtf8().constData()); } else { - mEngineSettings.setString("hrtf", "Sound", ""); + Settings::Manager::setString("hrtf", "Sound", ""); } } @@ -336,14 +334,14 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera"); saveSettingBool(headBobbingCheckBox, "head bobbing", "Camera"); - osg::Vec2f shoulderOffset = mEngineSettings.getVector2("view over shoulder offset", "Camera"); + osg::Vec2f shoulderOffset = Settings::Manager::getVector2("view over shoulder offset", "Camera"); if (defaultShoulderComboBox->currentIndex() != (shoulderOffset.x() >= 0 ? 0 : 1)) { if (defaultShoulderComboBox->currentIndex() == 0) shoulderOffset.x() = std::abs(shoulderOffset.x()); else shoulderOffset.x() = -std::abs(shoulderOffset.x()); - mEngineSettings.setVector2("view over shoulder offset", "Camera", shoulderOffset); + Settings::Manager::setVector2("view over shoulder offset", "Camera", shoulderOffset); } } @@ -355,13 +353,13 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game"); saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI"); int showOwnedCurrentIndex = showOwnedComboBox->currentIndex(); - if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game")) - mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex); + if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game")) + Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex); saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI"); saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game"); float uiScalingFactor = scalingSpinBox->value(); - if (uiScalingFactor != mEngineSettings.getFloat("scaling factor", "GUI")) - mEngineSettings.setFloat("scaling factor", "GUI", uiScalingFactor); + if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI")) + Settings::Manager::setFloat("scaling factor", "GUI", uiScalingFactor); } // Bug fixes @@ -375,15 +373,15 @@ void Launcher::AdvancedPage::saveSettings() // Saves Settings saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); int maximumQuicksaves = maximumQuicksavesComboBox->value(); - if (maximumQuicksaves != mEngineSettings.getInt("max quicksaves", "Saves")) + if (maximumQuicksaves != Settings::Manager::getInt("max quicksaves", "Saves")) { - mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves); + Settings::Manager::setInt("max quicksaves", "Saves", maximumQuicksaves); } // Other Settings std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString(); - if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General")) - mEngineSettings.setString("screenshot format", "General", screenshotFormatString); + if (screenshotFormatString != Settings::Manager::getString("screenshot format", "General")) + Settings::Manager::setString("screenshot format", "General", screenshotFormatString); } // Testing @@ -407,15 +405,15 @@ void Launcher::AdvancedPage::saveSettings() void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) { - if (mEngineSettings.getBool(setting, group)) + if (Settings::Manager::getBool(setting, group)) checkbox->setCheckState(Qt::Checked); } void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) { bool cValue = checkbox->checkState(); - if (cValue != mEngineSettings.getBool(setting, group)) - mEngineSettings.setBool(setting, group, cValue); + if (cValue != Settings::Manager::getBool(setting, group)) + Settings::Manager::setBool(setting, group, cValue); } void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames) diff --git a/apps/launcher/advancedpage.hpp b/apps/launcher/advancedpage.hpp index 93b818dbb..9685dcefe 100644 --- a/apps/launcher/advancedpage.hpp +++ b/apps/launcher/advancedpage.hpp @@ -17,8 +17,7 @@ namespace Launcher Q_OBJECT public: - AdvancedPage(Config::GameSettings &gameSettings, - Settings::Manager &engineSettings, QWidget *parent = nullptr); + explicit AdvancedPage(Config::GameSettings &gameSettings, QWidget *parent = nullptr); bool loadSettings(); void saveSettings(); @@ -34,7 +33,6 @@ namespace Launcher private: Config::GameSettings &mGameSettings; - Settings::Manager &mEngineSettings; QCompleter mCellNameCompleter; QStringListModel mCellNameCompleterModel; diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index c6e74573c..3bfd90fde 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -32,9 +32,8 @@ QString getAspect(int x, int y) return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); } -Launcher::GraphicsPage::GraphicsPage(Settings::Manager &engineSettings, QWidget *parent) +Launcher::GraphicsPage::GraphicsPage(QWidget *parent) : QWidget(parent) - , mEngineSettings(engineSettings) { setObjectName ("GraphicsPage"); setupUi(this); @@ -93,26 +92,26 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; - if (mEngineSettings.getBool("vsync", "Video")) + if (Settings::Manager::getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); - if (mEngineSettings.getBool("fullscreen", "Video")) + if (Settings::Manager::getBool("fullscreen", "Video")) fullScreenCheckBox->setCheckState(Qt::Checked); - if (mEngineSettings.getBool("window border", "Video")) + if (Settings::Manager::getBool("window border", "Video")) windowBorderCheckBox->setCheckState(Qt::Checked); // aaValue is the actual value (0, 1, 2, 4, 8, 16) - int aaValue = mEngineSettings.getInt("antialiasing", "Video"); + int aaValue = Settings::Manager::getInt("antialiasing", "Video"); // aaIndex is the index into the allowed values in the pull down. int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue)); if (aaIndex != -1) antiAliasingComboBox->setCurrentIndex(aaIndex); - int width = mEngineSettings.getInt("resolution x", "Video"); - int height = mEngineSettings.getInt("resolution y", "Video"); + int width = Settings::Manager::getInt("resolution x", "Video"); + int height = Settings::Manager::getInt("resolution y", "Video"); QString resolution = QString::number(width) + QString(" x ") + QString::number(height); - screenComboBox->setCurrentIndex(mEngineSettings.getInt("screen", "Video")); + screenComboBox->setCurrentIndex(Settings::Manager::getInt("screen", "Video")); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); @@ -125,40 +124,40 @@ bool Launcher::GraphicsPage::loadSettings() customHeightSpinBox->setValue(height); } - float fpsLimit = mEngineSettings.getFloat("framerate limit", "Video"); + float fpsLimit = Settings::Manager::getFloat("framerate limit", "Video"); if (fpsLimit != 0) { framerateLimitCheckBox->setCheckState(Qt::Checked); framerateLimitSpinBox->setValue(fpsLimit); } - if (mEngineSettings.getBool("actor shadows", "Shadows")) + if (Settings::Manager::getBool("actor shadows", "Shadows")) actorShadowsCheckBox->setCheckState(Qt::Checked); - if (mEngineSettings.getBool("player shadows", "Shadows")) + if (Settings::Manager::getBool("player shadows", "Shadows")) playerShadowsCheckBox->setCheckState(Qt::Checked); - if (mEngineSettings.getBool("terrain shadows", "Shadows")) + if (Settings::Manager::getBool("terrain shadows", "Shadows")) terrainShadowsCheckBox->setCheckState(Qt::Checked); - if (mEngineSettings.getBool("object shadows", "Shadows")) + if (Settings::Manager::getBool("object shadows", "Shadows")) objectShadowsCheckBox->setCheckState(Qt::Checked); - if (mEngineSettings.getBool("enable indoor shadows", "Shadows")) + if (Settings::Manager::getBool("enable indoor shadows", "Shadows")) indoorShadowsCheckBox->setCheckState(Qt::Checked); shadowComputeSceneBoundsComboBox->setCurrentIndex( shadowComputeSceneBoundsComboBox->findText( - QString(tr(mEngineSettings.getString("compute scene bounds", "Shadows").c_str())))); + QString(tr(Settings::Manager::getString("compute scene bounds", "Shadows").c_str())))); - int shadowDistLimit = mEngineSettings.getInt("maximum shadow map distance", "Shadows"); + int shadowDistLimit = Settings::Manager::getInt("maximum shadow map distance", "Shadows"); if (shadowDistLimit > 0) { shadowDistanceCheckBox->setCheckState(Qt::Checked); shadowDistanceSpinBox->setValue(shadowDistLimit); } - float shadowFadeStart = mEngineSettings.getFloat("shadow fade start", "Shadows"); + float shadowFadeStart = Settings::Manager::getFloat("shadow fade start", "Shadows"); if (shadowFadeStart != 0) fadeStartSpinBox->setValue(shadowFadeStart); - int shadowRes = mEngineSettings.getInt("shadow map resolution", "Shadows"); + int shadowRes = Settings::Manager::getInt("shadow map resolution", "Shadows"); int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes)); if (shadowResIndex != -1) shadowResolutionComboBox->setCurrentIndex(shadowResIndex); @@ -171,20 +170,20 @@ void Launcher::GraphicsPage::saveSettings() // Ensure we only set the new settings if they changed. This is to avoid cluttering the // user settings file (which by definition should only contain settings the user has touched) bool cVSync = vSyncCheckBox->checkState(); - if (cVSync != mEngineSettings.getBool("vsync", "Video")) - mEngineSettings.setBool("vsync", "Video", cVSync); + if (cVSync != Settings::Manager::getBool("vsync", "Video")) + Settings::Manager::setBool("vsync", "Video", cVSync); bool cFullScreen = fullScreenCheckBox->checkState(); - if (cFullScreen != mEngineSettings.getBool("fullscreen", "Video")) - mEngineSettings.setBool("fullscreen", "Video", cFullScreen); + if (cFullScreen != Settings::Manager::getBool("fullscreen", "Video")) + Settings::Manager::setBool("fullscreen", "Video", cFullScreen); bool cWindowBorder = windowBorderCheckBox->checkState(); - if (cWindowBorder != mEngineSettings.getBool("window border", "Video")) - mEngineSettings.setBool("window border", "Video", cWindowBorder); + if (cWindowBorder != Settings::Manager::getBool("window border", "Video")) + Settings::Manager::setBool("window border", "Video", cWindowBorder); int cAAValue = antiAliasingComboBox->currentText().toInt(); - if (cAAValue != mEngineSettings.getInt("antialiasing", "Video")) - mEngineSettings.setInt("antialiasing", "Video", cAAValue); + if (cAAValue != Settings::Manager::getInt("antialiasing", "Video")) + Settings::Manager::setInt("antialiasing", "Video", cAAValue); int cWidth = 0; int cHeight = 0; @@ -199,33 +198,33 @@ void Launcher::GraphicsPage::saveSettings() cHeight = customHeightSpinBox->value(); } - if (cWidth != mEngineSettings.getInt("resolution x", "Video")) - mEngineSettings.setInt("resolution x", "Video", cWidth); + if (cWidth != Settings::Manager::getInt("resolution x", "Video")) + Settings::Manager::setInt("resolution x", "Video", cWidth); - if (cHeight != mEngineSettings.getInt("resolution y", "Video")) - mEngineSettings.setInt("resolution y", "Video", cHeight); + if (cHeight != Settings::Manager::getInt("resolution y", "Video")) + Settings::Manager::setInt("resolution y", "Video", cHeight); int cScreen = screenComboBox->currentIndex(); - if (cScreen != mEngineSettings.getInt("screen", "Video")) - mEngineSettings.setInt("screen", "Video", cScreen); + if (cScreen != Settings::Manager::getInt("screen", "Video")) + Settings::Manager::setInt("screen", "Video", cScreen); if (framerateLimitCheckBox->checkState() != Qt::Unchecked) { float cFpsLimit = framerateLimitSpinBox->value(); - if (cFpsLimit != mEngineSettings.getFloat("framerate limit", "Video")) - mEngineSettings.setFloat("framerate limit", "Video", cFpsLimit); + if (cFpsLimit != Settings::Manager::getFloat("framerate limit", "Video")) + Settings::Manager::setFloat("framerate limit", "Video", cFpsLimit); } - else if (mEngineSettings.getFloat("framerate limit", "Video") != 0) + else if (Settings::Manager::getFloat("framerate limit", "Video") != 0) { - mEngineSettings.setFloat("framerate limit", "Video", 0); + Settings::Manager::setFloat("framerate limit", "Video", 0); } int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0; - if (mEngineSettings.getInt("maximum shadow map distance", "Shadows") != cShadowDist) - mEngineSettings.setInt("maximum shadow map distance", "Shadows", cShadowDist); + if (Settings::Manager::getInt("maximum shadow map distance", "Shadows") != cShadowDist) + Settings::Manager::setInt("maximum shadow map distance", "Shadows", cShadowDist); float cFadeStart = fadeStartSpinBox->value(); - if (cShadowDist > 0 && mEngineSettings.getFloat("shadow fade start", "Shadows") != cFadeStart) - mEngineSettings.setFloat("shadow fade start", "Shadows", cFadeStart); + if (cShadowDist > 0 && Settings::Manager::getFloat("shadow fade start", "Shadows") != cFadeStart) + Settings::Manager::setFloat("shadow fade start", "Shadows", cFadeStart); bool cActorShadows = actorShadowsCheckBox->checkState(); bool cObjectShadows = objectShadowsCheckBox->checkState(); @@ -233,42 +232,42 @@ void Launcher::GraphicsPage::saveSettings() bool cPlayerShadows = playerShadowsCheckBox->checkState(); if (cActorShadows || cObjectShadows || cTerrainShadows || cPlayerShadows) { - if (!mEngineSettings.getBool("enable shadows", "Shadows")) - mEngineSettings.setBool("enable shadows", "Shadows", true); - if (mEngineSettings.getBool("actor shadows", "Shadows") != cActorShadows) - mEngineSettings.setBool("actor shadows", "Shadows", cActorShadows); - if (mEngineSettings.getBool("player shadows", "Shadows") != cPlayerShadows) - mEngineSettings.setBool("player shadows", "Shadows", cPlayerShadows); - if (mEngineSettings.getBool("object shadows", "Shadows") != cObjectShadows) - mEngineSettings.setBool("object shadows", "Shadows", cObjectShadows); - if (mEngineSettings.getBool("terrain shadows", "Shadows") != cTerrainShadows) - mEngineSettings.setBool("terrain shadows", "Shadows", cTerrainShadows); + if (!Settings::Manager::getBool("enable shadows", "Shadows")) + Settings::Manager::setBool("enable shadows", "Shadows", true); + if (Settings::Manager::getBool("actor shadows", "Shadows") != cActorShadows) + Settings::Manager::setBool("actor shadows", "Shadows", cActorShadows); + if (Settings::Manager::getBool("player shadows", "Shadows") != cPlayerShadows) + Settings::Manager::setBool("player shadows", "Shadows", cPlayerShadows); + if (Settings::Manager::getBool("object shadows", "Shadows") != cObjectShadows) + Settings::Manager::setBool("object shadows", "Shadows", cObjectShadows); + if (Settings::Manager::getBool("terrain shadows", "Shadows") != cTerrainShadows) + Settings::Manager::setBool("terrain shadows", "Shadows", cTerrainShadows); } else { - if (mEngineSettings.getBool("enable shadows", "Shadows")) - mEngineSettings.setBool("enable shadows", "Shadows", false); - if (mEngineSettings.getBool("actor shadows", "Shadows")) - mEngineSettings.setBool("actor shadows", "Shadows", false); - if (mEngineSettings.getBool("player shadows", "Shadows")) - mEngineSettings.setBool("player shadows", "Shadows", false); - if (mEngineSettings.getBool("object shadows", "Shadows")) - mEngineSettings.setBool("object shadows", "Shadows", false); - if (mEngineSettings.getBool("terrain shadows", "Shadows")) - mEngineSettings.setBool("terrain shadows", "Shadows", false); + if (Settings::Manager::getBool("enable shadows", "Shadows")) + Settings::Manager::setBool("enable shadows", "Shadows", false); + if (Settings::Manager::getBool("actor shadows", "Shadows")) + Settings::Manager::setBool("actor shadows", "Shadows", false); + if (Settings::Manager::getBool("player shadows", "Shadows")) + Settings::Manager::setBool("player shadows", "Shadows", false); + if (Settings::Manager::getBool("object shadows", "Shadows")) + Settings::Manager::setBool("object shadows", "Shadows", false); + if (Settings::Manager::getBool("terrain shadows", "Shadows")) + Settings::Manager::setBool("terrain shadows", "Shadows", false); } bool cIndoorShadows = indoorShadowsCheckBox->checkState(); - if (mEngineSettings.getBool("enable indoor shadows", "Shadows") != cIndoorShadows) - mEngineSettings.setBool("enable indoor shadows", "Shadows", cIndoorShadows); + if (Settings::Manager::getBool("enable indoor shadows", "Shadows") != cIndoorShadows) + Settings::Manager::setBool("enable indoor shadows", "Shadows", cIndoorShadows); int cShadowRes = shadowResolutionComboBox->currentText().toInt(); - if (cShadowRes != mEngineSettings.getInt("shadow map resolution", "Shadows")) - mEngineSettings.setInt("shadow map resolution", "Shadows", cShadowRes); + if (cShadowRes != Settings::Manager::getInt("shadow map resolution", "Shadows")) + Settings::Manager::setInt("shadow map resolution", "Shadows", cShadowRes); auto cComputeSceneBounds = shadowComputeSceneBoundsComboBox->currentText().toStdString(); - if (cComputeSceneBounds != mEngineSettings.getString("compute scene bounds", "Shadows")) - mEngineSettings.setString("compute scene bounds", "Shadows", cComputeSceneBounds); + if (cComputeSceneBounds != Settings::Manager::getString("compute scene bounds", "Shadows")) + Settings::Manager::setString("compute scene bounds", "Shadows", cComputeSceneBounds); } QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 7801e6475..a6754ccb0 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -18,7 +18,7 @@ namespace Launcher Q_OBJECT public: - GraphicsPage(Settings::Manager &engineSettings, QWidget *parent = nullptr); + explicit GraphicsPage(QWidget *parent = nullptr); void saveSettings(); bool loadSettings(); @@ -33,8 +33,6 @@ namespace Launcher void slotShadowDistLimitToggled(bool checked); private: - Settings::Manager &mEngineSettings; - QVector mResolutionsPerScreen; static QStringList getAvailableResolutions(int screen); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 692415309..fa61b5fa8 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -123,9 +123,9 @@ void Launcher::MainDialog::createPages() mPlayPage = new PlayPage(this); mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); - mGraphicsPage = new GraphicsPage(mEngineSettings, this); + mGraphicsPage = new GraphicsPage(this); mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this); - mAdvancedPage = new AdvancedPage(mGameSettings, mEngineSettings, this); + mAdvancedPage = new AdvancedPage(mGameSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage mPlayPage->setProfilesModel(mDataFilesPage->profilesModel()); From a939cb669256b49efb3381edfdc9494a283f0b53 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 9 May 2021 14:10:35 +0400 Subject: [PATCH 023/101] Skip hidden nodes for ObjectPaging --- apps/openmw/mwrender/objectpaging.cpp | 29 ++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 064d3aa35..c36ceefe2 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -105,6 +105,7 @@ namespace MWRender bool mOptimizeBillboards = true; float mSqrDistance = 0.f; osg::Vec3f mViewVector; + osg::Node::NodeMask mCopyMask = ~0u; mutable std::vector mNodePath; void copy(const osg::Node* toCopy, osg::Group* attachTo) @@ -121,6 +122,9 @@ namespace MWRender osg::Node* operator() (const osg::Node* node) const override { + if (!(node->getNodeMask() & mCopyMask)) + return nullptr; + if (const osg::Drawable* d = node->asDrawable()) return operator()(d); @@ -224,6 +228,9 @@ namespace MWRender } osg::Drawable* operator() (const osg::Drawable* drawable) const override { + if (!(drawable->getNodeMask() & mCopyMask)) + return nullptr; + if (dynamic_cast(drawable)) return nullptr; @@ -261,9 +268,10 @@ namespace MWRender class AnalyzeVisitor : public osg::NodeVisitor { public: - AnalyzeVisitor() + AnalyzeVisitor(osg::Node::NodeMask analyzeMask) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mCurrentStateSet(nullptr) {} + , mCurrentStateSet(nullptr) + , mAnalyzeMask(analyzeMask) {} typedef std::unordered_map StateSetCounter; struct Result @@ -274,12 +282,18 @@ namespace MWRender void apply(osg::Node& node) override { + if (!(node.getNodeMask() & mAnalyzeMask)) + return; + if (node.getStateSet()) mCurrentStateSet = node.getStateSet(); traverse(node); } void apply(osg::Geometry& geom) override { + if (!(geom.getNodeMask() & mAnalyzeMask)) + return; + if (osg::Array* array = geom.getVertexArray()) mResult.mNumVerts += array->getNumElements(); @@ -313,6 +327,7 @@ namespace MWRender Result mResult; osg::StateSet* mCurrentStateSet; StateSetCounter mGlobalStateSetCounter; + osg::Node::NodeMask mAnalyzeMask; }; class DebugVisitor : public osg::NodeVisitor @@ -438,7 +453,14 @@ namespace MWRender typedef std::map, InstanceList> NodeMap; NodeMap nodes; osg::ref_ptr refnumSet = activeGrid ? new RefnumSet : nullptr; - AnalyzeVisitor analyzeVisitor; + + // Mask_UpdateVisitor is used in such cases in NIF loader: + // 1. For collision nodes, which is not supposed to be rendered. + // 2. For nodes masked via Flag_Hidden (VisController can change this flag value at runtime). + // Since ObjectPaging does not handle VisController, we can just ignore both types of nodes. + constexpr auto copyMask = ~Mask_UpdateVisitor; + + AnalyzeVisitor analyzeVisitor(copyMask); float minSize = mMinSize; if (mMinSizeMergeFactor) minSize *= mMinSizeMergeFactor; @@ -525,6 +547,7 @@ namespace MWRender osg::ref_ptr templateRefs = new Resource::TemplateMultiRef; osgUtil::StateToCompile stateToCompile(0, nullptr); CopyOp copyop; + copyop.mCopyMask = copyMask; for (const auto& pair : nodes) { const osg::Node* cnode = pair.first; From 132fedf2909a209afc04281b1a328d279e1ea58b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 9 May 2021 15:43:13 +0400 Subject: [PATCH 024/101] Analyze only used LOD levels in ObjectPaging --- apps/openmw/mwrender/objectpaging.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index c36ceefe2..4217c4714 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -271,6 +271,7 @@ namespace MWRender AnalyzeVisitor(osg::Node::NodeMask analyzeMask) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mCurrentStateSet(nullptr) + , mCurrentDistance(0.f) , mAnalyzeMask(analyzeMask) {} typedef std::unordered_map StateSetCounter; @@ -287,6 +288,22 @@ namespace MWRender if (node.getStateSet()) mCurrentStateSet = node.getStateSet(); + + if (osg::Switch* sw = node.asSwitch()) + { + for (unsigned int i=0; igetNumChildren(); ++i) + if (sw->getValue(i)) + traverse(*sw->getChild(i)); + return; + } + if (osg::LOD* lod = dynamic_cast(&node)) + { + for (unsigned int i=0; igetNumChildren(); ++i) + if (lod->getMinRange(i) * lod->getMinRange(i) <= mCurrentDistance && mCurrentDistance < lod->getMaxRange(i) * lod->getMaxRange(i)) + traverse(*lod->getChild(i)); + return; + } + traverse(node); } void apply(osg::Geometry& geom) override @@ -327,6 +344,7 @@ namespace MWRender Result mResult; osg::StateSet* mCurrentStateSet; StateSetCounter mGlobalStateSetCounter; + float mCurrentDistance; osg::Node::NodeMask mAnalyzeMask; }; @@ -530,6 +548,7 @@ namespace MWRender continue; } + analyzeVisitor.mCurrentDistance = dSqr; auto emplaced = nodes.emplace(cnode, InstanceList()); if (emplaced.second) { From b806445a361214d604307baab4da2eea89515e3c Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 7 May 2021 18:14:44 +0200 Subject: [PATCH 025/101] Use existing min implementation --- components/esm/esmcommon.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index bb4069d26..749e9a85d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_ESM_COMMON_H #define OPENMW_ESM_COMMON_H +#include #include #include #include @@ -110,8 +111,7 @@ struct FIXED_STRING<4> : public FIXED_STRING_BASE void assign(const std::string& value) { intval = 0; - std::memcpy(data, value.data(), (value.size() < 4)? value.size(): 4); - + std::memcpy(data, value.data(), std::min(value.size(), sizeof(data))); } char const* ro_data() const { return data; } From ffd84502f95fcd578c4415391fef8592ccec898c Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 9 May 2021 19:07:15 +0200 Subject: [PATCH 026/101] Remove unimplemented method declaration --- apps/openmw/mwmechanics/aiwander.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index db8701c74..f8506ff59 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -126,7 +126,6 @@ namespace MWMechanics short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); - 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); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); From c5aa3d4f77f16c9c1954ecc2a36f32f281745b8c Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 9 May 2021 19:55:27 +0200 Subject: [PATCH 027/101] Don't stop and turn to the player while sneaking or jumping --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/actors.cpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 5 +++-- apps/openmw/mwmechanics/aiwander.cpp | 15 +++++++++------ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba8081dae..856e10438 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ Bug #5975: NIF controllers from sheath meshes are used Bug #5991: Activate should always be allowed for inventory items Bug #5995: NiUVController doesn't calculate the UV offset properly + Bug #6016: Greeting interrupts Fargoth's sneak-walk Feature #390: 3rd person look "over the shoulder" Feature #832: OpenMW-CS: Handle deleted references Feature #1536: Show more information about level on menu diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 95633bd00..4629ad2d3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -589,7 +589,8 @@ namespace MWMechanics { greetingTimer++; - if (greetingTimer <= GREETING_SHOULD_END || MWBase::Environment::get().getSoundManager()->sayActive(actor)) + if (!stats.getMovementFlag(CreatureStats::Flag_ForceJump) && !stats.getMovementFlag(CreatureStats::Flag_ForceSneak) + && (greetingTimer <= GREETING_SHOULD_END || MWBase::Environment::get().getSoundManager()->sayActive(actor))) turnActorToFacePlayer(actor, actorState, dir); if (greetingTimer >= GREETING_COOLDOWN) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b2a506ca6..8e5372c46 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -52,14 +52,15 @@ namespace MWMechanics bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager(); + auto& stats = actor.getClass().getCreatureStats(actor); - if (mechMgr->isTurningToPlayer(actor) || mechMgr->getGreetingState(actor) == Greet_InProgress) + if (!stats.getMovementFlag(CreatureStats::Flag_ForceJump) && !stats.getMovementFlag(CreatureStats::Flag_ForceSneak) + && (mechMgr->isTurningToPlayer(actor) || mechMgr->getGreetingState(actor) == Greet_InProgress)) return false; const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); const osg::Vec3f targetPos(mX, mY, mZ); - auto& stats = actor.getClass().getCreatureStats(actor); stats.setMovementFlag(CreatureStats::Flag_Run, false); stats.setDrawState(DrawState_Nothing); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 01088d967..0e424b2f8 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -209,14 +209,17 @@ namespace MWMechanics storage.setState(AiWanderStorage::Wander_Walking); } - GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor); - if (greetingState == Greet_InProgress) + if(!cStats.getMovementFlag(CreatureStats::Flag_ForceJump) && !cStats.getMovementFlag(CreatureStats::Flag_ForceSneak)) { - if (storage.mState == AiWanderStorage::Wander_Walking) + GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor); + if (greetingState == Greet_InProgress) { - stopMovement(actor); - mObstacleCheck.clear(); - storage.setState(AiWanderStorage::Wander_IdleNow); + if (storage.mState == AiWanderStorage::Wander_Walking) + { + stopMovement(actor); + mObstacleCheck.clear(); + storage.setState(AiWanderStorage::Wander_IdleNow); + } } } From 0d737a3501f3f7e97be5ae906235597d69fbc982 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 9 May 2021 21:00:49 +0100 Subject: [PATCH 028/101] Create defaults.bin at configure time --- CMakeLists.txt | 8 ++++---- apps/openmw/CMakeLists.txt | 2 +- cmake/OpenMWMacros.cmake | 12 ++++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 104140107..b97657ffd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,8 +438,8 @@ endif (APPLE) # Other files -configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg - "${OpenMW_BINARY_DIR}" "settings-default.cfg") +pack_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg + "${OpenMW_BINARY_DIR}" "defaults.bin") configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.appdata.xml "${OpenMW_BINARY_DIR}" "openmw.appdata.xml") @@ -808,7 +808,7 @@ elseif(NOT APPLE) INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/LICENSE" DESTINATION "." RENAME "LICENSE.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/mygui/DejaVuFontLicense.txt" DESTINATION ".") - INSTALL(FILES "${INSTALL_SOURCE}/settings-default.cfg" DESTINATION ".") + INSTALL(FILES "${INSTALL_SOURCE}/defaults.bin" DESTINATION ".") INSTALL(FILES "${INSTALL_SOURCE}/gamecontrollerdb.txt" DESTINATION ".") INSTALL(DIRECTORY "${INSTALL_SOURCE}/resources" DESTINATION ".") @@ -916,7 +916,7 @@ elseif(NOT APPLE) ENDIF(BUILD_OPENCS) # Install global configuration files - INSTALL(FILES "${INSTALL_SOURCE}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${INSTALL_SOURCE}/defaults.bin" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${INSTALL_SOURCE}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") INSTALL(FILES "${INSTALL_SOURCE}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${INSTALL_SOURCE}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5e5bb8a9f..3fb762d30 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -198,7 +198,7 @@ if(APPLE) add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files) - configure_file("${OpenMW_BINARY_DIR}/settings-default.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY) + configure_file("${OpenMW_BINARY_DIR}/defaults.bin" ${BUNDLE_RESOURCES_DIR} COPYONLY) configure_file("${OpenMW_BINARY_DIR}/openmw.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY) configure_file("${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" ${BUNDLE_RESOURCES_DIR} COPYONLY) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 2408cae2b..1621a08cf 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -199,6 +199,18 @@ macro (configure_resource_file source_path destination_dir_base dest_path_relati endif (multi_config) endmacro (configure_resource_file) +macro (pack_resource_file source_path destination_dir_base dest_path_relative) + get_generator_is_multi_config(multi_config) + if (multi_config) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + execute_process(COMMAND ${CMAKE_COMMAND} "-DINPUT_FILE=${source_path}" "-DOUTPUT_FILE=${destination_dir_base}/${cfgtype}/${dest_path_relative}" -P "${CMAKE_SOURCE_DIR}/cmake/base64.cmake") + endforeach(cfgtype) + else (multi_config) + execute_process(COMMAND ${CMAKE_COMMAND} "-DINPUT_FILE=${source_path}" "-DOUTPUT_FILE=${destination_dir_base}/${dest_path_relative}" -P "${CMAKE_SOURCE_DIR}/cmake/base64.cmake") + endif (multi_config) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${source_path}") +endmacro (pack_resource_file) + macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) foreach (f ${files}) get_filename_component(filename ${f} NAME) From 92325976e94c0440181bbbe1b365404dfa8d1d3b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 9 May 2021 21:13:34 +0100 Subject: [PATCH 029/101] Update documentation to refer to defaults.bin --- apps/launcher/maindialog.cpp | 4 ++-- apps/openmw/engine.cpp | 2 +- components/settings/parser.cpp | 2 +- components/settings/settings.cpp | 2 +- docs/source/reference/modding/settings/index.rst | 14 ++++++++++++-- files/settings-default.cfg | 7 ++++--- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 692415309..9d497e879 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -436,7 +436,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() // Something's very wrong if we can't find the file at all. else { cfgError(tr("Error reading OpenMW configuration file"), - tr("
Could not find settings-default.cfg

\ + tr("
Could not find defaults.bin

\ The problem may be due to an incomplete installation of OpenMW.
\ Reinstalling OpenMW may resolve the problem.")); return false; @@ -447,7 +447,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() mEngineSettings.loadDefault(defaultPath); } catch (std::exception& e) { - std::string msg = std::string("
Error reading settings-default.cfg

") + e.what(); + std::string msg = std::string("
Error reading defaults.bin

") + e.what(); cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); return false; } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d7c315323..b52bfc7ef 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -487,7 +487,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) else if (boost::filesystem::exists(globaldefault)) settings.loadDefault(globaldefault); else - throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); + throw std::runtime_error ("No default settings file found! Make sure the file \"defaults.bin\" was properly installed."); // load user settings if they exist const std::string settingspath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index 9693bf511..72ff3aac4 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -255,7 +255,7 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::string& file, con ostream << "# This is the OpenMW user 'settings.cfg' file. This file only contains" << std::endl; ostream << "# explicitly changed settings. If you would like to revert a setting" << std::endl; ostream << "# to its default, simply remove it from this file. For available" << std::endl; - ostream << "# settings, see the file 'settings-default.cfg' or the documentation at:" << std::endl; + ostream << "# settings, see the file 'files/settings-default.cfg' in our source repo or the documentation at:" << std::endl; ostream << "#" << std::endl; ostream << "# https://openmw.readthedocs.io/en/master/reference/modding/settings/index.html" << std::endl; } diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index b29dadcdc..52dbb6e21 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -49,7 +49,7 @@ std::string Manager::getString(const std::string &setting, const std::string &ca return it->second; throw std::runtime_error(std::string("Trying to retrieve a non-existing setting: ") + setting - + ".\nMake sure the settings-default.cfg file was properly installed."); + + ".\nMake sure the defaults.bin file was properly installed."); } float Manager::getFloat (const std::string& setting, const std::string& category) diff --git a/docs/source/reference/modding/settings/index.rst b/docs/source/reference/modding/settings/index.rst index 220ee88c4..e9607fd9d 100644 --- a/docs/source/reference/modding/settings/index.rst +++ b/docs/source/reference/modding/settings/index.rst @@ -8,6 +8,14 @@ If you are familiar with ``.ini`` tweaks in Morrowind or the other games, this w All settings described in this section are changed in ``settings.cfg``, located in your OpenMW user directory. See :doc:`../paths` for this location. +When creating a new game based on the OpenMW engine, it may be desirable to change the default settings - the defaults are chosen for compatibility with Morrowind. +This can be done by editing ``defaults.bin`` in the OpenMW installation directory without rebuilding OpenMW itself. +If you're using a custom fork of OpenMW, ``files/settings-default.cfg`` in the source repository should be edited instead. +To edit ``defaults.bin``, base64 decode it, make any changes, and then base64 encode it again. + +If you feel a need to edit the default settings for any other reason than when creating a new OpenMW-based game, you should not. +We may be able to accommodate your desired workflow some other way if you make a feature request. + Changing Settings ################# @@ -25,8 +33,10 @@ Changing Settings Then to the line above, type ``[GUI]``, as the tooltip delay setting comes from the "GUI Settings" section. Although this guide attempts to be comprehensive and up to date, -you will always be able to find the full list of settings available and their default values in ``settings-default.cfg`` -in your main OpenMW installation directory. +you will always be able to find the full list of settings available and their default values in ``settings-default.cfg``, +available in the ``files`` directory of our source repo, or by base64 decoding ``defaults.bin`` in your main OpenMW installation directory. +This has changed compared to previous versions of OpenMW as more users were confused by the existence of a file they weren't supposed to edit +than were helped by the existence of a file listing settings they could edit in a different file. The ranges included with each setting are the physically possible ranges, not recommendations. .. warning:: diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ea678c70f..d94c43b01 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,6 +1,7 @@ -# WARNING: If this file is named settings-default.cfg, then editing -# this file might have no effect, as these settings may be overwritten -# by your user settings.cfg file (see documentation for its location). +# WARNING: If this file is named settings-default.cfg or was generated +# from defaults.bin, then editing this file might have no effect, as +# these settings may be overwritten by your user settings.cfg file +# (see documentation for its location). # # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the From 09f39b29f0019a90219549dfa2c0af4cc0a66e0f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 9 May 2021 21:14:06 +0100 Subject: [PATCH 030/101] Load defaults.bin instead of settings-default.cfg. Do not decode yet. --- apps/launcher/maindialog.cpp | 6 +++--- apps/openmw/engine.cpp | 4 ++-- components/settings/parser.cpp | 2 +- components/settings/parser.hpp | 2 +- components/settings/settings.cpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 9d497e879..0a7d495ab 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -424,11 +424,11 @@ bool Launcher::MainDialog::setupGraphicsSettings() mEngineSettings.clear(); // Create the settings manager and load default settings file - const std::string localDefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); - const std::string globalDefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); + const std::string localDefault = (mCfgMgr.getLocalPath() / "defaults.bin").string(); + const std::string globalDefault = (mCfgMgr.getGlobalPath() / "defaults.bin").string(); std::string defaultPath; - // Prefer the settings-default.cfg in the current directory. + // Prefer the defaults.bin in the current directory. if (boost::filesystem::exists(localDefault)) defaultPath = localDefault; else if (boost::filesystem::exists(globalDefault)) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b52bfc7ef..b227ae04e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -478,8 +478,8 @@ void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) std::string OMW::Engine::loadSettings (Settings::Manager & settings) { // Create the settings manager and load default settings file - const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); - const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); + const std::string localdefault = (mCfgMgr.getLocalPath() / "defaults.bin").string(); + const std::string globaldefault = (mCfgMgr.getGlobalPath() / "defaults.bin").string(); // prefer local if (boost::filesystem::exists(localdefault)) diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index 72ff3aac4..ee14eb5de 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -7,7 +7,7 @@ #include -void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, CategorySettingValueMap& settings) +void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, CategorySettingValueMap& settings, bool base64Encoded) { mFile = file; boost::filesystem::ifstream stream; diff --git a/components/settings/parser.hpp b/components/settings/parser.hpp index 449e54223..69e9cdaa4 100644 --- a/components/settings/parser.hpp +++ b/components/settings/parser.hpp @@ -10,7 +10,7 @@ namespace Settings class SettingsFileParser { public: - void loadSettingsFile(const std::string& file, CategorySettingValueMap& settings); + void loadSettingsFile(const std::string& file, CategorySettingValueMap& settings, bool base64encoded = false); void saveSettingsFile(const std::string& file, const CategorySettingValueMap& settings); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 52dbb6e21..13501ac8c 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -22,7 +22,7 @@ void Manager::clear() void Manager::loadDefault(const std::string &file) { SettingsFileParser parser; - parser.loadSettingsFile(file, mDefaultSettings); + parser.loadSettingsFile(file, mDefaultSettings, true); } void Manager::loadUser(const std::string &file) From 6492e9522a301d20e1dc1672ec3dd31b890bf75a Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 10 May 2021 00:16:24 +0200 Subject: [PATCH 031/101] Run benchmarks on gitlab CI --- .gitlab-ci.yml | 1 + CI/before_script.linux.sh | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 20b233c66..7be8fc997 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,6 +25,7 @@ stages: - cmake --build . -- -j $(nproc) - cmake --install . - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw_test_suite; fi + - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi - ccache -s artifacts: paths: diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index 5f74b4714..17292e4e9 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -4,9 +4,14 @@ set -xeo pipefail free -m +BUILD_UNITTESTS=OFF +BUILD_BENCHMARKS=OFF + if [[ "${BUILD_TESTS_ONLY}" ]]; then export GOOGLETEST_DIR="${PWD}/googletest/build/install" env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh + BUILD_UNITTESTS=ON + BUILD_BENCHMARKS=ON fi declare -a CMAKE_CONF_OPTS=( @@ -43,7 +48,8 @@ if [[ "${BUILD_TESTS_ONLY}" ]]; then -DBUILD_ESSIMPORTER=OFF \ -DBUILD_OPENCS=OFF \ -DBUILD_WIZARD=OFF \ - -DBUILD_UNITTESTS=ON \ + -DBUILD_UNITTESTS=${BUILD_UNITTESTS} \ + -DBUILD_BENCHMARKS=${BUILD_BENCHMARKS} \ -DGTEST_ROOT="${GOOGLETEST_DIR}" \ -DGMOCK_ROOT="${GOOGLETEST_DIR}" \ .. From de37ca8e2c85703fb6b8b5763a73fd9b16a79dfb Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 9 May 2021 13:20:53 +0200 Subject: [PATCH 032/101] Catch exceptions in VideoThread --- CHANGELOG.md | 1 + extern/osg-ffmpeg-videoplayer/videostate.cpp | 57 +++++++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 856e10438..154f8639a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ Bug #5975: NIF controllers from sheath meshes are used Bug #5991: Activate should always be allowed for inventory items Bug #5995: NiUVController doesn't calculate the UV offset properly + Bug #6007: Crash when ending cutscene is playing Bug #6016: Greeting interrupts Fargoth's sneak-walk Feature #390: 3rd person look "over the shoulder" Feature #832: OpenMW-CS: Handle deleted references diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index c153aa14c..d6c99051e 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -409,43 +409,50 @@ public: pFrame = av_frame_alloc(); - while(self->videoq.get(packet, self) >= 0) + try { - if(packet->data == flush_pkt.data) + while(self->videoq.get(packet, self) >= 0) { - avcodec_flush_buffers(self->video_ctx); + if(packet->data == flush_pkt.data) + { + avcodec_flush_buffers(self->video_ctx); - self->pictq_mutex.lock(); - self->pictq_size = 0; - self->pictq_rindex = 0; - self->pictq_windex = 0; - self->pictq_mutex.unlock(); + self->pictq_mutex.lock(); + self->pictq_size = 0; + self->pictq_rindex = 0; + self->pictq_windex = 0; + self->pictq_mutex.unlock(); - self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); - continue; - } + self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); + continue; + } - // Decode video frame - int ret = avcodec_send_packet(self->video_ctx, packet); - // EAGAIN is not expected - if (ret < 0) - throw std::runtime_error("Error decoding video frame"); + // Decode video frame + int ret = avcodec_send_packet(self->video_ctx, packet); + // EAGAIN is not expected + if (ret < 0) + throw std::runtime_error("Error decoding video frame"); - while (!ret) - { - ret = avcodec_receive_frame(self->video_ctx, pFrame); - if (!ret) + while (!ret) { - double pts = pFrame->best_effort_timestamp; - pts *= av_q2d((*self->video_st)->time_base); + ret = avcodec_receive_frame(self->video_ctx, pFrame); + if (!ret) + { + double pts = pFrame->best_effort_timestamp; + pts *= av_q2d((*self->video_st)->time_base); - pts = self->synchronize_video(pFrame, pts); + pts = self->synchronize_video(pFrame, pts); - if(self->queue_picture(pFrame, pts) < 0) - break; + if(self->queue_picture(pFrame, pts) < 0) + break; + } } } } + catch(std::exception& e) + { + std::cerr << "An error occurred playing the video: " << e.what () << std::endl; + } av_packet_unref(packet); From 339d347aea7fe71642d75582214cbbe5eb51614f Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 10 May 2021 22:44:07 -0500 Subject: [PATCH 033/101] Fixing performance-faster-string-find issues This addresses the Clang Tidy check [performance-faster-string-find](https://clang.llvm.org/extra/clang-tidy/checks/performance-faster-string-find.html). --- apps/mwiniimporter/importer.cpp | 8 ++++---- apps/niftest/niftest.cpp | 2 +- apps/opencs/model/prefs/shortcutmanager.cpp | 6 +++--- apps/opencs/view/render/terraintexturemode.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- components/debug/gldebug.cpp | 2 +- components/fallback/validate.cpp | 2 +- components/resource/scenemanager.cpp | 2 +- components/widgets/imagebutton.cpp | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 23aea2deb..94b5cf7d0 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -686,12 +686,12 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::p continue; } - int comment_pos = line.find(";"); + int comment_pos = line.find(';'); if(comment_pos > 0) { line = line.substr(0,comment_pos); } - int pos = line.find("="); + int pos = line.find('='); if(pos < 1) { continue; } @@ -722,7 +722,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::p while (std::getline(file, line)) { // we cant say comment by only looking at first char anymore - int comment_pos = line.find("#"); + int comment_pos = line.find('#'); if(comment_pos > 0) { line = line.substr(0,comment_pos); } @@ -731,7 +731,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::p continue; } - int pos = line.find("="); + int pos = line.find('='); if(pos < 1) { continue; } diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index e9484d5f5..e403562d3 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -20,7 +20,7 @@ namespace bfs = boost::filesystem; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) { - std::string extension = filename.substr(filename.find_last_of(".")+1); + std::string extension = filename.substr(filename.find_last_of('.')+1); //Convert strings to lower case for comparison std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 781ad4de3..4c5f77900 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -178,7 +178,7 @@ namespace CSMPrefs { const int MaxKeys = 4; // A limitation of QKeySequence - size_t end = data.find(";"); + size_t end = data.find(';'); size_t size = std::min(end, data.size()); std::string value = data.substr(0, size); @@ -191,7 +191,7 @@ namespace CSMPrefs while (start < value.size()) { - end = data.find("+", start); + end = data.find('+', start); end = std::min(end, value.size()); std::string name = value.substr(start, end - start); @@ -243,7 +243,7 @@ namespace CSMPrefs void ShortcutManager::convertFromString(const std::string& data, int& modifier) const { - size_t start = data.find(";") + 1; + size_t start = data.find(';') + 1; start = std::min(start, data.size()); std::string name = data.substr(start); diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index fa46cf673..1519d3efd 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -332,7 +332,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); - std::size_t hashlocation = mBrushTexture.find("#"); + std::size_t hashlocation = mBrushTexture.find('#'); std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c0694e403..a821d0106 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -266,7 +266,7 @@ namespace MWGui std::map userStrings = focus->getUserStrings(); for (auto& userStringPair : userStrings) { - size_t underscorePos = userStringPair.first.find("_"); + size_t underscorePos = userStringPair.first.find('_'); if (underscorePos == std::string::npos) continue; std::string key = userStringPair.first.substr(0, underscorePos); diff --git a/components/debug/gldebug.cpp b/components/debug/gldebug.cpp index 37829a8c1..ccf49edd4 100644 --- a/components/debug/gldebug.cpp +++ b/components/debug/gldebug.cpp @@ -179,7 +179,7 @@ namespace Debug if (str.length() == 0) return true; - return str.find("OFF") == std::string::npos && str.find("0") == std::string::npos && str.find("NO") == std::string::npos; + return str.find("OFF") == std::string::npos && str.find('0') == std::string::npos && str.find("NO") == std::string::npos; } DebugGroup::DebugGroup(const std::string & message, GLuint id) diff --git a/components/fallback/validate.cpp b/components/fallback/validate.cpp index 982c709af..a482d40fa 100644 --- a/components/fallback/validate.cpp +++ b/components/fallback/validate.cpp @@ -12,7 +12,7 @@ void Fallback::validate(boost::any& v, std::vector const& tokens, F for (const auto& token : tokens) { std::string temp = Files::EscapeHashString::processString(token); - size_t sep = temp.find(","); + size_t sep = temp.find(','); if (sep < 1 || sep == temp.length() - 1 || sep == std::string::npos) throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index a3c751f7a..2e2fb9aa1 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -500,7 +500,7 @@ namespace Resource { std::string str(env); - if(str.find("OFF")!=std::string::npos || str.find("0")!= std::string::npos) options = 0; + if(str.find("OFF")!=std::string::npos || str.find('0')!= std::string::npos) options = 0; if(str.find("~FLATTEN_STATIC_TRANSFORMS")!=std::string::npos) options ^= Optimizer::FLATTEN_STATIC_TRANSFORMS; else if(str.find("FLATTEN_STATIC_TRANSFORMS")!=std::string::npos) options |= Optimizer::FLATTEN_STATIC_TRANSFORMS; diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 0d1f798da..bf2b1b24c 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -118,7 +118,7 @@ namespace Gui void ImageButton::setImage(const std::string &image) { - size_t extpos = image.find_last_of("."); + size_t extpos = image.find_last_of('.'); std::string imageNoExt = image.substr(0, extpos); std::string ext = image.substr(extpos); From ad6cc6e775df684a555d2c99fd2109cdaaeb9135 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 10 May 2021 23:04:37 -0500 Subject: [PATCH 034/101] Grouping settings on Advanced -> Visuals Since we'll be adding additional settings in the near future and the list is already getting very long, I figured I would group these like we do on the "Miscellaneous" tab. --- files/ui/advancedpage.ui | 474 +++++++++++++++++++++------------------ 1 file changed, 255 insertions(+), 219 deletions(-) diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 8c3dea4b3..645f8629f 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -272,238 +272,274 @@ - - - - - <html><head/><body><p>By default, the fog becomes thicker proportionally to your distance from the clipping plane set at the clipping distance, which causes distortion at the edges of the screen. -This setting makes the fog use the actual eye point distance (or so called Euclidean distance) to calculate the fog, which makes the fog look less artificial, especially if you have a wide FOV.</p></body></html> - - - Radial fog - - - - - - - <html><head/><body><p>Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark. -Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option. -Affected objects will use shaders. -</p></body></html> - - - Bump/reflect map local lighting - - - - - - - <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html> - - - Turn to movement direction - - - - - - - <html><head/><body><p>Load per-group KF-files and skeleton files from Animations folder</p></body></html> - - - Use additional animation sources - - - - - - - - - Lighting Method: - - - - - - - - legacy - - - - - shaders compatibility - - - - - shaders - - - - - - - - - - <html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html> - - - Distant land - - - - - - - <html><head/><body><p>Use object paging for active cells grid.</p></body></html> - - - Active grid object paging - - - - - - - - - Viewing distance - - - + + + true + + + + + 0 + 0 + 645 + 413 + + + - - - Cells - - - 0.000000000000000 - - - 0.500000000000000 + + + Animations + + + + + <html><head/><body><p>Use casting animations for magic items, just as for spells.</p></body></html> + + + Use magic item animation + + + + + + + <html><head/><body><p>Makes NPCs and player movement more smooth. Recommended to use with "turn to movement direction" enabled.</p></body></html> + + + Smooth movement + + + + + + + <html><head/><body><p>Load per-group KF-files and skeleton files from Animations folder</p></body></html> + + + Use additional animation sources + + + + + + + <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html> + + + Turn to movement direction + + + + + + + 20 + + + + + false + + + <html><head/><body><p>Render holstered weapons (with quivers and scabbards), requires modded assets.</p></body></html> + + + Weapon sheathing + + + + + + + false + + + <html><head/><body><p>Render holstered shield, requires modded assets.</p></body></html> + + + Shield sheathing + + + + + + - - - - - - <html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html> - - - Auto use terrain normal maps - - - - - - - <html><head/><body><p>If this option is enabled, specular maps are automatically recognized and used if they are named appropriately -(see 'specular map pattern', e.g. for a base texture foo.dds, -the specular map texture would have to be named foo_spec.dds). -If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file -(.osg file, not supported in .nif files). Affects objects.</p></body></html> - - - Auto use object specular maps - - - - - - - <html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html> - - - Auto use terrain specular maps - - - - - - - <html><head/><body><p>Makes NPCs and player movement more smooth. Recommended to use with "turn to movement direction" enabled.</p></body></html> - - - Smooth movement - - - - - - - <html><head/><body><p>Use casting animations for magic items, just as for spells.</p></body></html> - - - Use magic item animation - - - - - - - <html><head/><body><p>If this option is enabled, normal maps are automatically recognized and used if they are named appropriately -(see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds). -If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). Affects objects.</p></body></html> - - - Auto use object normal maps - - - - - - - 20 - - - - false - - - <html><head/><body><p>Render holstered weapons (with quivers and scabbards), requires modded assets.</p></body></html> - - - Weapon sheathing + + + Shaders + + + + + <html><head/><body><p>If this option is enabled, normal maps are automatically recognized and used if they are named appropriately + (see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds). + If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). Affects objects.</p></body></html> + + + Auto use object normal maps + + + + + + + <html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html> + + + Auto use terrain normal maps + + + + + + + <html><head/><body><p>If this option is enabled, specular maps are automatically recognized and used if they are named appropriately + (see 'specular map pattern', e.g. for a base texture foo.dds, + the specular map texture would have to be named foo_spec.dds). + If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file + (.osg file, not supported in .nif files). Affects objects.</p></body></html> + + + Auto use object specular maps + + + + + + + <html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html> + + + Auto use terrain specular maps + + + + + + + <html><head/><body><p>Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark. + Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option. + Affected objects will use shaders. + </p></body></html> + + + Bump/reflect map local lighting + + + + + + + <html><head/><body><p>By default, the fog becomes thicker proportionally to your distance from the clipping plane set at the clipping distance, which causes distortion at the edges of the screen. + This setting makes the fog use the actual eye point distance (or so called Euclidean distance) to calculate the fog, which makes the fog look less artificial, especially if you have a wide FOV.</p></body></html> + + + Radial fog + + + + + + + + + Lighting Method: + + + + + + + + legacy + + + + + shaders compatibility + + + + + shaders + + + + + + + - - - false - - - <html><head/><body><p>Render holstered shield, requires modded assets.</p></body></html> - - - Shield sheathing + + + Terrain + + + + + + + Viewing distance + + + + + + + Cells + + + 0.000000000000000 + + + 0.500000000000000 + + + + + + + + + <html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html> + + + Distant land + + + + + + + 20 + + + + + <html><head/><body><p>Use object paging for active cells grid.</p></body></html> + + + Active grid object paging + + + + + + - - - - - - - Qt::Vertical - - - - 20 - 40 - - - + + From 3e281f625debed685f97b789f7ea1035173b2468 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 10 May 2021 20:10:27 +0400 Subject: [PATCH 035/101] Return check for distance when we try to reuse data (bug #6026) --- components/terrain/viewdata.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index e4d043ffc..48e882ea7 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -141,9 +141,9 @@ ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPo vd = found->second; needsUpdate = false; - if (!(vd->suitableToUse(activeGrid) && (vd->getViewPoint()-viewPoint).length2() < mReuseDistance*mReuseDistance && vd->getWorldUpdateRevision() >= mWorldUpdateRevision)) + if (!vd->suitableToUse(activeGrid) || (vd->getViewPoint()-viewPoint).length2() >= mReuseDistance*mReuseDistance || vd->getWorldUpdateRevision() < mWorldUpdateRevision) { - float shortestDist = std::numeric_limits::max(); + float shortestDist = mReuseDistance*mReuseDistance; const ViewData* mostSuitableView = nullptr; for (const ViewData* other : mUsedViews) { @@ -157,11 +157,16 @@ ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPo } } } - if (mostSuitableView && mostSuitableView != vd) + if (mostSuitableView) { vd->copyFrom(*mostSuitableView); return vd; } + else + { + vd->setViewPoint(viewPoint); + needsUpdate = true; + } } if (!vd->suitableToUse(activeGrid)) { From 4d7e5245a3f1d7a6691f96bd6c6d15621861f427 Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 10 May 2021 00:17:11 +0200 Subject: [PATCH 036/101] Support benchmarks for windows Don't run the binary because gitlab can't execute it successfully due to unknown reason. --- .gitlab-ci.yml | 28 ++++++++++++++++++++++++++-- CI/before_script.msvc.sh | 10 ++++++++++ CMakeLists.txt | 4 ++++ apps/benchmarks/CMakeLists.txt | 7 ------- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7be8fc997..8d486ebf9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -170,6 +170,10 @@ variables: &cs-targets targets: "openmw-cs,bsatool,esmtool,niftest" package: "CS" +variables: &tests-targets + targets: "openmw_detournavigator_navmeshtilescache_benchmark" + package: "Tests" + .Windows_Ninja_Base: tags: - windows @@ -188,7 +192,7 @@ variables: &cs-targets - $time = (Get-Date -Format "HH:mm:ss") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N + - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N -b - cd MSVC2019_64_Ninja - .\ActivateMSVC.ps1 - cmake --build . --config $config --target ($targets.Split(',')) @@ -200,6 +204,7 @@ variables: &cs-targets Get-ChildItem -Recurse *.pdb | Remove-Item } - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*' + - if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } } after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log cache: @@ -263,6 +268,15 @@ Windows_Ninja_CS_RelWithDebInfo: <<: *cs-targets config: "RelWithDebInfo" +Windows_Ninja_Tests_RelWithDebInfo: + extends: .Windows_Ninja_Base + stage: build + variables: + <<: *tests-targets + config: "RelWithDebInfo" + # Gitlab can't successfully execute benchamark binary due to unknown reason + # executables: "openmw_detournavigator_navmeshtilescache_benchmark.exe" + .Windows_MSBuild_Base: tags: - windows @@ -280,7 +294,7 @@ Windows_Ninja_CS_RelWithDebInfo: - $time = (Get-Date -Format "HH:mm:ss") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V + - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b - cd MSVC2019_64 - cmake --build . --config $config --target ($targets.Split(',')) - cd $config @@ -291,6 +305,7 @@ Windows_Ninja_CS_RelWithDebInfo: Get-ChildItem -Recurse *.pdb | Remove-Item } - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*' + - if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } } after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log cache: @@ -354,6 +369,15 @@ Windows_MSBuild_CS_RelWithDebInfo: <<: *cs-targets config: "RelWithDebInfo" +Windows_MSBuild_Tests_RelWithDebInfo: + extends: .Windows_MSBuild_Base + stage: build + variables: + <<: *tests-targets + config: "RelWithDebInfo" + # Gitlab can't successfully execute benchamark binary due to unknown reason + # executables: "openmw_detournavigator_navmeshtilescache_benchmark.exe" + Debian_AndroidNDK_arm64-v8a: tags: - linux diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index d98c28038..bb662c9de 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -73,6 +73,7 @@ CONFIGURATIONS=() TEST_FRAMEWORK="" GOOGLE_INSTALL_ROOT="" INSTALL_PREFIX="." +BUILD_BENCHMARKS="" ACTIVATE_MSVC="" SINGLE_CONFIG="" @@ -133,6 +134,9 @@ while [ $# -gt 0 ]; do INSTALL_PREFIX=$(echo "$1" | sed 's;\\;/;g' | sed -E 's;/+;/;g') shift ;; + b ) + BUILD_BENCHMARKS=true ;; + h ) cat </dev/null 2>&1 || { echo "Error: vswhere is not on the path."; wrappedExit 1; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 104140107..a9f33c743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -669,6 +669,10 @@ if (WIN32) if (BUILD_WIZARD) set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif() + + if (BUILD_BENCHMARKS) + set_target_properties(openmw_detournavigator_navmeshtilescache_benchmark PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() endif(MSVC) # TODO: At some point release builds should not use the console but rather write to a log file diff --git a/apps/benchmarks/CMakeLists.txt b/apps/benchmarks/CMakeLists.txt index b7170003e..f9aa9aad4 100644 --- a/apps/benchmarks/CMakeLists.txt +++ b/apps/benchmarks/CMakeLists.txt @@ -19,16 +19,9 @@ FetchContent_MakeAvailableExcludeFromAll(benchmark) set(CMAKE_CXX_FLAGS "${SAVED_CMAKE_CXX_FLAGS}") openmw_add_executable(openmw_detournavigator_navmeshtilescache_benchmark detournavigator/navmeshtilescache.cpp) -target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE -Wall) target_compile_features(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE cxx_std_17) target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark benchmark::benchmark components) if (UNIX AND NOT APPLE) target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT}) endif() - -if (MSVC) - if (CMAKE_CL_64) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") - endif (CMAKE_CL_64) -endif (MSVC) From 54c8375672e52160e39df860b50ad02a45828806 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 11 May 2021 16:34:02 +0400 Subject: [PATCH 037/101] Recreate a special case for IntersectionVisitor on QuadTreeWorld --- components/terrain/viewdata.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index 48e882ea7..996bf909c 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -143,7 +143,7 @@ ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPo if (!vd->suitableToUse(activeGrid) || (vd->getViewPoint()-viewPoint).length2() >= mReuseDistance*mReuseDistance || vd->getWorldUpdateRevision() < mWorldUpdateRevision) { - float shortestDist = mReuseDistance*mReuseDistance; + float shortestDist = viewer ? mReuseDistance*mReuseDistance : std::numeric_limits::max(); const ViewData* mostSuitableView = nullptr; for (const ViewData* other : mUsedViews) { @@ -157,12 +157,12 @@ ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPo } } } - if (mostSuitableView) + if (mostSuitableView && mostSuitableView != vd) { vd->copyFrom(*mostSuitableView); return vd; } - else + else if (!mostSuitableView) { vd->setViewPoint(viewPoint); needsUpdate = true; From 08f30e6f5040a037b12d022abc32204ffd3d18ea Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 11 May 2021 21:15:13 +0400 Subject: [PATCH 038/101] Temporary increase default near clip distance, until reverse-z depth buffer is implemented --- docs/source/reference/modding/settings/camera.rst | 2 +- files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/settings/camera.rst b/docs/source/reference/modding/settings/camera.rst index e15b06e74..a880a2b62 100644 --- a/docs/source/reference/modding/settings/camera.rst +++ b/docs/source/reference/modding/settings/camera.rst @@ -6,7 +6,7 @@ near clip :Type: floating point :Range: > 0 -:Default: 1.0 +:Default: 3.0 This setting controls the distance to the near clipping plane. The value must be greater than zero. Values greater than approximately 18.0 will occasionally clip objects in the world in front of the character. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ea678c70f..ecce453d4 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -14,7 +14,7 @@ [Camera] # Near clipping plane (>0.0, e.g. 0.01 to 18.0). -near clip = 1 +near clip = 3 # Cull objects that occupy less than 'small feature culling pixel size' on the screen. small feature culling = true From 49a744b65a6d5436608224f567e364ccd83587bf Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 12 May 2021 09:18:54 +0400 Subject: [PATCH 039/101] Make groundcover to use rendering distance in units instead of cells --- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++++---- .../reference/modding/settings/groundcover.rst | 13 ++++++------- files/settings-default.cfg | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7093c2b98..e497fdecd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -262,7 +262,7 @@ namespace MWRender globalDefines[itr->first] = itr->second; // Refactor this at some point - most shaders don't care about these defines - float groundcoverDistance = (Constants::CellSizeInUnits * std::max(1, Settings::Manager::getInt("distance", "Groundcover")) - 1024) * 0.93; + float groundcoverDistance = std::max(0.f, Settings::Manager::getFloat("rendering distance", "Groundcover")); globalDefines["groundcoverFadeStart"] = std::to_string(groundcoverDistance * 0.9f); globalDefines["groundcoverFadeEnd"] = std::to_string(groundcoverDistance); globalDefines["groundcoverStompMode"] = std::to_string(std::clamp(Settings::Manager::getInt("stomp mode", "Groundcover"), 0, 2)); @@ -349,6 +349,10 @@ namespace MWRender mGroundcover.reset(new Groundcover(mResourceSystem->getSceneManager(), density)); static_cast(mGroundcoverWorld.get())->addChunkManager(mGroundcover.get()); mResourceSystem->addResourceManager(mGroundcover.get()); + + // Groundcover it is handled in the same way indifferently from if it is from active grid or from distant cell. + // Use a stub grid to avoid splitting between chunks for active grid and chunks for distant cells. + mGroundcoverWorld->setActiveGrid(osg::Vec4i(0, 0, 0, 0)); } // water goes after terrain for correct waterculling order mWater.reset(new Water(sceneRoot->getParent(0), sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath)); @@ -1076,7 +1080,7 @@ namespace MWRender if (mGroundcoverWorld) { - int groundcoverDistance = Constants::CellSizeInUnits * std::max(1, Settings::Manager::getInt("distance", "Groundcover")); + float groundcoverDistance = std::max(0.f, Settings::Manager::getFloat("rendering distance", "Groundcover")); mGroundcoverWorld->setViewDistance(groundcoverDistance * (distanceMult ? 1.f/distanceMult : 1.f)); } } @@ -1311,8 +1315,6 @@ namespace MWRender void RenderingManager::setActiveGrid(const osg::Vec4i &grid) { mTerrain->setActiveGrid(grid); - if (mGroundcoverWorld) - mGroundcoverWorld->setActiveGrid(grid); } bool RenderingManager::pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled) { diff --git a/docs/source/reference/modding/settings/groundcover.rst b/docs/source/reference/modding/settings/groundcover.rst index ef97caeec..7c5a965e0 100644 --- a/docs/source/reference/modding/settings/groundcover.rst +++ b/docs/source/reference/modding/settings/groundcover.rst @@ -28,15 +28,14 @@ are used in the game. Can affect performance a lot. This setting can only be configured by editing the settings configuration file. -distance --------- +rendering distance +------------------ -:Type: integer -:Range: > 0 -:Default: 1 +:Type: floating point +:Range: >= 0.0 +:Default: 6144.0 -Determines on which distance in cells grass pages are rendered. -Default 1 value means 3x3 cells area (active grid). +Determines on which distance in game units grass pages are rendered. May affect performance a lot. This setting can only be configured by editing the settings configuration file. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ecce453d4..b4910c9b8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1071,8 +1071,8 @@ enabled = false # 1.0 means 100% density density = 1.0 -# A maximum distance in cells on which groundcover is rendered. -distance = 1 +# A maximum distance in game units on which groundcover is rendered. +rendering distance = 6144.0 # A minimum size of groundcover chunk in cells (0.125, 0.25, 0.5, 1.0) min chunk size = 0.5 From f9d42ed3960430ab0d2c605caafb94a28ee77948 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 2 May 2021 10:43:44 +0400 Subject: [PATCH 040/101] Fix MSVC's C4267 warnings --- CMakeLists.txt | 1 - apps/mwiniimporter/importer.cpp | 10 +++++----- apps/opencs/model/doc/blacklist.cpp | 2 +- apps/opencs/model/filter/narynode.cpp | 2 +- apps/opencs/model/tools/mandatoryid.cpp | 2 +- apps/opencs/model/tools/reportmodel.cpp | 6 +++--- apps/opencs/model/world/idtable.cpp | 2 +- apps/opencs/model/world/resources.cpp | 6 +++--- apps/opencs/view/doc/operations.cpp | 4 ++-- apps/opencs/view/widget/scenetoolrun.cpp | 2 +- apps/opencs/view/widget/scenetooltoggle.cpp | 4 ++-- apps/opencs/view/widget/scenetooltoggle2.cpp | 2 +- apps/opencs/view/world/idvalidator.cpp | 2 +- components/bsa/bsa_file.cpp | 16 ++++++++-------- components/bsa/bsa_file.hpp | 4 ++-- components/compiler/controlparser.cpp | 6 +++--- components/compiler/literals.cpp | 8 ++++---- components/crashcatcher/windows_crashcatcher.cpp | 4 ++-- components/esm/esmreader.cpp | 6 +++--- components/esm/esmwriter.cpp | 2 +- components/files/lowlevelfile.cpp | 4 ++-- components/interpreter/runtime.cpp | 2 +- components/widgets/list.cpp | 2 +- extern/osg-ffmpeg-videoplayer/audiodecoder.cpp | 2 +- 24 files changed, 50 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 104140107..fe31951df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -607,7 +607,6 @@ if (WIN32) 4100 # Unreferenced formal parameter (-Wunused-parameter) 4127 # Conditional expression is constant 4244 # Storing value of one type in variable of another (size_t in int, for example) - 4267 # Conversion from 'size_t' to 'int', possible loss of data 4996 # Function was declared deprecated ) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 94b5cf7d0..2763d8ad9 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -676,7 +676,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::p } if(line[0] == '[') { - int pos = line.find(']'); + int pos = static_cast(line.find(']')); if(pos < 2) { std::cout << "Warning: ini file wrongly formatted (" << line << "). Line ignored." << std::endl; continue; @@ -686,12 +686,12 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::p continue; } - int comment_pos = line.find(';'); + int comment_pos = static_cast(line.find(';')); if(comment_pos > 0) { line = line.substr(0,comment_pos); } - int pos = line.find('='); + int pos = static_cast(line.find('=')); if(pos < 1) { continue; } @@ -722,7 +722,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::p while (std::getline(file, line)) { // we cant say comment by only looking at first char anymore - int comment_pos = line.find('#'); + int comment_pos = static_cast(line.find('#')); if(comment_pos > 0) { line = line.substr(0,comment_pos); } @@ -731,7 +731,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::p continue; } - int pos = line.find('='); + int pos = static_cast(line.find('=')); if(pos < 1) { continue; } diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index b1d402c69..690d79983 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -21,7 +21,7 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type, { std::vector& list = mIds[type]; - int size = list.size(); + size_t size = list.size(); list.resize (size+ids.size()); diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index 2fa9ac6cc..9415f1daf 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -9,7 +9,7 @@ CSMFilter::NAryNode::NAryNode (const std::vector >& nodes, int CSMFilter::NAryNode::getSize() const { - return mNodes.size(); + return static_cast(mNodes.size()); } const CSMFilter::Node& CSMFilter::NAryNode::operator[] (int index) const diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 23adb9d37..d0d9cc0b9 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -11,7 +11,7 @@ CSMTools::MandatoryIdStage::MandatoryIdStage (const CSMWorld::CollectionBase& id int CSMTools::MandatoryIdStage::setup() { - return mIds.size(); + return static_cast(mIds.size()); } void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index f9a1fdb0c..a2901a663 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -24,7 +24,7 @@ int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return mRows.size(); + return static_cast(mRows.size()); } int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const @@ -140,7 +140,7 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p void CSMTools::ReportModel::add (const CSMDoc::Message& message) { - beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); + beginInsertRows (QModelIndex(), static_cast(mRows.size()), static_cast(mRows.size())); mRows.push_back (message); @@ -176,7 +176,7 @@ void CSMTools::ReportModel::clear() { if (!mRows.empty()) { - beginRemoveRows (QModelIndex(), 0, mRows.size()-1); + beginRemoveRows (QModelIndex(), 0, static_cast(mRows.size())-1); mRows.clear(); endRemoveRows(); } diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 27d60ae98..30fe6f639 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -270,7 +270,7 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector& newO if (!newOrder.empty()) if (mIdCollection->reorderRows (baseIndex, newOrder)) emit dataChanged (index (baseIndex, 0), - index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1)); + index (baseIndex+static_cast(newOrder.size())-1, mIdCollection->getColumns()-1)); } std::pair CSMWorld::IdTable::view (int row) const diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index b40ab1389..c3eb9762e 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -20,13 +20,13 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const * mFiles.clear(); mIndex.clear(); - int baseSize = mBaseDirectory.size(); + size_t baseSize = mBaseDirectory.size(); const std::map& index = vfs->getIndex(); for (std::map::const_iterator it = index.begin(); it != index.end(); ++it) { std::string filepath = it->first; - if (static_cast (filepath.size())(mFiles.size()); } std::string CSMWorld::Resources::getId (int index) const diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 7ee4b8726..9ed77ff9c 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -30,7 +30,7 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread return; } - int oldCount = mOperations.size(); + int oldCount = static_cast(mOperations.size()); int newCount = oldCount + 1; Operation *operation = new Operation (type, this); @@ -51,7 +51,7 @@ void CSVDoc::Operations::quitOperation (int type) for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) if ((*iter)->getType()==type) { - int oldCount = mOperations.size(); + int oldCount = static_cast(mOperations.size()); int newCount = oldCount - 1; mLayout->removeItem ((*iter)->getLayout()); diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index b53282036..24bcf3f13 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -30,7 +30,7 @@ void CSVWidget::SceneToolRun::updateIcon() void CSVWidget::SceneToolRun::updatePanel() { - mTable->setRowCount (mProfiles.size()); + mTable->setRowCount (static_cast(mProfiles.size())); int i = 0; diff --git a/apps/opencs/view/widget/scenetooltoggle.cpp b/apps/opencs/view/widget/scenetooltoggle.cpp index fa0be3155..04ac3322b 100644 --- a/apps/opencs/view/widget/scenetooltoggle.cpp +++ b/apps/opencs/view/widget/scenetooltoggle.cpp @@ -80,7 +80,7 @@ QRect CSVWidget::SceneToolToggle::getIconBox (int index) const int y = index / xMax; int x = index % xMax; - int total = mButtons.size(); + int total = static_cast(mButtons.size()); int actualYIcons = total/xMax; @@ -154,7 +154,7 @@ void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned in desc.mMask = mask; desc.mSmallIcon = smallIcon; desc.mName = name; - desc.mIndex = mButtons.size(); + desc.mIndex = static_cast(mButtons.size()); mButtons.insert (std::make_pair (button, desc)); diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index cf9bfe349..363cae570 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -99,7 +99,7 @@ void CSVWidget::SceneToolToggle2::addButton (unsigned int id, unsigned int mask, desc.mButtonId = id; desc.mMask = mask; desc.mName = name; - desc.mIndex = mButtons.size(); + desc.mIndex = static_cast(mButtons.size()); mButtons.insert (std::make_pair (button, desc)); diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 1092d7217..442157ac5 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -42,7 +42,7 @@ QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) con if (!mNamespace.empty()) { - std::string namespace_ = input.left (mNamespace.size()).toUtf8().constData(); + std::string namespace_ = input.left (static_cast(mNamespace.size())).toUtf8().constData(); if (Misc::StringUtils::lowerCase (namespace_)!=mNamespace) return QValidator::Invalid; // incorrect namespace diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index ec455ea1f..4758d0a86 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -43,7 +43,7 @@ void BSAFile::fail(const std::string &msg) BSAFile::Hash getHash(const std::string& name) { BSAFile::Hash hash; - unsigned l = (name.size() >> 1); + unsigned l = (static_cast(name.size()) >> 1); unsigned sum, off, temp, i, n; for (sum = off = i = 0; i < l; i++) { @@ -163,7 +163,7 @@ void BSAFile::readHeader() { FileStruct &fs = mFiles[i]; fs.fileSize = offsets[i*2]; - fs.offset = offsets[i*2+1] + fileDataOffset; + fs.offset = static_cast(offsets[i*2+1] + fileDataOffset); auto namesOffset = offsets[2*filenum+i]; fs.setNameInfos(namesOffset, &mStringBuf); fs.hash = hashes[i]; @@ -203,11 +203,11 @@ void Bsa::BSAFile::writeHeader() uint32_t head[3]; head[0] = 0x100; auto fileDataOffset = mFiles.empty() ? 12 : mFiles.front().offset; - head[1] = fileDataOffset - 12 - 8*mFiles.size(); + head[1] = static_cast(fileDataOffset - 12 - 8*mFiles.size()); output.seekp(0, std::ios_base::end); - head[2] = mFiles.size(); + head[2] = static_cast(mFiles.size()); output.seekp(0); output.write(reinterpret_cast(head), 12); @@ -239,9 +239,9 @@ int BSAFile::getIndex(const char *str) const if(it == mLookup.end()) return -1; - int res = it->second; - assert(res >= 0 && (size_t)res < mFiles.size()); - return res; + size_t res = it->second; + assert(res >= 0 && res < mFiles.size()); + return static_cast(res); } /// Open an archive file. @@ -300,7 +300,7 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) newFile.hash = getHash(filename); if(mFiles.empty()) - newFile.offset = newStartOfDataBuffer; + newFile.offset = static_cast(newStartOfDataBuffer); else { std::vector buffer; diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index fa6e5fc1c..f9b4d4fa3 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -58,7 +58,7 @@ public: void setNameInfos(size_t index, std::vector* stringBuf ) { - namesOffset = index; + namesOffset = static_cast(index); namesBuffer = stringBuf; } @@ -102,7 +102,7 @@ protected: the files[] vector above. The iltstr ensures that file name checks are case insensitive. */ - typedef std::map Lookup; + typedef std::map Lookup; Lookup mLookup; /// Error handling diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index ec69fffa2..a5a68edbd 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -39,14 +39,14 @@ namespace Compiler Codes block; if (iter!=mIfCode.rbegin()) - Generator::jump (iter->second, codes.size()+1); + Generator::jump (iter->second, static_cast(codes.size()+1)); if (!iter->first.empty()) { // if or elseif std::copy (iter->first.begin(), iter->first.end(), std::back_inserter (block)); - Generator::jumpOnZero (block, iter->second.size()+1); + Generator::jumpOnZero (block, static_cast(iter->second.size()+1)); } std::copy (iter->second.begin(), iter->second.end(), @@ -113,7 +113,7 @@ namespace Compiler Codes skip; - Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1); + Generator::jumpOnZero (skip, static_cast (mCodeBlock.size()+loop.size()+1)); std::copy (skip.begin(), skip.end(), std::back_inserter (mCode)); diff --git a/components/compiler/literals.cpp b/components/compiler/literals.cpp index 774ca4ca7..a40ff2a02 100644 --- a/components/compiler/literals.cpp +++ b/components/compiler/literals.cpp @@ -6,12 +6,12 @@ namespace Compiler { int Literals::getIntegerSize() const { - return mIntegers.size() * sizeof (Interpreter::Type_Integer); + return static_cast(mIntegers.size() * sizeof (Interpreter::Type_Integer)); } int Literals::getFloatSize() const { - return mFloats.size() * sizeof (Interpreter::Type_Float); + return static_cast(mFloats.size() * sizeof (Interpreter::Type_Float)); } int Literals::getStringSize() const @@ -41,11 +41,11 @@ namespace Compiler code.resize (size+stringBlockSize/4); - int offset = 0; + size_t offset = 0; for (const auto & mString : mStrings) { - int stringSize = mString.size()+1; + size_t stringSize = mString.size()+1; std::copy (mString.c_str(), mString.c_str()+stringSize, reinterpret_cast (&code[size]) + offset); diff --git a/components/crashcatcher/windows_crashcatcher.cpp b/components/crashcatcher/windows_crashcatcher.cpp index 185eee6aa..39ac86d7b 100644 --- a/components/crashcatcher/windows_crashcatcher.cpp +++ b/components/crashcatcher/windows_crashcatcher.cpp @@ -130,12 +130,12 @@ namespace Crash DWORD copied = 0; do { executablePath.resize(executablePath.size() + MAX_PATH); - copied = GetModuleFileNameW(nullptr, executablePath.data(), executablePath.size()); + copied = GetModuleFileNameW(nullptr, executablePath.data(), static_cast(executablePath.size())); } while (copied >= executablePath.size()); executablePath.resize(copied); memset(mShm->mStartup.mLogFilePath, 0, sizeof(mShm->mStartup.mLogFilePath)); - int length = crashLogPath.length(); + size_t length = crashLogPath.length(); if (length >= MAX_LONG_PATH) length = MAX_LONG_PATH - 1; strncpy(mShm->mStartup.mLogFilePath, crashLogPath.c_str(), length); mShm->mStartup.mLogFilePath[length] = '\0'; diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 30c38d739..b779d7f7f 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -203,9 +203,9 @@ void ESMReader::getSubName() } // reading the subrecord data anyway. - const size_t subNameSize = mCtx.subName.data_size(); + const int subNameSize = static_cast(mCtx.subName.data_size()); getExact(mCtx.subName.rw_data(), subNameSize); - mCtx.leftRec -= subNameSize; + mCtx.leftRec -= static_cast(subNameSize); } void ESMReader::skipHSub() @@ -327,7 +327,7 @@ std::string ESMReader::getString(int size) char *ptr = mBuffer.data(); getExact(ptr, size); - size = strnlen(ptr, size); + size = static_cast(strnlen(ptr, size)); // Convert to UTF8 and return if (mEncoder) diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index 09fca4b26..f65340f70 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -217,7 +217,7 @@ namespace ESM if (mCounting && !mRecords.empty()) { for (std::list::iterator it = mRecords.begin(); it != mRecords.end(); ++it) - it->size += size; + it->size += static_cast(size); } mStream->write(data, size); diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 07915abba..d89ae5838 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -326,7 +326,7 @@ void LowLevelFile::seek (size_t position) { assert (mHandle != INVALID_HANDLE_VALUE); - if (SetFilePointer (mHandle, position, nullptr, SEEK_SET) == INVALID_SET_FILE_POINTER) + if (SetFilePointer (mHandle, static_cast(position), nullptr, SEEK_SET) == INVALID_SET_FILE_POINTER) if (GetLastError () != NO_ERROR) throw std::runtime_error ("A seek operation on a file failed."); } @@ -349,7 +349,7 @@ size_t LowLevelFile::read (void * data, size_t size) DWORD read; - if (!ReadFile (mHandle, data, size, &read, nullptr)) + if (!ReadFile (mHandle, data, static_cast(size), &read, nullptr)) throw std::runtime_error ("A read operation on a file failed."); return read; diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index 35ad93a8a..1cb8f558c 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -45,7 +45,7 @@ namespace Interpreter for (; index; --index) { - offset += std::strlen (literalBlock+offset) + 1; + offset += static_cast(std::strlen (literalBlock+offset)) + 1; if (offset / 4 >= static_cast (mCode[3])) throw std::out_of_range("out of range"); } diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 73ca94929..e961b04cb 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -115,7 +115,7 @@ namespace Gui unsigned int MWList::getItemCount() { - return mItems.size(); + return static_cast(mItems.size()); } std::string MWList::getItemNameAt(unsigned int at) diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp index c32794d2a..c78328b2e 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp @@ -255,7 +255,7 @@ size_t MovieAudioDecoder::read(char *stream, size_t len) size_t sampleSize = av_get_bytes_per_sample(mOutputSampleFormat); char* data[1]; data[0] = stream; - av_samples_set_silence((uint8_t**)data, 0, len/sampleSize, 1, mOutputSampleFormat); + av_samples_set_silence((uint8_t**)data, 0, static_cast(len/sampleSize), 1, mOutputSampleFormat); return len; } From 963e1b8b3fdb46b85d813f7439129359d49a8316 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 2 May 2021 12:59:22 +0400 Subject: [PATCH 041/101] Fix MSVC's C4244 warnings --- CMakeLists.txt | 2 -- apps/openmw/mwsound/ffmpeg_decoder.hpp | 10 ++++++++++ components/bsa/bsa_file.cpp | 6 +++--- components/compiler/locals.cpp | 2 +- components/compiler/scanner.hpp | 6 +++--- components/esm/statstate.cpp | 7 +++---- components/myguiplatform/scalinglayer.cpp | 12 ++++++------ extern/osg-ffmpeg-videoplayer/audiodecoder.cpp | 13 ++++++++++--- extern/osg-ffmpeg-videoplayer/audiodecoder.hpp | 9 +++++++++ extern/osg-ffmpeg-videoplayer/videostate.cpp | 9 +++++++++ extern/osg-ffmpeg-videoplayer/videostate.hpp | 9 +++++++++ 11 files changed, 63 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe31951df..053f9def1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -603,10 +603,8 @@ if (WIN32) set(WARNINGS "/W4") set(WARNINGS_DISABLE - # OpenMW specific warnings 4100 # Unreferenced formal parameter (-Wunused-parameter) 4127 # Conditional expression is constant - 4244 # Storing value of one type in variable of another (size_t in int, for example) 4996 # Function was declared deprecated ) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index f099c831c..0a67a4758 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -2,6 +2,12 @@ #define GAME_SOUND_FFMPEG_DECODER_H #include + +#if defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable : 4244) +#endif + extern "C" { #include @@ -14,6 +20,10 @@ extern "C" #include } +#if defined(_MSC_VER) + #pragma warning (pop) +#endif + #include #include diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 4758d0a86..158080ea3 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -295,7 +295,7 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) FileStruct newFile; file.seekg(0, std::ios::end); - newFile.fileSize = file.tellg(); + newFile.fileSize = static_cast(file.tellg()); newFile.setNameInfos(mStringBuf.size(), &mStringBuf); newFile.hash = getHash(filename); @@ -312,7 +312,7 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) stream.read(buffer.data(), firstFile.fileSize); stream.seekp(0, std::ios::end); - firstFile.offset = stream.tellp(); + firstFile.offset = static_cast(stream.tellp()); stream.write(buffer.data(), firstFile.fileSize); @@ -320,7 +320,7 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) std::rotate(mFiles.begin(), mFiles.begin() + 1, mFiles.end()); } stream.seekp(0, std::ios::end); - newFile.offset = stream.tellp(); + newFile.offset = static_cast(stream.tellp()); } mStringBuf.insert(mStringBuf.end(), filename.begin(), filename.end()); diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index 9b233b8f5..f31acb1a8 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -30,7 +30,7 @@ namespace Compiler if (iter==collection.end()) return -1; - return iter-collection.begin(); + return static_cast(iter-collection.begin()); } bool Locals::search (char type, const std::string& name) const diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 9c7bd656e..fd7de5b6b 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -103,7 +103,7 @@ namespace Compiler { blank(); - char ch = in.peek(); + char ch = static_cast(in.peek()); if (!in.good()) return false; @@ -130,7 +130,7 @@ namespace Compiler { std::streampos p_orig = in.tellg(); - char ch = in.peek(); + char ch = static_cast(in.peek()); if (!in.good()) return false; @@ -156,7 +156,7 @@ namespace Compiler void blank() { - std::fill(mData, mData + sizeof(mData), 0); + std::fill(std::begin(mData), std::end(mData), '\0'); mLength = -1; } diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp index b9ddc3efd..30d39e3c6 100644 --- a/components/esm/statstate.cpp +++ b/components/esm/statstate.cpp @@ -16,17 +16,16 @@ namespace ESM { int base = 0; esm.getHNT(base, "STBA"); - mBase = static_cast(base); + mBase = static_cast(base); int mod = 0; esm.getHNOT(mod, "STMO"); - mMod = static_cast(mod); + mMod = static_cast(mod); int current = 0; esm.getHNOT(current, "STCU"); - mCurrent = static_cast(current); + mCurrent = static_cast(current); - // mDamage was changed to a float; ensure backwards compatibility int oldDamage = 0; esm.getHNOT(oldDamage, "STDA"); mDamage = static_cast(oldDamage); diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp index 99ed6d07a..51c148253 100644 --- a/components/myguiplatform/scalinglayer.cpp +++ b/components/myguiplatform/scalinglayer.cpp @@ -74,8 +74,8 @@ namespace osgMyGUI _left -= globalViewSize.width/2; _top -= globalViewSize.height/2; - _left /= scale; - _top /= scale; + _left = static_cast(_left/scale); + _top = static_cast(_top/scale); _left += mViewSize.width/2; _top += mViewSize.height/2; @@ -84,8 +84,8 @@ namespace osgMyGUI float ScalingLayer::getScaleFactor() const { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - float w = viewSize.width; - float h = viewSize.height; + float w = static_cast(viewSize.width); + float h = static_cast(viewSize.height); float heightScale = (h / mViewSize.height); float widthScale = (w / mViewSize.width); @@ -103,8 +103,8 @@ namespace osgMyGUI MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize viewSize = globalViewSize; float scale = getScaleFactor(); - viewSize.width /= scale; - viewSize.height /= scale; + viewSize.width = static_cast(viewSize.width / scale); + viewSize.height = static_cast(viewSize.height / scale); float hoffset = (globalViewSize.width - mViewSize.width*getScaleFactor())/2.f / static_cast(globalViewSize.width); float voffset = (globalViewSize.height - mViewSize.height*getScaleFactor())/2.f / static_cast(globalViewSize.height); diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp index c78328b2e..b5b3b8a3e 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp @@ -4,13 +4,20 @@ #include #include +#if defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable : 4244) +#endif + extern "C" { - #include - #include } +#if defined(_MSC_VER) + #pragma warning (pop) +#endif + #include "videostate.hpp" namespace @@ -276,7 +283,7 @@ size_t MovieAudioDecoder::read(char *stream, size_t len) mFramePos = std::min(mFrameSize, sample_skip); if(sample_skip > 0 || mFrameSize > -sample_skip) - sample_skip -= mFramePos; + sample_skip -= static_cast(mFramePos); continue; } diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp index afb088431..bbb5a2783 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp @@ -6,6 +6,11 @@ #include #include +#if defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable : 4244) +#endif + extern "C" { #include @@ -14,6 +19,10 @@ extern "C" #include } +#if defined(_MSC_VER) + #pragma warning (pop) +#endif + #if defined(_WIN32) && !defined(__MINGW32__) #include diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index c153aa14c..a2ea71b19 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -9,6 +9,11 @@ #include +#if defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable : 4244) +#endif + extern "C" { #include @@ -17,6 +22,10 @@ extern "C" #include } +#if defined(_MSC_VER) + #pragma warning (pop) +#endif + static const char* flushString = "FLUSH"; struct FlushPacket : AVPacket { diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 015656084..244637b87 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -15,6 +15,11 @@ namespace osg class Texture2D; } +#if defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable : 4244) +#endif + extern "C" { #include @@ -28,6 +33,10 @@ extern "C" #include } +#if defined(_MSC_VER) + #pragma warning (pop) +#endif + #include "videodefs.hpp" #define VIDEO_PICTURE_QUEUE_SIZE 50 From 6e19e3a9bbde5090a1a4472646543056bc5ce1f0 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 12 May 2021 09:51:41 +0200 Subject: [PATCH 042/101] Add changelog entries for navigator features --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 856e10438..1b8c0c635 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -160,6 +160,8 @@ Feature #5814: Bsatool should be able to create BSA archives, not only to extract it Feature #5828: Support more than 8 lights Feature #5910: Fall back to delta time when physics can't keep up + Feature #6033: Include pathgrid to navigation mesh + Feature #6034: Find path based on area cost depending on NPC stats Task #5480: Drop Qt4 support Task #5520: Improve cell name autocompleter implementation Task #5844: Update 'toggle sneak' documentation From 89f721fad3aee343aae1af718984198d00e1e7fe Mon Sep 17 00:00:00 2001 From: jvoisin Date: Wed, 12 May 2021 22:35:00 +0200 Subject: [PATCH 043/101] Use a constexpr for esm cc --- components/esm/defs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 9bf9b01f3..1b623f69f 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -85,7 +85,7 @@ bool inline operator!= (const Position& left, const Position& right) noexcept template struct FourCC { - static const unsigned int value = (((((d << 8) | c) << 8) | b) << 8) | a; + static constexpr unsigned int value = (((((d << 8) | c) << 8) | b) << 8) | a; }; enum RecNameInts From 1b61ec979ddc60c45faf95c43af7fbbc4030d477 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 13 May 2021 11:25:58 +0200 Subject: [PATCH 044/101] switch to lock_guards --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 22 +++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index d6c99051e..7a4e7ede4 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -80,8 +80,7 @@ void VideoState::setAudioFactory(MovieAudioFactory *factory) void PacketQueue::put(AVPacket *pkt) { - AVPacketList *pkt1; - pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); + std::unique_ptr pkt1(static_cast(av_malloc(sizeof(AVPacketList)))); if(!pkt1) throw std::bad_alloc(); if(pkt == &flush_pkt) @@ -91,18 +90,16 @@ void PacketQueue::put(AVPacket *pkt) pkt1->next = nullptr; - this->mutex.lock (); + std::lock_guard lock(this->mutex); if(!last_pkt) - this->first_pkt = pkt1; + this->first_pkt = pkt1.get(); else - this->last_pkt->next = pkt1; - this->last_pkt = pkt1; + this->last_pkt->next = pkt1.get(); + this->last_pkt = pkt1.release(); this->nb_packets++; this->size += pkt1->pkt.size; this->cond.notify_one(); - - this->mutex.unlock(); } int PacketQueue::get(AVPacket *pkt, VideoState *is) @@ -144,7 +141,7 @@ void PacketQueue::clear() { AVPacketList *pkt, *pkt1; - this->mutex.lock(); + std::lock_guard lock(this->mutex); for(pkt = this->first_pkt; pkt != nullptr; pkt = pkt1) { pkt1 = pkt->next; @@ -156,7 +153,6 @@ void PacketQueue::clear() this->first_pkt = nullptr; this->nb_packets = 0; this->size = 0; - this->mutex.unlock (); } int VideoPicture::set_dimensions(int w, int h) { @@ -325,7 +321,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) if(this->mQuit) return -1; - this->pictq_mutex.lock(); + std::lock_guard lock(this->pictq_mutex); // windex is set to 0 initially vp = &this->pictq[this->pictq_windex]; @@ -350,10 +346,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) vp->pts = pts; if (vp->set_dimensions(w, h) < 0) - { - this->pictq_mutex.unlock(); return -1; - } sws_scale(this->sws_context, pFrame->data, pFrame->linesize, 0, this->video_ctx->height, vp->rgbaFrame->data, vp->rgbaFrame->linesize); @@ -361,7 +354,6 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) // now we inform our display thread that we have a pic ready this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->pictq_size++; - this->pictq_mutex.unlock(); return 0; } From 3b7cef9e8859dfd94a2e8b29f5ea008f0a2cc398 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 13 May 2021 12:01:32 +0200 Subject: [PATCH 045/101] add PacketGuard and move try/catch up --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 126 +++++++++++-------- 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 7a4e7ede4..7d5097ade 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -37,6 +37,39 @@ namespace { const int MAX_AUDIOQ_SIZE = (5 * 16 * 1024); const int MAX_VIDEOQ_SIZE = (5 * 256 * 1024); + + class PacketGuard + { + AVPacket mPacket; + bool mReleased; + public: + PacketGuard() : mReleased(false) + { + av_init_packet(&mPacket); + } + + AVPacket* operator->() + { + return &mPacket; + } + + AVPacket* operator*() + { + return &mPacket; + } + + AVPacket* release() + { + mReleased = true; + return &mPacket; + } + + ~PacketGuard() + { + if(!mReleased) + av_packet_unref(&mPacket); + } + }; } namespace Video @@ -98,7 +131,7 @@ void PacketQueue::put(AVPacket *pkt) this->last_pkt->next = pkt1.get(); this->last_pkt = pkt1.release(); this->nb_packets++; - this->size += pkt1->pkt.size; + this->size += this->last_pkt->pkt.size; this->cond.notify_one(); } @@ -383,7 +416,17 @@ class VideoThread public: VideoThread(VideoState* self) : mVideoState(self) - , mThread([this] { run(); }) + , mThread([this] + { + try + { + run(); + } + catch(std::exception& e) + { + std::cerr << "An error occurred playing the video: " << e.what () << std::endl; + } + }) { } @@ -395,60 +438,46 @@ public: void run() { VideoState* self = mVideoState; - AVPacket pkt1, *packet = &pkt1; - av_init_packet(packet); - AVFrame *pFrame; + PacketGuard packet; + std::unique_ptr pFrame{av_frame_alloc()}; - pFrame = av_frame_alloc(); - - try + while(self->videoq.get(*packet, self) >= 0) { - while(self->videoq.get(packet, self) >= 0) + if(packet->data == flush_pkt.data) { - if(packet->data == flush_pkt.data) - { - avcodec_flush_buffers(self->video_ctx); + avcodec_flush_buffers(self->video_ctx); - self->pictq_mutex.lock(); - self->pictq_size = 0; - self->pictq_rindex = 0; - self->pictq_windex = 0; - self->pictq_mutex.unlock(); + self->pictq_mutex.lock(); + self->pictq_size = 0; + self->pictq_rindex = 0; + self->pictq_windex = 0; + self->pictq_mutex.unlock(); - self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); - continue; - } + self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); + continue; + } - // Decode video frame - int ret = avcodec_send_packet(self->video_ctx, packet); - // EAGAIN is not expected - if (ret < 0) - throw std::runtime_error("Error decoding video frame"); + // Decode video frame + int ret = avcodec_send_packet(self->video_ctx, *packet); + // EAGAIN is not expected + if (ret < 0) + throw std::runtime_error("Error decoding video frame"); - while (!ret) + while (!ret) + { + ret = avcodec_receive_frame(self->video_ctx, pFrame.get()); + if (!ret) { - ret = avcodec_receive_frame(self->video_ctx, pFrame); - if (!ret) - { - double pts = pFrame->best_effort_timestamp; - pts *= av_q2d((*self->video_st)->time_base); + double pts = pFrame->best_effort_timestamp; + pts *= av_q2d((*self->video_st)->time_base); - pts = self->synchronize_video(pFrame, pts); + pts = self->synchronize_video(pFrame.get(), pts); - if(self->queue_picture(pFrame, pts) < 0) - break; - } + if(self->queue_picture(pFrame.get(), pts) < 0) + break; } } } - catch(std::exception& e) - { - std::cerr << "An error occurred playing the video: " << e.what () << std::endl; - } - - av_packet_unref(packet); - - av_frame_free(&pFrame); } private: @@ -475,8 +504,7 @@ public: VideoState* self = mVideoState; AVFormatContext *pFormatCtx = self->format_ctx; - AVPacket pkt1, *packet = &pkt1; - av_init_packet(packet); + PacketGuard packet; try { @@ -559,7 +587,7 @@ public: continue; } - if(av_read_frame(pFormatCtx, packet) < 0) + if(av_read_frame(pFormatCtx, *packet) < 0) { if (self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0) self->mVideoEnded = true; @@ -570,11 +598,9 @@ public: // Is this a packet from the video stream? if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams) - self->videoq.put(packet); + self->videoq.put(packet.release()); else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams) - self->audioq.put(packet); - else - av_packet_unref(packet); + self->audioq.put(packet.release()); } } catch(std::exception& e) { From ed118537a8a46f651913305b38772e47311e3fe0 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 13 May 2021 14:02:36 +0200 Subject: [PATCH 046/101] use unique_ptr instead --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 51 ++++++-------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 7d5097ade..cda965edd 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -38,36 +38,11 @@ namespace const int MAX_AUDIOQ_SIZE = (5 * 16 * 1024); const int MAX_VIDEOQ_SIZE = (5 * 256 * 1024); - class PacketGuard + struct AVPacketUnref { - AVPacket mPacket; - bool mReleased; - public: - PacketGuard() : mReleased(false) + void operator()(AVPacket* packet) const { - av_init_packet(&mPacket); - } - - AVPacket* operator->() - { - return &mPacket; - } - - AVPacket* operator*() - { - return &mPacket; - } - - AVPacket* release() - { - mReleased = true; - return &mPacket; - } - - ~PacketGuard() - { - if(!mReleased) - av_packet_unref(&mPacket); + av_packet_unref(packet); } }; } @@ -438,10 +413,12 @@ public: void run() { VideoState* self = mVideoState; - PacketGuard packet; + AVPacket packetData; + av_init_packet(&packetData); + std::unique_ptr packet(&packetData, AVPacketUnref{}); std::unique_ptr pFrame{av_frame_alloc()}; - while(self->videoq.get(*packet, self) >= 0) + while(self->videoq.get(packet.get(), self) >= 0) { if(packet->data == flush_pkt.data) { @@ -458,7 +435,7 @@ public: } // Decode video frame - int ret = avcodec_send_packet(self->video_ctx, *packet); + int ret = avcodec_send_packet(self->video_ctx, packet.get()); // EAGAIN is not expected if (ret < 0) throw std::runtime_error("Error decoding video frame"); @@ -504,7 +481,9 @@ public: VideoState* self = mVideoState; AVFormatContext *pFormatCtx = self->format_ctx; - PacketGuard packet; + AVPacket packetData; + av_init_packet(&packetData); + std::unique_ptr packet(&packetData, AVPacketUnref{}); try { @@ -587,7 +566,7 @@ public: continue; } - if(av_read_frame(pFormatCtx, *packet) < 0) + if(av_read_frame(pFormatCtx, packet.get()) < 0) { if (self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0 && self->pictq_size == 0) self->mVideoEnded = true; @@ -598,9 +577,11 @@ public: // Is this a packet from the video stream? if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams) - self->videoq.put(packet.release()); + self->videoq.put(packet.get()); else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams) - self->audioq.put(packet.release()); + self->audioq.put(packet.get()); + else + av_packet_unref(packet.get()); } } catch(std::exception& e) { From bcd8190516d3efb8bce0bfa49c25ce8f5d745379 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Thu, 13 May 2021 13:58:56 +0200 Subject: [PATCH 047/101] Fix a crash in aipackage.cpp --- components/esm/aipackage.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index abbd2c62c..fa20d271c 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -15,7 +15,12 @@ namespace ESM { AIPackage pack; if (esm.retSubName() == AI_CNDT) { - mList.back().mCellName = esm.getHString(); + if (mList.empty()) + { + esm.fail("AIPackge with an AI_CNDT applying to no cell."); + } else { + mList.back().mCellName = esm.getHString(); + } } else if (esm.retSubName() == AI_Wander) { pack.mType = AI_Wander; esm.getHExact(&pack.mWander, 14); From 69aaf6ab0491d99011c4f031641295bb5fa98195 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 13 May 2021 14:45:13 +0200 Subject: [PATCH 048/101] don't touch frame->data --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 30 +++++++++++++------- extern/osg-ffmpeg-videoplayer/videostate.hpp | 4 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index cda965edd..99c1dc7ec 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -45,6 +45,14 @@ namespace av_packet_unref(packet); } }; + + struct AVFrameFree + { + void operator()(AVFrame* frame) const + { + av_frame_free(&frame); + } + }; } namespace Video @@ -316,7 +324,7 @@ void VideoState::video_refresh() } -int VideoState::queue_picture(AVFrame *pFrame, double pts) +int VideoState::queue_picture(const AVFrame &pFrame, double pts) { VideoPicture *vp; @@ -337,8 +345,8 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) // Convert the image into RGBA format // TODO: we could do this in a pixel shader instead, if the source format // matches a commonly used format (ie YUV420P) - const int w = pFrame->width; - const int h = pFrame->height; + const int w = pFrame.width; + const int h = pFrame.height; if(this->sws_context == nullptr || this->sws_context_w != w || this->sws_context_h != h) { if (this->sws_context != nullptr) @@ -356,7 +364,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) if (vp->set_dimensions(w, h) < 0) return -1; - sws_scale(this->sws_context, pFrame->data, pFrame->linesize, + sws_scale(this->sws_context, pFrame.data, pFrame.linesize, 0, this->video_ctx->height, vp->rgbaFrame->data, vp->rgbaFrame->linesize); // now we inform our display thread that we have a pic ready @@ -366,7 +374,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) return 0; } -double VideoState::synchronize_video(AVFrame *src_frame, double pts) +double VideoState::synchronize_video(const AVFrame &src_frame, double pts) { double frame_delay; @@ -380,7 +388,7 @@ double VideoState::synchronize_video(AVFrame *src_frame, double pts) frame_delay = av_q2d(this->video_ctx->pkt_timebase); /* if we are repeating a frame, adjust clock accordingly */ - frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); + frame_delay += src_frame.repeat_pict * (frame_delay * 0.5); this->video_clock += frame_delay; return pts; @@ -415,8 +423,8 @@ public: VideoState* self = mVideoState; AVPacket packetData; av_init_packet(&packetData); - std::unique_ptr packet(&packetData, AVPacketUnref{}); - std::unique_ptr pFrame{av_frame_alloc()}; + std::unique_ptr packet(&packetData); + std::unique_ptr pFrame{av_frame_alloc()}; while(self->videoq.get(packet.get(), self) >= 0) { @@ -448,9 +456,9 @@ public: double pts = pFrame->best_effort_timestamp; pts *= av_q2d((*self->video_st)->time_base); - pts = self->synchronize_video(pFrame.get(), pts); + pts = self->synchronize_video(*pFrame, pts); - if(self->queue_picture(pFrame.get(), pts) < 0) + if(self->queue_picture(*pFrame, pts) < 0) break; } } @@ -483,7 +491,7 @@ public: AVFormatContext *pFormatCtx = self->format_ctx; AVPacket packetData; av_init_packet(&packetData); - std::unique_ptr packet(&packetData, AVPacketUnref{}); + std::unique_ptr packet(&packetData); try { diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 015656084..8f7f1cadd 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -132,8 +132,8 @@ struct VideoState { void video_display(VideoPicture* vp); void video_refresh(); - int queue_picture(AVFrame *pFrame, double pts); - double synchronize_video(AVFrame *src_frame, double pts); + int queue_picture(const AVFrame &pFrame, double pts); + double synchronize_video(const AVFrame &src_frame, double pts); double get_audio_clock(); double get_video_clock(); From bdfbf01772d424d971d4dcd37865615a048dda32 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Fri, 14 May 2021 00:05:00 +0100 Subject: [PATCH 049/101] Update extern Bullet to 3.17 Includes performance improvements that affect OpenMW: * https://github.com/bulletphysics/bullet3/pull/3287 * https://github.com/bulletphysics/bullet3/pull/3293 --- extern/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 8257b6b23..5dc9642d7 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -44,11 +44,11 @@ if(NOT OPENMW_USE_SYSTEM_BULLET) set(USE_MSVC_RUNTIME_LIBRARY_DLL ON CACHE BOOL "" FORCE) endif() - # master on 12 Mar 2021 + # May 7, 2021 include(FetchContent) FetchContent_Declare(bullet - URL https://github.com/bulletphysics/bullet3/archive/87e668f6b2a883b4ef63db8a07c8e9283916e9d9.zip - URL_HASH MD5=9f13246439968494c2b595cf412d83c8 + URL https://github.com/bulletphysics/bullet3/archive/refs/tags/3.17.tar.gz + URL_HASH MD5=7711bce9a49c289a08ecda34eaa0f32e SOURCE_DIR fetched/bullet ) FetchContent_MakeAvailableExcludeFromAll(bullet) From 06ae26037fd09edd7023f9035c8f4a34b8897af2 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 14 May 2021 10:57:31 +0200 Subject: [PATCH 050/101] Remove some superfluous includes in the opencs --- apps/opencs/model/doc/loader.cpp | 1 - apps/opencs/model/doc/operation.cpp | 1 - apps/opencs/model/world/refcollection.cpp | 1 - apps/opencs/view/doc/viewmanager.cpp | 1 - apps/opencs/view/render/orbitcameramode.cpp | 1 - apps/opencs/view/render/pagedworldspacewidget.cpp | 4 ---- apps/opencs/view/render/pathgridmode.cpp | 2 -- apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/render/terrainshapemode.cpp | 3 --- apps/opencs/view/render/terraintexturemode.cpp | 6 ------ apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 - apps/opencs/view/render/worldspacewidget.cpp | 1 - apps/opencs/view/widget/scenetoolshapebrush.cpp | 5 ----- apps/opencs/view/world/colordelegate.cpp | 2 -- apps/opencs/view/world/dialoguesubview.cpp | 1 - apps/opencs/view/world/scenesubview.cpp | 1 - apps/opencs/view/world/scriptsubview.cpp | 1 - 17 files changed, 33 deletions(-) diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 69c78bd5e..1c5a7348c 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -5,7 +5,6 @@ #include "../tools/reportmodel.hpp" #include "document.hpp" -#include "state.hpp" CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLoaded (0), mRecordsLeft (false) {} diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 218e13e38..369c6bb10 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -7,7 +7,6 @@ #include "../world/universalid.hpp" -#include "state.hpp" #include "stage.hpp" void CSMDoc::Operation::prepareStages() diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 126a0ea78..51588cbc2 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -1,6 +1,5 @@ #include "refcollection.hpp" -#include #include #include "ref.hpp" diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 8cca3a849..95f9f606d 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -11,7 +11,6 @@ #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" -#include "../../model/world/universalid.hpp" #include "../../model/world/idcompletionmanager.hpp" #include "../../model/prefs/state.hpp" diff --git a/apps/opencs/view/render/orbitcameramode.cpp b/apps/opencs/view/render/orbitcameramode.cpp index 79ac0167a..c81402ed1 100644 --- a/apps/opencs/view/render/orbitcameramode.cpp +++ b/apps/opencs/view/render/orbitcameramode.cpp @@ -3,7 +3,6 @@ #include #include "../../model/prefs/shortcut.hpp" -#include "../../model/prefs/shortcuteventhandler.hpp" #include "worldspacewidget.hpp" diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ed3558422..a0b4de979 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -7,18 +7,14 @@ #include #include -#include - #include #include "../../model/prefs/shortcut.hpp" -#include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolmode.hpp" -#include "../widget/scenetooltoggle2.hpp" #include "editmode.hpp" #include "mask.hpp" diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp index 7a3fc8ecf..193cb664d 100644 --- a/apps/opencs/view/render/pathgridmode.cpp +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -9,8 +9,6 @@ #include "../../model/world/commands.hpp" #include "../../model/world/commandmacro.hpp" -#include "../../model/world/idtable.hpp" -#include "../../model/world/idtree.hpp" #include "../widget/scenetoolbar.hpp" diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 534093996..dbed1ba97 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -25,7 +25,6 @@ #include "../../model/prefs/state.hpp" #include "../../model/prefs/shortcut.hpp" -#include "../../model/prefs/shortcuteventhandler.hpp" #include "lighting.hpp" #include "mask.hpp" diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index e495d2355..1739e143d 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -25,14 +25,11 @@ #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" -#include "../../model/world/columnbase.hpp" -#include "../../model/world/commandmacro.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/idtree.hpp" #include "../../model/world/land.hpp" -#include "../../model/world/resourcetable.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index fa46cf673..2c7d3529f 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -12,23 +12,17 @@ #include -#include - #include "../widget/modebutton.hpp" #include "../widget/scenetoolbar.hpp" #include "../widget/scenetooltexturebrush.hpp" #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" -#include "../../model/world/columnbase.hpp" -#include "../../model/world/commandmacro.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/idtree.hpp" -#include "../../model/world/land.hpp" #include "../../model/world/landtexture.hpp" -#include "../../model/world/resourcetable.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" #include "../widget/brushshapes.hpp" diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index c4fef45dd..20dc5b8d1 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -12,7 +12,6 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/tablemimedata.hpp" -#include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle2.hpp" #include "cameracontroller.hpp" diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 6eb437daf..723ffcb6a 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -17,7 +17,6 @@ #include "../../model/world/idtable.hpp" #include "../../model/prefs/shortcut.hpp" -#include "../../model/prefs/shortcuteventhandler.hpp" #include "../../model/prefs/state.hpp" #include "../render/orbitcameramode.hpp" diff --git a/apps/opencs/view/widget/scenetoolshapebrush.cpp b/apps/opencs/view/widget/scenetoolshapebrush.cpp index 4b2d20004..d0419a13a 100644 --- a/apps/opencs/view/widget/scenetoolshapebrush.cpp +++ b/apps/opencs/view/widget/scenetoolshapebrush.cpp @@ -27,11 +27,6 @@ #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" #include "../../model/world/commands.hpp" -#include "../../model/world/data.hpp" -#include "../../model/world/idcollection.hpp" -#include "../../model/world/idtable.hpp" -#include "../../model/world/landtexture.hpp" -#include "../../model/world/universalid.hpp" CSVWidget::ShapeBrushSizeControls::ShapeBrushSizeControls(const QString &title, QWidget *parent) diff --git a/apps/opencs/view/world/colordelegate.cpp b/apps/opencs/view/world/colordelegate.cpp index 15a07b42c..3b5f692fe 100644 --- a/apps/opencs/view/world/colordelegate.cpp +++ b/apps/opencs/view/world/colordelegate.cpp @@ -3,8 +3,6 @@ #include #include -#include "../widget/coloreditor.hpp" - CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 3d3b3cdbe..f2360b137 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -28,7 +28,6 @@ #include "../../model/world/columns.hpp" #include "../../model/world/record.hpp" #include "../../model/world/tablemimedata.hpp" -#include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 44542c529..58d159a17 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -15,7 +15,6 @@ #include "../render/pagedworldspacewidget.hpp" #include "../render/unpagedworldspacewidget.hpp" -#include "../render/editmode.hpp" #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 096fc8a9e..6eab7aaa5 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -12,7 +12,6 @@ #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/data.hpp" -#include "../../model/world/columnbase.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" #include "../../model/prefs/state.hpp" From 4bbbbb00f659d261fc7ebf58d4aea3437075335f Mon Sep 17 00:00:00 2001 From: "glassmancody.info" Date: Fri, 14 May 2021 10:52:19 -0700 Subject: [PATCH 051/101] use particle data for particle system quota --- CHANGELOG.md | 1 + components/nifosg/nifloader.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 647a8fa56..7f22c4aa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,7 @@ Bug #5995: NiUVController doesn't calculate the UV offset properly Bug #6007: Crash when ending cutscene is playing Bug #6016: Greeting interrupts Fargoth's sneak-walk + Bug #6028: Particle system controller values are incorrectly used Feature #390: 3rd person look "over the shoulder" Feature #832: OpenMW-CS: Handle deleted references Feature #1536: Show more information about level on menu diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f7d6fd3ed..ab25fd744 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -954,13 +954,17 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) + void handleParticleInitialState(const Nif::Node* nifNode, ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { auto particleNode = static_cast(nifNode); if (particleNode->data.empty() || particleNode->data->recType != Nif::RC_NiParticlesData) + { + partsys->setQuota(partctrl->numParticles); return; + } auto particledata = static_cast(particleNode->data.getPtr()); + partsys->setQuota(particledata->numParticles); osg::BoundingBox box; @@ -1095,8 +1099,6 @@ namespace NifOsg handleParticleInitialState(nifNode, partsys, partctrl); - partsys->setQuota(partctrl->numParticles); - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); From 28d5e5e8bed861d0bb1b16c3e5b3c619551d9bc5 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 14 May 2021 20:45:59 +0200 Subject: [PATCH 052/101] Remove some superfluous includes in components/detournavigator --- components/detournavigator/findrandompointaroundcircle.cpp | 1 - components/detournavigator/findsmoothpath.hpp | 2 -- components/detournavigator/makenavmesh.cpp | 1 - components/detournavigator/makenavmesh.hpp | 2 -- components/detournavigator/navigatorimpl.cpp | 2 -- components/detournavigator/navmeshmanager.hpp | 1 - components/detournavigator/raycast.cpp | 1 - components/detournavigator/recastmesh.hpp | 2 -- components/detournavigator/recastmeshmanager.cpp | 2 -- 9 files changed, 14 deletions(-) diff --git a/components/detournavigator/findrandompointaroundcircle.cpp b/components/detournavigator/findrandompointaroundcircle.cpp index 29d4e9da4..ed73dca61 100644 --- a/components/detournavigator/findrandompointaroundcircle.cpp +++ b/components/detournavigator/findrandompointaroundcircle.cpp @@ -4,7 +4,6 @@ #include -#include #include #include diff --git a/components/detournavigator/findsmoothpath.hpp b/components/detournavigator/findsmoothpath.hpp index 29a3ce805..0a9b5bed8 100644 --- a/components/detournavigator/findsmoothpath.hpp +++ b/components/detournavigator/findsmoothpath.hpp @@ -14,8 +14,6 @@ #include #include -#include - #include #include diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 70fd44c6c..bcfd1b22f 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -1,6 +1,5 @@ #include "makenavmesh.hpp" #include "debug.hpp" -#include "dtstatus.hpp" #include "exceptions.hpp" #include "recastmesh.hpp" #include "settings.hpp" diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index f9cf68a73..95720634c 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -2,10 +2,8 @@ #define OPENMW_COMPONENTS_DETOURNAVIGATOR_MAKENAVMESH_H #include "offmeshconnectionsmanager.hpp" -#include "settings.hpp" #include "navmeshcacheitem.hpp" #include "tileposition.hpp" -#include "tilebounds.hpp" #include "sharednavmesh.hpp" #include "navmeshtilescache.hpp" diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index d1e75b864..9ae9171a7 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -5,8 +5,6 @@ #include #include -#include - namespace DetourNavigator { NavigatorImpl::NavigatorImpl(const Settings& settings) diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index ce90aafc5..25e0b763b 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -4,7 +4,6 @@ #include "asyncnavmeshupdater.hpp" #include "cachedrecastmeshmanager.hpp" #include "offmeshconnectionsmanager.hpp" -#include "sharednavmesh.hpp" #include "recastmeshtiles.hpp" #include diff --git a/components/detournavigator/raycast.cpp b/components/detournavigator/raycast.cpp index 86fabe9c1..271da2249 100644 --- a/components/detournavigator/raycast.cpp +++ b/components/detournavigator/raycast.cpp @@ -2,7 +2,6 @@ #include "settings.hpp" #include "findsmoothpath.hpp" -#include #include #include diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index 1961d518d..0e6bc4920 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -11,8 +11,6 @@ #include #include -#include - #include namespace DetourNavigator diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 146038ae6..cdb9169d9 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -1,7 +1,5 @@ #include "recastmeshmanager.hpp" -#include - namespace DetourNavigator { RecastMeshManager::RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation) From d0ea9c482a9a489ae9b0b4dd93a0c0d1d73db4f6 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 14 May 2021 19:57:11 +0200 Subject: [PATCH 053/101] Reorder async navmesh updater jobs when player tile changes When player tile changes distance to player that is part of jobs priority is invalidated. So jobs are no longer in the right order. This can lead to processing of farests tiles first. Sort queue each time player tile is changed. --- .../detournavigator/asyncnavmeshupdater.cpp | 38 ++++++++++++++----- .../detournavigator/asyncnavmeshupdater.hpp | 7 ++-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index ff51e39aa..3f7114b85 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -88,13 +88,22 @@ namespace DetourNavigator const SharedNavMeshCacheItem& navMeshCacheItem, const TilePosition& playerTile, const std::map& changedTiles) { - *mPlayerTile.lock() = playerTile; + bool playerTileChanged = false; + { + auto locked = mPlayerTile.lock(); + playerTileChanged = *locked != playerTile; + *locked = playerTile; + } - if (changedTiles.empty()) + if (!playerTileChanged && changedTiles.empty()) return; const std::lock_guard lock(mMutex); + if (playerTileChanged) + for (auto& job : mJobs) + job.mDistanceToPlayer = getManhattanDistance(job.mChangedTile, playerTile); + for (const auto& changedTile : changedTiles) { if (mPushed[agentHalfExtents].insert(changedTile.first).second) @@ -112,10 +121,21 @@ namespace DetourNavigator ? mLastUpdates[job.mAgentHalfExtents][job.mChangedTile] + mSettings.get().mMinUpdateInterval : std::chrono::steady_clock::time_point(); - mJobs.push(std::move(job)); + if (playerTileChanged) + { + mJobs.push_back(std::move(job)); + } + else + { + const auto it = std::upper_bound(mJobs.begin(), mJobs.end(), job); + mJobs.insert(it, std::move(job)); + } } } + if (playerTileChanged) + std::sort(mJobs.begin(), mJobs.end()); + Log(Debug::Debug) << "Posted " << mJobs.size() << " navigator jobs"; if (!mJobs.empty()) @@ -283,7 +303,7 @@ namespace DetourNavigator while (true) { const auto hasJob = [&] { - return (!mJobs.empty() && mJobs.top().mProcessTime <= std::chrono::steady_clock::now()) + return (!mJobs.empty() && mJobs.front().mProcessTime <= std::chrono::steady_clock::now()) || !threadQueue.mJobs.empty(); }; @@ -318,11 +338,11 @@ namespace DetourNavigator { const auto now = std::chrono::steady_clock::now(); - if (jobs.top().mProcessTime > now) + if (jobs.front().mProcessTime > now) return {}; - Job job = jobs.top(); - jobs.pop(); + Job job = jobs.front(); + jobs.pop_front(); if (changeLastUpdate && job.mChangeType == ChangeType::update) mLastUpdates[job.mAgentHalfExtents][job.mChangedTile] = now; @@ -376,7 +396,7 @@ namespace DetourNavigator if (mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second) { ++job.mTryNumber; - mJobs.push(std::move(job)); + mJobs.push_back(std::move(job)); mHasJob.notify_all(); } } @@ -385,7 +405,7 @@ namespace DetourNavigator { if (queue.mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second) { - queue.mJobs.push(std::move(job)); + queue.mJobs.push_back(std::move(job)); mHasJob.notify_all(); } } diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index c28d8f21d..fb9532519 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -14,9 +14,10 @@ #include #include #include -#include +#include #include #include +#include class dtNavMesh; @@ -83,11 +84,11 @@ namespace DetourNavigator friend inline bool operator <(const Job& lhs, const Job& rhs) { - return lhs.getPriority() > rhs.getPriority(); + return lhs.getPriority() < rhs.getPriority(); } }; - using Jobs = std::priority_queue>; + using Jobs = std::deque; using Pushed = std::map>; struct Queue From 59f89d22f8e586c63be961b5606041e22c506ea7 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 14 May 2021 21:06:29 +0200 Subject: [PATCH 054/101] Apply min distance only for not present tiles To avoid waiting when navmesh update is triggered by transformed object for already present tiles. --- apps/openmw/mwworld/scene.cpp | 4 +- .../detournavigator/navigator.cpp | 44 ++++++++--------- .../detournavigator/asyncnavmeshupdater.cpp | 49 +++++++++++++++---- .../detournavigator/asyncnavmeshupdater.hpp | 8 ++- components/detournavigator/navigator.hpp | 6 ++- components/detournavigator/navigatorimpl.cpp | 4 +- components/detournavigator/navigatorimpl.hpp | 2 +- components/detournavigator/navigatorstub.hpp | 2 +- components/detournavigator/navmeshmanager.cpp | 5 +- components/detournavigator/navmeshmanager.hpp | 3 +- .../detournavigator/waitconditiontype.hpp | 13 +++++ 11 files changed, 95 insertions(+), 45 deletions(-) create mode 100644 components/detournavigator/waitconditiontype.hpp diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 23525dea8..83e9805f6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -619,7 +619,7 @@ namespace MWWorld if (changeEvent) mCellChanged = true; - mNavigator.wait(*loadingListener); + mNavigator.wait(*loadingListener, DetourNavigator::WaitConditionType::requiredTilesPresent); } void Scene::testExteriorCells() @@ -848,7 +848,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); - mNavigator.wait(*loadingListener); + mNavigator.wait(*loadingListener, DetourNavigator::WaitConditionType::requiredTilesPresent); } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index cb8ae4152..41671993d 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -127,7 +127,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -177,7 +177,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -209,7 +209,7 @@ namespace mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mPath.clear(); mOut = std::back_inserter(mPath); @@ -262,7 +262,7 @@ namespace mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -296,7 +296,7 @@ namespace mNavigator->updateObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mPath.clear(); mOut = std::back_inserter(mPath); @@ -355,7 +355,7 @@ namespace mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape2), shape2, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -411,7 +411,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), ObjectShapes {shape, &shapeAvoid}, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -459,7 +459,7 @@ namespace mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mStart.x() = 0; mStart.z() = 300; @@ -507,7 +507,7 @@ namespace mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mStart.x() = 0; mEnd.x() = 0; @@ -554,7 +554,7 @@ namespace mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits::max(), -25, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mStart.x() = 0; mEnd.x() = 0; @@ -601,7 +601,7 @@ namespace mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mStart.x() = 0; mEnd.x() = 0; @@ -645,15 +645,15 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->removeObject(ObjectId(&shape)); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -699,7 +699,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); Misc::Rng::init(42); @@ -748,7 +748,7 @@ namespace } mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); @@ -791,7 +791,7 @@ namespace mNavigator->addObject(ObjectId(&shapes[i]), shapes[i], transform); } mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); const auto start = std::chrono::steady_clock::now(); for (std::size_t i = 0; i < shapes.size(); ++i) @@ -800,7 +800,7 @@ namespace mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); } mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); for (std::size_t i = 0; i < shapes.size(); ++i) { @@ -808,7 +808,7 @@ namespace mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); } mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); const auto duration = std::chrono::steady_clock::now() - start; @@ -831,7 +831,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); const auto result = mNavigator->raycast(mAgentHalfExtents, mStart, mEnd, Flag_walk); @@ -862,7 +862,7 @@ namespace mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape, btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); const auto navMeshes = mNavigator->getNavMeshes(); ASSERT_EQ(navMeshes.size(), 1); @@ -878,7 +878,7 @@ namespace oscillatingBoxShapePosition); mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform); mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); } ASSERT_EQ(navMeshes.size(), 1); diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 3f7114b85..bee4510b4 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -10,7 +10,9 @@ #include +#include #include +#include namespace { @@ -23,12 +25,14 @@ namespace } int getMinDistanceTo(const TilePosition& position, int maxDistance, - const std::map>& tilesPerHalfExtents) + const std::map>& tilesPerHalfExtents, + const std::set>& presentTiles) { int result = maxDistance; for (const auto& [halfExtents, tiles] : tilesPerHalfExtents) for (const TilePosition& tile : tiles) - result = std::min(result, getManhattanDistance(position, tile)); + if (presentTiles.find(std::make_tuple(halfExtents, tile)) == presentTiles.end()) + result = std::min(result, getManhattanDistance(position, tile)); return result; } } @@ -142,7 +146,7 @@ namespace DetourNavigator mHasJob.notify_all(); } - void AsyncNavMeshUpdater::wait(Loading::Listener& listener) + void AsyncNavMeshUpdater::wait(Loading::Listener& listener, WaitConditionType waitConditionType) { if (mSettings.get().mWaitUntilMinDistanceToPlayer == 0) return; @@ -150,15 +154,26 @@ namespace DetourNavigator const std::size_t initialJobsLeft = getTotalJobs(); std::size_t maxProgress = initialJobsLeft + mThreads.size(); listener.setProgressRange(maxProgress); - const int minDistanceToPlayer = waitUntilJobsDone(initialJobsLeft, maxProgress, listener); - if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer) + switch (waitConditionType) { - mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); - listener.setProgress(maxProgress); + case WaitConditionType::requiredTilesPresent: + { + const int minDistanceToPlayer = waitUntilJobsDoneForNotPresentTiles(initialJobsLeft, maxProgress, listener); + if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer) + { + mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); + listener.setProgress(maxProgress); + } + break; + } + case WaitConditionType::allJobsDone: + waitUntilAllJobsDone(); + listener.setProgress(maxProgress); + break; } } - int AsyncNavMeshUpdater::waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener) + int AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener) { std::size_t prevJobsLeft = initialJobsLeft; std::size_t jobsDone = 0; @@ -174,9 +189,9 @@ namespace DetourNavigator minDistanceToPlayer = 0; return true; } - minDistanceToPlayer = getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed); + minDistanceToPlayer = getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles); for (const auto& [threadId, queue] : mThreadsQueues) - minDistanceToPlayer = getMinDistanceTo(playerPosition, minDistanceToPlayer, queue.mPushed); + minDistanceToPlayer = getMinDistanceTo(playerPosition, minDistanceToPlayer, queue.mPushed, mPresentTiles); return minDistanceToPlayer >= maxDistanceToPlayer; }; std::unique_lock lock(mMutex); @@ -199,6 +214,15 @@ namespace DetourNavigator return minDistanceToPlayer; } + void AsyncNavMeshUpdater::waitUntilAllJobsDone() + { + { + std::unique_lock lock(mMutex); + mDone.wait(lock, [this] { return mJobs.size() + getTotalThreadJobsUnsafe() == 0; }); + } + mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); + } + void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const { std::size_t jobs = 0; @@ -273,6 +297,11 @@ namespace DetourNavigator navMeshVersion); } + if (status == UpdateNavMeshStatus::removed || status == UpdateNavMeshStatus::lost) + mPresentTiles.erase(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile)); + else if (isSuccess(status) && status != UpdateNavMeshStatus::ignored) + mPresentTiles.insert(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile)); + const auto finish = std::chrono::steady_clock::now(); writeDebugFiles(job, recastMesh.get()); diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index fb9532519..e8b2611e9 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -6,6 +6,7 @@ #include "tilecachedrecastmeshmanager.hpp" #include "tileposition.hpp" #include "navmeshtilescache.hpp" +#include "waitconditiontype.hpp" #include @@ -61,7 +62,7 @@ namespace DetourNavigator void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& mNavMeshCacheItem, const TilePosition& playerTile, const std::map& changedTiles); - void wait(Loading::Listener& listener); + void wait(Loading::Listener& listener, WaitConditionType waitConditionType); void reportStats(unsigned int frameNumber, osg::Stats& stats) const; @@ -114,6 +115,7 @@ namespace DetourNavigator NavMeshTilesCache mNavMeshTilesCache; Misc::ScopeGuarded>> mProcessingTiles; std::map> mLastUpdates; + std::set> mPresentTiles; std::map mThreadsQueues; std::vector mThreads; @@ -143,7 +145,9 @@ namespace DetourNavigator void cleanupLastUpdates(); - int waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener); + int waitUntilJobsDoneForNotPresentTiles(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener); + + void waitUntilAllJobsDone(); }; } diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 3ec5e5acc..8cf4cb80e 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -7,6 +7,7 @@ #include "objectid.hpp" #include "navmeshcacheitem.hpp" #include "recastmeshtiles.hpp" +#include "waitconditiontype.hpp" namespace ESM { @@ -165,9 +166,10 @@ namespace DetourNavigator virtual void setUpdatesEnabled(bool enabled) = 0; /** - * @brief wait locks thread until all tiles are updated from last update call. + * @brief wait locks thread until tiles are updated from last update call based on passed condition type. + * @param waitConditionType defines when waiting will stop */ - virtual void wait(Loading::Listener& listener) = 0; + virtual void wait(Loading::Listener& listener, WaitConditionType waitConditionType) = 0; /** * @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through. diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index d1e75b864..1d02ba266 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -153,9 +153,9 @@ namespace DetourNavigator mUpdatesEnabled = enabled; } - void NavigatorImpl::wait(Loading::Listener& listener) + void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType) { - mNavMeshManager.wait(listener); + mNavMeshManager.wait(listener, waitConditionType); } SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index a53c9608d..324946261 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -48,7 +48,7 @@ namespace DetourNavigator void setUpdatesEnabled(bool enabled) override; - void wait(Loading::Listener& listener) override; + void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override; SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index c21db2bf8..2c12c45eb 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -73,7 +73,7 @@ namespace DetourNavigator void setUpdatesEnabled(bool /*enabled*/) override {} - void wait(Loading::Listener& /*listener*/) override {} + void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {} SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 71a4def4f..8f1aa86d4 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -5,6 +5,7 @@ #include "makenavmesh.hpp" #include "navmeshcacheitem.hpp" #include "settings.hpp" +#include "waitconditiontype.hpp" #include @@ -190,9 +191,9 @@ namespace DetourNavigator " recastMeshManagerRevision=" << lastRevision; } - void NavMeshManager::wait(Loading::Listener& listener) + void NavMeshManager::wait(Loading::Listener& listener, WaitConditionType waitConditionType) { - mAsyncNavMeshUpdater.wait(listener); + mAsyncNavMeshUpdater.wait(listener, waitConditionType); } SharedNavMeshCacheItem NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index ce90aafc5..a38e221a7 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -6,6 +6,7 @@ #include "offmeshconnectionsmanager.hpp" #include "sharednavmesh.hpp" #include "recastmeshtiles.hpp" +#include "waitconditiontype.hpp" #include @@ -45,7 +46,7 @@ namespace DetourNavigator void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents); - void wait(Loading::Listener& listener); + void wait(Loading::Listener& listener, WaitConditionType waitConditionType); SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const; diff --git a/components/detournavigator/waitconditiontype.hpp b/components/detournavigator/waitconditiontype.hpp new file mode 100644 index 000000000..06a590128 --- /dev/null +++ b/components/detournavigator/waitconditiontype.hpp @@ -0,0 +1,13 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_WAITCONDITIONTYPE_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_WAITCONDITIONTYPE_H + +namespace DetourNavigator +{ + enum class WaitConditionType + { + requiredTilesPresent, + allJobsDone, + }; +} + +#endif From fb344d27e033da9b095d677f2cf5ae4b6f44d05a Mon Sep 17 00:00:00 2001 From: fredzio Date: Fri, 14 May 2021 23:38:39 +0200 Subject: [PATCH 055/101] Use insert_or_assign() instead of hand rolled version. --- apps/openmw/mwworld/store.cpp | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index fb66b0a1d..53ba3cfc2 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -58,10 +58,7 @@ namespace MWWorld record.load(esm, isDeleted); - // Try to overwrite existing record - std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); - if (!ret.second) - ret.first->second = record; + mStatic.insert_or_assign(record.mIndex, record); } template int IndexedStore::getSize() const @@ -181,11 +178,9 @@ namespace MWWorld record.load(esm, isDeleted); Misc::StringUtils::lowerCaseInPlace(record.mId); - std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); + std::pair inserted = mStatic.insert_or_assign(record.mId, record); if (inserted.second) mShared.push_back(&inserted.first->second); - else - inserted.first->second = record; return RecordId(record.mId, isDeleted); } @@ -235,28 +230,20 @@ namespace MWWorld if(it == mStatic.end()) return nullptr; } - std::pair result = - mDynamic.insert(std::pair(id, item)); + std::pair result = mDynamic.insert_or_assign(id, item); T *ptr = &result.first->second; - if (result.second) { + if (result.second) mShared.push_back(ptr); - } else { - *ptr = item; - } return ptr; } template T *Store::insertStatic(const T &item) { std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mStatic.insert(std::pair(id, item)); + std::pair result = mStatic.insert_or_assign(id, item); T *ptr = &result.first->second; - if (result.second) { + if (result.second) mShared.push_back(ptr); - } else { - *ptr = item; - } return ptr; } template From b63f53f5bb0ccd5b6a97e5eb1d4f7cf13d2dffab Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 15 May 2021 11:31:08 +0400 Subject: [PATCH 056/101] Disable shield animation when we launch a torch one (bug #6043) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f22c4aa2..271711c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,6 +124,7 @@ Bug #6007: Crash when ending cutscene is playing Bug #6016: Greeting interrupts Fargoth's sneak-walk Bug #6028: Particle system controller values are incorrectly used + Bug #6043: Actor can have torch missing when torch animation is played Feature #390: 3rd person look "over the shoulder" Feature #832: OpenMW-CS: Handle deleted references Feature #1536: Show more information about level on menu diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6758df9c4..cb1330535 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1876,8 +1876,10 @@ bool CharacterController::updateWeaponState(CharacterState& idle) MWWorld::ConstContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() && updateCarriedLeftVisible(mWeaponType)) - { + if (mAnimation->isPlaying("shield")) + mAnimation->disable("shield"); + mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); } From 5373cf1cd5e2899c7d9fd7976ec39fbf4e5efc95 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 15 May 2021 12:36:37 +0200 Subject: [PATCH 057/101] Replace raw pointer by observer_ptr to avoid dangling pointer dereferencing When game exit is requests when initial loading screen is active LightManager can be destructed in the main thread before LightManagerStateAttribute::apply is completed by different thread. Given that it uses raw pointer at some point it becomes dangling because object is destructed this leads to UB and eventual SIGSEGV. --- components/sceneutil/lightmanager.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index b5c7af780..00c19dd40 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -731,7 +731,7 @@ namespace SceneUtil META_StateAttribute(NifOsg, LightManagerStateAttribute, osg::StateAttribute::LIGHT) - void initSharedLayout(osg::GLExtensions* ext, int handle) const + void initSharedLayout(osg::GLExtensions* ext, int handle, LightManager& lightManager) const { constexpr std::array index = { static_cast(Shader::UBOBinding::LightBuffer) }; int totalBlockSize = -1; @@ -753,13 +753,17 @@ namespace SceneUtil for (int i = 0; i < 2; ++i) { - auto& buf = mLightManager->getLightBuffer(i); + auto& buf = lightManager.getLightBuffer(i); buf->configureLayout(offsets[0], offsets[1], offsets[2], totalBlockSize, stride); } } void apply(osg::State& state) const override { + osg::ref_ptr lightManager; + if (!mLightManager.lock(lightManager)) + return; + if (!mInitLayout) { mDummyProgram->apply(state); @@ -772,12 +776,12 @@ namespace SceneUtil // wait until the UBO binding is created if (activeUniformBlocks > 0) { - initSharedLayout(ext, handle); + initSharedLayout(ext, handle, *lightManager); mInitLayout = true; } } - mLightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->uploadCachedSunPos(state.getInitialViewMatrix()); - mLightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->dirty(); + lightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->uploadCachedSunPos(state.getInitialViewMatrix()); + lightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->dirty(); } private: @@ -807,7 +811,7 @@ namespace SceneUtil return shader; } - LightManager* mLightManager; + osg::observer_ptr mLightManager; osg::ref_ptr mDummyProgram; mutable bool mInitLayout; }; From 690d85d0e9ddeb1b881f5c259b92885f144f94cb Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sat, 15 May 2021 15:38:17 +0200 Subject: [PATCH 058/101] Don't use at() instead [] when length is checked/known --- apps/openmw/mwrender/objectpaging.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 4 ++-- apps/openmw/mwworld/store.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4217c4714..c6b568183 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -417,7 +417,7 @@ namespace MWRender { try { - unsigned int index = cell->mContextList.at(i).index; + unsigned int index = cell->mContextList[i].index; if (esm.size()<=index) esm.resize(index+1); cell->restore(esm[index], i); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 73f69e220..efe575a1d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -547,7 +547,7 @@ namespace MWWorld try { // Reopen the ESM reader and seek to the right position. - int index = mCell->mContextList.at(i).index; + int index = mCell->mContextList[i].index; mCell->restore (esm[index], i); ESM::CellRef ref; @@ -605,7 +605,7 @@ namespace MWWorld try { // Reopen the ESM reader and seek to the right position. - int index = mCell->mContextList.at(i).index; + int index = mCell->mContextList[i].index; mCell->restore (esm[index], i); ESM::CellRef ref; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 53ba3cfc2..e99b05a29 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1003,7 +1003,7 @@ namespace MWWorld if (index >= mStatic.size()) { return nullptr; } - return &mStatic.at(index); + return &mStatic[index]; } const ESM::Attribute *Store::find(size_t index) const From 13f060623f894d092be07de3582d595a9ae32340 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 15 May 2021 10:45:39 -0400 Subject: [PATCH 059/101] Fix out-of-bounds access in JournalBooks::createCyrillicJournalIndex --- apps/openmw/mwgui/journalbooks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 065a503e6..40053b3c8 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -278,7 +278,7 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () mIndexPagesCount = 2; } - unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + unsigned char ch[3] = {0xd0, 0x90, 0x00}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 for (int i = 0; i < 32; ++i) { From b717103fe0ea8cbdce3b64504eb455cd6b65e02f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 15 May 2021 19:56:14 +0400 Subject: [PATCH 060/101] Fix warning in assert - size_t can not be negative --- components/bsa/bsa_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 158080ea3..3375882f5 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -240,7 +240,7 @@ int BSAFile::getIndex(const char *str) const return -1; size_t res = it->second; - assert(res >= 0 && res < mFiles.size()); + assert(res < mFiles.size()); return static_cast(res); } From f2188d25336a0721d874a9d1436dc2eb3ad60c6e Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 15 May 2021 02:29:50 +0200 Subject: [PATCH 061/101] Reduce temporary allocations on ESM loading By moving objects instead of copying when possible. --- apps/opencs/model/world/refcollection.cpp | 8 +++++--- apps/openmw/mwrender/groundcover.cpp | 2 +- apps/openmw/mwrender/objectpaging.cpp | 4 ++-- apps/openmw/mwworld/cellstore.cpp | 3 ++- apps/openmw/mwworld/esmstore.cpp | 12 ++++++------ apps/openmw/mwworld/store.cpp | 4 ++-- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 51588cbc2..dfdb8e73b 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -108,11 +108,13 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool Record record; record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - (base ? record.mBase : record.mModified) = ref; + const ESM::RefNum refNum = ref.mRefNum; + std::string refId = ref.mId; + (base ? record.mBase : record.mModified) = std::move(ref); appendRecord (record); - cache.insert (std::make_pair (ref.mRefNum, ref.mId)); + cache.emplace(refNum, std::move(refId)); } else { @@ -123,7 +125,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool Record record = getRecord (index); record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified; - (base ? record.mBase : record.mModified) = ref; + (base ? record.mBase : record.mModified) = std::move(ref); setRecord (index, record); } diff --git a/apps/openmw/mwrender/groundcover.cpp b/apps/openmw/mwrender/groundcover.cpp index fd2246253..63df3e249 100644 --- a/apps/openmw/mwrender/groundcover.cpp +++ b/apps/openmw/mwrender/groundcover.cpp @@ -241,7 +241,7 @@ namespace MWRender if (model.empty()) continue; model = "meshes/" + model; - instances[model].emplace_back(ref, model); + instances[model].emplace_back(std::move(ref), std::move(model)); } } } diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4217c4714..05acb35d1 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -432,7 +432,7 @@ namespace MWRender if (!typeFilter(type,size>=2)) continue; if (deleted) { refs.erase(ref.mRefNum); continue; } if (ref.mRefNum.fromGroundcoverFile()) continue; - refs[ref.mRefNum] = ref; + refs[ref.mRefNum] = std::move(ref); } } catch (std::exception&) @@ -448,7 +448,7 @@ namespace MWRender if (deleted) { refs.erase(ref.mRefNum); continue; } int type = store.findStatic(ref.mRefID); if (!typeFilter(type,size>=2)) continue; - refs[ref.mRefNum] = ref; + refs[ref.mRefNum] = std::move(ref); } } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 73f69e220..813042f15 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -566,7 +566,8 @@ namespace MWWorld continue; } - mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID)); + Misc::StringUtils::lowerCaseInPlace(ref.mRefID); + mIds.push_back(std::move(ref.mRefID)); } } catch (std::exception& e) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index a69d74b05..8b2eeb2fc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -31,7 +31,7 @@ namespace else if (std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum) == cell.mMovedRefs.end()) { Misc::StringUtils::lowerCaseInPlace(ref.mRefID); - refs[ref.mRefNum] = ref.mRefID; + refs[ref.mRefNum] = std::move(ref.mRefID); } } } @@ -42,9 +42,9 @@ namespace refs.erase(it.first.mRefNum); else { - ESM::CellRef ref = it.first; - Misc::StringUtils::lowerCaseInPlace(ref.mRefID); - refs[ref.mRefNum] = ref.mRefID; + std::string refId = it.first.mRefID; + Misc::StringUtils::lowerCaseInPlace(refId); + refs[it.first.mRefNum] = std::move(refId); } } } @@ -254,8 +254,8 @@ void ESMStore::countRecords() readRefs(*it, refs, readers); for(auto it = mCells.extBegin(); it != mCells.extEnd(); it++) readRefs(*it, refs, readers); - for(const auto& pair : refs) - mRefCount[pair.second]++; + for(auto& pair : refs) + mRefCount[std::move(pair.second)]++; } int ESMStore::getRefCount(const std::string& id) const diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 53ba3cfc2..8e6596cd3 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -518,9 +518,9 @@ namespace MWWorld // But there may be duplicates here! ESM::CellRefTracker::iterator iter = std::find_if(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(ref.mRefNum)); if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(std::make_pair(ref, deleted)); + cellAlt->mLeasedRefs.emplace_back(std::move(ref), deleted); else - *iter = std::make_pair(ref, deleted); + *iter = std::make_pair(std::move(ref), deleted); } } const ESM::Cell *Store::search(const std::string &id) const From 6248dc72cbaf079608619bf195783e42d3693b13 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 15 May 2021 03:43:26 +0200 Subject: [PATCH 062/101] Convert to lower case only when needed --- apps/openmw/mwrender/objectpaging.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 05acb35d1..72ea70000 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -426,8 +426,8 @@ namespace MWRender bool deleted = false; while(cell->getNextRef(esm[index], ref, deleted)) { - Misc::StringUtils::lowerCaseInPlace(ref.mRefID); if (std::find(cell->mMovedRefs.begin(), cell->mMovedRefs.end(), ref.mRefNum) != cell->mMovedRefs.end()) continue; + Misc::StringUtils::lowerCaseInPlace(ref.mRefID); int type = store.findStatic(ref.mRefID); if (!typeFilter(type,size>=2)) continue; if (deleted) { refs.erase(ref.mRefNum); continue; } @@ -443,9 +443,9 @@ namespace MWRender for (ESM::CellRefTracker::const_iterator it = cell->mLeasedRefs.begin(); it != cell->mLeasedRefs.end(); ++it) { ESM::CellRef ref = it->first; - Misc::StringUtils::lowerCaseInPlace(ref.mRefID); bool deleted = it->second; if (deleted) { refs.erase(ref.mRefNum); continue; } + Misc::StringUtils::lowerCaseInPlace(ref.mRefID); int type = store.findStatic(ref.mRefID); if (!typeFilter(type,size>=2)) continue; refs[ref.mRefNum] = std::move(ref); From 9938af2289d3cae5b4c476ea75c0c48a3b517b81 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 6 Apr 2021 23:58:57 +0200 Subject: [PATCH 063/101] Use unordered_map for ref count Reduces ESMStore::countRecords time by 8%. --- apps/openmw/mwworld/esmstore.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 26f497a52..608b5489e 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "store.hpp" @@ -76,7 +77,7 @@ namespace MWWorld std::map mIds; std::map mStaticIds; - std::map mRefCount; + std::unordered_map mRefCount; std::map mStores; From 1e2aae809516d7051c36f94863f51f603de38547 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 6 Apr 2021 23:59:58 +0200 Subject: [PATCH 064/101] Use stable sort+unique to collect RefIDs for ESMStore records counting The idea is to avoid std::map lookup for each CellRef. Instead generate a sequence of added and removed RefNums into a vector then order them by RefNum using a stable sort that preserves relative order of elements with the same RefNum. RefIDs are stored in a different vector to avoid std::string move ctor calls when swapping elements while sorting. Reversed iteration over added and removed RefNums for each unique RefNum is an equivalent to what map-based algorithm produces. The main benefit from sorting a vector is a data locality that means less cache misses for each access. Reduces ESMStore::countRecords perf cycles by 25%. --- apps/openmw/mwworld/esmstore.cpp | 52 +++++++++++++++++++++++--------- components/misc/algorithm.hpp | 36 ++++++++++++++++++++++ 2 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 components/misc/algorithm.hpp diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 8b2eeb2fc..71ee2f5c3 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -1,5 +1,6 @@ #include "esmstore.hpp" +#include #include #include @@ -8,12 +9,23 @@ #include #include #include +#include #include "../mwmechanics/spelllist.hpp" namespace { - void readRefs(const ESM::Cell& cell, std::map& refs, std::vector& readers) + struct Ref + { + ESM::RefNum mRefNum; + std::size_t mRefID; + + Ref(ESM::RefNum refNum, std::size_t refID) : mRefNum(refNum), mRefID(refID) {} + }; + + constexpr std::size_t deletedRefID = std::numeric_limits::max(); + + void readRefs(const ESM::Cell& cell, std::vector& refs, std::vector& refIDs, std::vector& readers) { for (size_t i = 0; i < cell.mContextList.size(); i++) { @@ -27,24 +39,22 @@ namespace while(cell.getNextRef(readers[index], ref, deleted)) { if(deleted) - refs.erase(ref.mRefNum); + refs.emplace_back(ref.mRefNum, deletedRefID); else if (std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum) == cell.mMovedRefs.end()) { - Misc::StringUtils::lowerCaseInPlace(ref.mRefID); - refs[ref.mRefNum] = std::move(ref.mRefID); + refs.emplace_back(ref.mRefNum, refIDs.size()); + refIDs.push_back(std::move(ref.mRefID)); } } } - for(const auto& it : cell.mLeasedRefs) + for(const auto& [value, deleted] : cell.mLeasedRefs) { - bool deleted = it.second; if(deleted) - refs.erase(it.first.mRefNum); + refs.emplace_back(value.mRefNum, deletedRefID); else { - std::string refId = it.first.mRefID; - Misc::StringUtils::lowerCaseInPlace(refId); - refs[it.first.mRefNum] = std::move(refId); + refs.emplace_back(value.mRefNum, refIDs.size()); + refIDs.push_back(value.mRefID); } } } @@ -248,14 +258,26 @@ void ESMStore::countRecords() { if(!mRefCount.empty()) return; - std::map refs; + std::vector refs; + std::vector refIDs; std::vector readers; for(auto it = mCells.intBegin(); it != mCells.intEnd(); it++) - readRefs(*it, refs, readers); + readRefs(*it, refs, refIDs, readers); for(auto it = mCells.extBegin(); it != mCells.extEnd(); it++) - readRefs(*it, refs, readers); - for(auto& pair : refs) - mRefCount[std::move(pair.second)]++; + readRefs(*it, refs, refIDs, readers); + const auto lessByRefNum = [] (const Ref& l, const Ref& r) { return l.mRefNum < r.mRefNum; }; + std::stable_sort(refs.begin(), refs.end(), lessByRefNum); + const auto equalByRefNum = [] (const Ref& l, const Ref& r) { return l.mRefNum == r.mRefNum; }; + const auto incrementRefCount = [&] (const Ref& value) + { + if (value.mRefID != deletedRefID) + { + std::string& refId = refIDs[value.mRefID]; + Misc::StringUtils::lowerCaseInPlace(refId); + ++mRefCount[std::move(refId)]; + } + }; + Misc::forEachUnique(refs.rbegin(), refs.rend(), equalByRefNum, incrementRefCount); } int ESMStore::getRefCount(const std::string& id) const diff --git a/components/misc/algorithm.hpp b/components/misc/algorithm.hpp new file mode 100644 index 000000000..4d70afa86 --- /dev/null +++ b/components/misc/algorithm.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_COMPONENTS_MISC_ALGORITHM_H +#define OPENMW_COMPONENTS_MISC_ALGORITHM_H + +#include +#include + +namespace Misc +{ + template + inline Iterator forEachUnique(Iterator begin, Iterator end, BinaryPredicate predicate, Function function) + { + static_assert( + std::is_base_of_v< + std::forward_iterator_tag, + typename std::iterator_traits::iterator_category + > + ); + if (begin == end) + return begin; + function(*begin); + auto last = begin; + ++begin; + while (begin != end) + { + if (!predicate(*begin, *last)) + { + function(*begin); + last = begin; + } + ++begin; + } + return begin; + } +} + +#endif From c1e3869f25fa54d73f24a0973d27560c666ffd4d Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sat, 15 May 2021 19:49:15 +0200 Subject: [PATCH 065/101] Remove an unused struct --- apps/openmw/mwphysics/mtphysics.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 82214b628..9b98e7e8f 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -106,16 +106,6 @@ namespace return actorData.mPosition * interpolationFactor + actorData.mActorRaw->getPreviousPosition() * (1.f - interpolationFactor); } - struct WorldFrameData - { - WorldFrameData() : mIsInStorm(MWBase::Environment::get().getWorld()->isInStorm()) - , mStormDirection(MWBase::Environment::get().getWorld()->getStormDirection()) - {} - - bool mIsInStorm; - osg::Vec3f mStormDirection; - }; - namespace Config { /// @return either the number of thread as configured by the user, or 1 if Bullet doesn't support multithreading From 7deb6a6ffd3e46a58441ac6fa94a538447e90ea5 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sat, 15 May 2021 19:50:01 +0200 Subject: [PATCH 066/101] Use const references when possible in for loops No need for useless copies. --- apps/openmw/mwgui/dialogue.cpp | 2 +- apps/openmw/mwmechanics/spelllist.cpp | 2 +- apps/openmw/mwrender/objectpaging.cpp | 4 ++-- apps/openmw/mwworld/esmstore.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1f155bd47..0fda54eba 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -306,7 +306,7 @@ namespace MWGui deleteLater(); for (Link* link : mLinks) delete link; - for (auto link : mTopicLinks) + for (const auto& link : mTopicLinks) delete link.second; for (auto history : mHistoryContents) delete history; diff --git a/apps/openmw/mwmechanics/spelllist.cpp b/apps/openmw/mwmechanics/spelllist.cpp index 24a04788e..9328d533e 100644 --- a/apps/openmw/mwmechanics/spelllist.cpp +++ b/apps/openmw/mwmechanics/spelllist.cpp @@ -70,7 +70,7 @@ namespace MWMechanics auto& id = spell->mId; bool changed = withBaseRecord([&] (auto& spells) { - for(auto it : spells) + for(const auto& it : spells) { if(Misc::StringUtils::ciEqual(id, it)) return false; diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4217c4714..174c25959 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -743,7 +743,7 @@ namespace MWRender ccf.mCell = cell; mCache->call(ccf); if (ccf.mToClear.empty()) return false; - for (auto chunk : ccf.mToClear) + for (const auto& chunk : ccf.mToClear) mCache->removeFromObjectCache(chunk); return true; } @@ -765,7 +765,7 @@ namespace MWRender ccf.mActiveGridOnly = true; mCache->call(ccf); if (ccf.mToClear.empty()) return false; - for (auto chunk : ccf.mToClear) + for (const auto& chunk : ccf.mToClear) mCache->removeFromObjectCache(chunk); return true; } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index a69d74b05..0ec6d8d73 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -63,7 +63,7 @@ namespace // We will replace invalid entries by fixed ones std::vector npcsToReplace; - for (auto npcIter : npcs) + for (const auto& npcIter : npcs) { ESM::NPC npc = npcIter.second; bool changed = false; From 1cd15613a6af25bc629f91a32d8d92544833b937 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sat, 15 May 2021 22:14:08 +0200 Subject: [PATCH 067/101] Remove some useless headers in apps/openmw/mwmechanics --- apps/openmw/mwmechanics/aiavoiddoor.hpp | 4 ---- apps/openmw/mwmechanics/aipackage.hpp | 1 - apps/openmw/mwmechanics/aisequence.cpp | 2 -- apps/openmw/mwmechanics/spelllist.hpp | 2 -- apps/openmw/mwmechanics/spells.hpp | 1 - apps/openmw/mwmechanics/weaponpriority.hpp | 2 -- 6 files changed, 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 1781c5e4a..183f429f3 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -3,10 +3,6 @@ #include "typedaipackage.hpp" -#include - -#include - #include "../mwworld/class.hpp" #include "pathfinding.hpp" diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 81b09c8b9..5ad73c2da 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -3,7 +3,6 @@ #include -#include #include #include "pathfinding.hpp" diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 575a03434..fada7761d 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -5,8 +5,6 @@ #include #include -#include "../mwbase/world.hpp" - #include "aipackage.hpp" #include "aistate.hpp" #include "aiwander.hpp" diff --git a/apps/openmw/mwmechanics/spelllist.hpp b/apps/openmw/mwmechanics/spelllist.hpp index c95ee812b..5920949d6 100644 --- a/apps/openmw/mwmechanics/spelllist.hpp +++ b/apps/openmw/mwmechanics/spelllist.hpp @@ -9,8 +9,6 @@ #include -#include "magiceffects.hpp" - namespace ESM { struct SpellState; diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 055339795..9737b72cd 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "../mwworld/timestamp.hpp" diff --git a/apps/openmw/mwmechanics/weaponpriority.hpp b/apps/openmw/mwmechanics/weaponpriority.hpp index 67de7b50f..9dcef3e2e 100644 --- a/apps/openmw/mwmechanics/weaponpriority.hpp +++ b/apps/openmw/mwmechanics/weaponpriority.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_WEAPON_PRIORITY_H #define OPENMW_WEAPON_PRIORITY_H -#include - #include "../mwworld/ptr.hpp" namespace MWMechanics From 9522a64e7d674db5485d2adb846b85d55fce08ee Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sat, 15 May 2021 22:15:46 +0200 Subject: [PATCH 068/101] Remove some useless includes from apps/openmw/mwgui --- apps/openmw/mwgui/bookpage.hpp | 1 - apps/openmw/mwgui/console.cpp | 4 ++++ apps/openmw/mwgui/console.hpp | 4 ---- apps/openmw/mwgui/itemview.cpp | 2 -- apps/openmw/mwgui/loadingscreen.hpp | 1 - apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 -- apps/openmw/mwgui/repair.cpp | 3 +-- apps/openmw/mwgui/repair.hpp | 2 -- apps/openmw/mwgui/spellwindow.cpp | 2 -- apps/openmw/mwgui/waitdialog.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 2 -- 12 files changed, 6 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index f9fd93089..512a43992 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -10,7 +10,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index d0d3b87a6..b9004fcdb 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -9,6 +9,10 @@ #include #include +#include +#include +#include +#include #include "../mwscript/extensions.hpp" diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 52aa42f2a..2b8cecbc0 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -6,12 +6,8 @@ #include #include -#include -#include -#include #include #include -#include #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 94dcc77c5..14f2c1dd9 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -5,9 +5,7 @@ #include #include #include -#include #include -#include #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index e1c652386..ac911ab60 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -3,7 +3,6 @@ #include -#include #include #include diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1bf3b24ee..df6962c78 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -1,7 +1,6 @@ #include "recharge.hpp" #include -#include #include @@ -18,6 +17,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/recharge.hpp" +#include "itemselection.hpp" #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 3d469bac5..c260b1554 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -3,8 +3,6 @@ #include "windowbase.hpp" -#include "itemselection.hpp" - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index ea79e0326..351b97603 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include @@ -17,6 +15,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" +#include "itemselection.hpp" #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 594ad2823..701009f54 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -3,8 +3,6 @@ #include "windowbase.hpp" -#include "itemselection.hpp" - #include "../mwmechanics/repair.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d76a59820..873037db1 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,9 +1,7 @@ #include "spellwindow.hpp" -#include #include #include -#include #include #include diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 18cc187c1..42a70dcfa 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -23,8 +23,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "../mwstate/charactermanager.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 68dd9faa3..f45990f21 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -65,7 +64,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" From 9373e4ada761648ad957a233f0675e5e18b8e031 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sat, 15 May 2021 23:13:46 +0200 Subject: [PATCH 069/101] Remove some useless includes in apps/openmw/mwphysics --- apps/openmw/mwphysics/actor.hpp | 1 - apps/openmw/mwphysics/actorconvexcallback.cpp | 2 -- apps/openmw/mwphysics/contacttestresultcallback.hpp | 2 -- apps/openmw/mwphysics/movementsolver.hpp | 2 -- apps/openmw/mwphysics/projectileconvexcallback.hpp | 2 -- apps/openmw/mwphysics/stepper.cpp | 2 -- 6 files changed, 11 deletions(-) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 54f9009bf..45e2039ba 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -10,7 +10,6 @@ #include #include #include -#include class btCollisionShape; class btCollisionObject; diff --git a/apps/openmw/mwphysics/actorconvexcallback.cpp b/apps/openmw/mwphysics/actorconvexcallback.cpp index cdd432289..ef52e07c2 100644 --- a/apps/openmw/mwphysics/actorconvexcallback.cpp +++ b/apps/openmw/mwphysics/actorconvexcallback.cpp @@ -1,5 +1,3 @@ -#include - #include "actorconvexcallback.hpp" #include "collisiontype.hpp" #include "contacttestwrapper.h" diff --git a/apps/openmw/mwphysics/contacttestresultcallback.hpp b/apps/openmw/mwphysics/contacttestresultcallback.hpp index fbe12d5dc..3d1b3b8aa 100644 --- a/apps/openmw/mwphysics/contacttestresultcallback.hpp +++ b/apps/openmw/mwphysics/contacttestresultcallback.hpp @@ -5,8 +5,6 @@ #include -#include "../mwworld/ptr.hpp" - #include "physicssystem.hpp" class btCollisionObject; diff --git a/apps/openmw/mwphysics/movementsolver.hpp b/apps/openmw/mwphysics/movementsolver.hpp index 76141ec0e..90b10c275 100644 --- a/apps/openmw/mwphysics/movementsolver.hpp +++ b/apps/openmw/mwphysics/movementsolver.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MWPHYSICS_MOVEMENTSOLVER_H #define OPENMW_MWPHYSICS_MOVEMENTSOLVER_H -#include - #include #include "constants.hpp" diff --git a/apps/openmw/mwphysics/projectileconvexcallback.hpp b/apps/openmw/mwphysics/projectileconvexcallback.hpp index c687de36c..96c84b1fe 100644 --- a/apps/openmw/mwphysics/projectileconvexcallback.hpp +++ b/apps/openmw/mwphysics/projectileconvexcallback.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MWPHYSICS_PROJECTILECONVEXCALLBACK_H #define OPENMW_MWPHYSICS_PROJECTILECONVEXCALLBACK_H -#include - #include class btCollisionObject; diff --git a/apps/openmw/mwphysics/stepper.cpp b/apps/openmw/mwphysics/stepper.cpp index 4f5a27e53..1f53c1ac5 100644 --- a/apps/openmw/mwphysics/stepper.cpp +++ b/apps/openmw/mwphysics/stepper.cpp @@ -1,7 +1,5 @@ #include "stepper.hpp" -#include - #include #include From c55db790f30eac1c501578cf2a1e1fd8f97d37a2 Mon Sep 17 00:00:00 2001 From: fredzio Date: Sun, 16 May 2021 09:40:41 +0200 Subject: [PATCH 070/101] Make the code less verbose / more readable using for range loop and structured binding. No functional changes. --- apps/openmw/mwphysics/object.cpp | 5 +- apps/openmw/mwrender/objectpaging.cpp | 4 +- apps/openmw/mwworld/cellstore.cpp | 70 ++++++++++----------------- apps/openmw/mwworld/store.cpp | 24 +++------ 4 files changed, 34 insertions(+), 69 deletions(-) diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index e3615989d..636306532 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -119,11 +119,8 @@ namespace MWPhysics assert (mShapeInstance->getCollisionShape()->isCompound()); btCompoundShape* compound = static_cast(mShapeInstance->getCollisionShape()); - for (const auto& shape : mShapeInstance->mAnimatedShapes) + for (const auto& [recIndex, shapeIndex] : mShapeInstance->mAnimatedShapes) { - int recIndex = shape.first; - int shapeIndex = shape.second; - auto nodePathFound = mRecIndexToNodePath.find(recIndex); if (nodePathFound == mRecIndexToNodePath.end()) { diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 78e05675a..8920cead9 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -440,10 +440,8 @@ namespace MWRender continue; } } - for (ESM::CellRefTracker::const_iterator it = cell->mLeasedRefs.begin(); it != cell->mLeasedRefs.end(); ++it) + for (auto [ref, deleted] : cell->mLeasedRefs) { - ESM::CellRef ref = it->first; - bool deleted = it->second; if (deleted) { refs.erase(ref.mRefNum); continue; } Misc::StringUtils::lowerCaseInPlace(ref.mRefID); int type = store.findStatic(ref.mRefID); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 813042f15..3c0bf1a66 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -345,8 +345,8 @@ namespace MWWorld void merge() { - for (std::map::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) - mMergeTo.push_back(it->first); + for (const auto & [base, _] : mMovedHere) + mMergeTo.push_back(base); } private: @@ -453,9 +453,9 @@ namespace MWWorld if (Ptr ptr = ::searchViaActorId (mCreatures, id, this, mMovedToAnotherCell)) return ptr; - for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + for (const auto& [base, _] : mMovedHere) { - MWWorld::Ptr actor (it->first, this); + MWWorld::Ptr actor (base, this); if (!actor.getClass().isActor()) continue; if (actor.getClass().getCreatureStats (actor).matchesActorId (id) && actor.getRefData().getCount() > 0) @@ -577,11 +577,8 @@ namespace MWWorld } // List moved references, from separately tracked list. - for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) + for (const auto& [ref, deleted]: mCell->mLeasedRefs) { - const ESM::CellRef &ref = it->first; - bool deleted = it->second; - if (!deleted) mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } @@ -633,10 +630,10 @@ namespace MWWorld } // Load moved references, from separately tracked list. - for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) + for (const auto& leasedRef : mCell->mLeasedRefs) { - ESM::CellRef &ref = const_cast(it->first); - bool deleted = it->second; + ESM::CellRef &ref = const_cast(leasedRef.first); + bool deleted = leasedRef.second; loadRef (ref, deleted, refNumToID); } @@ -807,11 +804,10 @@ namespace MWWorld writeReferenceCollection (writer, mWeapons); writeReferenceCollection (writer, mBodyParts); - for (MovedRefTracker::const_iterator it = mMovedToAnotherCell.begin(); it != mMovedToAnotherCell.end(); ++it) + for (const auto& [base, store] : mMovedToAnotherCell) { - LiveCellRefBase* base = it->first; ESM::RefNum refNum = base->mRef.getRefNum(); - ESM::CellId movedTo = it->second->getCell()->getCellId(); + ESM::CellId movedTo = store->getCell()->getCellId(); refNum.save(writer, true, "MVRF"); movedTo.save(writer); @@ -1138,9 +1134,9 @@ namespace MWWorld updateRechargingItems(); mRechargingItemsUpToDate = true; } - for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it) + for (const auto& [item, charge] : mRechargingItems) { - MWMechanics::rechargeItem(it->first, it->second, duration); + MWMechanics::rechargeItem(item, charge, duration); } } @@ -1148,38 +1144,22 @@ namespace MWWorld { mRechargingItems.clear(); - for (CellRefList::List::iterator it (mWeapons.mList.begin()); it!=mWeapons.mList.end(); ++it) - { - Ptr ptr = getCurrentPtr(&*it); - if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) - { - checkItem(ptr); - } - } - for (CellRefList::List::iterator it (mArmors.mList.begin()); it!=mArmors.mList.end(); ++it) - { - Ptr ptr = getCurrentPtr(&*it); - if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) - { - checkItem(ptr); - } - } - for (CellRefList::List::iterator it (mClothes.mList.begin()); it!=mClothes.mList.end(); ++it) + const auto update = [this](auto& list) { - Ptr ptr = getCurrentPtr(&*it); - if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) + for (auto & item : list) { - checkItem(ptr); - } - } - for (CellRefList::List::iterator it (mBooks.mList.begin()); it!=mBooks.mList.end(); ++it) - { - Ptr ptr = getCurrentPtr(&*it); - if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) - { - checkItem(ptr); + Ptr ptr = getCurrentPtr(&item); + if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) + { + checkItem(ptr); + } } - } + }; + + update(mWeapons.mList); + update(mArmors.mList); + update(mClothes.mList); + update(mBooks.mList); } void MWWorld::CellStore::checkItem(Ptr ptr) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 8e6596cd3..9b505f7cf 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -621,20 +621,15 @@ namespace MWWorld void Store::setUp() { - typedef DynamicExt::iterator ExtIterator; - typedef std::map::iterator IntIterator; - mSharedInt.clear(); mSharedInt.reserve(mInt.size()); - for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { - mSharedInt.push_back(&(it->second)); - } + for (auto & [_, cell] : mInt) + mSharedInt.push_back(&cell); mSharedExt.clear(); mSharedExt.reserve(mExt.size()); - for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { - mSharedExt.push_back(&(it->second)); - } + for (auto & [_, cell] : mExt) + mSharedExt.push_back(&cell); } RecordId Store::load(ESM::ESMReader &esm) { @@ -1050,18 +1045,13 @@ namespace MWWorld { // DialInfos marked as deleted are kept during the loading phase, so that the linked list // structure is kept intact for inserting further INFOs. Delete them now that loading is done. - for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - ESM::Dialogue& dial = it->second; + for (auto & [_, dial] : mStatic) dial.clearDeletedInfos(); - } mShared.clear(); mShared.reserve(mStatic.size()); - std::map::iterator it = mStatic.begin(); - for (; it != mStatic.end(); ++it) { - mShared.push_back(&(it->second)); - } + for (auto & [_, dial] : mStatic) + mShared.push_back(&dial); } template <> From 5b63019719855394a731be77fc186b81770ebf0a Mon Sep 17 00:00:00 2001 From: fredzio Date: Sat, 1 May 2021 20:28:17 +0200 Subject: [PATCH 071/101] Embed actor velocity inside its class. It makes the code simpler. --- apps/openmw/mwmechanics/character.cpp | 5 ---- apps/openmw/mwphysics/actor.cpp | 12 +++++++- apps/openmw/mwphysics/actor.hpp | 4 +++ apps/openmw/mwphysics/physicssystem.cpp | 39 +++++++++---------------- apps/openmw/mwphysics/physicssystem.hpp | 5 +--- 5 files changed, 29 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cb1330535..f7c50c5b6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2405,9 +2405,6 @@ void CharacterController::update(float duration) if (!mMovementAnimationControlled) world->queueMovement(mPtr, vec); } - else - // We must always queue movement, even if there is none, to apply gravity. - world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); movement = vec; movementSettings.mPosition[0] = movementSettings.mPosition[1] = 0; @@ -2429,8 +2426,6 @@ void CharacterController::update(float duration) if (cls.isPersistent(mPtr) || cls.getCreatureStats(mPtr).isDeathAnimationFinished()) playDeath(1.f, mDeathState); } - // We must always queue movement, even if there is none, to apply gravity. - world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } bool isPersist = isPersistentAnimPlaying(); diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 4b97ecffb..979390609 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -22,7 +22,7 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler) : mStandingOnPtr(nullptr), mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBox.center), mHalfExtents(shape->mCollisionBox.extents) - , mStuckFrames(0), mLastStuckPosition{0, 0, 0} + , mVelocity(0,0,0), mStuckFrames(0), mLastStuckPosition{0, 0, 0} , mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mInternalCollisionMode(true) , mExternalCollisionMode(true) @@ -303,4 +303,14 @@ bool Actor::skipCollisions() return std::exchange(mSkipCollisions, false); } +void Actor::setVelocity(osg::Vec3f velocity) +{ + mVelocity = velocity; +} + +osg::Vec3f Actor::velocity() +{ + return std::exchange(mVelocity, osg::Vec3f()); +} + } diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 45e2039ba..acbf33ca7 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -178,6 +178,9 @@ namespace MWPhysics bool skipCollisions(); + void setVelocity(osg::Vec3f velocity); + osg::Vec3f velocity(); + private: MWWorld::Ptr mStandingOnPtr; /// Removes then re-adds the collision object to the dynamics world @@ -206,6 +209,7 @@ namespace MWPhysics osg::Vec3f mPosition; osg::Vec3f mPreviousPosition; osg::Vec3f mPositionOffset; + osg::Vec3f mVelocity; bool mWorldPositionChanged; bool mSkipCollisions; btTransform mLocalTransform; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 382c95120..a5d6018f4 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -725,21 +725,15 @@ namespace MWPhysics void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity) { - for(auto& movementItem : mMovementQueue) - { - if (movementItem.first == ptr) - { - movementItem.second = velocity; - return; - } - } - - mMovementQueue.emplace_back(ptr, velocity); + ActorMap::iterator found = mActors.find(ptr); + if (found != mActors.end()) + found->second->setVelocity(velocity); } void PhysicsSystem::clearQueuedMovement() { - mMovementQueue.clear(); + for (const auto& [_, actor] : mActors) + actor->setVelocity(osg::Vec3f()); } const std::vector& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats) @@ -756,27 +750,21 @@ namespace MWPhysics std::vector PhysicsSystem::prepareFrameData(bool willSimulate) { std::vector actorsFrameData; - actorsFrameData.reserve(mMovementQueue.size()); + actorsFrameData.reserve(mActors.size()); const MWBase::World *world = MWBase::Environment::get().getWorld(); - for (const auto& [character, movement] : mMovementQueue) + for (const auto& [ptr, physicActor] : mActors) { - const auto foundActor = mActors.find(character); - if (foundActor == mActors.end()) // actor was already removed from the scene - continue; - - auto physicActor = foundActor->second; - float waterlevel = -std::numeric_limits::max(); - const MWWorld::CellStore *cell = character.getCell(); + const MWWorld::CellStore *cell = ptr.getCell(); if(cell->getCell()->hasWater()) waterlevel = cell->getWaterLevel(); - const MWMechanics::MagicEffects& effects = character.getClass().getCreatureStats(character).getMagicEffects(); + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(physicActor->getPtr()).getMagicEffects(); bool waterCollision = false; if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()) { - if (physicActor->getCollisionMode() || !world->isUnderwater(character.getCell(), osg::Vec3f(character.getRefData().getPosition().asVec3()))) + if (physicActor->getCollisionMode() || !world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))) waterCollision = true; } @@ -790,9 +778,8 @@ namespace MWPhysics if (!willSimulate) standingOn = physicActor->getStandingOnPtr(); - actorsFrameData.emplace_back(std::move(physicActor), standingOn, waterCollision, movement, slowFall, waterlevel); + actorsFrameData.emplace_back(physicActor, standingOn, waterCollision, slowFall, waterlevel); } - mMovementQueue.clear(); return actorsFrameData; } @@ -933,10 +920,10 @@ namespace MWPhysics } ActorFrameData::ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr standingOn, - bool waterCollision, osg::Vec3f movement, float slowFall, float waterlevel) + bool waterCollision, float slowFall, float waterlevel) : mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn), mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision), mSkipCollisionDetection(actor->skipCollisions()), - mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos() + mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(actor->velocity()), mPosition(), mRefpos() { const MWBase::World *world = MWBase::Environment::get().getWorld(); const auto ptr = actor->getPtr(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 23b278675..3d2a3c580 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -78,7 +78,7 @@ namespace MWPhysics struct ActorFrameData { - ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel); + ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, float slowFall, float waterlevel); void updatePosition(btCollisionWorld* world); std::weak_ptr mActor; Actor* mActorRaw; @@ -281,9 +281,6 @@ namespace MWPhysics bool mDebugDrawEnabled; - using PtrVelocityList = std::vector>; - PtrVelocityList mMovementQueue; - float mTimeAccum; unsigned int mProjectileId; From 5b9a2b73b0f47728c12759f7918da50dd9ef6f2a Mon Sep 17 00:00:00 2001 From: madsbuvi Date: Sun, 16 May 2021 13:04:30 +0200 Subject: [PATCH 072/101] Retain final draw callback as a member variable in ScreenshotManager, and do not call setFinalDrawCallback after init. --- apps/openmw/mwrender/screenshotmanager.cpp | 47 ++++++++++++++-------- apps/openmw/mwrender/screenshotmanager.hpp | 4 ++ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/screenshotmanager.cpp b/apps/openmw/mwrender/screenshotmanager.cpp index 89b225da4..60ac1eedd 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -36,8 +36,8 @@ namespace MWRender class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback { public: - NotifyDrawCompletedCallback(unsigned int frame) - : mDone(false), mFrame(frame) + NotifyDrawCompletedCallback() + : mDone(false), mFrame(0) { } @@ -59,6 +59,12 @@ namespace MWRender mCondition.wait(lock); } + void reset(unsigned int frame) + { + mDone = false; + mFrame = frame; + } + mutable std::condition_variable mCondition; mutable std::mutex mMutex; mutable bool mDone; @@ -94,8 +100,18 @@ namespace MWRender : mViewer(viewer) , mRootNode(rootNode) , mSceneRoot(sceneRoot) + , mDrawCompleteCallback(new NotifyDrawCompletedCallback) , mResourceSystem(resourceSystem) , mWater(water) + { + // Note: This assumes no other final draw callbacks are set anywhere and that this callback will remain set until the application exits. + // This works around *DrawCallback manipulation being unsafe in OSG >= 3.5.10 for release 0.47 + // If you need to set other final draw callbacks, read the comments of issue 6013 for a suggestion + // Ref https://gitlab.com/OpenMW/openmw/-/issues/6013 + mViewer->getCamera()->setFinalDrawCallback(mDrawCompleteCallback); + } + + ScreenshotManager::~ScreenshotManager() { } @@ -107,16 +123,10 @@ namespace MWRender tempDrw->setCullingActive(false); tempDrw->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin", osg::StateSet::USE_RENDERBIN_DETAILS); // so its after all scene bins but before POST_RENDER gui camera camera->addChild(tempDrw); - osg::ref_ptr callback (new NotifyDrawCompletedCallback(mViewer->getFrameStamp()->getFrameNumber())); - camera->setFinalDrawCallback(callback); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); - callback->waitTillDone(); + traversalsAndWait(mViewer->getFrameStamp()->getFrameNumber()); // now that we've "used up" the current frame, get a fresh frame number for the next frame() following after the screenshot is completed mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); camera->removeChild(tempDrw); - camera->setFinalDrawCallback(nullptr); } bool ScreenshotManager::screenshot360(osg::Image* image) @@ -257,6 +267,15 @@ namespace MWRender return true; } + void ScreenshotManager::traversalsAndWait(unsigned int frame) + { + mDrawCompleteCallback->reset(frame); + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mDrawCompleteCallback->waitTillDone(); + } + void ScreenshotManager::renderCameraToImage(osg::Camera *camera, osg::Image *image, int w, int h) { camera->setNodeMask(Mask_RenderToTexture); @@ -280,16 +299,10 @@ namespace MWRender mRootNode->addChild(camera); - // The draw needs to complete before we can copy back our image. - osg::ref_ptr callback (new NotifyDrawCompletedCallback(0)); - camera->setFinalDrawCallback(callback); - MWBase::Environment::get().getWindowManager()->getLoadingScreen()->loadingOn(false); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); - callback->waitTillDone(); + // The draw needs to complete before we can copy back our image. + traversalsAndWait(0); MWBase::Environment::get().getWindowManager()->getLoadingScreen()->loadingOff(); diff --git a/apps/openmw/mwrender/screenshotmanager.hpp b/apps/openmw/mwrender/screenshotmanager.hpp index 2ac50bdf0..373fe3be8 100644 --- a/apps/openmw/mwrender/screenshotmanager.hpp +++ b/apps/openmw/mwrender/screenshotmanager.hpp @@ -16,11 +16,13 @@ namespace Resource namespace MWRender { class Water; + class NotifyDrawCompletedCallback; class ScreenshotManager { public: ScreenshotManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, osg::ref_ptr sceneRoot, Resource::ResourceSystem* resourceSystem, Water* water); + ~ScreenshotManager(); void screenshot(osg::Image* image, int w, int h); bool screenshot360(osg::Image* image); @@ -29,9 +31,11 @@ namespace MWRender osg::ref_ptr mViewer; osg::ref_ptr mRootNode; osg::ref_ptr mSceneRoot; + osg::ref_ptr mDrawCompleteCallback; Resource::ResourceSystem* mResourceSystem; Water* mWater; + void traversalsAndWait(unsigned int frame); void renderCameraToImage(osg::Camera *camera, osg::Image *image, int w, int h); void makeCubemapScreenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd()); }; From e38063dcdb5dbfdf45a83032e84c115715804b33 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 16 May 2021 16:04:28 +0400 Subject: [PATCH 073/101] Discard button press events during save loading (bug #5619) --- CHANGELOG.md | 1 + components/sdlutil/sdlinputwrapper.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 271711c76..328b83852 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Bug #5603: Setting constant effect cast style doesn't correct effects view Bug #5604: Only one valid NIF root node is loaded from a single file Bug #5611: Usable items with "0 Uses" should be used only once + Bug #5619: Input events are queued during save loading Bug #5622: Can't properly interact with the console when in pause menu Bug #5627: Bookart not shown if it isn't followed by
statement Bug #5633: Damage Spells in effect before god mode is enabled continue to hurt the player character and can kill them diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 7ebfd710f..42276cc2a 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -52,9 +52,14 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v if (windowEventsOnly) { - // During loading, just handle window events, and keep others for later + // During loading, handle window events, discard button presses and keep others for later while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) handleWindowEvent(evt); + + SDL_FlushEvent(SDL_KEYDOWN); + SDL_FlushEvent(SDL_CONTROLLERBUTTONDOWN); + SDL_FlushEvent(SDL_MOUSEBUTTONDOWN); + return; } From f3e17e7c52f3ac940e53f71f3aa6e5ac3700b4a8 Mon Sep 17 00:00:00 2001 From: madsbuvi Date: Sun, 16 May 2021 18:09:48 +0200 Subject: [PATCH 074/101] Don't redundantly call notify on every frame. --- apps/openmw/mwrender/screenshotmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/screenshotmanager.cpp b/apps/openmw/mwrender/screenshotmanager.cpp index 60ac1eedd..af2970fd8 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -44,7 +44,7 @@ namespace MWRender void operator () (osg::RenderInfo& renderInfo) const override { std::lock_guard lock(mMutex); - if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame) + if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame && !mDone) { mDone = true; mCondition.notify_one(); From d520b440aa2df4478358ea3adfa32fa44071a7c2 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 15 May 2021 13:01:02 +0200 Subject: [PATCH 075/101] Copy LightBuffer data into a new object when changing layout Before this change LightBuffer copy constructor copied only mData pointer into a new object. Then memcpy was applied to an overlapping source and destination that is UB. Replace configureLayout function by a special constructor. That copies all mData values and a pointer to a buffer object into a newly allocated object. --- components/sceneutil/lightmanager.cpp | 67 +++++++++++++-------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 00c19dd40..16af3880f 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -114,15 +114,35 @@ namespace SceneUtil mOffsets[AttenuationRadius] = 8; } - LightBuffer(const LightBuffer& copy) - : osg::Referenced() - , mData(copy.mData) - , mEndian(copy.mEndian) - , mCount(copy.mCount) - , mStride(copy.mStride) - , mOffsets(copy.mOffsets) - , mCachedSunPos(copy.mCachedSunPos) - {} + LightBuffer(const LightBuffer&) = delete; + + LightBuffer(const LightBuffer& other, int offsetColors, int offsetPosition, int offsetAttenuationRadius, int size, int stride) + : mData(new osg::FloatArray(size / sizeof(GL_FLOAT))) + , mEndian(other.mEndian) + , mCount(other.mCount) + , mStride((offsetAttenuationRadius + sizeof(GL_FLOAT) * osg::Vec4::num_components + stride) / 4) + , mCachedSunPos(other.mCachedSunPos) + { + mData->setBufferObject(other.mData->getBufferObject()); + + constexpr auto sizeofFloat = sizeof(GL_FLOAT); + const auto diffuseOffset = offsetColors / sizeofFloat; + + mOffsets[Diffuse] = diffuseOffset; + mOffsets[Ambient] = diffuseOffset + 1; + mOffsets[Specular] = diffuseOffset + 2; + mOffsets[DiffuseSign] = diffuseOffset + 3; + mOffsets[Position] = offsetPosition / sizeofFloat; + mOffsets[AttenuationRadius] = offsetAttenuationRadius / sizeofFloat; + + // Copy over previous buffers light data. Buffers populate before we know the layout. + for (int i = 0; i < other.mCount; ++i) + { + std::memcpy(&(*mData)[getOffset(i, Diffuse)], &(*other.mData)[other.getOffset(i, Diffuse)], sizeof(osg::Vec4f)); + std::memcpy(&(*mData)[getOffset(i, Position)], &(*other.mData)[other.getOffset(i, Position)], sizeof(osg::Vec4f)); + std::memcpy(&(*mData)[getOffset(i, AttenuationRadius)], &(*other.mData)[other.getOffset(i, AttenuationRadius)], sizeof(osg::Vec4f)); + } + } void setDiffuse(int index, const osg::Vec4& value) { @@ -192,36 +212,11 @@ namespace SceneUtil return mEndian == osg::BigEndian ? value.asABGR() : value.asRGBA(); } - int getOffset(int index, LayoutOffset slot) + int getOffset(int index, LayoutOffset slot) const { return mStride * index + mOffsets[slot]; } - void configureLayout(int offsetColors, int offsetPosition, int offsetAttenuationRadius, int size, int stride) - { - constexpr auto sizeofFloat = sizeof(GL_FLOAT); - constexpr auto sizeofVec4 = sizeofFloat * osg::Vec4::num_components; - - LightBuffer oldBuffer = LightBuffer(*this); - - mOffsets[Diffuse] = offsetColors / sizeofFloat; - mOffsets[Ambient] = mOffsets[Diffuse] + 1; - mOffsets[Specular] = mOffsets[Diffuse] + 2; - mOffsets[DiffuseSign] = mOffsets[Diffuse] + 3; - mOffsets[Position] = offsetPosition / sizeofFloat; - mOffsets[AttenuationRadius] = offsetAttenuationRadius / sizeofFloat; - mStride = (offsetAttenuationRadius + sizeofVec4 + stride) / 4; - - // Copy over previous buffers light data. Buffers populate before we know the layout. - mData->resize(size / sizeofFloat); - for (int i = 0; i < oldBuffer.mCount; ++i) - { - std::memcpy(&(*mData)[getOffset(i, Diffuse)], &(*oldBuffer.mData)[oldBuffer.getOffset(i, Diffuse)], sizeof(osg::Vec4f)); - std::memcpy(&(*mData)[getOffset(i, Position)], &(*oldBuffer.mData)[oldBuffer.getOffset(i, Position)], sizeof(osg::Vec4f)); - std::memcpy(&(*mData)[getOffset(i, AttenuationRadius)], &(*oldBuffer.mData)[oldBuffer.getOffset(i, AttenuationRadius)], sizeof(osg::Vec4f)); - } - } - private: osg::ref_ptr mData; osg::Endian mEndian; @@ -754,7 +749,7 @@ namespace SceneUtil for (int i = 0; i < 2; ++i) { auto& buf = lightManager.getLightBuffer(i); - buf->configureLayout(offsets[0], offsets[1], offsets[2], totalBlockSize, stride); + buf = new LightBuffer(*buf, offsets[0], offsets[1], offsets[2], totalBlockSize, stride); } } From c11774f2789f256229e26549e5759c3b107a3623 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 May 2021 12:23:56 +0400 Subject: [PATCH 076/101] Do not trigger in-game bindings via mouse buttons when controls are disabled (bug #6047) --- CHANGELOG.md | 1 + apps/openmw/mwinput/mousemanager.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 328b83852..9d5c97352 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -126,6 +126,7 @@ Bug #6016: Greeting interrupts Fargoth's sneak-walk Bug #6028: Particle system controller values are incorrectly used Bug #6043: Actor can have torch missing when torch animation is played + Bug #6047: Mouse bindings can be triggered during save loading Feature #390: 3rd person look "over the shoulder" Feature #832: OpenMW-CS: Handle deleted references Feature #1536: Show more information about level on menu diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index a696332df..cf151dfac 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -144,7 +144,8 @@ namespace MWInput void MouseManager::mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id) { - MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false); + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + input->setJoystickLastUsed(false); bool guiMode = false; if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events @@ -165,7 +166,8 @@ namespace MWInput mBindingsManager->setPlayerControlsEnabled(!guiMode); // Don't trigger any mouse bindings while in settings menu, otherwise rebinding controls becomes impossible - if (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings) + // Also do not trigger bindings when input controls are disabled, e.g. during save loading + if (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings && !input->controlsDisabled()) mBindingsManager->mousePressed(arg, id); } From c54ef55ebb982bd453a8d51b8c1094c711ec295c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 May 2021 12:40:55 +0400 Subject: [PATCH 077/101] Revert "Replace raw pointer by observer_ptr to avoid dangling pointer dereferencing" This reverts commit 5373cf1cd5e2899c7d9fd7976ec39fbf4e5efc95. --- components/sceneutil/lightmanager.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 16af3880f..e8cfad522 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -726,7 +726,7 @@ namespace SceneUtil META_StateAttribute(NifOsg, LightManagerStateAttribute, osg::StateAttribute::LIGHT) - void initSharedLayout(osg::GLExtensions* ext, int handle, LightManager& lightManager) const + void initSharedLayout(osg::GLExtensions* ext, int handle) const { constexpr std::array index = { static_cast(Shader::UBOBinding::LightBuffer) }; int totalBlockSize = -1; @@ -748,17 +748,13 @@ namespace SceneUtil for (int i = 0; i < 2; ++i) { - auto& buf = lightManager.getLightBuffer(i); + auto& buf = mLightManager->getLightBuffer(i); buf = new LightBuffer(*buf, offsets[0], offsets[1], offsets[2], totalBlockSize, stride); } } void apply(osg::State& state) const override { - osg::ref_ptr lightManager; - if (!mLightManager.lock(lightManager)) - return; - if (!mInitLayout) { mDummyProgram->apply(state); @@ -771,12 +767,12 @@ namespace SceneUtil // wait until the UBO binding is created if (activeUniformBlocks > 0) { - initSharedLayout(ext, handle, *lightManager); + initSharedLayout(ext, handle); mInitLayout = true; } } - lightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->uploadCachedSunPos(state.getInitialViewMatrix()); - lightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->dirty(); + mLightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->uploadCachedSunPos(state.getInitialViewMatrix()); + mLightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->dirty(); } private: @@ -806,7 +802,7 @@ namespace SceneUtil return shader; } - osg::observer_ptr mLightManager; + LightManager* mLightManager; osg::ref_ptr mDummyProgram; mutable bool mInitLayout; }; From 11c57978b69174eb87b6d8ec572a57696fd0bc73 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 May 2021 13:01:15 +0400 Subject: [PATCH 078/101] Fix crashes on exit in the LightManager (bug #6044) --- components/sceneutil/lightmanager.cpp | 11 ++++++++++- components/sceneutil/lightmanager.hpp | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index e8cfad522..a69a64ba3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -439,7 +439,11 @@ namespace SceneUtil void apply(osg::State &state) const override { - auto* lightUniform = mLightManager->getStateSet()->getUniform("LightBuffer"); + osg::StateSet* stateSet = mLightManager->getStateSet(); + if (!stateSet) + return; + + auto* lightUniform = stateSet->getUniform("LightBuffer"); for (size_t i = 0; i < mLights.size(); ++i) { auto light = mLights[i]; @@ -832,6 +836,11 @@ namespace SceneUtil return ""; } + LightManager::~LightManager() + { + getOrCreateStateSet()->removeAttribute(osg::StateAttribute::LIGHT); + } + LightManager::LightManager(bool ffp) : mStartLight(0) , mLightingMask(~0u) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index dc7f36e96..6dbe7a3f7 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -137,6 +137,8 @@ namespace SceneUtil LightManager(const LightManager& copy, const osg::CopyOp& copyop); + ~LightManager(); + /// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired. /// By default, it's ~0u i.e. always on. /// If you have some views that do not require lighting, then set the Camera's cull mask to not include From a73ffc25c3c3f331f6daa43dfd4086d63566c5cc Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 17 May 2021 17:44:26 +0200 Subject: [PATCH 079/101] Add missing synchronization for present tiles modification insert/erase can be done from multiple threads simultaneously. mMutex is already used to synchronize reads so use it for writes too. --- components/detournavigator/asyncnavmeshupdater.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index bee4510b4..11de60745 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -298,9 +298,15 @@ namespace DetourNavigator } if (status == UpdateNavMeshStatus::removed || status == UpdateNavMeshStatus::lost) + { + const std::scoped_lock lock(mMutex); mPresentTiles.erase(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile)); + } else if (isSuccess(status) && status != UpdateNavMeshStatus::ignored) + { + const std::scoped_lock lock(mMutex); mPresentTiles.insert(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile)); + } const auto finish = std::chrono::steady_clock::now(); From aba735e6158f5b0bae9ca9f12ff0092ab2df1476 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 17 May 2021 22:45:10 +0100 Subject: [PATCH 080/101] Check in external Base64 implementation Taken from https://gist.github.com/tomykaira/f0fd86b6c73063283afe550bc5d77594 MIT licenced --- extern/Base64/Base64.h | 124 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 extern/Base64/Base64.h diff --git a/extern/Base64/Base64.h b/extern/Base64/Base64.h new file mode 100644 index 000000000..cdfdc04d0 --- /dev/null +++ b/extern/Base64/Base64.h @@ -0,0 +1,124 @@ +#ifndef _MACARON_BASE64_H_ +#define _MACARON_BASE64_H_ + +/** + * The MIT License (MIT) + * Copyright (c) 2016 tomykaira + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +namespace macaron { + +class Base64 { + public: + + static std::string Encode(const std::string data) { + static constexpr char sEncodingTable[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + + size_t in_len = data.size(); + size_t out_len = 4 * ((in_len + 2) / 3); + std::string ret(out_len, '\0'); + size_t i; + char *p = const_cast(ret.c_str()); + + for (i = 0; i < in_len - 2; i += 3) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; + *p++ = sEncodingTable[data[i + 2] & 0x3F]; + } + if (i < in_len) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + if (i == (in_len - 1)) { + *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; + *p++ = '='; + } + else { + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + return ret; + } + + static std::string Decode(const std::string& input, std::string& out) { + static constexpr unsigned char kDecodingTable[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + size_t in_len = input.size(); + if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; + + size_t out_len = in_len / 4 * 3; + if (input[in_len - 1] == '=') out_len--; + if (input[in_len - 2] == '=') out_len--; + + out.resize(out_len); + + for (size_t i = 0, j = 0; i < in_len;) { + uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + + uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); + + if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; + } + + return ""; + } + +}; + +} + +#endif /* _MACARON_BASE64_H_ */ From d66cc3b7aeaf2ca5c0a5bff1cffe9e464907bea6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 17 May 2021 22:47:08 +0100 Subject: [PATCH 081/101] Fix undefined behaviour --- extern/Base64/Base64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/Base64/Base64.h b/extern/Base64/Base64.h index cdfdc04d0..498d2be12 100644 --- a/extern/Base64/Base64.h +++ b/extern/Base64/Base64.h @@ -48,7 +48,7 @@ class Base64 { size_t out_len = 4 * ((in_len + 2) / 3); std::string ret(out_len, '\0'); size_t i; - char *p = const_cast(ret.c_str()); + char *p = ret.data(); for (i = 0; i < in_len - 2; i += 3) { *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; From 2b1326cb745406215c17f574ee844a70505d14e0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 17 May 2021 22:50:32 +0100 Subject: [PATCH 082/101] Change namespace to Base64 The functions do Base64 encoding and decoding and do not feed me delicious almond and meringue based confectionary. --- extern/Base64/Base64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/Base64/Base64.h b/extern/Base64/Base64.h index 498d2be12..4e9f51747 100644 --- a/extern/Base64/Base64.h +++ b/extern/Base64/Base64.h @@ -27,7 +27,7 @@ #include -namespace macaron { +namespace Base64 { class Base64 { public: From 081650a2e536c1a6a79cedadd3e0f10bf166d8ab Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 17 May 2021 23:00:23 +0100 Subject: [PATCH 083/101] Integrate Base64 library with build --- CMakeLists.txt | 1 + components/CMakeLists.txt | 2 ++ components/settings/parser.cpp | 2 ++ extern/Base64/CMakeLists.txt | 2 ++ 4 files changed, 7 insertions(+) create mode 100644 extern/Base64/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index b97657ffd..2ed4eafd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -516,6 +516,7 @@ endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clan add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) +add_subdirectory (extern/Base64) if (BUILD_OPENCS) add_subdirectory (extern/osgQt) endif() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9041ee533..06ae0791d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -251,6 +251,8 @@ target_link_libraries(components RecastNavigation::DebugUtils RecastNavigation::Detour RecastNavigation::Recast + + Base64 ) target_link_libraries(components ${BULLET_LIBRARIES}) diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index ee14eb5de..f375bf85b 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -7,6 +7,8 @@ #include +#include + void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, CategorySettingValueMap& settings, bool base64Encoded) { mFile = file; diff --git a/extern/Base64/CMakeLists.txt b/extern/Base64/CMakeLists.txt new file mode 100644 index 000000000..d1adf91bc --- /dev/null +++ b/extern/Base64/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(Base64 INTERFACE) +target_include_directories(Base64 INTERFACE .) \ No newline at end of file From 21f04f0d0f785fc59e302ba8865c1e257f7ba969 Mon Sep 17 00:00:00 2001 From: Benjamin Winger Date: Mon, 17 May 2021 18:36:59 -0400 Subject: [PATCH 084/101] Fixed data subrecord name for Armour record used in error --- components/esm/loadarmo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 929c111a9..674370253 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -90,7 +90,7 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) - esm.fail("Missing CTDT subrecord"); + esm.fail("Missing AODT subrecord"); } void Armor::save(ESMWriter &esm, bool isDeleted) const From 4cedb3549b53c54b31d581ce6538846aede2e136 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 17 May 2021 23:39:56 +0100 Subject: [PATCH 085/101] Decode base64-packed settings files --- components/settings/parser.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index f375bf85b..24f359b31 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -12,16 +12,31 @@ void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, CategorySettingValueMap& settings, bool base64Encoded) { mFile = file; - boost::filesystem::ifstream stream; - stream.open(boost::filesystem::path(file)); + boost::filesystem::ifstream fstream; + fstream.open(boost::filesystem::path(file)); + auto stream = std::ref(fstream); + + std::istringstream decodedStream; + if (base64Encoded) + { + std::string base64String(std::istreambuf_iterator(fstream), {}); + std::string decodedString; + auto result = Base64::Base64::Decode(base64String, decodedString); + if (!result.empty()) + fail("Could not decode Base64 file: " + result); + // Move won't do anything until C++20, but won't hurt to do it anyway. + decodedStream.str(std::move(decodedString)); + stream = std::ref(decodedStream); + } + Log(Debug::Info) << "Loading settings file: " << file; std::string currentCategory; mLine = 0; - while (!stream.eof() && !stream.fail()) + while (!stream.get().eof() && !stream.get().fail()) { ++mLine; std::string line; - std::getline( stream, line ); + std::getline( stream.get(), line ); size_t i = 0; if (!skipWhiteSpace(i, line)) From 3ef1b270993a9b09e3a3613a142206e6ea9a9a27 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 18 May 2021 01:21:42 +0200 Subject: [PATCH 086/101] Add missing includes --- apps/openmw_test_suite/detournavigator/navigator.cpp | 1 + apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 619276588..333613e77 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -11,6 +11,7 @@ #include #include +#include #include MATCHER_P3(Vec3fEq, x, y, z, "") diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 5f43f4800..b4b664569 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -14,6 +14,8 @@ #include #include +#include + namespace DetourNavigator { static inline bool operator ==(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs) From 959165bcb99140d38afbf7dc420f5ce647a321ea Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 18 May 2021 01:33:11 +0200 Subject: [PATCH 087/101] Support running unit tests on gitlab CI for windows But not actually run them because gitlab fails to do this. --- .gitlab-ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8d486ebf9..ceba2841f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -171,7 +171,7 @@ variables: &cs-targets package: "CS" variables: &tests-targets - targets: "openmw_detournavigator_navmeshtilescache_benchmark" + targets: "openmw_test_suite,openmw_detournavigator_navmeshtilescache_benchmark" package: "Tests" .Windows_Ninja_Base: @@ -192,7 +192,7 @@ variables: &tests-targets - $time = (Get-Date -Format "HH:mm:ss") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N -b + - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N -b -t - cd MSVC2019_64_Ninja - .\ActivateMSVC.ps1 - cmake --build . --config $config --target ($targets.Split(',')) @@ -274,8 +274,8 @@ Windows_Ninja_Tests_RelWithDebInfo: variables: <<: *tests-targets config: "RelWithDebInfo" - # Gitlab can't successfully execute benchamark binary due to unknown reason - # executables: "openmw_detournavigator_navmeshtilescache_benchmark.exe" + # Gitlab can't successfully execute following binaries due to unknown reason + # executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe" .Windows_MSBuild_Base: tags: @@ -294,7 +294,7 @@ Windows_Ninja_Tests_RelWithDebInfo: - $time = (Get-Date -Format "HH:mm:ss") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b + - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b -t - cd MSVC2019_64 - cmake --build . --config $config --target ($targets.Split(',')) - cd $config @@ -375,8 +375,8 @@ Windows_MSBuild_Tests_RelWithDebInfo: variables: <<: *tests-targets config: "RelWithDebInfo" - # Gitlab can't successfully execute benchamark binary due to unknown reason - # executables: "openmw_detournavigator_navmeshtilescache_benchmark.exe" + # Gitlab can't successfully execute following binaries due to unknown reason + # executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe" Debian_AndroidNDK_arm64-v8a: tags: From 18ea4d8eb232821987c47a862f23057e797a4fde Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Sun, 9 May 2021 22:19:57 +0200 Subject: [PATCH 088/101] First step toward fixing terrain selection issues. --- apps/opencs/view/render/terrainselection.cpp | 79 +++++++++++++++++++- apps/opencs/view/render/terrainselection.hpp | 3 +- apps/opencs/view/render/terrainshapemode.cpp | 18 ++++- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 4e209af57..be7fefe30 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -42,13 +42,84 @@ void CSVRender::TerrainSelection::onlySelect(const std::vector &localPos) +void CSVRender::TerrainSelection::addSelect(const std::vector>& localPositions, bool toggleInProgress) { - if (std::find(mSelection.begin(), mSelection.end(), localPos) == mSelection.end()) + if (toggleInProgress) + { + for (auto const& localPos : localPositions) + { + auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); + mDraggedOperationFlag = true; + + if (iterTemp == mTemporarySelection.end()) + { + auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + if (iter == mSelection.end()) + { + mSelection.emplace_back(localPos); + } + } + + mTemporarySelection.push_back(localPos); + } + } + else if (mDraggedOperationFlag == false) { - mSelection.emplace_back(localPos); - update(); + for (auto const& localPos : localPositions) + { + const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + if (iter == mSelection.end()) + { + mSelection.emplace_back(localPos); + } + } } + else + { + mDraggedOperationFlag = false; + mTemporarySelection.clear(); + } + update(); +} + +void CSVRender::TerrainSelection::removeSelect(const std::vector>& localPositions, bool toggleInProgress) +{ + if (toggleInProgress) + { + for (auto const& localPos : localPositions) + { + auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); + mDraggedOperationFlag = true; + + if (iterTemp == mTemporarySelection.end()) + { + auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + if (iter != mSelection.end()) + { + mSelection.erase(iter); + } + } + + mTemporarySelection.push_back(localPos); + } + } + else if (mDraggedOperationFlag == false) + { + for (auto const& localPos : localPositions) + { + const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + if (iter != mSelection.end()) + { + mSelection.erase(iter); + } + } + } + else + { + mDraggedOperationFlag = false; + mTemporarySelection.clear(); + } + update(); } void CSVRender::TerrainSelection::toggleSelect(const std::vector> &localPositions, bool toggleInProgress) diff --git a/apps/opencs/view/render/terrainselection.hpp b/apps/opencs/view/render/terrainselection.hpp index 84ee6f25a..9c1eb55b1 100644 --- a/apps/opencs/view/render/terrainselection.hpp +++ b/apps/opencs/view/render/terrainselection.hpp @@ -36,7 +36,8 @@ namespace CSVRender ~TerrainSelection(); void onlySelect(const std::vector> &localPositions); - void addSelect(const std::pair &localPos); + void addSelect(const std::vector>& localPositions, bool toggleInProgress); + void removeSelect(const std::vector>& localPositions, bool toggleInProgress); void toggleSelect(const std::vector> &localPositions, bool toggleInProgress); void activate(); diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index 1739e143d..6209e161e 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -42,7 +42,7 @@ #include "worldspacewidget.hpp" CSVRender::TerrainShapeMode::TerrainShapeMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent) -: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-shape"}, Mask_Terrain | Mask_Reference, "Terrain land editing", parent), +: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-shape"}, Mask_Terrain, "Terrain land editing", parent), mParentNode(parentNode) { } @@ -1089,9 +1089,21 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& } } - if(selectMode == 0) mTerrainShapeSelection->onlySelect(selections); - if(selectMode == 1) mTerrainShapeSelection->toggleSelect(selections, dragOperation); + std::string selectAction; + if (selectMode == 0) + selectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString(); + else + selectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString(); + + if (selectAction == "Select only") + mTerrainShapeSelection->onlySelect(selections); + else if (selectAction == "Add to selection") + mTerrainShapeSelection->addSelect(selections, dragOperation); + else if (selectAction == "Remove from selection") + mTerrainShapeSelection->removeSelect(selections, dragOperation); + else if (selectAction == "Invert selection") + mTerrainShapeSelection->toggleSelect(selections, dragOperation); } void CSVRender::TerrainShapeMode::pushEditToCommand(const CSMWorld::LandHeightsColumn::DataType& newLandGrid, CSMDoc::Document& document, From 008bf64dd916a926156c0e19ffe215c8bf32db9e Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Mon, 10 May 2021 14:20:53 +0200 Subject: [PATCH 089/101] Second step toward fixing terrain selection issues. --- apps/opencs/view/render/cellborder.cpp | 9 +++--- apps/opencs/view/render/cellborder.hpp | 3 +- apps/opencs/view/render/commands.cpp | 20 +++++++++++++ apps/opencs/view/render/commands.hpp | 30 ++++++++++++++++++++ apps/opencs/view/render/terrainshapemode.cpp | 3 ++ 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/render/commands.cpp create mode 100644 apps/opencs/view/render/commands.hpp diff --git a/apps/opencs/view/render/cellborder.cpp b/apps/opencs/view/render/cellborder.cpp index 6073807ce..88de12ca5 100644 --- a/apps/opencs/view/render/cellborder.cpp +++ b/apps/opencs/view/render/cellborder.cpp @@ -19,9 +19,12 @@ const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 3; CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords) : mParentNode(cellNode) { + mBorderGeode = new osg::Geode(); + mBaseNode = new osg::PositionAttitudeTransform(); mBaseNode->setNodeMask(Mask_CellBorder); mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10)); + mBaseNode->addChild(mBorderGeode); mParentNode->addChild(mBaseNode); } @@ -79,10 +82,8 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand) geometry->addPrimitiveSet(primitives); geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - - osg::ref_ptr geode = new osg::Geode(); - geode->addDrawable(geometry); - mBaseNode->addChild(geode); + mBorderGeode->removeDrawables(0); + mBorderGeode->addDrawable(geometry); } size_t CSVRender::CellBorder::landIndex(int x, int y) diff --git a/apps/opencs/view/render/cellborder.hpp b/apps/opencs/view/render/cellborder.hpp index c91aa46c6..c7e47a00f 100644 --- a/apps/opencs/view/render/cellborder.hpp +++ b/apps/opencs/view/render/cellborder.hpp @@ -7,6 +7,7 @@ namespace osg { + class Geode; class Group; class PositionAttitudeTransform; } @@ -47,7 +48,7 @@ namespace CSVRender osg::Group* mParentNode; osg::ref_ptr mBaseNode; - + osg::ref_ptr mBorderGeode; }; } diff --git a/apps/opencs/view/render/commands.cpp b/apps/opencs/view/render/commands.cpp new file mode 100644 index 000000000..40634acec --- /dev/null +++ b/apps/opencs/view/render/commands.cpp @@ -0,0 +1,20 @@ +#include "commands.hpp" + +#include + +#include "cell.hpp" +#include "terrainselection.hpp" + +CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent) + : mTerrainSelection(terrainSelection) +{ } + +void CSVRender::DrawTerrainSelectionCommand::redo() +{ + mTerrainSelection.update(); +} + +void CSVRender::DrawTerrainSelectionCommand::undo() +{ + mTerrainSelection.update(); +} diff --git a/apps/opencs/view/render/commands.hpp b/apps/opencs/view/render/commands.hpp new file mode 100644 index 000000000..f11a76461 --- /dev/null +++ b/apps/opencs/view/render/commands.hpp @@ -0,0 +1,30 @@ +#ifndef CSV_RENDER_COMMANDS_HPP +#define CSV_RENDER_COMMANDS_HPP + +#include + +namespace ESM +{ + struct Land; +} + +namespace CSVRender +{ + class Cell; + class TerrainSelection; + + + class DrawTerrainSelectionCommand : public QUndoCommand + { + private: + TerrainSelection& mTerrainSelection; + + public: + DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent = nullptr); + + void redo() override; + void undo() override; + }; +} + +#endif diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index 6209e161e..418655f2f 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -34,6 +34,7 @@ #include "../../model/world/universalid.hpp" #include "brushdraw.hpp" +#include "commands.hpp" #include "editmode.hpp" #include "pagedworldspacewidget.hpp" #include "mask.hpp" @@ -284,6 +285,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges() sortAndLimitAlteredCells(); undoStack.beginMacro ("Edit shape and normal records"); + undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection)); for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells) { @@ -353,6 +355,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges() } pushNormalsEditToCommand(landNormalsNew, document, landTable, cellId); } + undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection)); undoStack.endMacro(); clearTransientEdits(); } From 6c49074765240064e5fab9b403cb4afb1d0358f2 Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Mon, 10 May 2021 15:19:24 +0200 Subject: [PATCH 090/101] Remove old references to Cell class. --- apps/opencs/view/render/commands.cpp | 1 - apps/opencs/view/render/commands.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/opencs/view/render/commands.cpp b/apps/opencs/view/render/commands.cpp index 40634acec..7b3760296 100644 --- a/apps/opencs/view/render/commands.cpp +++ b/apps/opencs/view/render/commands.cpp @@ -2,7 +2,6 @@ #include -#include "cell.hpp" #include "terrainselection.hpp" CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent) diff --git a/apps/opencs/view/render/commands.hpp b/apps/opencs/view/render/commands.hpp index f11a76461..545d8071f 100644 --- a/apps/opencs/view/render/commands.hpp +++ b/apps/opencs/view/render/commands.hpp @@ -10,7 +10,6 @@ namespace ESM namespace CSVRender { - class Cell; class TerrainSelection; From 73949d5bd063f5b1e9c227e5a55b658c617f90ae Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Mon, 10 May 2021 16:07:46 +0200 Subject: [PATCH 091/101] Updating the CMake file isn't a bad idea either... --- apps/opencs/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b73cd37b8..19c32df60 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -89,7 +89,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller - cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw + cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands ) opencs_units_noqt (view/render From 7be891b4409178c9001d6690112a2b441e858ff9 Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Mon, 10 May 2021 23:05:34 +0200 Subject: [PATCH 092/101] Directly use Geometry instead of Geode; fix for loop; add size_t type-cast. --- apps/opencs/view/render/cellborder.cpp | 35 +++++++++++++------------- apps/opencs/view/render/cellborder.hpp | 4 +-- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/render/cellborder.cpp b/apps/opencs/view/render/cellborder.cpp index 88de12ca5..a1ae4f452 100644 --- a/apps/opencs/view/render/cellborder.cpp +++ b/apps/opencs/view/render/cellborder.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -19,12 +18,12 @@ const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 3; CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords) : mParentNode(cellNode) { - mBorderGeode = new osg::Geode(); + mBorderGeometry = new osg::Geometry(); mBaseNode = new osg::PositionAttitudeTransform(); mBaseNode->setNodeMask(Mask_CellBorder); mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10)); - mBaseNode->addChild(mBorderGeode); + mBaseNode->addChild(mBorderGeometry); mParentNode->addChild(mBaseNode); } @@ -41,54 +40,56 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand) if (!landData) return; - osg::ref_ptr geometry = new osg::Geometry(); + mBaseNode->removeChild(mBorderGeometry); + mBorderGeometry = new osg::Geometry(); // Vertices osg::ref_ptr vertices = new osg::Vec3Array(); - int x = 0, y = 0; - for (; x < ESM::Land::LAND_SIZE; ++x) + int x = 0; + int y = 0; + + for (/* */; x < ESM::Land::LAND_SIZE - 1; ++x) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); x = ESM::Land::LAND_SIZE - 1; - for (; y < ESM::Land::LAND_SIZE; ++y) + for (/* */; y < ESM::Land::LAND_SIZE - 1; ++y) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); y = ESM::Land::LAND_SIZE - 1; - for (; x >= 0; --x) + for (/* */; x > 0; --x) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); x = 0; - for (; y >= 0; --y) + for (/* */; y >= 0; --y) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); - geometry->setVertexArray(vertices); + mBorderGeometry->setVertexArray(vertices); // Color osg::ref_ptr colors = new osg::Vec4Array(); colors->push_back(osg::Vec4f(0.f, 0.5f, 0.f, 1.f)); - geometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET); + mBorderGeometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET); // Primitive osg::ref_ptr primitives = - new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount+1); + new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount); for (size_t i = 0; i < VertexCount; ++i) primitives->setElement(i, i); primitives->setElement(VertexCount, 0); - geometry->addPrimitiveSet(primitives); - geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mBorderGeometry->addPrimitiveSet(primitives); + mBorderGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - mBorderGeode->removeDrawables(0); - mBorderGeode->addDrawable(geometry); + mBaseNode->addChild(mBorderGeometry); } size_t CSVRender::CellBorder::landIndex(int x, int y) { - return y * ESM::Land::LAND_SIZE + x; + return static_cast(y) * ESM::Land::LAND_SIZE + x; } float CSVRender::CellBorder::scaleToWorld(int value) diff --git a/apps/opencs/view/render/cellborder.hpp b/apps/opencs/view/render/cellborder.hpp index c7e47a00f..be2e18eee 100644 --- a/apps/opencs/view/render/cellborder.hpp +++ b/apps/opencs/view/render/cellborder.hpp @@ -7,7 +7,7 @@ namespace osg { - class Geode; + class Geometry; class Group; class PositionAttitudeTransform; } @@ -48,7 +48,7 @@ namespace CSVRender osg::Group* mParentNode; osg::ref_ptr mBaseNode; - osg::ref_ptr mBorderGeode; + osg::ref_ptr mBorderGeometry; }; } From 425f745d53ae6858de353564f0d1ee3c12d0984b Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Tue, 18 May 2021 15:03:56 +0200 Subject: [PATCH 093/101] Resolved merge conflicts with changelog. --- CHANGELOG.md | 4 ++++ CHANGELOG_PR.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d5c97352..632e02309 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Bug #5452: Autowalk is being included in savegames Bug #5469: Local map is reset when re-entering certain cells Bug #5472: Mistify mod causes CTD in 0.46 on Mac + Bug #5473: OpenMW-CS: Cell border lines don't update properly on terrain change Bug #5479: NPCs who should be walking around town are standing around without walking Bug #5484: Zero value items shouldn't be able to be bought or sold for 1 gold Bug #5485: Intimidate doesn't increase disposition on marginal wins @@ -124,6 +125,8 @@ Bug #5995: NiUVController doesn't calculate the UV offset properly Bug #6007: Crash when ending cutscene is playing Bug #6016: Greeting interrupts Fargoth's sneak-walk + Bug #6022: OpenMW-CS: Terrain selection is not updated when undoing/redoing terrain changes + Bug #6023: OpenMW-CS: Clicking on a reference in "Terrain land editing" mode discards corresponding select/edit action Bug #6028: Particle system controller values are incorrectly used Bug #6043: Actor can have torch missing when torch animation is played Bug #6047: Mouse bindings can be triggered during save loading @@ -166,6 +169,7 @@ Feature #5814: Bsatool should be able to create BSA archives, not only to extract it Feature #5828: Support more than 8 lights Feature #5910: Fall back to delta time when physics can't keep up + Feature #6024: OpenMW-CS: Selecting terrain in "Terrain land editing" should support "Add to selection" and "Remove from selection" modes Feature #6033: Include pathgrid to navigation mesh Feature #6034: Find path based on area cost depending on NPC stats Task #5480: Drop Qt4 support diff --git a/CHANGELOG_PR.md b/CHANGELOG_PR.md index cfe709e97..25528f21d 100644 --- a/CHANGELOG_PR.md +++ b/CHANGELOG_PR.md @@ -38,9 +38,13 @@ Editor Bug Fixes: - Disabled record sorting in Topic and Journal Info tables, implemented drag-move for records (#4357) - Topic and Journal Info records can now be cloned with a different parent Topic/Journal Id (#4363) - Verifier no longer checks for alleged 'race' entries in clothing body parts (#5400) +- Cell borders are now properly redrawn when undoing/redoing terrain changes (#5473) - Loading mods now keeps the master index (#5675) - Flicker and crashing on XFCE4 fixed (#5703) - Collada models render properly in the Editor (#5713) +- Terrain-selection grid is now properly updated when undoing/redoing terrain changes (#6022) +- Tool outline and select/edit actions in "Terrain land editing" mode now ignore references (#6023) +- Primary-select and secondary-select actions in "Terrain land editing" mode now behave like in "Instance editing" mode (#6024) Miscellaneous: - Prevent save-game bloating by using an appropriate fog texture format (#5108) From 356efa15a2bcfc2d57f002ba8f424acb4a111846 Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Wed, 12 May 2021 13:33:36 +0200 Subject: [PATCH 094/101] Fixes #6035 (circle brush selects outside of circle) and #6036 (some corner vertices not selected). --- apps/opencs/view/render/terrainshapemode.cpp | 30 ++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index 418655f2f..c1b20da4c 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -433,7 +433,9 @@ void CSVRender::TerrainShapeMode::editTerrainShapeGrid(const std::pair float smoothedByDistance = 0.0f; if (mShapeEditTool == ShapeEditTool_Drag) smoothedByDistance = calculateBumpShape(distance, r, mTotalDiffY); if (mShapeEditTool == ShapeEditTool_PaintToRaise || mShapeEditTool == ShapeEditTool_PaintToLower) smoothedByDistance = calculateBumpShape(distance, r, r + mShapeEditToolStrength); - if (distance <= r) + + // Using floating-point radius here to prevent selecting too few vertices. + if (distance <= mBrushSize / 2.0f) { if (mShapeEditTool == ShapeEditTool_Drag) alterHeight(cellCoords, x, y, smoothedByDistance); if (mShapeEditTool == ShapeEditTool_PaintToRaise || mShapeEditTool == ShapeEditTool_PaintToLower) @@ -1036,10 +1038,25 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob return; int selectionX = globalSelectionX; int selectionY = globalSelectionY; - if (xIsAtCellBorder) + + if (xIsAtCellBorder && yIsAtCellBorder) + { + if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1) + || isInCellSelection(globalSelectionX + 1, globalSelectionY - 1) + || isInCellSelection(globalSelectionX - 1, globalSelectionY + 1)) + { + selections->emplace_back(globalSelectionX, globalSelectionY); + } + } + else if (xIsAtCellBorder) + { selectionX--; - if (yIsAtCellBorder) + } + else if (yIsAtCellBorder) + { selectionY--; + } + if (isInCellSelection(selectionX, selectionY)) selections->emplace_back(globalSelectionX, globalSelectionY); } @@ -1074,8 +1091,11 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& { int distanceX = abs(i - vertexCoords.first); int distanceY = abs(j - vertexCoords.second); - int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (distance <= r) handleSelection(i, j, &selections); + float distance = sqrt(pow(distanceX, 2)+pow(distanceY, 2)); + + // Using floating-point radius here to prevent selecting too few vertices. + if (distance <= mBrushSize / 2.0f) + handleSelection(i, j, &selections); } } } From d500507dec6db05e0f458c3b2527f4c74363232d Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Tue, 18 May 2021 15:05:19 +0200 Subject: [PATCH 095/101] Resolved merge conflicts with changelog (cont.) --- CHANGELOG.md | 2 ++ CHANGELOG_PR.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 632e02309..e11d05d3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,8 @@ Bug #6022: OpenMW-CS: Terrain selection is not updated when undoing/redoing terrain changes Bug #6023: OpenMW-CS: Clicking on a reference in "Terrain land editing" mode discards corresponding select/edit action Bug #6028: Particle system controller values are incorrectly used + Bug #6035: OpenMW-CS: Circle brush in "Terrain land editing" mode sometimes includes vertices outside its radius + Bug #6036: OpenMW-CS: Terrain selection at the border of cells omits certain corner vertices Bug #6043: Actor can have torch missing when torch animation is played Bug #6047: Mouse bindings can be triggered during save loading Feature #390: 3rd person look "over the shoulder" diff --git a/CHANGELOG_PR.md b/CHANGELOG_PR.md index 25528f21d..100bc376f 100644 --- a/CHANGELOG_PR.md +++ b/CHANGELOG_PR.md @@ -45,6 +45,8 @@ Editor Bug Fixes: - Terrain-selection grid is now properly updated when undoing/redoing terrain changes (#6022) - Tool outline and select/edit actions in "Terrain land editing" mode now ignore references (#6023) - Primary-select and secondary-select actions in "Terrain land editing" mode now behave like in "Instance editing" mode (#6024) +- Using the circle brush to select terrain in the "Terrain land editing" mode no longer selects vertices outside the circle (#6035) +- Vertices at the NW and SE corners of a cell can now also be selected in "Terrain land editing" mode if the adjacent cells aren't loaded yet (#6036) Miscellaneous: - Prevent save-game bloating by using an appropriate fog texture format (#5108) From ca80aeaaeac1b90736c107eb8d1dda320f18f4d1 Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Thu, 13 May 2021 01:21:24 +0200 Subject: [PATCH 096/101] Fix vertex calculation for cell-border drawing. --- apps/opencs/view/render/cellborder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/cellborder.cpp b/apps/opencs/view/render/cellborder.cpp index a1ae4f452..674572232 100644 --- a/apps/opencs/view/render/cellborder.cpp +++ b/apps/opencs/view/render/cellborder.cpp @@ -12,7 +12,7 @@ #include "../../model/world/cellcoordinates.hpp" const int CSVRender::CellBorder::CellSize = ESM::Land::REAL_SIZE; -const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 3; +const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 4; CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords) @@ -61,7 +61,7 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); x = 0; - for (/* */; y >= 0; --y) + for (/* */; y > 0; --y) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); mBorderGeometry->setVertexArray(vertices); @@ -74,7 +74,7 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand) // Primitive osg::ref_ptr primitives = - new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount); + new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount + 1); for (size_t i = 0; i < VertexCount; ++i) primitives->setElement(i, i); From 3a1243a5d074cf5861886a6bad94103c276a619c Mon Sep 17 00:00:00 2001 From: Atahualpa Date: Tue, 18 May 2021 17:53:00 +0200 Subject: [PATCH 097/101] Rebased branch, reduced code duplication, added comments, adjusted formatting. --- apps/opencs/view/render/cellborder.cpp | 22 +- apps/opencs/view/render/commands.hpp | 18 +- apps/opencs/view/render/terrainselection.cpp | 216 +++++++++---------- apps/opencs/view/render/terrainselection.hpp | 10 + apps/opencs/view/render/terrainshapemode.cpp | 14 ++ 5 files changed, 150 insertions(+), 130 deletions(-) diff --git a/apps/opencs/view/render/cellborder.cpp b/apps/opencs/view/render/cellborder.cpp index 674572232..d8ff63801 100644 --- a/apps/opencs/view/render/cellborder.cpp +++ b/apps/opencs/view/render/cellborder.cpp @@ -12,6 +12,11 @@ #include "../../model/world/cellcoordinates.hpp" const int CSVRender::CellBorder::CellSize = ESM::Land::REAL_SIZE; + +/* + The number of vertices per cell border is equal to the number of vertices per edge + minus the duplicated corner vertices. An additional vertex to close the loop is NOT needed. +*/ const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 4; @@ -43,42 +48,45 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand) mBaseNode->removeChild(mBorderGeometry); mBorderGeometry = new osg::Geometry(); - // Vertices osg::ref_ptr vertices = new osg::Vec3Array(); int x = 0; int y = 0; - for (/* */; x < ESM::Land::LAND_SIZE - 1; ++x) + /* + Traverse the cell border counter-clockwise starting at the SW corner vertex (0, 0). + Each loop starts at a corner vertex and ends right before the next corner vertex. + */ + for (; x < ESM::Land::LAND_SIZE - 1; ++x) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); x = ESM::Land::LAND_SIZE - 1; - for (/* */; y < ESM::Land::LAND_SIZE - 1; ++y) + for (; y < ESM::Land::LAND_SIZE - 1; ++y) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); y = ESM::Land::LAND_SIZE - 1; - for (/* */; x > 0; --x) + for (; x > 0; --x) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); x = 0; - for (/* */; y > 0; --y) + for (; y > 0; --y) vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); mBorderGeometry->setVertexArray(vertices); - // Color osg::ref_ptr colors = new osg::Vec4Array(); colors->push_back(osg::Vec4f(0.f, 0.5f, 0.f, 1.f)); mBorderGeometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET); - // Primitive osg::ref_ptr primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount + 1); + // Assign one primitive to each vertex. for (size_t i = 0; i < VertexCount; ++i) primitives->setElement(i, i); + // Assign the last primitive to the first vertex to close the loop. primitives->setElement(VertexCount, 0); mBorderGeometry->addPrimitiveSet(primitives); diff --git a/apps/opencs/view/render/commands.hpp b/apps/opencs/view/render/commands.hpp index 545d8071f..cdc389e33 100644 --- a/apps/opencs/view/render/commands.hpp +++ b/apps/opencs/view/render/commands.hpp @@ -3,16 +3,22 @@ #include -namespace ESM -{ - struct Land; -} - namespace CSVRender { class TerrainSelection; - + /* + Current solution to force a redrawing of the terrain-selection grid + when undoing/redoing changes in the editor. + This only triggers a simple redraw of the grid, so only use it in + conjunction with actual data changes which deform the grid. + + Please note that this command needs to be put onto the QUndoStack twice: + at the start and at the end of the related terrain manipulation. + This makes sure that the grid is always updated after all changes have + been undone or redone -- but it also means that the selection is redrawn + once at the beginning of either action. Future refinement may solve that. + */ class DrawTerrainSelectionCommand : public QUndoCommand { private: diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index be7fefe30..0593917e0 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -39,135 +39,23 @@ std::vector> CSVRender::TerrainSelection::getTerrainSelectio void CSVRender::TerrainSelection::onlySelect(const std::vector> &localPositions) { mSelection = localPositions; + update(); } void CSVRender::TerrainSelection::addSelect(const std::vector>& localPositions, bool toggleInProgress) { - if (toggleInProgress) - { - for (auto const& localPos : localPositions) - { - auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); - mDraggedOperationFlag = true; - - if (iterTemp == mTemporarySelection.end()) - { - auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); - if (iter == mSelection.end()) - { - mSelection.emplace_back(localPos); - } - } - - mTemporarySelection.push_back(localPos); - } - } - else if (mDraggedOperationFlag == false) - { - for (auto const& localPos : localPositions) - { - const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); - if (iter == mSelection.end()) - { - mSelection.emplace_back(localPos); - } - } - } - else - { - mDraggedOperationFlag = false; - mTemporarySelection.clear(); - } - update(); + handleSelection(localPositions, toggleInProgress, SelectionMethod::AddSelect); } void CSVRender::TerrainSelection::removeSelect(const std::vector>& localPositions, bool toggleInProgress) { - if (toggleInProgress) - { - for (auto const& localPos : localPositions) - { - auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); - mDraggedOperationFlag = true; - - if (iterTemp == mTemporarySelection.end()) - { - auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); - if (iter != mSelection.end()) - { - mSelection.erase(iter); - } - } - - mTemporarySelection.push_back(localPos); - } - } - else if (mDraggedOperationFlag == false) - { - for (auto const& localPos : localPositions) - { - const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); - if (iter != mSelection.end()) - { - mSelection.erase(iter); - } - } - } - else - { - mDraggedOperationFlag = false; - mTemporarySelection.clear(); - } - update(); + handleSelection(localPositions, toggleInProgress, SelectionMethod::RemoveSelect); } -void CSVRender::TerrainSelection::toggleSelect(const std::vector> &localPositions, bool toggleInProgress) +void CSVRender::TerrainSelection::toggleSelect(const std::vector>& localPositions, bool toggleInProgress) { - if (toggleInProgress) - { - for(auto const& localPos: localPositions) - { - auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); - mDraggedOperationFlag = true; - - if (iterTemp == mTemporarySelection.end()) - { - auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); - if (iter != mSelection.end()) - { - mSelection.erase(iter); - } - else - { - mSelection.emplace_back(localPos); - } - } - - mTemporarySelection.push_back(localPos); - } - } - else if (mDraggedOperationFlag == false) - { - for(auto const& localPos: localPositions) - { - const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); - if (iter != mSelection.end()) - { - mSelection.erase(iter); - } - else - { - mSelection.emplace_back(localPos); - } - } - } - else - { - mDraggedOperationFlag = false; - mTemporarySelection.clear(); - } - update(); + handleSelection(localPositions, toggleInProgress, SelectionMethod::ToggleSelect); } void CSVRender::TerrainSelection::activate() @@ -310,6 +198,100 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr>& localPositions, bool toggleInProgress, SelectionMethod selectionMethod) +{ + if (toggleInProgress) + { + for (auto const& localPos : localPositions) + { + auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); + mDraggedOperationFlag = true; + + if (iterTemp == mTemporarySelection.end()) + { + auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + + switch (selectionMethod) + { + case SelectionMethod::AddSelect: + if (iter == mSelection.end()) + { + mSelection.emplace_back(localPos); + } + + break; + case SelectionMethod::RemoveSelect: + if (iter != mSelection.end()) + { + mSelection.erase(iter); + } + + break; + case SelectionMethod::ToggleSelect: + if (iter == mSelection.end()) + { + mSelection.emplace_back(localPos); + } + else + { + mSelection.erase(iter); + } + + break; + default: break; + } + } + + mTemporarySelection.push_back(localPos); + } + } + else if (mDraggedOperationFlag == false) + { + for (auto const& localPos : localPositions) + { + const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + + switch (selectionMethod) + { + case SelectionMethod::AddSelect: + if (iter == mSelection.end()) + { + mSelection.emplace_back(localPos); + } + + break; + case SelectionMethod::RemoveSelect: + if (iter != mSelection.end()) + { + mSelection.erase(iter); + } + + break; + case SelectionMethod::ToggleSelect: + if (iter == mSelection.end()) + { + mSelection.emplace_back(localPos); + } + else + { + mSelection.erase(iter); + } + + break; + default: break; + } + } + } + else + { + mDraggedOperationFlag = false; + + mTemporarySelection.clear(); + } + + update(); +} + bool CSVRender::TerrainSelection::noCell(const std::string& cellId) { CSMDoc::Document& document = mWorldspaceWidget->getDocument(); diff --git a/apps/opencs/view/render/terrainselection.hpp b/apps/opencs/view/render/terrainselection.hpp index 9c1eb55b1..18622ad13 100644 --- a/apps/opencs/view/render/terrainselection.hpp +++ b/apps/opencs/view/render/terrainselection.hpp @@ -27,6 +27,14 @@ namespace CSVRender Shape }; + enum class SelectionMethod + { + OnlySelect, + AddSelect, + RemoveSelect, + ToggleSelect + }; + /// \brief Class handling the terrain selection data and rendering class TerrainSelection { @@ -56,6 +64,8 @@ namespace CSVRender private: + void handleSelection(const std::vector>& localPositions, bool toggleInProgress, SelectionMethod selectionMethod); + bool noCell(const std::string& cellId); bool noLand(const std::string& cellId); diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index c1b20da4c..866ff69cd 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -285,6 +285,8 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges() sortAndLimitAlteredCells(); undoStack.beginMacro ("Edit shape and normal records"); + + // One command at the beginning of the macro for redrawing the terrain-selection grid when undoing the changes. undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection)); for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells) @@ -355,7 +357,9 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges() } pushNormalsEditToCommand(landNormalsNew, document, landTable, cellId); } + // One command at the end of the macro for redrawing the terrain-selection grid when redoing the changes. undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection)); + undoStack.endMacro(); clearTransientEdits(); } @@ -1039,8 +1043,18 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob int selectionX = globalSelectionX; int selectionY = globalSelectionY; + /* + The northern and eastern edges don't belong to the current cell. + If the corresponding adjacent cell is not loaded, some special handling is necessary to select border vertices. + */ if (xIsAtCellBorder && yIsAtCellBorder) { + /* + Handle the NW, NE, and SE corner vertices. + NW corner: (+1, -1) offset to reach current cell. + NE corner: (-1, -1) offset to reach current cell. + SE corner: (-1, +1) offset to reach current cell. + */ if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1) || isInCellSelection(globalSelectionX + 1, globalSelectionY - 1) || isInCellSelection(globalSelectionX - 1, globalSelectionY + 1)) From d11a6bd92c54ba229936d65f9d4353a1ec8f0eae Mon Sep 17 00:00:00 2001 From: CedricMocquillon Date: Tue, 18 May 2021 14:03:16 +0200 Subject: [PATCH 098/101] Share state --- apps/openmw/mwrender/objectpaging.cpp | 1 + components/resource/scenemanager.cpp | 6 ++++++ components/resource/scenemanager.hpp | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index d8f0215c0..b6bae8cbb 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -651,6 +651,7 @@ namespace MWRender } optimizer.setIsOperationPermissibleForObjectCallback(new CanOptimizeCallback); unsigned int options = SceneUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS|SceneUtil::Optimizer::REMOVE_REDUNDANT_NODES|SceneUtil::Optimizer::MERGE_GEOMETRY; + mSceneManager->shareState(mergeGroup); optimizer.optimize(mergeGroup, options); group->addChild(mergeGroup); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 201767ab3..f6035a47d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -514,6 +514,12 @@ namespace Resource return options; } + void SceneManager::shareState(osg::ref_ptr node) { + mSharedStateMutex.lock(); + mSharedStateManager->share(node.get()); + mSharedStateMutex.unlock(); + } + osg::ref_ptr SceneManager::getTemplate(const std::string &name, bool compile) { std::string normalized = name; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 7635cd20f..de014165b 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -135,7 +135,7 @@ namespace Resource osg::ref_ptr createInstance(const std::string& name); osg::ref_ptr createInstance(const osg::Node* base); - + void shareState(osg::ref_ptr node); /// Get an instance of the given scene template /// @see getTemplate /// @note Thread safe. From 4a15868c0e12a45d9178a9779d388b59a942dfab Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 18 May 2021 18:05:54 -0500 Subject: [PATCH 099/101] Moving Lighting Method from Advanced -> Visuals to Graphics -> Lighting The plan is to add additional options to this new tab, and since it's of similar status as the Shaders settings, it makes sense to put them next to them on the Graphics page. --- apps/launcher/advancedpage.cpp | 10 ------- apps/launcher/graphicspage.cpp | 17 ++++++++++++ files/ui/advancedpage.ui | 30 -------------------- files/ui/graphicspage.ui | 50 ++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 5199be07e..ed36634b6 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -136,13 +136,6 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain"); viewingDistanceComboBox->setValue(convertToCells(Settings::Manager::getInt("viewing distance", "Camera"))); - - int lightingMethod = 1; - if (Settings::Manager::getString("lighting method", "Shaders") == "legacy") - lightingMethod = 0; - else if (Settings::Manager::getString("lighting method", "Shaders") == "shaders") - lightingMethod = 2; - lightingMethodComboBox->setCurrentIndex(lightingMethod); } // Audio @@ -294,9 +287,6 @@ void Launcher::AdvancedPage::saveSettings() { Settings::Manager::setInt("viewing distance", "Camera", convertToUnits(viewingDistance)); } - - static std::array lightingMethodMap = {"legacy", "shaders compatibility", "shaders"}; - Settings::Manager::setString("lighting method", "Shaders", lightingMethodMap[lightingMethodComboBox->currentIndex()]); } // Audio diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 3bfd90fde..ebb031e9e 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -92,6 +92,7 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; + // Visuals if (Settings::Manager::getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -131,6 +132,15 @@ bool Launcher::GraphicsPage::loadSettings() framerateLimitSpinBox->setValue(fpsLimit); } + // Lighting + int lightingMethod = 1; + if (Settings::Manager::getString("lighting method", "Shaders") == "legacy") + lightingMethod = 0; + else if (Settings::Manager::getString("lighting method", "Shaders") == "shaders") + lightingMethod = 2; + lightingMethodComboBox->setCurrentIndex(lightingMethod); + + // Shadows if (Settings::Manager::getBool("actor shadows", "Shadows")) actorShadowsCheckBox->setCheckState(Qt::Checked); if (Settings::Manager::getBool("player shadows", "Shadows")) @@ -167,6 +177,8 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { + // Visuals + // Ensure we only set the new settings if they changed. This is to avoid cluttering the // user settings file (which by definition should only contain settings the user has touched) bool cVSync = vSyncCheckBox->checkState(); @@ -219,6 +231,11 @@ void Launcher::GraphicsPage::saveSettings() Settings::Manager::setFloat("framerate limit", "Video", 0); } + // Lighting + static std::array lightingMethodMap = {"legacy", "shaders compatibility", "shaders"}; + Settings::Manager::setString("lighting method", "Shaders", lightingMethodMap[lightingMethodComboBox->currentIndex()]); + + // Shadows int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0; if (Settings::Manager::getInt("maximum shadow map distance", "Shadows") != cShadowDist) Settings::Manager::setInt("maximum shadow map distance", "Shadows", cShadowDist); diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 645f8629f..5859f1f38 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -444,36 +444,6 @@
- - - - - - Lighting Method: - - - - - - - - legacy - - - - - shaders compatibility - - - - - shaders - - - - - - diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index 5ec72611f..508a955d7 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -187,6 +187,56 @@ + + + Lighting + + + + + + + + Lighting Method: + + + + + + + + legacy + + + + + shaders compatibility + + + + + shaders + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + Shadows From 54d32817d5dd49effb2ce71e0ca76f939729e128 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 19 May 2021 17:12:41 +0200 Subject: [PATCH 100/101] Use av_free and maybe get Coverity to understand --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 1c2fcee4e..c3cb412e9 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -62,6 +62,15 @@ namespace av_frame_free(&frame); } }; + + template + struct AVFree + { + void operator()(T* frame) const + { + av_free(&frame); + } + }; } namespace Video @@ -105,7 +114,7 @@ void VideoState::setAudioFactory(MovieAudioFactory *factory) void PacketQueue::put(AVPacket *pkt) { - std::unique_ptr pkt1(static_cast(av_malloc(sizeof(AVPacketList)))); + std::unique_ptr> pkt1(static_cast(av_malloc(sizeof(AVPacketList)))); if(!pkt1) throw std::bad_alloc(); if(pkt == &flush_pkt) @@ -116,14 +125,14 @@ void PacketQueue::put(AVPacket *pkt) pkt1->next = nullptr; std::lock_guard lock(this->mutex); - + AVPacketList* ptr = pkt1.release(); if(!last_pkt) - this->first_pkt = pkt1.get(); + this->first_pkt = ptr; else - this->last_pkt->next = pkt1.get(); - this->last_pkt = pkt1.release(); + this->last_pkt->next = ptr; + this->last_pkt = ptr; this->nb_packets++; - this->size += this->last_pkt->pkt.size; + this->size += ptr->pkt.size; this->cond.notify_one(); } From b13afd758c9da47414df8d3cd8c60c2625ce3be3 Mon Sep 17 00:00:00 2001 From: fredzio Date: Thu, 20 May 2021 05:53:26 +0200 Subject: [PATCH 101/101] Remove both racy and useless code. Actor's position can be determined in 3 ways: 1/ as a result of physics simulation 2/ after a script require a relative position change (SetPos, Move) 3/ absolutely set from games mechanics event (teleport) or script (PositionCell) In case 1/, RefData::mPosition is updated with the physics simulation result In case 2/, when RefData::mPosition is updated, physics simulation is informed of the change and update accordingly In case 3/, when RefData::mPosition is updated, the physics simulation state is reset In all 3 cases, we don't need to check the RefData::mPosition to get a correct behaviour. TSAN reported the following data race: Read of size 4 at 0x7b50005b75b0 by thread T12 (mutexes: write M656173, write M84859534346343880): #0 ESM::Position::asVec3() const /build/openmw/openmw/master2/.build/freebsd/TSAN/../../.././components/esm/defs.hpp:55:27 (openmw+0xb809d5) #1 MWPhysics::Actor::updateWorldPosition() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/actor.cpp:131:59 (openmw+0xb809d5) #2 MWPhysics::Actor::setPosition(osg::Vec3f const&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/actor.cpp:177:5 (openmw+0xb809d5) #3 MWPhysics::PhysicsTaskScheduler::updateActorsPositions() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:524:28 (openmw+0xb91ac0) #4 MWPhysics::PhysicsTaskScheduler::afterPostStep() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:614:13 (openmw+0xb915e7) #5 MWPhysics::PhysicsTaskScheduler::worker()::$_5::operator()() const /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:498:45 (openmw+0xb915e7) #6 void Misc::Barrier::wait(MWPhysics::PhysicsTaskScheduler::worker()::$_5&&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../.././components/misc/barrier.hpp:30:21 (openmw+0xb915e7) #7 MWPhysics::PhysicsTaskScheduler::worker() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:498:31 (openmw+0xb915e7) #8 MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0::operator()() const /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:162:45 (openmw+0xb92630) #9 decltype(std::__1::forward(fp)()) std::__1::__invoke(MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0&&) /usr/include/c++/v1/type_traits:3899:1 (openmw+0xb92630) #10 void std::__1::__thread_execute >, MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0>(std::__1::tuple >, MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0>&, std::__1::__tuple_indices<>) /usr/include/c++/v1/thread:280:5 (openmw+0xb92630) #11 void* std::__1::__thread_proxy >, MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0> >(void*) /usr/include/c++/v1/thread:291:5 (openmw+0xb92630) Previous write of size 8 at 0x7b50005b75b0 by main thread: #0 memcpy /wrkdirs/usr/ports/devel/llvm-devel/work-default/llvm-project-3f6753efe1990a928ed120bd907940a9fb3e2fc3/compiler-rt/lib/tsan/../sanitizer_common/sanitizer_common_interceptors.inc:827:5 (openmw+0x55a057) #1 MWWorld::RefData::setPosition(ESM::Position const&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/refdata.cpp:216:19 (openmw+0xa3de1c) #2 MWWorld::World::moveObject(MWWorld::Ptr const&, MWWorld::CellStore*, float, float, float, bool) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1130:26 (openmw+0xa57300) #3 MWWorld::World::moveObject(MWWorld::Ptr const&, float, float, float, bool, bool) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1253:16 (openmw+0xa580c8) #4 MWWorld::World::doPhysics(float, unsigned long long, unsigned int, osg::Stats&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1530:17 (openmw+0xa5af8f) #5 MWWorld::World::updatePhysics(float, bool, unsigned long long, unsigned int, osg::Stats&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1862:13 (openmw+0xa61a7c) #6 OMW::Engine::frame(float) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/engine.cpp:333:42 (openmw+0xcce9e7) #7 OMW::Engine::go() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/engine.cpp:935:14 (openmw+0xcd86ed) #8 runApplication(int, char**) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/main.cpp:296:17 (openmw+0xcbffac) #9 wrapApplication(int (*)(int, char**), int, char**, std::__1::basic_string, std::__1::allocator > const&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../components/debug/debugging.cpp:205:15 (openmw+0x1335442) #10 main /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/main.cpp:308:12 (openmw+0xcc008a) :wqa --- apps/openmw/mwphysics/actor.cpp | 21 ++++----------------- apps/openmw/mwphysics/actor.hpp | 8 -------- apps/openmw/mwphysics/physicssystem.cpp | 1 - 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 979390609..f0bc23413 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -117,27 +117,15 @@ int Actor::getCollisionMask() const void Actor::updatePosition() { std::scoped_lock lock(mPositionMutex); - updateWorldPosition(); - mPreviousPosition = mWorldPosition; - mPosition = mWorldPosition; - mSimulationPosition = mWorldPosition; + const auto worldPosition = mPtr.getRefData().getPosition().asVec3(); + mPreviousPosition = worldPosition; + mPosition = worldPosition; + mSimulationPosition = worldPosition; mPositionOffset = osg::Vec3f(); mStandingOnPtr = nullptr; mSkipCollisions = true; } -void Actor::updateWorldPosition() -{ - if (mWorldPosition != mPtr.getRefData().getPosition().asVec3()) - mWorldPositionChanged = true; - mWorldPosition = mPtr.getRefData().getPosition().asVec3(); -} - -osg::Vec3f Actor::getWorldPosition() const -{ - return mWorldPosition; -} - void Actor::setSimulationPosition(const osg::Vec3f& position) { mSimulationPosition = position; @@ -174,7 +162,6 @@ osg::Vec3f Actor::getCollisionObjectPosition() const bool Actor::setPosition(const osg::Vec3f& position) { std::scoped_lock lock(mPositionMutex); - updateWorldPosition(); applyOffsetChange(); bool hasChanged = mPosition != position || mWorldPositionChanged; mPreviousPosition = mPosition; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index acbf33ca7..7b53e8812 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -55,13 +55,6 @@ namespace MWPhysics */ bool isRotationallyInvariant() const; - /** - * Set mWorldPosition to the position in the Ptr's RefData. This is used by the physics simulation to account for - * when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation. - */ - void updateWorldPosition(); - osg::Vec3f getWorldPosition() const; - /** * Used by the physics simulation to store the simulation result. Used in conjunction with mWorldPosition * to account for e.g. scripted movements @@ -204,7 +197,6 @@ namespace MWPhysics osg::Vec3f mScale; osg::Vec3f mRenderingScale; - osg::Vec3f mWorldPosition; osg::Vec3f mSimulationPosition; osg::Vec3f mPosition; osg::Vec3f mPreviousPosition; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index a5d6018f4..705e15187 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -938,7 +938,6 @@ namespace MWPhysics void ActorFrameData::updatePosition(btCollisionWorld* world) { - mActorRaw->updateWorldPosition(); mActorRaw->applyOffsetChange(); mPosition = mActorRaw->getPosition(); if (mWaterCollision && mPosition.z() < mWaterlevel && canMoveToWaterSurface(mActorRaw, mWaterlevel, world))