From 070f01bf67453b8f53151e08f63e4d0ce0d33dda Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 14 Mar 2023 10:55:53 +0800 Subject: [PATCH] Particles WIP --- Assets/Scenes/Scene2.shade | 25 ++++-- Assets/Shaders/ParticleEmit_CS.glsl | 16 +++- Assets/Shaders/ParticleEmit_CS.shshaderb | Bin 7197 -> 7685 bytes .../Inspector/SHEditorComponentView.hpp | 42 ++++++++++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 +- .../Particles/SHParticleEmitterComponent.cpp | 60 ++++++++++++++ .../Particles/SHParticleEmitterComponent.h | 29 +++++-- .../Particles/SHParticleSubSystem.cpp | 23 ++++-- .../src/Serialization/SHSerialization.cpp | 1 + .../src/Serialization/SHYAMLConverters.h | 75 ++++++++++++++++++ 10 files changed, 253 insertions(+), 20 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 704d2028..96d2e525 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -22,18 +22,18 @@ Scripts: ~ - EID: 1 Name: Raccoon - IsActive: true + IsActive: false NumberOfChildren: 1 Components: Transform Component: Translate: {x: 0, y: 0.201105013, z: 0} Rotate: {x: 0.00523597933, y: -2.96353412, z: -6.40293041e-10} Scale: {x: 1.00000191, y: 1, z: 1.00000191} - IsActive: true + IsActive: false Renderable Component: Mesh: 149697411 Material: 126974645 - IsActive: true + IsActive: false Scripts: ~ - EID: 3 Name: Bag @@ -87,18 +87,18 @@ Scripts: ~ - EID: 5 Name: Floor - IsActive: true + IsActive: false NumberOfChildren: 0 Components: Transform Component: Translate: {x: 0, y: 0.0810000002, z: 0} Rotate: {x: -1.57079625, y: 0, z: -0} Scale: {x: 50, y: 49.9999924, z: 49.9999924} - IsActive: true + IsActive: false Renderable Component: Mesh: 141771688 Material: 124370424 - IsActive: true + IsActive: false Scripts: ~ - EID: 6 Name: TrajectoryTest @@ -156,4 +156,17 @@ Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} IsActive: true + classSHADE::SHParticleEmitterComponent: + Emission Count: 1 + Is Passive: false + Emission Interval: 3 + Min Life: 7 + Max Life: 20 + Angular Min: {x: 2.29999995, y: 1.70000005, z: 2.9000001} + Angular Max: {x: 0, y: 0, z: 0} + Minimum Velocity: {x: 2, y: 3, z: 4} + Maximum Velocity: {x: 0, y: 0, z: 0} + Minimum Size: 5 + Maximum Size: 10 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl index 33beaccc..f54a58fa 100644 --- a/Assets/Shaders/ParticleEmit_CS.glsl +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -6,6 +6,8 @@ struct EmitterParameters { vec4 angularMin; vec4 angularMax; + vec4 minVel; + vec4 maxVel; vec4 lifeAndSizeRange; // min life, max life, min size, max size }; @@ -109,6 +111,7 @@ void main() if (emitterInvocationIndex >= emitterPushConstant.emissionCount) return; +// Freecount will start at max particles. Here we subtract every time we emit. int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1; if (freelistIndex < 0) atomicAdd (freelist.freeCount, 1); @@ -124,9 +127,18 @@ void main() // emit particle from emitter position particle.position = vec4 (emitterPosition.xyz, 1.0f); - // randomize life value that ranges from minLife to maxLife - particle.life = map (rand(seed), -1.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y); + // Set its velocity + particle.velocity = emitterParams.data.minVel; + // randomize life value that ranges from minLife to maxLife + particle.life = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y); + + // Set size of particle + particle.scaleAndDecay.x = emitterParams.data.lifeAndSizeRange.z; + particle.scaleAndDecay.y = emitterParams.data.lifeAndSizeRange.z; + + particle.rotation = vec4 (5.0f); + particle.acceleration = vec4 (0.01f); inputParticles.data[index] = particle; } \ No newline at end of file diff --git a/Assets/Shaders/ParticleEmit_CS.shshaderb b/Assets/Shaders/ParticleEmit_CS.shshaderb index e0318886a5ac002a537ec1c652a1d9c162dc37f8..8e2eba23cc690b20ad995dc63d858c62bda47d8f 100644 GIT binary patch delta 2477 zcmZ9MOKcTY7{|}_zG?}r3UW2XTIkX)h>1xX3u#FWupr@KTsvu}i>5-=XRL6`RDuo-}&BW=DyqcR(G*& z@o8h9OhbFY7|%4BwWh&4Ti{zZy^nc`oi`0PVGZ|23dpRm+l z4*KHitO&cFT9|+ADRkCS9S;4lG^}NGI`{%lNkmtr>smf&K)m)>-~z1zk9AdYPXYgUw2^N5+R<(u0hE`l3pZuSXhuAe1o z2^(|6*(o;87h;`Q*UFM~#^L-yd=BRvX*^@zl;{vU0QKnHt6gfI+{^z=L7>)p$(a=A ze ze@6IRcwgX*mf>BB<(f|kj|Q1f97)5PCJugyh$PYn<2S zRe|Ib{6^rMIOd1DxNoIT^QAH|fo}^g@SJoU2%MFKcj=WN>3LzJK!Y?!LnOzKEpa&) z1h#ZiAP1Z{SA0&oZCdqhab9p&{E~DWxEhjO7D(o%BOx~YT*52TlUqpUyQ(wJUB2(6 zyL=H-lMo}0?w)VNPUG=8{CeX2$M~GDi+DI+5<`TNzX+2tKO%WYpeRi&NZu9nxkPsT zIPcZ!Dw4knIP=g9FXwLp0bCWu;P|$zuF#*- z336{Y97h-Qmvjp0tE|WTEu9#*2{?W(<{#xo%$_WHb rNd6}f45XO6$O^E~|5HMp95 zz5~hbyg%Uc$B*G(<;EAJN5e5^T)SS@Jp=9Si9X?o>fvV{j;G@2u)Gt}310_P51Wv= zE1mB&WbUoN_gCP_JWkg~N`n!TO`nKVtjo&J>h0-Irjk86L+%vW^oX}xAkWc6XHQ!) zbv(Bl6?Zlg3uM!OBC&EZge9HH_C$VvQ#2NsPVb9uD4)iu*{dA{8~AG0E^#W?xG5zl#0n(m%S<2xj27PdpISbYxHag|-Dcrp>6;Q`hQ_MAYvFNNsq)6lbyX|=wlq^2 zmu&YiBgaR+l=K}BSDDrBv~4b*POm90ayUFwrUr)qQ{%Zb`S4K#%t7$6|H`xBf@eKU ze%r$**$luk&7C|67PLWfZh`>xqGU)?C)6RmBv~}+bHyXA{CY$s^j0R# zH|ocHqkhac>c@Peems>qTk<#P?DQ&M)Aj|)E**eU;09d{S9M*oR)XKg-|#T;@W9x# zMLaewan0DYb4AjqCWfUSNG6P4>3|IG?udls6nrQl03v;ZE%A|T5tn(VWn123+3drc zk_I>EJ&^N>BqpIj8l#~}z7hf(by9}?FC-%#z9jupLVTm{iwE*r z!lU6(#I`DLxAYqcu`Fuwc-~50tG*jdF&qS1(wuBa0f{BOlTDF92^{d8#B$!thQq_M zoDZ_$Fl9Jk;@~)R_fZ0gr)x={WkcdgLjn_L3w@Cdhv#iM-(GetEmissionInterval(); }, [comp = component](float interval) {comp->SetEmissionInterval(interval); }); SHEditorWidgets::DragFloat("Min Life", [comp = component]() {return comp->GetMinLife(); }, [comp = component](float val) {comp->SetMinLife(val); }); SHEditorWidgets::DragFloat("Max Life", [comp = component]() {return comp->GetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); }); + SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); }); + SHEditorWidgets::DragFloat("Man Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); + + SHEditorWidgets::DragVec3("Angular Min", {"x", "y", "z"}, + [comp = component]() + { + return comp->GetAngularMin(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetAngularMin(val); + }); + + SHEditorWidgets::DragVec3("Angular Max", { "x", "y", "z" }, + [comp = component]() + { + return comp->GetAngularMax(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetAngularMax(val); + }); + + SHEditorWidgets::DragVec3("Min Vel", { "x", "y", "z" }, + [comp = component]() + { + return comp->GetMinVelocity(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetMinVelocity(val); + }); + + SHEditorWidgets::DragVec3("Max Vel", { "x", "y", "z" }, + [comp = component]() + { + return comp->GetMaxVelocity(); + }, + [comp = component](SHVec3 const& val) + { + comp->SetMaxVelocity(val); + }); SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index b34eb8de..62e3c455 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -361,7 +361,7 @@ namespace SHADE vfxSubpass->AddExteriorDrawCalls([=](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex); - //particleSubSystem->Render(cmdBuffer, renderer, frameIndex); + particleSubSystem->Render(cmdBuffer, renderer, frameIndex); }); /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp index 8a652381..d2c0e05a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -46,6 +46,36 @@ namespace SHADE cpuEmitterData.lifeAndSizeRange.y = val; } + void SHParticleEmitterComponent::SetAngularMin(SHVec3 const& min) noexcept + { + cpuEmitterData.angularMin = SHVec4 (min); + } + + void SHParticleEmitterComponent::SetAngularMax(SHVec3 const& max) noexcept + { + cpuEmitterData.angularMax = SHVec4(max); + } + + void SHParticleEmitterComponent::SetMinVelocity(SHVec3 const& vel) noexcept + { + cpuEmitterData.minVel = vel; + } + + void SHParticleEmitterComponent::SetMaxVelocity(SHVec3 const& vel) noexcept + { + cpuEmitterData.maxVel = vel; + } + + void SHParticleEmitterComponent::SetMinSize(float size) noexcept + { + cpuEmitterData.lifeAndSizeRange.z = size; + } + + void SHParticleEmitterComponent::SetMaxSize(float size) noexcept + { + cpuEmitterData.lifeAndSizeRange.w = size; + } + uint32_t SHParticleEmitterComponent::GetEmissionCount(void) const noexcept { return emissionCount; @@ -72,4 +102,34 @@ namespace SHADE } + SHVec3 SHParticleEmitterComponent::GetAngularMin(void) const noexcept + { + return SHVec3 (cpuEmitterData.angularMin.x, cpuEmitterData.angularMin.y, cpuEmitterData.angularMin.z); + } + + SHVec3 SHParticleEmitterComponent::GetMinVelocity(void) const noexcept + { + return SHVec3(cpuEmitterData.minVel.x, cpuEmitterData.minVel.y, cpuEmitterData.minVel.z); + } + + SHVec3 SHParticleEmitterComponent::GetMaxVelocity(void) const noexcept + { + return SHVec3(cpuEmitterData.maxVel.x, cpuEmitterData.maxVel.y, cpuEmitterData.maxVel.z); + } + + float SHParticleEmitterComponent::GetMinSize(void) const noexcept + { + return cpuEmitterData.lifeAndSizeRange.z; + } + + float SHParticleEmitterComponent::GetMaxSize(void) const noexcept + { + return cpuEmitterData.lifeAndSizeRange.w; + } + + SHVec3 SHParticleEmitterComponent::GetAngularMax(void) const noexcept + { + return SHVec3(cpuEmitterData.angularMax.x, cpuEmitterData.angularMax.y, cpuEmitterData.angularMax.z); + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h index ac2556b1..7781c29f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -22,6 +22,12 @@ namespace SHADE //! Maximum emitting angular range SHVec4 angularMax; + //! minimum starting velocity + SHVec4 minVel; + + //! Maximum starting velocity + SHVec4 maxVel; + //! Spawn lifetime and size range (min and max) SHVec4 lifeAndSizeRange; }; @@ -110,12 +116,25 @@ namespace SHADE void SetEmissionInterval (float interval) noexcept; void SetMinLife (float val) noexcept; void SetMaxLife (float val) noexcept; + void SetAngularMin (SHVec3 const& min) noexcept; + void SetAngularMax (SHVec3 const& max) noexcept; + void SetMinVelocity (SHVec3 const& vel) noexcept; + void SetMaxVelocity (SHVec3 const& vel) noexcept; + void SetMinSize (float size) noexcept; + void SetMaxSize (float size) noexcept; - uint32_t GetEmissionCount (void) const noexcept; - bool GetPassive (void) const noexcept; - float GetEmissionInterval (void) const noexcept; - float GetMinLife (void) const noexcept; - float GetMaxLife (void) const noexcept; + + uint32_t GetEmissionCount (void) const noexcept; + bool GetPassive (void) const noexcept; + float GetEmissionInterval (void) const noexcept; + float GetMinLife (void) const noexcept; + float GetMaxLife (void) const noexcept; + SHVec3 GetAngularMax (void) const noexcept; + SHVec3 GetAngularMin (void) const noexcept; + SHVec3 GetMinVelocity (void) const noexcept; + SHVec3 GetMaxVelocity (void) const noexcept; + float GetMinSize (void) const noexcept; + float GetMaxSize (void) const noexcept; friend class SHParticleSubSystem; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index 5141112e..5e526ae2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -27,7 +27,7 @@ namespace SHADE uint32_t sizeofUint = static_cast(sizeof(uint32_t)); uint32_t sizeofIndirectCmdAligned = logicalDevice->PadSSBOSize(sizeof(vk::DrawIndirectCommand)); uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct)); - uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct) * comp.maxParticles); + uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct)) * comp.maxParticles; uint32_t indicesDataAligned = logicalDevice->PadSSBOSize(sizeofUint * comp.maxParticles); @@ -36,9 +36,11 @@ namespace SHADE // Buffer Initialization { - // count, value + // count, value. Initialize free count to max particles and indices to particle indices std::vector freelistInit(comp.maxParticles + 1, 0); freelistInit[0] = comp.maxParticles; + for (uint32_t i = 0; i < comp.maxParticles; ++i) + freelistInit[i + 1] = i; // Particle emitter buffer. Multiple copies, Host-visible mapped. We want multiple copies because we'll be writing to it from the CPU. We don't want to do that while the GPU // is using it during compute operations so we write to another portion. @@ -89,10 +91,10 @@ namespace SHADE // After buffers are created, we want to populate all bindings(6) with the buffers set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA, { &comp.emitterData, 1 }, 0, emitterStructAligned); - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); // input and output will be th same until we bind using dynamic offsets - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned); // input and output will be th same until we bind using dynamic offsets + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, { &comp.freelistData, 1 }, 0, sizeofUint * (comp.maxParticles + 1)); - set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, sizeofUint * (comp.maxParticles)); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, indicesDataAligned); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmdAligned); set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA); @@ -139,6 +141,8 @@ namespace SHADE cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE); cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE); + cmdBuffer->SubmitPushConstants(SH_PIPELINE_TYPE::COMPUTE); + // emit particles cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1); } @@ -388,17 +392,24 @@ namespace SHADE /* AFTER UPDATING, RENDER PARTICLES */ /*-----------------------------------------------------------------------*/ // issue the barrier to wait for output particles to be done updating and indices data to finish being modified. - //cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); } void SHParticleSubSystem::Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept { auto& emitters = SHComponentManager::GetDense(); + auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); + + // bind the pipeline for updating + cmdBuffer->BindPipeline(renderingPipelineData.pipeline); // TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem for (auto& emitter : emitters) { + // bind the descriptor sets required for emitting particles + cmdBuffer->BindDescriptorSet(emitter.particleDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), emitter.dynamicOffsets[frameIndex]); + RenderComponent(cmdBuffer, emitter, frameIndex); } } diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 2451414d..8dec9ad6 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -311,6 +311,7 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); return componentIDList; } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 0bf66a16..6826efa7 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -17,6 +17,7 @@ #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Physics/Collision/Shapes/SHCapsule.h" +#include namespace YAML { @@ -35,6 +36,9 @@ namespace YAML struct HasYAMLConv : std::true_type {}; template<> struct HasYAMLConv : std::true_type {}; + template<> + struct HasYAMLConv : std::true_type {}; + template<> struct convert @@ -497,4 +501,75 @@ namespace YAML } }; + template<> + struct convert + { + static constexpr std::string_view EMISSION_COUNT_TAG = "Emission Count"; + static constexpr std::string_view IS_PASSIVE_TAG = "Is Passive"; + static constexpr std::string_view EMISSION_INTERVAL_TAG = "Emission Interval"; + static constexpr std::string_view MIN_LIFE_TAG = "Min Life"; + static constexpr std::string_view MAX_LIFE_TAG = "Max Life"; + static constexpr std::string_view ANGULAR_MIN_TAG = "Angular Min"; + static constexpr std::string_view ANGULAR_MAX_TAG = "Angular Max"; + static constexpr std::string_view MIN_VEL_TAG = "Minimum Velocity"; + static constexpr std::string_view MAX_VEL_TAG = "Maximum Velocity"; + static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size"; + static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size"; + + static YAML::Node encode(SHParticleEmitterComponent const& rhs) + { + YAML::Node node; + node[EMISSION_COUNT_TAG.data()] = rhs.GetEmissionCount(); + node[IS_PASSIVE_TAG.data()] = rhs.GetPassive(); + node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval(); + node[MIN_LIFE_TAG.data()] = rhs.GetMinLife(); + node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife(); + node[ANGULAR_MIN_TAG.data()] = rhs.GetAngularMin(); + node[ANGULAR_MAX_TAG.data()] = rhs.GetAngularMax(); + node[MIN_VEL_TAG.data()] = rhs.GetMinVelocity(); + node[MAX_VEL_TAG.data()] = rhs.GetMaxVelocity(); + node[MIN_SIZE_TAG.data()] = rhs.GetMinSize(); + node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize(); + + return node; + } + static bool decode(YAML::Node const& node, SHParticleEmitterComponent& rhs) + { + if (node[EMISSION_COUNT_TAG.data()].IsDefined()) + rhs.SetEmissionCount(node[EMISSION_COUNT_TAG.data()].as()); + + if (node[IS_PASSIVE_TAG.data()].IsDefined()) + rhs.SetPassive(node[IS_PASSIVE_TAG.data()].as()); + + if (node[EMISSION_INTERVAL_TAG.data()].IsDefined()) + rhs.SetEmissionInterval(node[EMISSION_INTERVAL_TAG.data()].as()); + + if (node[MIN_LIFE_TAG.data()].IsDefined()) + rhs.SetMinLife(node[MIN_LIFE_TAG.data()].as()); + + if (node[MAX_LIFE_TAG.data()].IsDefined()) + rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as()); + + if (node[ANGULAR_MIN_TAG.data()].IsDefined()) + rhs.SetAngularMin(node[ANGULAR_MIN_TAG.data()].as()); + + if (node[ANGULAR_MAX_TAG.data()].IsDefined()) + rhs.SetAngularMax(node[ANGULAR_MAX_TAG.data()].as()); + + if (node[MIN_VEL_TAG.data()].IsDefined()) + rhs.SetMinVelocity(node[MIN_VEL_TAG.data()].as()); + + if (node[MAX_VEL_TAG.data()].IsDefined()) + rhs.SetMaxVelocity(node[MAX_VEL_TAG.data()].as()); + + if (node[MIN_SIZE_TAG.data()].IsDefined()) + rhs.SetMinSize(node[MIN_SIZE_TAG.data()].as()); + + if (node[MAX_SIZE_TAG.data()].IsDefined()) + rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as()); + + return true; + } + }; + }