// 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 };