// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Level/Actor.h" #include "Engine/Content/AssetReference.h" #include "Engine/Scripting/ScriptingObjectReference.h" #include "Engine/Graphics/RenderTask.h" #include "ParticleSystem.h" #include "ParticlesSimulation.h" /// /// Particle system parameter. /// API_CLASS(NoSpawn) class ParticleEffectParameter : public ScriptingObject { DECLARE_SCRIPTING_TYPE_NO_SPAWN(ParticleEffectParameter); friend ParticleEffect; private: ParticleEffect* _effect = nullptr; int32 _emitterIndex; int32 _paramIndex; void Init(ParticleEffect* effect, int32 emitterIndex, int32 paramIndex); public: /// /// Initializes a new instance of the class. /// ParticleEffectParameter() : ScriptingObject(SpawnParams(Guid::New(), TypeInitializer)) { } ParticleEffectParameter(const ParticleEffectParameter& other) : ParticleEffectParameter() { #if !BUILD_RELEASE CRASH; // Not used #endif } ParticleEffectParameter& operator=(const ParticleEffectParameter& other) { #if !BUILD_RELEASE CRASH; // Not used #endif return *this; } /// /// Returns true if parameter object handle is valid. /// bool IsValid() const; /// /// Gets the index of the emitter (not the emitter track but the emitter). /// API_PROPERTY() int32 GetEmitterIndex() const { return _emitterIndex; } /// /// Gets the emitter that this parameter belongs to. /// API_PROPERTY() ParticleEmitter* GetEmitter() const; /// /// Gets the parameter index (in the emitter parameters list). /// API_PROPERTY() int32 GetParamIndex() const { return _paramIndex; } /// /// Gets the parameter type. /// API_PROPERTY() VariantType GetParamType() const; /// /// Gets the parameter unique ID. /// API_PROPERTY() Guid GetParamIdentifier() const; /// /// Gets the emitter track name. /// API_PROPERTY() const String& GetTrackName() const; /// /// Gets the parameter name. /// API_PROPERTY() const String& GetName() const; /// /// Gets the parameter flag that indicates whenever it's exposed to public. /// API_PROPERTY() bool GetIsPublic() const; /// /// Gets the default value of the parameter (set in particle system asset). /// /// The default value. API_PROPERTY() Variant GetDefaultValue() const; /// /// Gets the default value of the parameter (set in particle emitter asset). /// /// The default value. API_PROPERTY() Variant GetDefaultEmitterValue() const; /// /// Gets the value of the parameter. /// /// The value. API_PROPERTY() Variant GetValue() const; /// /// Sets the value of the parameter. /// /// The value. API_PROPERTY() void SetValue(const Variant& value) const; /// /// Gets the particle emitter parameter from the asset (the parameter instanced by this object). /// /// The particle emitter parameter overriden by this object. API_PROPERTY() GraphParameter* GetEmitterParameter() const; }; /// /// The particle system instance that plays the particles simulation in the game. /// API_CLASS() class FLAXENGINE_API ParticleEffect : public Actor { DECLARE_SCENE_OBJECT(ParticleEffect); public: /// /// The particles simulation update modes. /// API_ENUM() enum class SimulationUpdateMode { /// /// Use realtime simulation updates. Updates particles during every game logic update. /// Realtime = 0, /// /// Use fixed timestep delta time to update particles simulation with a custom frequency. /// FixedTimestep = 1, }; /// /// The particle parameter override data. /// API_STRUCT() struct ParameterOverride { DECLARE_SCRIPTING_TYPE_NO_SPAWN(ParameterOverride); /// /// The name of the track that has overriden parameter. /// API_FIELD() String Track; /// /// The overriden parameter id. /// API_FIELD() Guid Id; /// /// The overriden value. /// API_FIELD() Variant Value; }; private: uint64 _lastUpdateFrame; Real _lastMinDstSqr; int32 _sceneRenderingKey = -1; uint32 _parametersVersion = 0; // Version number for _parameters to be in sync with Instance.ParametersVersion Array _parameters; // Cached for scripting API Array _parametersOverrides; // Cached parameter modifications to be applied to the parameters public: /// /// The particle system to play. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(null), EditorOrder(0)") AssetReference ParticleSystem; /// /// The instance data of the particle system. /// ParticleSystemInstance Instance; /// /// The custom render task used as a view information source (effect will use its render buffers and rendering resolution information for particles simulation). /// API_FIELD(Attributes="NoSerialize, HideInEditor") ScriptingObjectReference CustomViewRenderTask; public: /// /// The particles simulation update mode. Defines how to update particles emitter. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(SimulationUpdateMode.Realtime), EditorOrder(10)") SimulationUpdateMode UpdateMode = SimulationUpdateMode::Realtime; /// /// The fixed timestep for simulation updates. Used only if UpdateMode is set to FixedTimestep. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(1.0f / 60.0f), EditorOrder(20), VisibleIf(nameof(IsFixedTimestep))") float FixedTimestep = 1.0f / 60.0f; /// /// The particles simulation speed factor. Scales the particle system update delta time. Can be used to speed up or slow down the particles. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(1.0f), EditorOrder(30)") float SimulationSpeed = 1.0f; /// /// Determines whether the particle effect should take into account the global game time scale for simulation updates. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(true), EditorOrder(40)") bool UseTimeScale = true; /// /// Determines whether the particle effect should loop when it finishes playing. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(true), EditorOrder(50)") bool IsLooping = true; /// /// If true, the particle simulation will be updated even when an actor cannot be seen by any camera. Otherwise, the simulation will stop running when the actor is off-screen. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), DefaultValue(true), EditorOrder(60)") bool UpdateWhenOffscreen = true; /// /// The draw passes to use for rendering this object. /// API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), EditorOrder(75), DefaultValue(DrawPass.Default)") DrawPass DrawModes = DrawPass::Default; public: /// /// Gets the effect parameters collection. Those parameters are instanced from the that contains a linear list of emitters and every emitter has a list of own parameters. /// API_PROPERTY() const Array& GetParameters(); /// /// Gets the effect parameters collection version number. It can be used to track parameters changes that occur when particle system or one of the emitters gets reloaded/edited. /// API_PROPERTY() uint32 GetParametersVersion() const; /// /// Gets the particle parameter. /// /// The emitter track name (in particle system asset). /// The emitter parameter name (in particle emitter asset). /// The effect parameter or null if failed to find. API_FUNCTION() ParticleEffectParameter* GetParameter(const StringView& emitterTrackName, const StringView& paramName); /// /// Gets the particle parameter. /// /// The emitter track name (in particle system asset). /// The emitter parameter ID (in particle emitter asset). /// The effect parameter or null if failed to find. API_FUNCTION() ParticleEffectParameter* GetParameter(const StringView& emitterTrackName, const Guid& paramId); /// /// Gets the particle parameter value. /// /// The emitter track name (in particle system asset). /// The emitter parameter name (in particle emitter asset). /// The value. API_FUNCTION() Variant GetParameterValue(const StringView& emitterTrackName, const StringView& paramName); /// /// Set the particle parameter value. /// /// The emitter track name (in particle system asset). /// The emitter parameter name (in particle emitter asset). /// The value to set. API_FUNCTION() void SetParameterValue(const StringView& emitterTrackName, const StringView& paramName, const Variant& value); /// /// Resets the particle system parameters to the default values from asset. /// API_FUNCTION() void ResetParameters(); public: /// /// Gets the current time position of the particle system timeline animation playback (in seconds). /// API_PROPERTY(Attributes="NoSerialize, HideInEditor") float GetTime() const; /// /// Sets the current time position of the particle system timeline animation playback (in seconds). /// API_PROPERTY() void SetTime(float time); /// /// Gets the last game time when particle system was updated. Value -1 indicates no previous updates. /// API_PROPERTY(Attributes="NoSerialize, HideInEditor") float GetLastUpdateTime() const; /// /// Sets the last game time when particle system was updated. Value -1 indicates no previous updates. /// API_PROPERTY() void SetLastUpdateTime(float time); /// /// Gets the particles count (total). GPU particles count is read with one frame delay (due to GPU execution). /// API_PROPERTY() int32 GetParticlesCount() const; /// /// Resets the particles simulation state (clears the instance state data but preserves the instance parameters values). /// API_FUNCTION() void ResetSimulation(); /// /// Performs the full particles simulation update (postponed for the next particle manager update). /// API_FUNCTION() void UpdateSimulation(); /// /// Updates the actor bounds. /// void UpdateBounds(); /// /// Synchronizes this instance data with the particle system and all emitters data. /// void Sync(); /// /// Gets the render task to use for particles simulation (eg. depth buffer collisions or view information). /// SceneRenderTask* GetRenderTask() const; #if USE_EDITOR protected: // Exposed parameters overrides for Editor Undo. API_PROPERTY(Attributes="HideInEditor, Serialize") Array GetParametersOverrides(); API_PROPERTY() void SetParametersOverrides(const Array& value); #endif private: void Update(); #if USE_EDITOR void UpdateExecuteInEditor(); #endif void CacheModifiedParameters(); void ApplyModifiedParameters(); void OnParticleSystemModified(); void OnParticleSystemLoaded(); public: // [Actor] bool HasContentLoaded() const override; void Draw(RenderContext& renderContext) override; #if USE_EDITOR void OnDebugDrawSelected() override; #endif void OnLayerChanged() override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; #if USE_EDITOR BoundingBox GetEditorBox() const override { const Vector3 size(50); return BoundingBox(_transform.Translation - size, _transform.Translation + size); } #endif protected: // [Actor] void EndPlay() override; void OnEnable() override; void OnDisable() override; void OnActiveInTreeChanged() override; void OnTransformChanged() override; };