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"); LOG(Info, "Prepare scene objects");
SceneBeginData beginData; 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(); beginData.OnDone();
} }

View File

@@ -30,13 +30,37 @@ bool SceneAsset::IsInternalType() const
return true; 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_COLLIDER_NAME TEXT("CSG.Collider")
#define CSG_MODEL_NAME TEXT("CSG.Model") #define CSG_MODEL_NAME TEXT("CSG.Model")
Scene::Scene(const SpawnParams& params) Scene::Scene(const SpawnParams& params)
: Actor(params) : Actor(params)
, Rendering(this) , Rendering(this)
, Ticking(this)
, LightmapsData(this) , LightmapsData(this)
, CSGData(this) , CSGData(this)
{ {
@@ -65,31 +89,6 @@ void Scene::SetLightmapSettings(const LightmapSettings& value)
Info.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() void Scene::ClearLightmaps()
{ {
LightmapsData.ClearLightmaps(); LightmapsData.ClearLightmaps();
@@ -283,7 +282,7 @@ void Scene::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
CSGData.DeserializeIfExists(stream, "CSG", modifier); CSGData.DeserializeIfExists(stream, "CSG", modifier);
// [Deprecated on 13.01.2021, expires on 13.01.2023] // [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"); const auto e = SERIALIZE_FIND_MEMBER(stream, "NavMesh");
if (e != stream.MemberEnd()) if (e != stream.MemberEnd())

View File

@@ -8,22 +8,18 @@
#include "SceneCSGData.h" #include "SceneCSGData.h"
#include "SceneRendering.h" #include "SceneRendering.h"
#include "SceneTicking.h" #include "SceneTicking.h"
#include "SceneNavigation.h"
class MeshCollider; class MeshCollider;
class Level;
class ReloadScriptsAction;
class NavMeshBoundsVolume;
class NavMesh;
/// <summary> /// <summary>
/// The scene root object that contains a hierarchy of actors. /// The scene root object that contains a hierarchy of actors.
/// </summary> /// </summary>
API_CLASS() class FLAXENGINE_API Scene : public Actor API_CLASS() class FLAXENGINE_API Scene : public Actor
{ {
friend class Level;
friend class ReloadScriptsAction;
DECLARE_SCENE_OBJECT(Scene); DECLARE_SCENE_OBJECT(Scene);
friend Level;
friend ReloadScriptsAction;
public:
/// <summary> /// <summary>
/// Finalizes an instance of the <see cref="Scene"/> class. /// Finalizes an instance of the <see cref="Scene"/> class.
@@ -47,8 +43,6 @@ public:
/// </summary> /// </summary>
DateTime SaveTime; DateTime SaveTime;
public:
/// <summary> /// <summary>
/// The scene rendering manager. /// The scene rendering manager.
/// </summary> /// </summary>
@@ -59,6 +53,11 @@ public:
/// </summary> /// </summary>
SceneTicking Ticking; SceneTicking Ticking;
/// <summary>
/// The navigation data.
/// </summary>
SceneNavigation Navigation;
/// <summary> /// <summary>
/// The static light manager for this scene. /// The static light manager for this scene.
/// </summary> /// </summary>
@@ -80,31 +79,6 @@ public:
/// </summary> /// </summary>
API_PROPERTY() void SetLightmapSettings(const LightmapSettings& value); 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: public:
/// <summary> /// <summary>
@@ -119,8 +93,6 @@ public:
/// <param name="timeoutMs">The timeout to wait before building CSG (in milliseconds).</param> /// <param name="timeoutMs">The timeout to wait before building CSG (in milliseconds).</param>
API_FUNCTION() void BuildCSG(float timeoutMs = 50); API_FUNCTION() void BuildCSG(float timeoutMs = 50);
public:
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>

View File

@@ -2,13 +2,13 @@
#pragma once #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/Math/Triangle.h"
#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Physics/CollisionData.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; class Scene;
@@ -74,7 +74,6 @@ namespace CSG
/// <summary> /// <summary>
/// Determines whether this container has CSG data linked. /// Determines whether this container has CSG data linked.
/// </summary> /// </summary>
/// <returns><c>true</c> if this CSG data container is valid; otherwise, <c>false</c>.</returns>
bool HasData() const; bool HasData() const;
public: 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 "Scene.h"
#include "Engine/Scripting/Script.h" #include "Engine/Scripting/Script.h"
SceneTicking::TickData::TickData(int32 capacity)
: Scripts(capacity)
, Ticks(capacity)
{
}
void SceneTicking::TickData::AddScript(Script* script) void SceneTicking::TickData::AddScript(Script* script)
{ {
Scripts.Add(script); Scripts.Add(script);
@@ -22,6 +28,65 @@ void SceneTicking::TickData::RemoveScript(Script* script)
#endif #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) void SceneTicking::FixedUpdateTickData::TickScripts(const Array<Script*>& scripts)
{ {
for (auto* 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) void SceneTicking::UpdateTickData::TickScripts(const Array<Script*>& scripts)
{ {
for (auto* 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) void SceneTicking::LateUpdateTickData::TickScripts(const Array<Script*>& scripts)
{ {
for (auto* 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) 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) if (obj->_tickFixedUpdate)
FixedUpdate.AddScript(obj); FixedUpdate.AddScript(obj);
if (obj->_tickUpdate) if (obj->_tickUpdate)
@@ -65,8 +134,7 @@ void SceneTicking::AddScript(Script* obj)
void SceneTicking::RemoveScript(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) if (obj->_tickFixedUpdate)
FixedUpdate.RemoveScript(obj); FixedUpdate.RemoveScript(obj);
if (obj->_tickUpdate) if (obj->_tickUpdate)

View File

@@ -10,8 +10,6 @@
/// </summary> /// </summary>
class FLAXENGINE_API SceneTicking class FLAXENGINE_API SceneTicking
{ {
friend Scene;
public: public:
/// <summary> /// <summary>
@@ -28,13 +26,9 @@ public:
(static_cast<T*>(callee)->*Method)(); (static_cast<T*>(callee)->*Method)();
} }
public:
void* Callee; void* Callee;
SignatureObj FunctionObj; SignatureObj FunctionObj;
public:
template<class T, void(T::*Method)()> template<class T, void(T::*Method)()>
void Bind(T* callee) void Bind(T* callee)
{ {
@@ -42,15 +36,15 @@ public:
FunctionObj = &MethodCaller<T, Method>; FunctionObj = &MethodCaller<T, Method>;
} }
/// <summary>
/// Calls the binded function.
/// </summary>
FORCE_INLINE void Call() const FORCE_INLINE void Call() const
{ {
(*FunctionObj)(Callee); (*FunctionObj)(Callee);
} }
}; };
/// <summary>
/// Ticking data container.
/// </summary>
class FLAXENGINE_API TickData class FLAXENGINE_API TickData
{ {
public: public:
@@ -62,32 +56,10 @@ public:
Array<Tick> TicksExecuteInEditor; Array<Tick> TicksExecuteInEditor;
#endif #endif
TickData(int32 capacity) TickData(int32 capacity);
: Scripts(capacity)
, Ticks(capacity)
{
}
virtual void TickScripts(const Array<Script*>& scripts) = 0; 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 AddScript(Script* script);
void RemoveScript(Script* script); void RemoveScript(Script* script);
@@ -99,17 +71,8 @@ public:
Ticks.Add(tick); Ticks.Add(tick);
} }
void RemoveTick(void* callee) void RemoveTick(void* callee);
{ void Tick();
for (int32 i = 0; i < Ticks.Count(); i++)
{
if (Ticks[i].Callee == callee)
{
Ticks.RemoveAt(i);
break;
}
}
}
#if USE_EDITOR #if USE_EDITOR
template<class T, void(T::*Method)()> template<class T, void(T::*Method)()>
@@ -120,39 +83,18 @@ public:
TicksExecuteInEditor.Add(tick); TicksExecuteInEditor.Add(tick);
} }
void RemoveTickExecuteInEditor(void* callee) void RemoveTickExecuteInEditor(void* callee);
{ void TickExecuteInEditor();
for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++)
{
if (TicksExecuteInEditor[i].Callee == callee)
{
TicksExecuteInEditor.RemoveAt(i);
break;
}
}
}
#endif #endif
void Clear() void Clear();
{
Scripts.Clear();
Ticks.Clear();
#if USE_EDITOR
ScriptsExecuteInEditor.Clear();
TicksExecuteInEditor.Clear();
#endif
}
}; };
class FLAXENGINE_API FixedUpdateTickData : public TickData class FLAXENGINE_API FixedUpdateTickData : public TickData
{ {
public: public:
FixedUpdateTickData() FixedUpdateTickData();
: TickData(512)
{
}
void TickScripts(const Array<Script*>& scripts) override; void TickScripts(const Array<Script*>& scripts) override;
}; };
@@ -160,11 +102,7 @@ public:
{ {
public: public:
UpdateTickData() UpdateTickData();
: TickData(1024)
{
}
void TickScripts(const Array<Script*>& scripts) override; void TickScripts(const Array<Script*>& scripts) override;
}; };
@@ -172,20 +110,10 @@ public:
{ {
public: public:
LateUpdateTickData() LateUpdateTickData();
: TickData(64)
{
}
void TickScripts(const Array<Script*>& scripts) override; void TickScripts(const Array<Script*>& scripts) override;
}; };
private:
Scene* Scene;
explicit SceneTicking(::Scene* scene);
public: public:
/// <summary> /// <summary>

View File

@@ -156,14 +156,14 @@ void NavMesh::OnEnable()
// Base // Base
Actor::OnEnable(); Actor::OnEnable();
GetScene()->NavigationMeshes.Add(this); GetScene()->Navigation.Meshes.Add(this);
AddTiles(); AddTiles();
} }
void NavMesh::OnDisable() void NavMesh::OnDisable()
{ {
RemoveTiles(); RemoveTiles();
GetScene()->NavigationMeshes.Remove(this); GetScene()->Navigation.Meshes.Remove(this);
// Base // Base
Actor::OnDisable(); Actor::OnDisable();

View File

@@ -37,12 +37,12 @@ void NavMeshBoundsVolume::OnEnable()
// Base // Base
Actor::OnEnable(); Actor::OnEnable();
GetScene()->NavigationVolumes.Add(this); GetScene()->Navigation.Volumes.Add(this);
} }
void NavMeshBoundsVolume::OnDisable() void NavMeshBoundsVolume::OnDisable()
{ {
GetScene()->NavigationVolumes.Remove(this); GetScene()->Navigation.Volumes.Remove(this);
// Base // Base
Actor::OnDisable(); 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 // Check if any navmesh volume intersects with the tile
bool foundAnyVolume = false; bool foundAnyVolume = false;
Vector2 rangeY; 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)) if (!volume->AgentsMask.IsNavMeshSupported(navMesh->Properties))
continue; continue;
const auto& volumeBounds = volume->GetBox(); const auto& volumeBounds = volume->GetBox();
@@ -925,7 +925,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild
for (auto& navMeshProperties : settings->NavMeshes) for (auto& navMeshProperties : settings->NavMeshes)
{ {
NavMesh* navMesh = nullptr; NavMesh* navMesh = nullptr;
for (auto e : scene->NavigationMeshes) for (auto e : scene->Navigation.Meshes)
{ {
if (e->Properties.Name == navMeshProperties.Name) 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 // Build all navmeshes on the scene
for (NavMesh* navMesh : scene->NavigationMeshes) for (NavMesh* navMesh : scene->Navigation.Meshes)
{ {
BuildDirtyBounds(scene, navMesh, dirtyBounds, rebuild); BuildDirtyBounds(scene, navMesh, dirtyBounds, rebuild);
} }
@@ -961,7 +961,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild
// Remove unused navmeshes // Remove unused navmeshes
if (settings->AutoRemoveMissingNavMeshes) if (settings->AutoRemoveMissingNavMeshes)
{ {
for (NavMesh* navMesh : scene->NavigationMeshes) for (NavMesh* navMesh : scene->Navigation.Meshes)
{ {
// Skip used navmeshes // Skip used navmeshes
if (navMesh->Data.Tiles.HasItems()) if (navMesh->Data.Tiles.HasItems())
@@ -987,7 +987,7 @@ void BuildDirtyBounds(Scene* scene, const BoundingBox& dirtyBounds, bool rebuild
void BuildWholeScene(Scene* scene) void BuildWholeScene(Scene* scene)
{ {
// Compute total navigation area bounds // Compute total navigation area bounds
const BoundingBox worldBounds = scene->GetNavigationBounds(); const BoundingBox worldBounds = scene->Navigation.GetNavigationBounds();
BuildDirtyBounds(scene, worldBounds, true); BuildDirtyBounds(scene, worldBounds, true);
} }
@@ -995,7 +995,7 @@ void BuildWholeScene(Scene* scene)
void ClearNavigation(Scene* scene) void ClearNavigation(Scene* scene)
{ {
const bool autoRemoveMissingNavMeshes = NavigationSettings::Get()->AutoRemoveMissingNavMeshes; const bool autoRemoveMissingNavMeshes = NavigationSettings::Get()->AutoRemoveMissingNavMeshes;
for (NavMesh* navMesh : scene->NavigationMeshes) for (NavMesh* navMesh : scene->Navigation.Meshes)
{ {
navMesh->ClearData(); navMesh->ClearData();
if (autoRemoveMissingNavMeshes) if (autoRemoveMissingNavMeshes)
@@ -1020,7 +1020,7 @@ void NavMeshBuilder::Update()
continue; continue;
// Early out if scene has no bounds volumes to define nav mesh area // Early out if scene has no bounds volumes to define nav mesh area
if (scene->NavigationVolumes.IsEmpty()) if (scene->Navigation.Volumes.IsEmpty())
{ {
ClearNavigation(scene); ClearNavigation(scene);
continue; continue;
@@ -1042,7 +1042,7 @@ void NavMeshBuilder::Update()
void NavMeshBuilder::Build(Scene* scene, float timeoutMs) void NavMeshBuilder::Build(Scene* scene, float timeoutMs)
{ {
// Early out if scene is not using navigation // Early out if scene is not using navigation
if (scene->NavigationVolumes.IsEmpty()) if (scene->Navigation.Volumes.IsEmpty())
{ {
ClearNavigation(scene); ClearNavigation(scene);
return; return;
@@ -1073,7 +1073,7 @@ void NavMeshBuilder::Build(Scene* scene, float timeoutMs)
void NavMeshBuilder::Build(Scene* scene, const BoundingBox& dirtyBounds, float timeoutMs) void NavMeshBuilder::Build(Scene* scene, const BoundingBox& dirtyBounds, float timeoutMs)
{ {
// Early out if scene is not using navigation // Early out if scene is not using navigation
if (scene->NavigationVolumes.IsEmpty()) if (scene->Navigation.Volumes.IsEmpty())
{ {
ClearNavigation(scene); ClearNavigation(scene);
return; return;

View File

@@ -371,7 +371,7 @@ void Navigation::DrawNavMesh()
bool skip = false; bool skip = false;
for (auto scene : Level::Scenes) for (auto scene : Level::Scenes)
{ {
for (auto e : scene->NavigationMeshes) for (auto e : scene->Navigation.Meshes)
{ {
if (e->Properties == navMesh->Properties) if (e->Properties == navMesh->Properties)
{ {