// Copyright (c) Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Content/BinaryAsset.h"
#include "Engine/Core/Math/BoundingBox.h"
#include "Engine/Graphics/Shaders/Cache/ShaderAssetBase.h"
#include "Graph/CPU/ParticleEmitterGraph.CPU.h"
#if COMPILE_WITH_GPU_PARTICLES
#include "Graph/GPU/GPUParticles.h"
#endif
class Actor;
class ParticleEffect;
class ParticleEmitterInstance;
///
/// Binary asset that contains a particle emitter definition graph for running particles simulation on CPU and GPU.
///
API_CLASS(NoSpawn) class FLAXENGINE_API ParticleEmitter : public ShaderAssetTypeBase
{
DECLARE_BINARY_ASSET_HEADER(ParticleEmitter, ShadersSerializedVersion);
public:
///
/// The loaded particle graph.
///
ParticleEmitterGraphCPU Graph;
///
/// The CPU graph executor runtime.
///
ParticleEmitterGraphCPUExecutor GraphExecutorCPU;
///
/// The particle system capacity (the maximum amount of particles to simulate at once).
///
int32 Capacity;
///
/// The particles simulation execution mode.
///
ParticlesSimulationMode SimulationMode;
///
/// The particles simulation space.
///
ParticlesSimulationSpace SimulationSpace;
///
/// True if enable pooling emitter instance data, otherwise immediately dispose. Pooling can improve performance and reduce memory usage.
///
bool EnablePooling;
///
/// True if use automatic bounds.
///
bool UseAutoBounds;
///
/// True if emitter uses lights rendering, otherwise false.
///
bool IsUsingLights;
///
/// The custom bounds to use for the particles. Set to zero to use automatic bounds (valid only for CPU particles).
///
BoundingBox CustomBounds;
#if COMPILE_WITH_GPU_PARTICLES
///
/// The GPU particle simulation handler.
///
GPUParticles GPU;
#endif
public:
///
/// Tries to load surface graph from the asset.
///
/// True if create default surface if missing.
/// The output surface data, or empty if failed to load.
API_FUNCTION() BytesContainer LoadSurface(bool createDefaultIfMissing);
#if USE_EDITOR
///
/// Updates surface (saves new one, discard cached data, reloads asset).
///
/// The surface graph data.
/// True if cannot save it, otherwise false.
API_FUNCTION() bool SaveSurface(const BytesContainer& data);
#endif
public:
///
/// Spawns the particles at the given location.
///
/// The spawn position.
/// The effect playback duration (in seconds).
/// If set to true effect will be auto-destroyed after duration.
/// The spawned effect.
API_FUNCTION() ParticleEffect* Spawn(const Vector3& position, float duration = MAX_float, bool autoDestroy = false)
{
return Spawn(nullptr, Transform(position), duration, autoDestroy);
}
///
/// Spawns the particles at the given location.
///
/// The spawn position.
/// The spawn rotation.
/// The effect playback duration (in seconds).
/// If set to true effect will be auto-destroyed after duration.
/// The spawned effect.
API_FUNCTION() ParticleEffect* Spawn(const Vector3& position, const Quaternion& rotation, float duration = MAX_float, bool autoDestroy = false)
{
return Spawn(nullptr, Transform(position, rotation), duration, autoDestroy);
}
///
/// Spawns the particles at the given location.
///
/// The spawn transform.
/// The effect playback duration (in seconds).
/// If set to true effect will be auto-destroyed after duration.
/// The spawned effect.
API_FUNCTION() ParticleEffect* Spawn(const Transform& transform, float duration = MAX_float, bool autoDestroy = false)
{
return Spawn(nullptr, transform, duration, autoDestroy);
}
///
/// Spawns the particles at the given location.
///
/// The parent actor (can be null to link it to the first loaded scene).
/// The spawn position.
/// The effect playback duration (in seconds).
/// If set to true effect will be auto-destroyed after duration.
/// The spawned effect.
API_FUNCTION() ParticleEffect* Spawn(Actor* parent, const Vector3& position, float duration = MAX_float, bool autoDestroy = false)
{
return Spawn(parent, Transform(position), duration, autoDestroy);
}
///
/// Spawns the particles at the given location.
///
/// The parent actor (can be null to link it to the first loaded scene).
/// The spawn position.
/// The spawn rotation.
/// The effect playback duration (in seconds).
/// If set to true effect will be auto-destroyed after duration.
/// The spawned effect.
API_FUNCTION() ParticleEffect* Spawn(Actor* parent, const Vector3& position, const Quaternion& rotation, float duration = MAX_float, bool autoDestroy = false)
{
return Spawn(parent, Transform(position, rotation), duration, autoDestroy);
}
///
/// Spawns the particles at the given location.
///
/// The parent actor (can be null to link it to the first loaded scene).
/// The spawn transform.
/// The effect playback duration (in seconds).
/// If set to true effect will be auto-destroyed after duration.
/// The spawned effect.
API_FUNCTION() ParticleEffect* Spawn(Actor* parent, const Transform& transform, float duration = MAX_float, bool autoDestroy = false);
private:
void WaitForAsset(Asset* asset);
public:
// [BinaryAsset]
#if USE_EDITOR
void GetReferences(Array& assets, Array& files) const override;
bool Save(const StringView& path = StringView::Empty) override;
API_STRUCT(Internal) struct Attribute
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Attribute);
API_FIELD() PixelFormat Format;
API_FIELD() String Name;
};
private:
API_PROPERTY(Internal) bool HasShaderCode() const;
API_PROPERTY(Internal) Array GetLayout() const;
#endif
protected:
// [ParticleEmitterBase]
LoadResult load() override;
void unload(bool isReloading) override;
AssetChunksFlag getChunksToPreload() const override;
#if USE_EDITOR
void OnDependencyModified(BinaryAsset* asset) override;
void InitCompilationOptions(ShaderCompilationOptions& options) override;
#endif
};