Add SceneNavigation for scene data for navigation system

This commit is contained in:
Wojtek Figat
2021-06-27 22:41:43 +02:00
parent d9fe1b257f
commit e61ebaa71b
11 changed files with 182 additions and 178 deletions

View File

@@ -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();
}

View File

@@ -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())

View File

@@ -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;
/// <summary>
/// The scene root object that contains a hierarchy of actors.
/// </summary>
API_CLASS() class FLAXENGINE_API Scene : public Actor
{
friend class Level;
friend class ReloadScriptsAction;
DECLARE_SCENE_OBJECT(Scene);
friend Level;
friend ReloadScriptsAction;
public:
/// <summary>
/// Finalizes an instance of the <see cref="Scene"/> class.
@@ -47,8 +43,6 @@ public:
/// </summary>
DateTime SaveTime;
public:
/// <summary>
/// The scene rendering manager.
/// </summary>
@@ -59,6 +53,11 @@ public:
/// </summary>
SceneTicking Ticking;
/// <summary>
/// The navigation data.
/// </summary>
SceneNavigation Navigation;
/// <summary>
/// The static light manager for this scene.
/// </summary>
@@ -80,31 +79,6 @@ public:
/// </summary>
API_PROPERTY() void SetLightmapSettings(const LightmapSettings& value);
public:
/// <summary>
/// The list of registered navigation bounds volumes (in the scene).
/// </summary>
Array<NavMeshBoundsVolume*> NavigationVolumes;
/// <summary>
/// The list of registered navigation meshes (in the scene).
/// </summary>
Array<NavMesh*> NavigationMeshes;
/// <summary>
/// Gets the total navigation volumes bounds.
/// </summary>
/// <returns>The navmesh bounds.</returns>
BoundingBox GetNavigationBounds();
/// <summary>
/// Finds the navigation volume bounds that have intersection with the given world-space bounding box.
/// </summary>
/// <param name="bounds">The bounds.</param>
/// <returns>The intersecting volume or null if none found.</returns>
NavMeshBoundsVolume* FindNavigationBoundsOverlap(const BoundingBox& bounds);
public:
/// <summary>
@@ -119,8 +93,6 @@ public:
/// <param name="timeoutMs">The timeout to wait before building CSG (in milliseconds).</param>
API_FUNCTION() void BuildCSG(float timeoutMs = 50);
public:
#if USE_EDITOR
/// <summary>

View File

@@ -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
/// <summary>
/// Determines whether this container has CSG data linked.
/// </summary>
/// <returns><c>true</c> if this CSG data container is valid; otherwise, <c>false</c>.</returns>
bool HasData() const;
public:

View File

@@ -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;
/// <summary>
/// Scene navigation subsystem.
/// </summary>
class FLAXENGINE_API SceneNavigation
{
public:
/// <summary>
/// The list of registered navigation bounds volumes (on the scene).
/// </summary>
Array<NavMeshBoundsVolume*> Volumes;
/// <summary>
/// The list of registered navigation meshes (on the scene).
/// </summary>
Array<NavMesh*> Meshes;
/// <summary>
/// Gets the total navigation volumes bounds.
/// </summary>
BoundingBox GetNavigationBounds();
/// <summary>
/// Finds the navigation volume bounds that have intersection with the given world-space bounding box.
/// </summary>
/// <param name="bounds">The bounds.</param>
/// <returns>The intersecting volume or null if none found.</returns>
NavMeshBoundsVolume* FindNavigationBoundsOverlap(const BoundingBox& bounds);
};

View File

@@ -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<Script*>& scripts)
{
for (auto* script : scripts)
@@ -30,6 +95,11 @@ void SceneTicking::FixedUpdateTickData::TickScripts(const Array<Script*>& script
}
}
SceneTicking::UpdateTickData::UpdateTickData()
: TickData(1024)
{
}
void SceneTicking::UpdateTickData::TickScripts(const Array<Script*>& scripts)
{
for (auto* script : scripts)
@@ -38,6 +108,11 @@ void SceneTicking::UpdateTickData::TickScripts(const Array<Script*>& scripts)
}
}
SceneTicking::LateUpdateTickData::LateUpdateTickData()
: TickData(64)
{
}
void SceneTicking::LateUpdateTickData::TickScripts(const Array<Script*>& scripts)
{
for (auto* script : scripts)
@@ -46,15 +121,9 @@ void SceneTicking::LateUpdateTickData::TickScripts(const Array<Script*>& 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)

View File

@@ -10,8 +10,6 @@
/// </summary>
class FLAXENGINE_API SceneTicking
{
friend Scene;
public:
/// <summary>
@@ -28,13 +26,9 @@ public:
(static_cast<T*>(callee)->*Method)();
}
public:
void* Callee;
SignatureObj FunctionObj;
public:
template<class T, void(T::*Method)()>
void Bind(T* callee)
{
@@ -42,15 +36,15 @@ public:
FunctionObj = &MethodCaller<T, Method>;
}
/// <summary>
/// Calls the binded function.
/// </summary>
FORCE_INLINE void Call() const
{
(*FunctionObj)(Callee);
}
};
/// <summary>
/// Ticking data container.
/// </summary>
class FLAXENGINE_API TickData
{
public:
@@ -62,32 +56,10 @@ public:
Array<Tick> TicksExecuteInEditor;
#endif
TickData(int32 capacity)
: Scripts(capacity)
, Ticks(capacity)
{
}
TickData(int32 capacity);
virtual void TickScripts(const Array<Script*>& 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<class T, void(T::*Method)()>
@@ -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<Script*>& scripts) override;
};
@@ -160,11 +102,7 @@ public:
{
public:
UpdateTickData()
: TickData(1024)
{
}
UpdateTickData();
void TickScripts(const Array<Script*>& scripts) override;
};
@@ -172,20 +110,10 @@ public:
{
public:
LateUpdateTickData()
: TickData(64)
{
}
LateUpdateTickData();
void TickScripts(const Array<Script*>& scripts) override;
};
private:
Scene* Scene;
explicit SceneTicking(::Scene* scene);
public:
/// <summary>

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;

View File

@@ -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)
{