Optimize asset references to support direct registration to reduce Delegate memory allocations and overhead

This commit is contained in:
Wojtek Figat
2025-06-08 00:58:15 +02:00
parent bffb175a9b
commit 73c30d3d89
26 changed files with 365 additions and 141 deletions

View File

@@ -73,9 +73,9 @@ void BehaviorService::Dispose()
Behavior::Behavior(const SpawnParams& params)
: Script(params)
, Tree(this)
{
_knowledge.Behavior = this;
Tree.Changed.Bind<Behavior, &Behavior::ResetLogic>(this);
}
void Behavior::UpdateAsync()
@@ -175,6 +175,19 @@ void Behavior::OnDisable()
BehaviorServiceInstance.UpdateList.Remove(this);
}
void Behavior::OnAssetChanged(Asset* asset, void* caller)
{
ResetLogic();
}
void Behavior::OnAssetLoaded(Asset* asset, void* caller)
{
}
void Behavior::OnAssetUnloaded(Asset* asset, void* caller)
{
}
#if USE_EDITOR
bool Behavior::GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior)

View File

@@ -11,7 +11,7 @@
/// <summary>
/// Behavior instance script that runs Behavior Tree execution.
/// </summary>
API_CLASS(Attributes="Category(\"Flax Engine\")") class FLAXENGINE_API Behavior : public Script
API_CLASS(Attributes="Category(\"Flax Engine\")") class FLAXENGINE_API Behavior : public Script, private IAssetReference
{
API_AUTO_SERIALIZATION();
DECLARE_SCRIPTING_TYPE(Behavior);
@@ -92,6 +92,11 @@ public:
void OnDisable() override;
private:
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
#if USE_EDITOR
// Editor-only utilities to debug nodes state.
API_FUNCTION(Internal) static bool GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior);

View File

@@ -21,9 +21,8 @@ AudioSource::AudioSource(const SpawnParams& params)
, _playOnStart(false)
, _startTime(0.0f)
, _allowSpatialization(true)
, Clip(this)
{
Clip.Changed.Bind<AudioSource, &AudioSource::OnClipChanged>(this);
Clip.Loaded.Bind<AudioSource, &AudioSource::OnClipLoaded>(this);
}
void AudioSource::SetVolume(float value)
@@ -264,7 +263,7 @@ void AudioSource::RequestStreamingBuffersUpdate()
_needToUpdateStreamingBuffers = true;
}
void AudioSource::OnClipChanged()
void AudioSource::OnAssetChanged(Asset* asset, void* caller)
{
Stop();
@@ -276,7 +275,7 @@ void AudioSource::OnClipChanged()
}
}
void AudioSource::OnClipLoaded()
void AudioSource::OnAssetLoaded(Asset* asset, void* caller)
{
if (!SourceID)
return;
@@ -302,6 +301,10 @@ void AudioSource::OnClipLoaded()
}
}
void AudioSource::OnAssetUnloaded(Asset* asset, void* caller)
{
}
bool AudioSource::UseStreaming() const
{
if (Clip == nullptr || Clip->WaitForLoaded())

View File

@@ -13,7 +13,7 @@
/// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
/// </remarks>
API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Source\"), ActorToolbox(\"Other\")")
class FLAXENGINE_API AudioSource : public Actor
class FLAXENGINE_API AudioSource : public Actor, IAssetReference
{
DECLARE_SCENE_OBJECT(AudioSource);
friend class AudioStreamingHandler;
@@ -293,8 +293,10 @@ public:
void RequestStreamingBuffersUpdate();
private:
void OnClipChanged();
void OnClipLoaded();
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
/// <summary>
/// Plays the audio source. Should have buffer(s) binded before.

View File

@@ -9,6 +9,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Core/LogContext.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Threading/MainThreadTask.h"
#include "Engine/Threading/ThreadLocal.h"
@@ -34,15 +35,18 @@ bool ContentDeprecated::Clear(bool newValue)
#endif
AssetReferenceBase::AssetReferenceBase(IAssetReference* owner)
: _owner(owner)
{
}
AssetReferenceBase::~AssetReferenceBase()
{
Asset* asset = _asset;
if (asset)
{
_asset = nullptr;
asset->OnLoaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnLoaded>(this);
asset->OnUnloaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnUnloaded>(this);
asset->RemoveReference();
asset->RemoveReference(this);
}
}
@@ -51,52 +55,60 @@ String AssetReferenceBase::ToString() const
return _asset ? _asset->ToString() : TEXT("<null>");
}
void AssetReferenceBase::OnAssetChanged(Asset* asset, void* caller)
{
if (_owner)
_owner->OnAssetChanged(asset, this);
}
void AssetReferenceBase::OnAssetLoaded(Asset* asset, void* caller)
{
if (_asset != asset)
return;
Loaded();
if (_owner)
_owner->OnAssetLoaded(asset, this);
}
void AssetReferenceBase::OnAssetUnloaded(Asset* asset, void* caller)
{
if (_asset != asset)
return;
Unload();
OnSet(nullptr);
if (_owner)
_owner->OnAssetUnloaded(asset, this);
}
void AssetReferenceBase::OnSet(Asset* asset)
{
auto e = _asset;
if (e != asset)
{
if (e)
{
e->OnLoaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnLoaded>(this);
e->OnUnloaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnUnloaded>(this);
e->RemoveReference();
}
e->RemoveReference(this);
_asset = e = asset;
if (e)
{
e->AddReference();
e->OnLoaded.Bind<AssetReferenceBase, &AssetReferenceBase::OnLoaded>(this);
e->OnUnloaded.Bind<AssetReferenceBase, &AssetReferenceBase::OnUnloaded>(this);
}
e->AddReference(this);
Changed();
if (_owner)
_owner->OnAssetChanged(asset, this);
if (e && e->IsLoaded())
{
Loaded();
if (_owner)
_owner->OnAssetLoaded(asset, this);
}
}
}
void AssetReferenceBase::OnLoaded(Asset* asset)
{
if (_asset != asset)
return;
Loaded();
}
void AssetReferenceBase::OnUnloaded(Asset* asset)
{
if (_asset != asset)
return;
Unload();
OnSet(nullptr);
}
WeakAssetReferenceBase::~WeakAssetReferenceBase()
{
Asset* asset = _asset;
if (asset)
{
_asset = nullptr;
asset->OnUnloaded.Unbind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
asset->RemoveReference(this, true);
}
}
@@ -105,36 +117,43 @@ String WeakAssetReferenceBase::ToString() const
return _asset ? _asset->ToString() : TEXT("<null>");
}
void WeakAssetReferenceBase::OnAssetChanged(Asset* asset, void* caller)
{
}
void WeakAssetReferenceBase::OnAssetLoaded(Asset* asset, void* caller)
{
}
void WeakAssetReferenceBase::OnAssetUnloaded(Asset* asset, void* caller)
{
if (_asset != asset)
return;
Unload();
asset->RemoveReference(this, true);
_asset = nullptr;
}
void WeakAssetReferenceBase::OnSet(Asset* asset)
{
auto e = _asset;
if (e != asset)
{
if (e)
e->OnUnloaded.Unbind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
e->RemoveReference(this, true);
_asset = e = asset;
if (e)
e->OnUnloaded.Bind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
e->AddReference(this, true);
}
}
void WeakAssetReferenceBase::OnUnloaded(Asset* asset)
{
if (_asset != asset)
return;
Unload();
asset->OnUnloaded.Unbind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
_asset = nullptr;
}
SoftAssetReferenceBase::~SoftAssetReferenceBase()
{
Asset* asset = _asset;
if (asset)
{
_asset = nullptr;
asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
asset->RemoveReference();
asset->RemoveReference(this);
}
#if !BUILD_RELEASE
_id = Guid::Empty;
@@ -146,22 +165,34 @@ String SoftAssetReferenceBase::ToString() const
return _asset ? _asset->ToString() : (_id.IsValid() ? _id.ToString() : TEXT("<null>"));
}
void SoftAssetReferenceBase::OnAssetChanged(Asset* asset, void* caller)
{
}
void SoftAssetReferenceBase::OnAssetLoaded(Asset* asset, void* caller)
{
}
void SoftAssetReferenceBase::OnAssetUnloaded(Asset* asset, void* caller)
{
if (_asset != asset)
return;
_asset->RemoveReference(this);
_asset = nullptr;
_id = Guid::Empty;
Changed();
}
void SoftAssetReferenceBase::OnSet(Asset* asset)
{
if (_asset == asset)
return;
if (_asset)
{
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset->RemoveReference();
}
_asset->RemoveReference(this);
_asset = asset;
_id = asset ? asset->GetID() : Guid::Empty;
if (asset)
{
asset->AddReference();
asset->OnUnloaded.Bind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
}
asset->AddReference(this);
Changed();
}
@@ -170,10 +201,7 @@ void SoftAssetReferenceBase::OnSet(const Guid& id)
if (_id == id)
return;
if (_asset)
{
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset->RemoveReference();
}
_asset->RemoveReference(this);
_asset = nullptr;
_id = id;
Changed();
@@ -184,21 +212,7 @@ void SoftAssetReferenceBase::OnResolve(const ScriptingTypeHandle& type)
ASSERT(!_asset);
_asset = ::LoadAsset(_id, type);
if (_asset)
{
_asset->OnUnloaded.Bind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset->AddReference();
}
}
void SoftAssetReferenceBase::OnUnloaded(Asset* asset)
{
if (_asset != asset)
return;
_asset->RemoveReference();
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset = nullptr;
_id = Guid::Empty;
Changed();
_asset->AddReference(this);
}
Asset::Asset(const SpawnParams& params, const AssetInfo* info)
@@ -216,6 +230,41 @@ int32 Asset::GetReferencesCount() const
return (int32)Platform::AtomicRead(const_cast<int64 volatile*>(&_refCount));
}
void Asset::AddReference()
{
Platform::InterlockedIncrement(&_refCount);
}
void Asset::AddReference(IAssetReference* ref, bool week)
{
if (!week)
Platform::InterlockedIncrement(&_refCount);
if (ref)
{
//PROFILE_MEM(EngineDelegate); // Include references tracking memory within Delegate memory
Locker.Lock();
_references.Add(ref);
Locker.Unlock();
}
}
void Asset::RemoveReference()
{
Platform::InterlockedDecrement(&_refCount);
}
void Asset::RemoveReference(IAssetReference* ref, bool week)
{
if (ref)
{
Locker.Lock();
_references.Remove(ref);
Locker.Unlock();
}
if (!week)
Platform::InterlockedDecrement(&_refCount);
}
String Asset::ToString() const
{
return String::Format(TEXT("{0}, {1}, {2}"), GetTypeName(), GetID(), GetPath());
@@ -354,6 +403,7 @@ uint64 Asset::GetMemoryUsage() const
if (Platform::AtomicRead(&_loadingTask))
result += sizeof(ContentLoadTask);
result += (OnLoaded.Capacity() + OnReloading.Capacity() + OnUnloaded.Capacity()) * sizeof(EventType::FunctionType);
result += _references.Capacity() * sizeof(HashSet<IAssetReference*>::Bucket);
Locker.Unlock();
return result;
}
@@ -628,6 +678,8 @@ void Asset::onLoaded_MainThread()
ASSERT(IsInMainThread());
// Send event
for (const auto& e : _references)
e.Item->OnAssetLoaded(this, this);
OnLoaded(this);
}
@@ -641,6 +693,8 @@ void Asset::onUnload_MainThread()
CancelStreaming();
// Send event
for (const auto& e : _references)
e.Item->OnAssetUnloaded(this, this);
OnUnloaded(this);
}

View File

@@ -18,6 +18,18 @@
public: \
explicit type(const SpawnParams& params, const AssetInfo* info)
// Utility interface for objects that reference asset and want to get notified about asset reference changes.
class FLAXENGINE_API IAssetReference
{
public:
// Asset reference got changed.
virtual void OnAssetChanged(Asset* asset, void* caller) = 0;
// Asset got loaded.
virtual void OnAssetLoaded(Asset* asset, void* caller) = 0;
// Asset gets unloaded.
virtual void OnAssetUnloaded(Asset* asset, void* caller) = 0;
};
/// <summary>
/// Asset objects base class.
/// </summary>
@@ -48,6 +60,8 @@ protected:
int8 _deleteFileOnUnload : 1; // Indicates that asset source file should be removed on asset unload
int8 _isVirtual : 1; // Indicates that asset is pure virtual (generated or temporary, has no storage so won't be saved)
HashSet<IAssetReference*> _references;
public:
/// <summary>
/// Initializes a new instance of the <see cref="Asset"/> class.
@@ -88,18 +102,22 @@ public:
/// <summary>
/// Adds reference to that asset.
/// </summary>
FORCE_INLINE void AddReference()
{
Platform::InterlockedIncrement(&_refCount);
}
void AddReference();
/// <summary>
/// Adds reference to that asset.
/// </summary>
void AddReference(IAssetReference* ref, bool week = false);
/// <summary>
/// Removes reference from that asset.
/// </summary>
FORCE_INLINE void RemoveReference()
{
Platform::InterlockedDecrement(&_refCount);
}
void RemoveReference();
/// <summary>
/// Removes reference from that asset.
/// </summary>
void RemoveReference(IAssetReference* ref, bool week = false);
public:
/// <summary>

View File

@@ -7,10 +7,11 @@
/// <summary>
/// Asset reference utility. Keeps reference to the linked asset object and handles load/unload events.
/// </summary>
class FLAXENGINE_API AssetReferenceBase
class FLAXENGINE_API AssetReferenceBase : public IAssetReference
{
protected:
Asset* _asset = nullptr;
IAssetReference* _owner = nullptr;
public:
/// <summary>
@@ -36,6 +37,12 @@ public:
/// </summary>
AssetReferenceBase() = default;
/// <summary>
/// Initializes a new instance of the <see cref="AssetReferenceBase"/> class.
/// </summary>
/// <param name="owner">The reference owner to keep notified about asset changes.</param>
AssetReferenceBase(IAssetReference* owner);
/// <summary>
/// Finalizes an instance of the <see cref="AssetReferenceBase"/> class.
/// </summary>
@@ -63,10 +70,14 @@ public:
/// </summary>
String ToString() const;
public:
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
protected:
void OnSet(Asset* asset);
void OnLoaded(Asset* asset);
void OnUnloaded(Asset* asset);
};
/// <summary>
@@ -87,6 +98,13 @@ public:
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AssetReference"/> class.
/// </summary>
explicit AssetReference(decltype(__nullptr))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AssetReference"/> class.
/// </summary>
@@ -96,6 +114,15 @@ public:
OnSet((Asset*)asset);
}
/// <summary>
/// Initializes a new instance of the <see cref="AssetReference"/> class.
/// </summary>
/// <param name="owner">The reference owner to keep notified about asset changes.</param>
explicit AssetReference(IAssetReference* owner)
: AssetReferenceBase(owner)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AssetReference"/> class.
/// </summary>

View File

@@ -19,6 +19,15 @@ API_STRUCT(NoDefault, Template, MarshalAs=JsonAsset*) struct JsonAssetReference
OnSet(asset);
}
explicit JsonAssetReference(decltype(__nullptr))
{
}
explicit JsonAssetReference(IAssetReference* owner)
: AssetReference<JsonAsset>(owner)
{
}
/// <summary>
/// Gets the deserialized native object instance of the given type. Returns null if asset is not loaded or loaded object has different type.
/// </summary>

View File

@@ -7,7 +7,7 @@
/// <summary>
/// The asset soft reference. Asset gets referenced (loaded) on actual use (ID reference is resolving it).
/// </summary>
class FLAXENGINE_API SoftAssetReferenceBase
class FLAXENGINE_API SoftAssetReferenceBase : public IAssetReference
{
protected:
Asset* _asset = nullptr;
@@ -46,11 +46,16 @@ public:
/// </summary>
String ToString() const;
public:
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
protected:
void OnSet(Asset* asset);
void OnSet(const Guid& id);
void OnResolve(const ScriptingTypeHandle& type);
void OnUnloaded(Asset* asset);
};
/// <summary>
@@ -71,6 +76,13 @@ public:
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
/// </summary>
explicit SoftAssetReference(decltype(__nullptr))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
/// </summary>

View File

@@ -7,7 +7,7 @@
/// <summary>
/// Asset reference utility that doesn't add reference to that asset. Handles asset unload event.
/// </summary>
API_CLASS(InBuild) class WeakAssetReferenceBase
API_CLASS(InBuild) class WeakAssetReferenceBase : public IAssetReference
{
public:
typedef Delegate<> EventType;
@@ -56,9 +56,14 @@ public:
/// </summary>
String ToString() const;
public:
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
protected:
void OnSet(Asset* asset);
void OnUnloaded(Asset* asset);
};
/// <summary>
@@ -72,7 +77,13 @@ public:
/// Initializes a new instance of the <see cref="WeakAssetReference"/> class.
/// </summary>
WeakAssetReference()
: WeakAssetReferenceBase()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WeakAssetReference"/> class.
/// </summary>
explicit WeakAssetReference(decltype(__nullptr))
{
}
@@ -81,7 +92,6 @@ public:
/// </summary>
/// <param name="asset">The asset to set.</param>
WeakAssetReference(T* asset)
: WeakAssetReferenceBase()
{
OnSet(asset);
}

View File

@@ -27,16 +27,13 @@ AnimatedModel::AnimatedModel(const SpawnParams& params)
, _counter(0)
, _lastMinDstSqr(MAX_Real)
, _lastUpdateFrame(0)
, SkinnedModel(this)
, AnimationGraph(this)
{
_drawCategory = SceneRendering::SceneDrawAsync;
GraphInstance.Object = this;
_box = BoundingBox(Vector3::Zero);
_sphere = BoundingSphere(Vector3::Zero, 0.0f);
SkinnedModel.Changed.Bind<AnimatedModel, &AnimatedModel::OnSkinnedModelChanged>(this);
SkinnedModel.Loaded.Bind<AnimatedModel, &AnimatedModel::OnSkinnedModelLoaded>(this);
AnimationGraph.Changed.Bind<AnimatedModel, &AnimatedModel::OnGraphChanged>(this);
AnimationGraph.Loaded.Bind<AnimatedModel, &AnimatedModel::OnGraphLoaded>(this);
}
AnimatedModel::~AnimatedModel()
@@ -889,6 +886,26 @@ void AnimatedModel::OnGraphLoaded()
SyncParameters();
}
void AnimatedModel::OnAssetChanged(Asset* asset, void* caller)
{
if (caller == &SkinnedModel)
OnSkinnedModelChanged();
else if (caller == &AnimationGraph)
OnGraphChanged();
}
void AnimatedModel::OnAssetLoaded(Asset* asset, void* caller)
{
if (caller == &SkinnedModel)
OnSkinnedModelLoaded();
else if (caller == &AnimationGraph)
OnGraphLoaded();
}
void AnimatedModel::OnAssetUnloaded(Asset* asset, void* caller)
{
}
bool AnimatedModel::HasContentLoaded() const
{
return (SkinnedModel == nullptr || SkinnedModel->IsLoaded()) && Entries.HasContentLoaded();

View File

@@ -13,7 +13,7 @@
/// Performs an animation and renders a skinned model.
/// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/Animation/Animated Model\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API AnimatedModel : public ModelInstanceActor
class FLAXENGINE_API AnimatedModel : public ModelInstanceActor, IAssetReference
{
DECLARE_SCENE_OBJECT(AnimatedModel);
friend class AnimationsSystem;
@@ -422,6 +422,11 @@ private:
void OnGraphChanged();
void OnGraphLoaded();
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
public:
// [ModelInstanceActor]
bool HasContentLoaded() const override;

View File

@@ -30,7 +30,6 @@ GPU_CB_STRUCT(Data {
Sky::Sky(const SpawnParams& params)
: Actor(params)
, _shader(nullptr)
, _psSky(nullptr)
, _psFog(nullptr)
{

View File

@@ -29,10 +29,9 @@ StaticModel::StaticModel(const SpawnParams& params)
, _vertexColorsDirty(false)
, _vertexColorsCount(0)
, _sortOrder(0)
, Model(this)
{
_drawCategory = SceneRendering::SceneDrawAsync;
Model.Changed.Bind<StaticModel, &StaticModel::OnModelChanged>(this);
Model.Loaded.Bind<StaticModel, &StaticModel::OnModelLoaded>(this);
}
StaticModel::~StaticModel()
@@ -224,7 +223,7 @@ void StaticModel::RemoveVertexColors()
_vertexColorsDirty = false;
}
void StaticModel::OnModelChanged()
void StaticModel::OnAssetChanged(Asset* asset, void* caller)
{
if (_residencyChangedModel)
{
@@ -241,7 +240,7 @@ void StaticModel::OnModelChanged()
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey);
}
void StaticModel::OnModelLoaded()
void StaticModel::OnAssetLoaded(Asset* asset, void* caller)
{
Entries.SetupIfInvalid(Model);
UpdateBounds();
@@ -316,6 +315,10 @@ void StaticModel::FlushVertexColors()
RenderContext::GPULocker.Unlock();
}
void StaticModel::OnAssetUnloaded(Asset* asset, void* caller)
{
}
bool StaticModel::HasContentLoaded() const
{
return (Model == nullptr || Model->IsLoaded()) && Entries.HasContentLoaded();

View File

@@ -11,7 +11,7 @@
/// Renders model on the screen.
/// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/Model\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API StaticModel : public ModelInstanceActor
class FLAXENGINE_API StaticModel : public ModelInstanceActor, IAssetReference
{
DECLARE_SCENE_OBJECT(StaticModel);
private:
@@ -154,11 +154,14 @@ public:
API_FUNCTION() void RemoveVertexColors();
private:
void OnModelChanged();
void OnModelLoaded();
void OnModelResidencyChanged();
void FlushVertexColors();
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
public:
// [ModelInstanceActor]
bool HasContentLoaded() const override;

View File

@@ -17,8 +17,8 @@
NavMesh::NavMesh(const SpawnParams& params)
: Actor(params)
, IsDataDirty(false)
, DataAsset(this)
{
DataAsset.Loaded.Bind<NavMesh, &NavMesh::OnDataAssetLoaded>(this);
}
void NavMesh::SaveNavMesh()
@@ -100,7 +100,11 @@ void NavMesh::RemoveTiles()
navMesh->RemoveTiles(this);
}
void NavMesh::OnDataAssetLoaded()
void NavMesh::OnAssetChanged(Asset* asset, void* caller)
{
}
void NavMesh::OnAssetLoaded(Asset* asset, void* caller)
{
// Skip if already has data (prevent reloading navmesh on saving)
if (Data.Tiles.HasItems())
@@ -126,6 +130,10 @@ void NavMesh::OnDataAssetLoaded()
}
}
void NavMesh::OnAssetUnloaded(Asset* asset, void* caller)
{
}
void NavMesh::Serialize(SerializeStream& stream, const void* otherObj)
{
// Base

View File

@@ -15,7 +15,7 @@ class NavMeshRuntime;
/// The navigation mesh actor that holds a navigation data for a scene.
/// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/Navigation/Nav Mesh\")")
class FLAXENGINE_API NavMesh : public Actor
class FLAXENGINE_API NavMesh : public Actor, IAssetReference
{
DECLARE_SCENE_OBJECT(NavMesh);
public:
@@ -67,7 +67,11 @@ public:
private:
void AddTiles();
void RemoveTiles();
void OnDataAssetLoaded();
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
private:
bool _navMeshActive = false;

View File

@@ -16,12 +16,10 @@ ParticleEffect::ParticleEffect(const SpawnParams& params)
: Actor(params)
, _lastUpdateFrame(0)
, _lastMinDstSqr(MAX_Real)
, ParticleSystem(this)
{
_box = BoundingBox(_transform.Translation);
BoundingSphere::FromBox(_box, _sphere);
ParticleSystem.Changed.Bind<ParticleEffect, &ParticleEffect::OnParticleSystemModified>(this);
ParticleSystem.Loaded.Bind<ParticleEffect, &ParticleEffect::OnParticleSystemLoaded>(this);
}
void ParticleEffectParameter::Init(ParticleEffect* effect, int32 emitterIndex, int32 paramIndex)
@@ -542,18 +540,22 @@ void ParticleEffect::ApplyModifiedParameters()
}
}
void ParticleEffect::OnParticleSystemModified()
void ParticleEffect::OnAssetChanged(Asset* asset, void* caller)
{
Instance.ClearState();
_parameters.Resize(0);
_parametersVersion = 0;
}
void ParticleEffect::OnParticleSystemLoaded()
void ParticleEffect::OnAssetLoaded(Asset* asset, void* caller)
{
ApplyModifiedParameters();
}
void ParticleEffect::OnAssetUnloaded(Asset* asset, void* caller)
{
}
bool ParticleEffect::HasContentLoaded() const
{
if (ParticleSystem == nullptr)

View File

@@ -118,7 +118,7 @@ public:
/// The particle system instance that plays the particles simulation in the game.
/// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/Visuals/Particle Effect\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API ParticleEffect : public Actor
class FLAXENGINE_API ParticleEffect : public Actor, IAssetReference
{
DECLARE_SCENE_OBJECT(ParticleEffect);
public:
@@ -388,6 +388,11 @@ private:
void OnParticleSystemModified();
void OnParticleSystemLoaded();
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
public:
// [Actor]
bool HasContentLoaded() const override;

View File

@@ -20,10 +20,8 @@ Collider::Collider(const SpawnParams& params)
, _staticActor(nullptr)
, _cachedScale(1.0f)
, _contactOffset(2.0f)
, Material(this)
{
Material.Loaded.Bind<Collider, &Collider::OnMaterialChanged>(this);
Material.Unload.Bind<Collider, &Collider::OnMaterialChanged>(this);
Material.Changed.Bind<Collider, &Collider::OnMaterialChanged>(this);
}
void* Collider::GetPhysicsShape() const
@@ -294,13 +292,6 @@ void Collider::DrawPhysicsDebug(RenderView& view)
#endif
void Collider::OnMaterialChanged()
{
// Update the shape material
if (_shape)
PhysicsBackend::SetShapeMaterial(_shape, Material);
}
void Collider::BeginPlay(SceneBeginData* data)
{
// Check if has no shape created (it means no rigidbody requested it but also collider may be spawned at runtime)
@@ -466,3 +457,20 @@ void Collider::OnPhysicsSceneChanged(PhysicsScene* previous)
PhysicsBackend::AddSceneActor(scene, _staticActor);
}
}
void Collider::OnAssetChanged(Asset* asset, void* caller)
{
// Update the shape material
if (_shape && caller == &Material)
PhysicsBackend::SetShapeMaterial(_shape, Material);
}
void Collider::OnAssetLoaded(Asset* asset, void* caller)
{
Collider::OnAssetChanged(asset, caller);
}
void Collider::OnAssetUnloaded(Asset* asset, void* caller)
{
Collider::OnAssetChanged(asset, caller);
}

View File

@@ -15,7 +15,7 @@ class RigidBody;
/// </summary>
/// <seealso cref="Actor" />
/// <seealso cref="PhysicsColliderActor" />
API_CLASS(Abstract) class FLAXENGINE_API Collider : public PhysicsColliderActor
API_CLASS(Abstract) class FLAXENGINE_API Collider : public PhysicsColliderActor, protected IAssetReference
{
API_AUTO_SERIALIZATION();
DECLARE_SCENE_OBJECT_ABSTRACT(Collider);
@@ -154,9 +154,6 @@ protected:
/// </summary>
void RemoveStaticActor();
private:
void OnMaterialChanged();
public:
// [PhysicsColliderActor]
RigidBody* GetAttachedRigidBody() const override;
@@ -181,4 +178,9 @@ protected:
void OnLayerChanged() override;
void OnStaticFlagsChanged() override;
void OnPhysicsSceneChanged(PhysicsScene* previous) override;
// [IAssetReference]
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
void OnAssetUnloaded(Asset* asset, void* caller) override;
};

View File

@@ -11,9 +11,8 @@
MeshCollider::MeshCollider(const SpawnParams& params)
: Collider(params)
, CollisionData(this)
{
CollisionData.Changed.Bind<MeshCollider, &MeshCollider::OnCollisionDataChanged>(this);
CollisionData.Loaded.Bind<MeshCollider, &MeshCollider::OnCollisionDataLoaded>(this);
}
void MeshCollider::OnCollisionDataChanged()
@@ -33,8 +32,9 @@ void MeshCollider::OnCollisionDataChanged()
void MeshCollider::OnCollisionDataLoaded()
{
UpdateGeometry();
UpdateBounds();
// Not needed as OnCollisionDataChanged waits for it to be loaded
//UpdateGeometry();
//UpdateBounds();
}
bool MeshCollider::CanAttach(RigidBody* rigidBody) const
@@ -152,3 +152,19 @@ void MeshCollider::GetGeometry(CollisionShape& collision)
else
collision.SetSphere(minSize);
}
void MeshCollider::OnAssetChanged(Asset* asset, void* caller)
{
Collider::OnAssetChanged(asset, caller);
if (caller == &CollisionData)
OnCollisionDataChanged();
}
void MeshCollider::OnAssetLoaded(Asset* asset, void* caller)
{
Collider::OnAssetLoaded(asset, caller);
if (caller == &CollisionData)
OnCollisionDataLoaded();
}

View File

@@ -42,4 +42,6 @@ protected:
#endif
void UpdateBounds() override;
void GetGeometry(CollisionShape& collision) override;
void OnAssetChanged(Asset* asset, void* caller) override;
void OnAssetLoaded(Asset* asset, void* caller) override;
};

View File

@@ -39,7 +39,6 @@ GPU_CB_STRUCT(Data {
ColorGradingPass::ColorGradingPass()
: _useVolumeTexture(false)
, _lutFormat()
, _shader(nullptr)
{
}

View File

@@ -14,8 +14,7 @@
#include "Engine/Graphics/Shaders/GPUShader.h"
ForwardPass::ForwardPass()
: _shader(nullptr)
, _psApplyDistortion(nullptr)
: _psApplyDistortion(nullptr)
{
}

View File

@@ -19,7 +19,6 @@ int32 VolumetricFogGridInjectionGroupSize = 4;
int32 VolumetricFogIntegrationGroupSize = 8;
VolumetricFogPass::VolumetricFogPass()
: _shader(nullptr)
{
}