Files
FlaxEngine/Source/Engine/Particles/ParticlesSimulation.cpp
2021-05-31 22:40:41 +02:00

161 lines
4.5 KiB
C++

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "ParticlesSimulation.h"
#include "ParticleSystem.h"
#include "ParticleEmitter.h"
#include "Particles.h"
#include "Engine/Graphics/GPUBuffer.h"
#include "Engine/Graphics/GPUDevice.h"
ParticleEmitterInstance::ParticleEmitterInstance()
{
}
ParticleEmitterInstance::~ParticleEmitterInstance()
{
if (Buffer)
{
Particles::RecycleParticleBuffer(Buffer);
}
}
void ParticleEmitterInstance::ClearState()
{
Version = 0;
Time = 0;
SpawnModulesData.Clear();
#if COMPILE_WITH_GPU_PARTICLES
GPU.DeltaTime = 0.0f;
GPU.SpawnCount = 0;
#endif
if (Buffer)
{
Particles::RecycleParticleBuffer(Buffer);
Buffer = nullptr;
}
}
void ParticleEmitterInstance::Sync(ParticleSystemInstance& systemInstance, ParticleSystem* system, int32 emitterIndex)
{
auto emitter = system->Emitters[emitterIndex].Get();
// Sync instance version
if (Version != emitter->Graph.Version)
{
ClearState();
Version = emitter->Graph.Version;
systemInstance.ParametersVersion++;
// Synchronize parameters
ParticleSystem::EmitterParameterOverrideKey key;
key.First = emitterIndex;
Parameters.Resize(emitter->Graph.Parameters.Count(), false);
for (int32 i = 0; i < emitter->Graph.Parameters.Count(); i++)
{
auto& e = emitter->Graph.Parameters.At(i);
key.Second = e.Identifier;
if (!system->EmittersParametersOverrides.TryGet(key, Parameters[i]))
Parameters[i] = e.Value;
}
if (SpawnModulesData.Count() != emitter->Graph.SpawnModules.Count())
{
SpawnModulesData.Resize(emitter->Graph.SpawnModules.Count(), false);
SpawnerData data;
data.SpawnCounter = 0;
data.NextSpawnTime = 0;
SpawnModulesData.SetAll(data);
}
}
// Sync buffer version
if (Buffer && Buffer->Version != Version)
{
Particles::RecycleParticleBuffer(Buffer);
Buffer = nullptr;
}
}
ParticleSystemInstance::~ParticleSystemInstance()
{
SAFE_DELETE_GPU_RESOURCE(GPUParticlesCountReadback);
}
int32 ParticleSystemInstance::GetParticlesCount() const
{
int32 result = 0;
// CPU particles
for (const auto& emitter : Emitters)
{
if (emitter.Buffer && emitter.Buffer->Mode == ParticlesSimulationMode::CPU)
{
result += emitter.Buffer->CPU.Count;
}
}
// GPU particles
if (GPUParticlesCountReadback && GPUParticlesCountReadback->IsAllocated())
{
auto data = static_cast<uint32*>(GPUParticlesCountReadback->Map(GPUResourceMapMode::Read));
for (const auto& emitter : Emitters)
{
if (emitter.Buffer && emitter.Buffer->Mode == ParticlesSimulationMode::GPU && emitter.Buffer->GPU.HasValidCount)
{
result += *data;
}
++data;
}
GPUParticlesCountReadback->Unmap();
}
else if (Emitters.HasItems())
{
// Initialize readback buffer (next GPU particles simulation update will copy the particle counters)
if (!GPUParticlesCountReadback)
GPUParticlesCountReadback = GPUDevice::Instance->CreateBuffer(TEXT("GPUParticlesCountReadback"));
const auto desc = GPUBufferDescription::Buffer(Emitters.Count() * sizeof(uint32), GPUBufferFlags::None, PixelFormat::Unknown, nullptr, sizeof(uint32), GPUResourceUsage::StagingReadback);
if (GPUParticlesCountReadback->Init(desc))
{
LOG(Error, "Failed to create GPU particles count readback buffer.");
}
}
return result;
}
void ParticleSystemInstance::ClearState()
{
Version = 0;
Time = 0;
LastUpdateTime = -1;
Emitters.Resize(0);
if (GPUParticlesCountReadback)
GPUParticlesCountReadback->ReleaseGPU();
}
void ParticleSystemInstance::Sync(ParticleSystem* system)
{
// Prepare instance data
if (Version != system->Version)
{
ClearState();
Version = system->Version;
ParametersVersion++;
Emitters.Resize(system->Emitters.Count(), false);
if (GPUParticlesCountReadback)
GPUParticlesCountReadback->ReleaseGPU();
}
ASSERT(Emitters.Count() == system->Emitters.Count());
}
bool ParticleSystemInstance::ContainsEmitter(ParticleEmitter* emitter) const
{
for (int32 i = 0; i < Emitters.Count(); i++)
{
if (Emitters[i].Buffer && Emitters[i].Buffer->Emitter == emitter)
return true;
}
return false;
}