From e61ebaa71bae9facb8aa660af46c33f1d1adaaf3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 27 Jun 2021 22:41:43 +0200 Subject: [PATCH] Add `SceneNavigation` for scene data for navigation system --- Source/Engine/Level/Level.cpp | 4 +- Source/Engine/Level/Scene/Scene.cpp | 53 +++++----- Source/Engine/Level/Scene/Scene.h | 44 ++------- Source/Engine/Level/Scene/SceneCSGData.h | 9 +- Source/Engine/Level/Scene/SceneNavigation.h | 38 ++++++++ Source/Engine/Level/Scene/SceneTicking.cpp | 86 +++++++++++++++-- Source/Engine/Level/Scene/SceneTicking.h | 96 +++---------------- Source/Engine/Navigation/NavMesh.cpp | 4 +- .../Engine/Navigation/NavMeshBoundsVolume.cpp | 4 +- Source/Engine/Navigation/NavMeshBuilder.cpp | 20 ++-- Source/Engine/Navigation/Navigation.cpp | 2 +- 11 files changed, 182 insertions(+), 178 deletions(-) create mode 100644 Source/Engine/Level/Scene/SceneNavigation.h diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index efc73dc63..2f77600b8 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -588,9 +588,9 @@ public: { LOG(Info, "Prepare scene objects"); SceneBeginData beginData; - for (int32 i = 0; i < Level::Scenes.Count(); i++) + for (auto scene : Level::Scenes) { - Level::Scenes[i]->BeginPlay(&beginData); + scene->BeginPlay(&beginData); } beginData.OnDone(); } diff --git a/Source/Engine/Level/Scene/Scene.cpp b/Source/Engine/Level/Scene/Scene.cpp index 9304b679a..b9b5444ab 100644 --- a/Source/Engine/Level/Scene/Scene.cpp +++ b/Source/Engine/Level/Scene/Scene.cpp @@ -30,13 +30,37 @@ bool SceneAsset::IsInternalType() const return true; } +BoundingBox SceneNavigation::GetNavigationBounds() +{ + if (Volumes.IsEmpty()) + return BoundingBox::Empty; + PROFILE_CPU_NAMED("GetNavigationBounds"); + auto box = Volumes[0]->GetBox(); + for (int32 i = 1; i < Volumes.Count(); i++) + BoundingBox::Merge(box, Volumes[i]->GetBox(), box); + return box; +} + +NavMeshBoundsVolume* SceneNavigation::FindNavigationBoundsOverlap(const BoundingBox& bounds) +{ + NavMeshBoundsVolume* result = nullptr; + for (int32 i = 0; i < Volumes.Count(); i++) + { + if (Volumes[i]->GetBox().Intersects(bounds)) + { + result = Volumes[i]; + break; + } + } + return result; +} + #define CSG_COLLIDER_NAME TEXT("CSG.Collider") #define CSG_MODEL_NAME TEXT("CSG.Model") Scene::Scene(const SpawnParams& params) : Actor(params) , Rendering(this) - , Ticking(this) , LightmapsData(this) , CSGData(this) { @@ -65,31 +89,6 @@ void Scene::SetLightmapSettings(const LightmapSettings& value) Info.LightmapSettings = value; } -BoundingBox Scene::GetNavigationBounds() -{ - if (NavigationVolumes.IsEmpty()) - return BoundingBox::Empty; - PROFILE_CPU_NAMED("GetNavigationBounds"); - auto box = NavigationVolumes[0]->GetBox(); - for (int32 i = 1; i < NavigationVolumes.Count(); i++) - BoundingBox::Merge(box, NavigationVolumes[i]->GetBox(), box); - return box; -} - -NavMeshBoundsVolume* Scene::FindNavigationBoundsOverlap(const BoundingBox& bounds) -{ - NavMeshBoundsVolume* result = nullptr; - for (int32 i = 0; i < NavigationVolumes.Count(); i++) - { - if (NavigationVolumes[i]->GetBox().Intersects(bounds)) - { - result = NavigationVolumes[i]; - break; - } - } - return result; -} - void Scene::ClearLightmaps() { LightmapsData.ClearLightmaps(); @@ -283,7 +282,7 @@ void Scene::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) CSGData.DeserializeIfExists(stream, "CSG", modifier); // [Deprecated on 13.01.2021, expires on 13.01.2023] - if (modifier->EngineBuild <= 6215 && NavigationMeshes.IsEmpty()) + if (modifier->EngineBuild <= 6215 && Navigation.Meshes.IsEmpty()) { const auto e = SERIALIZE_FIND_MEMBER(stream, "NavMesh"); if (e != stream.MemberEnd()) diff --git a/Source/Engine/Level/Scene/Scene.h b/Source/Engine/Level/Scene/Scene.h index 305a31ca6..474e0907f 100644 --- a/Source/Engine/Level/Scene/Scene.h +++ b/Source/Engine/Level/Scene/Scene.h @@ -8,22 +8,18 @@ #include "SceneCSGData.h" #include "SceneRendering.h" #include "SceneTicking.h" +#include "SceneNavigation.h" class MeshCollider; -class Level; -class ReloadScriptsAction; -class NavMeshBoundsVolume; -class NavMesh; /// /// The scene root object that contains a hierarchy of actors. /// API_CLASS() class FLAXENGINE_API Scene : public Actor { + friend class Level; + friend class ReloadScriptsAction; DECLARE_SCENE_OBJECT(Scene); - friend Level; - friend ReloadScriptsAction; -public: /// /// Finalizes an instance of the class. @@ -47,8 +43,6 @@ public: /// DateTime SaveTime; -public: - /// /// The scene rendering manager. /// @@ -59,6 +53,11 @@ public: /// SceneTicking Ticking; + /// + /// The navigation data. + /// + SceneNavigation Navigation; + /// /// The static light manager for this scene. /// @@ -80,31 +79,6 @@ public: /// API_PROPERTY() void SetLightmapSettings(const LightmapSettings& value); -public: - - /// - /// The list of registered navigation bounds volumes (in the scene). - /// - Array NavigationVolumes; - - /// - /// The list of registered navigation meshes (in the scene). - /// - Array NavigationMeshes; - - /// - /// Gets the total navigation volumes bounds. - /// - /// The navmesh bounds. - BoundingBox GetNavigationBounds(); - - /// - /// Finds the navigation volume bounds that have intersection with the given world-space bounding box. - /// - /// The bounds. - /// The intersecting volume or null if none found. - NavMeshBoundsVolume* FindNavigationBoundsOverlap(const BoundingBox& bounds); - public: /// @@ -119,8 +93,6 @@ public: /// The timeout to wait before building CSG (in milliseconds). API_FUNCTION() void BuildCSG(float timeoutMs = 50); -public: - #if USE_EDITOR /// diff --git a/Source/Engine/Level/Scene/SceneCSGData.h b/Source/Engine/Level/Scene/SceneCSGData.h index 0f85e75af..373ebd06c 100644 --- a/Source/Engine/Level/Scene/SceneCSGData.h +++ b/Source/Engine/Level/Scene/SceneCSGData.h @@ -2,13 +2,13 @@ #pragma once -#include "Engine/Content/AssetReference.h" -#include "Engine/Content/Assets/RawDataAsset.h" -#include "Engine/Content/Assets/Model.h" -#include "Engine/Serialization/ISerializable.h" #include "Engine/Core/Math/Triangle.h" #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Physics/CollisionData.h" +#include "Engine/Serialization/ISerializable.h" +#include "Engine/Content/AssetReference.h" +#include "Engine/Content/Assets/RawDataAsset.h" +#include "Engine/Content/Assets/Model.h" class Scene; @@ -74,7 +74,6 @@ namespace CSG /// /// Determines whether this container has CSG data linked. /// - /// true if this CSG data container is valid; otherwise, false. bool HasData() const; public: diff --git a/Source/Engine/Level/Scene/SceneNavigation.h b/Source/Engine/Level/Scene/SceneNavigation.h new file mode 100644 index 000000000..31ccb63b9 --- /dev/null +++ b/Source/Engine/Level/Scene/SceneNavigation.h @@ -0,0 +1,38 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Core/Collections/Array.h" + +class NavMesh; +class NavMeshBoundsVolume; + +/// +/// Scene navigation subsystem. +/// +class FLAXENGINE_API SceneNavigation +{ +public: + + /// + /// The list of registered navigation bounds volumes (on the scene). + /// + Array Volumes; + + /// + /// The list of registered navigation meshes (on the scene). + /// + Array Meshes; + + /// + /// Gets the total navigation volumes bounds. + /// + BoundingBox GetNavigationBounds(); + + /// + /// Finds the navigation volume bounds that have intersection with the given world-space bounding box. + /// + /// The bounds. + /// The intersecting volume or null if none found. + NavMeshBoundsVolume* FindNavigationBoundsOverlap(const BoundingBox& bounds); +}; diff --git a/Source/Engine/Level/Scene/SceneTicking.cpp b/Source/Engine/Level/Scene/SceneTicking.cpp index 862e3a352..b3a6c1cdc 100644 --- a/Source/Engine/Level/Scene/SceneTicking.cpp +++ b/Source/Engine/Level/Scene/SceneTicking.cpp @@ -4,6 +4,12 @@ #include "Scene.h" #include "Engine/Scripting/Script.h" +SceneTicking::TickData::TickData(int32 capacity) + : Scripts(capacity) + , Ticks(capacity) +{ +} + void SceneTicking::TickData::AddScript(Script* script) { Scripts.Add(script); @@ -22,6 +28,65 @@ void SceneTicking::TickData::RemoveScript(Script* script) #endif } +void SceneTicking::TickData::RemoveTick(void* callee) +{ + for (int32 i = 0; i < Ticks.Count(); i++) + { + if (Ticks[i].Callee == callee) + { + Ticks.RemoveAt(i); + break; + } + } +} + +void SceneTicking::TickData::Tick() +{ + TickScripts(Scripts); + + for (int32 i = 0; i < Ticks.Count(); i++) + Ticks[i].Call(); +} + +#if USE_EDITOR + +void SceneTicking::TickData::RemoveTickExecuteInEditor(void* callee) +{ + for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++) + { + if (TicksExecuteInEditor[i].Callee == callee) + { + TicksExecuteInEditor.RemoveAt(i); + break; + } + } +} + +void SceneTicking::TickData::TickExecuteInEditor() +{ + TickScripts(ScriptsExecuteInEditor); + + for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++) + TicksExecuteInEditor[i].Call(); +} + +#endif + +void SceneTicking::TickData::Clear() +{ + Scripts.Clear(); + Ticks.Clear(); +#if USE_EDITOR + ScriptsExecuteInEditor.Clear(); + TicksExecuteInEditor.Clear(); +#endif +} + +SceneTicking::FixedUpdateTickData::FixedUpdateTickData() + : TickData(512) +{ +} + void SceneTicking::FixedUpdateTickData::TickScripts(const Array& scripts) { for (auto* script : scripts) @@ -30,6 +95,11 @@ void SceneTicking::FixedUpdateTickData::TickScripts(const Array& script } } +SceneTicking::UpdateTickData::UpdateTickData() + : TickData(1024) +{ +} + void SceneTicking::UpdateTickData::TickScripts(const Array& scripts) { for (auto* script : scripts) @@ -38,6 +108,11 @@ void SceneTicking::UpdateTickData::TickScripts(const Array& scripts) } } +SceneTicking::LateUpdateTickData::LateUpdateTickData() + : TickData(64) +{ +} + void SceneTicking::LateUpdateTickData::TickScripts(const Array& scripts) { for (auto* script : scripts) @@ -46,15 +121,9 @@ void SceneTicking::LateUpdateTickData::TickScripts(const Array& scripts } } -SceneTicking::SceneTicking(::Scene* scene) - : Scene(scene) -{ -} - void SceneTicking::AddScript(Script* obj) { - ASSERT(obj && obj->GetParent() && obj->GetParent()->GetScene() == Scene); - + ASSERT_LOW_LAYER(obj && obj->GetParent() && obj->GetParent()->GetScene()); if (obj->_tickFixedUpdate) FixedUpdate.AddScript(obj); if (obj->_tickUpdate) @@ -65,8 +134,7 @@ void SceneTicking::AddScript(Script* obj) void SceneTicking::RemoveScript(Script* obj) { - ASSERT(obj && obj->GetParent() && obj->GetParent()->GetScene() == Scene); - + ASSERT_LOW_LAYER(obj && obj->GetParent() && obj->GetParent()->GetScene()); if (obj->_tickFixedUpdate) FixedUpdate.RemoveScript(obj); if (obj->_tickUpdate) diff --git a/Source/Engine/Level/Scene/SceneTicking.h b/Source/Engine/Level/Scene/SceneTicking.h index e8fbe8236..b90897792 100644 --- a/Source/Engine/Level/Scene/SceneTicking.h +++ b/Source/Engine/Level/Scene/SceneTicking.h @@ -10,8 +10,6 @@ /// class FLAXENGINE_API SceneTicking { - friend Scene; - public: /// @@ -28,13 +26,9 @@ public: (static_cast(callee)->*Method)(); } - public: - void* Callee; SignatureObj FunctionObj; - public: - template void Bind(T* callee) { @@ -42,15 +36,15 @@ public: FunctionObj = &MethodCaller; } - /// - /// Calls the binded function. - /// FORCE_INLINE void Call() const { (*FunctionObj)(Callee); } }; + /// + /// Ticking data container. + /// class FLAXENGINE_API TickData { public: @@ -62,32 +56,10 @@ public: Array TicksExecuteInEditor; #endif - TickData(int32 capacity) - : Scripts(capacity) - , Ticks(capacity) - { - } + TickData(int32 capacity); virtual void TickScripts(const Array& scripts) = 0; - void Tick() - { - TickScripts(Scripts); - - for (int32 i = 0; i < Ticks.Count(); i++) - Ticks[i].Call(); - } - -#if USE_EDITOR - void TickExecuteInEditor() - { - TickScripts(ScriptsExecuteInEditor); - - for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++) - TicksExecuteInEditor[i].Call(); - } -#endif - void AddScript(Script* script); void RemoveScript(Script* script); @@ -99,17 +71,8 @@ public: Ticks.Add(tick); } - void RemoveTick(void* callee) - { - for (int32 i = 0; i < Ticks.Count(); i++) - { - if (Ticks[i].Callee == callee) - { - Ticks.RemoveAt(i); - break; - } - } - } + void RemoveTick(void* callee); + void Tick(); #if USE_EDITOR template @@ -120,39 +83,18 @@ public: TicksExecuteInEditor.Add(tick); } - void RemoveTickExecuteInEditor(void* callee) - { - for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++) - { - if (TicksExecuteInEditor[i].Callee == callee) - { - TicksExecuteInEditor.RemoveAt(i); - break; - } - } - } + void RemoveTickExecuteInEditor(void* callee); + void TickExecuteInEditor(); #endif - void Clear() - { - Scripts.Clear(); - Ticks.Clear(); -#if USE_EDITOR - ScriptsExecuteInEditor.Clear(); - TicksExecuteInEditor.Clear(); -#endif - } + void Clear(); }; class FLAXENGINE_API FixedUpdateTickData : public TickData { public: - FixedUpdateTickData() - : TickData(512) - { - } - + FixedUpdateTickData(); void TickScripts(const Array& scripts) override; }; @@ -160,11 +102,7 @@ public: { public: - UpdateTickData() - : TickData(1024) - { - } - + UpdateTickData(); void TickScripts(const Array& scripts) override; }; @@ -172,20 +110,10 @@ public: { public: - LateUpdateTickData() - : TickData(64) - { - } - + LateUpdateTickData(); void TickScripts(const Array& scripts) override; }; -private: - - Scene* Scene; - - explicit SceneTicking(::Scene* scene); - public: /// diff --git a/Source/Engine/Navigation/NavMesh.cpp b/Source/Engine/Navigation/NavMesh.cpp index 32ba8c61f..1f78287ae 100644 --- a/Source/Engine/Navigation/NavMesh.cpp +++ b/Source/Engine/Navigation/NavMesh.cpp @@ -156,14 +156,14 @@ void NavMesh::OnEnable() // Base Actor::OnEnable(); - GetScene()->NavigationMeshes.Add(this); + GetScene()->Navigation.Meshes.Add(this); AddTiles(); } void NavMesh::OnDisable() { RemoveTiles(); - GetScene()->NavigationMeshes.Remove(this); + GetScene()->Navigation.Meshes.Remove(this); // Base Actor::OnDisable(); diff --git a/Source/Engine/Navigation/NavMeshBoundsVolume.cpp b/Source/Engine/Navigation/NavMeshBoundsVolume.cpp index 700442b2f..1e11ffe84 100644 --- a/Source/Engine/Navigation/NavMeshBoundsVolume.cpp +++ b/Source/Engine/Navigation/NavMeshBoundsVolume.cpp @@ -37,12 +37,12 @@ void NavMeshBoundsVolume::OnEnable() // Base Actor::OnEnable(); - GetScene()->NavigationVolumes.Add(this); + GetScene()->Navigation.Volumes.Add(this); } void NavMeshBoundsVolume::OnDisable() { - GetScene()->NavigationVolumes.Remove(this); + GetScene()->Navigation.Volumes.Remove(this); // Base Actor::OnDisable(); diff --git a/Source/Engine/Navigation/NavMeshBuilder.cpp b/Source/Engine/Navigation/NavMeshBuilder.cpp index 755f4179b..8187de90a 100644 --- a/Source/Engine/Navigation/NavMeshBuilder.cpp +++ b/Source/Engine/Navigation/NavMeshBuilder.cpp @@ -348,9 +348,9 @@ bool GetNavMeshTileBounds(Scene* scene, NavMesh* navMesh, int32 x, int32 y, floa // Check if any navmesh volume intersects with the tile bool foundAnyVolume = false; Vector2 rangeY; - for (int32 i = 0; i < scene->NavigationVolumes.Count(); i++) + for (int32 i = 0; i < scene->Navigation.Volumes.Count(); i++) { - const auto volume = scene->NavigationVolumes[i]; + const auto volume = scene->Navigation.Volumes[i]; if (!volume->AgentsMask.IsNavMeshSupported(navMesh->Properties)) continue; const auto& volumeBounds = volume->GetBox(); @@ -925,7 +925,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild for (auto& navMeshProperties : settings->NavMeshes) { NavMesh* navMesh = nullptr; - for (auto e : scene->NavigationMeshes) + for (auto e : scene->Navigation.Meshes) { if (e->Properties.Name == navMeshProperties.Name) { @@ -953,7 +953,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild } // Build all navmeshes on the scene - for (NavMesh* navMesh : scene->NavigationMeshes) + for (NavMesh* navMesh : scene->Navigation.Meshes) { BuildDirtyBounds(scene, navMesh, dirtyBounds, rebuild); } @@ -961,7 +961,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild // Remove unused navmeshes if (settings->AutoRemoveMissingNavMeshes) { - for (NavMesh* navMesh : scene->NavigationMeshes) + for (NavMesh* navMesh : scene->Navigation.Meshes) { // Skip used navmeshes if (navMesh->Data.Tiles.HasItems()) @@ -987,7 +987,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild void BuildWholeScene(Scene* scene) { // Compute total navigation area bounds - const BoundingBox worldBounds = scene->GetNavigationBounds(); + const BoundingBox worldBounds = scene->Navigation.GetNavigationBounds(); BuildDirtyBounds(scene, worldBounds, true); } @@ -995,7 +995,7 @@ void BuildWholeScene(Scene* scene) void ClearNavigation(Scene* scene) { const bool autoRemoveMissingNavMeshes = NavigationSettings::Get()->AutoRemoveMissingNavMeshes; - for (NavMesh* navMesh : scene->NavigationMeshes) + for (NavMesh* navMesh : scene->Navigation.Meshes) { navMesh->ClearData(); if (autoRemoveMissingNavMeshes) @@ -1020,7 +1020,7 @@ void NavMeshBuilder::Update() continue; // Early out if scene has no bounds volumes to define nav mesh area - if (scene->NavigationVolumes.IsEmpty()) + if (scene->Navigation.Volumes.IsEmpty()) { ClearNavigation(scene); continue; @@ -1042,7 +1042,7 @@ void NavMeshBuilder::Update() void NavMeshBuilder::Build(Scene* scene, float timeoutMs) { // Early out if scene is not using navigation - if (scene->NavigationVolumes.IsEmpty()) + if (scene->Navigation.Volumes.IsEmpty()) { ClearNavigation(scene); return; @@ -1073,7 +1073,7 @@ void NavMeshBuilder::Build(Scene* scene, float timeoutMs) void NavMeshBuilder::Build(Scene* scene, const BoundingBox& dirtyBounds, float timeoutMs) { // Early out if scene is not using navigation - if (scene->NavigationVolumes.IsEmpty()) + if (scene->Navigation.Volumes.IsEmpty()) { ClearNavigation(scene); return; diff --git a/Source/Engine/Navigation/Navigation.cpp b/Source/Engine/Navigation/Navigation.cpp index d7fdcfc33..2561a2176 100644 --- a/Source/Engine/Navigation/Navigation.cpp +++ b/Source/Engine/Navigation/Navigation.cpp @@ -371,7 +371,7 @@ void Navigation::DrawNavMesh() bool skip = false; for (auto scene : Level::Scenes) { - for (auto e : scene->NavigationMeshes) + for (auto e : scene->Navigation.Meshes) { if (e->Properties == navMesh->Properties) {