LumixEngine/src/renderer/particle_system.cpp

912 lines
20 KiB
C++
Raw Normal View History

2015-10-30 21:11:11 +01:00
#include "particle_system.h"
2016-05-10 08:24:31 +02:00
#include "engine/blob.h"
#include "engine/crc32.h"
#include "engine/math_utils.h"
#include "engine/profiler.h"
2016-06-22 00:46:48 +02:00
#include "engine/property_register.h"
2016-05-10 08:24:31 +02:00
#include "engine/resource_manager.h"
#include "engine/resource_manager_base.h"
#include "editor/gizmo.h"
#include "editor/world_editor.h"
#include "renderer/material.h"
#include "renderer/render_scene.h"
#include "engine/universe/universe.h"
2015-12-17 13:58:40 +01:00
#include <cmath>
2015-10-30 21:11:11 +01:00
2016-05-17 07:10:20 +02:00
namespace Lumix
{
2016-07-24 22:21:43 +02:00
static const ResourceType MATERIAL_TYPE("material");
2016-05-17 07:10:20 +02:00
enum class ParticleEmitterVersion : int
{
SPAWN_COUNT,
SIZE_ALPHA_SAVE,
2016-06-22 00:46:48 +02:00
COMPONENT_TYPE,
LATEST,
2015-12-19 23:35:39 +01:00
INVALID = -1
};
2015-12-17 13:58:40 +01:00
template <typename T>
static ParticleEmitter::ModuleBase* create(ParticleEmitter& emitter)
{
return LUMIX_NEW(emitter.getAllocator(), T)(emitter);
}
2016-06-22 00:46:48 +02:00
static ParticleEmitter::ModuleBase* createModule(ComponentType type, ParticleEmitter& emitter)
{
2015-12-17 13:58:40 +01:00
typedef ParticleEmitter::ModuleBase* (*Creator)(ParticleEmitter& emitter);
2016-06-22 00:46:48 +02:00
static const struct { ComponentType type; Creator creator; } creators[] = {
2015-12-17 13:58:40 +01:00
{ ParticleEmitter::ForceModule::s_type, create<ParticleEmitter::ForceModule> },
{ ParticleEmitter::PlaneModule::s_type, create<ParticleEmitter::PlaneModule> },
{ ParticleEmitter::LinearMovementModule::s_type, create<ParticleEmitter::LinearMovementModule> },
{ ParticleEmitter::AlphaModule::s_type, create<ParticleEmitter::AlphaModule> },
{ ParticleEmitter::RandomRotationModule::s_type, create<ParticleEmitter::RandomRotationModule> },
{ ParticleEmitter::SizeModule::s_type, create<ParticleEmitter::SizeModule> },
{ ParticleEmitter::AttractorModule::s_type, create<ParticleEmitter::AttractorModule> },
{ ParticleEmitter::SpawnShapeModule::s_type, create<ParticleEmitter::SpawnShapeModule> },
{ ParticleEmitter::SubimageModule::s_type, create<ParticleEmitter::SubimageModule> }
2015-12-17 13:58:40 +01:00
};
for(auto& i : creators)
2015-11-18 20:18:48 +01:00
{
2016-06-22 00:46:48 +02:00
if(i.type == type)
2015-12-17 13:58:40 +01:00
{
return i.creator(emitter);
}
2015-11-18 20:18:48 +01:00
}
return nullptr;
}
ParticleEmitter::ModuleBase::ModuleBase(ParticleEmitter& emitter)
: m_emitter(emitter)
2015-10-30 21:11:11 +01:00
{
}
2015-10-30 21:11:11 +01:00
2016-10-02 22:56:47 +02:00
ParticleEmitter::SubimageModule::SubimageModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, rows(1)
, cols(1)
{
}
void ParticleEmitter::SubimageModule::serialize(OutputBlob& blob)
{
blob.write(rows);
blob.write(cols);
}
void ParticleEmitter::SubimageModule::deserialize(InputBlob& blob, int)
{
blob.read(rows);
blob.read(cols);
}
const ComponentType ParticleEmitter::SubimageModule::s_type = PropertyRegister::getComponentType("particle_emitter_subimage");
ParticleEmitter::ForceModule::ForceModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
{
m_acceleration.set(0, 0, 0);
}
void ParticleEmitter::ForceModule::serialize(OutputBlob& blob)
{
blob.write(m_acceleration);
}
void ParticleEmitter::ForceModule::deserialize(InputBlob& blob, int)
{
blob.read(m_acceleration);
}
void ParticleEmitter::ForceModule::update(float time_delta)
{
if (m_emitter.m_velocity.empty()) return;
Vec3* LUMIX_RESTRICT particle_velocity = &m_emitter.m_velocity[0];
for (int i = 0, c = m_emitter.m_velocity.size(); i < c; ++i)
{
particle_velocity[i] += m_acceleration * time_delta;
}
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::ForceModule::s_type = PropertyRegister::getComponentType("particle_emitter_force");
void ParticleEmitter::drawGizmo(WorldEditor& editor, RenderScene& scene)
{
for (auto* module : m_modules)
{
module->drawGizmo(editor, scene);
}
}
2015-12-17 13:58:40 +01:00
ParticleEmitter::AttractorModule::AttractorModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, m_force(0)
{
m_count = 0;
for(auto& e : m_entities)
{
e = INVALID_ENTITY;
}
}
void ParticleEmitter::AttractorModule::drawGizmo(WorldEditor& editor, RenderScene& scene)
{
for (int i = 0; i < m_count; ++i)
{
if(m_entities[i] != INVALID_ENTITY) editor.getGizmo().add(m_entities[i]);
}
}
2015-12-17 13:58:40 +01:00
void ParticleEmitter::AttractorModule::update(float time_delta)
{
if(m_emitter.m_alpha.empty()) return;
Vec3* LUMIX_RESTRICT particle_pos = &m_emitter.m_position[0];
Vec3* LUMIX_RESTRICT particle_vel = &m_emitter.m_velocity[0];
for(int i = 0; i < m_count; ++i)
{
auto entity = m_entities[i];
if(entity == INVALID_ENTITY) continue;
if (!m_emitter.m_universe.hasEntity(entity)) continue;
2015-12-17 13:58:40 +01:00
Vec3 pos = m_emitter.m_universe.getPosition(entity);
for(int i = m_emitter.m_position.size() - 1; i >= 0; --i)
{
Vec3 to_center = pos - particle_pos[i];
float dist2 = to_center.squaredLength();
to_center *= 1 / sqrt(dist2);
particle_vel[i] = particle_vel[i] + to_center * (m_force / dist2) * time_delta;
}
}
}
void ParticleEmitter::AttractorModule::serialize(OutputBlob& blob)
{
blob.write(m_force);
blob.write(m_count);
for(int i = 0; i < m_count; ++i)
{
blob.write(m_entities[i]);
}
}
void ParticleEmitter::AttractorModule::deserialize(InputBlob& blob, int)
2015-12-17 13:58:40 +01:00
{
blob.read(m_force);
blob.read(m_count);
for(int i = 0; i < m_count; ++i)
{
blob.read(m_entities[i]);
}
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::AttractorModule::s_type =
PropertyRegister::getComponentType("particle_emitter_attractor");
2015-12-17 13:58:40 +01:00
2015-12-16 21:26:19 +01:00
ParticleEmitter::PlaneModule::PlaneModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, m_bounce(0.5f)
2015-12-16 21:26:19 +01:00
{
m_count = 0;
for (auto& e : m_entities)
{
e = INVALID_ENTITY;
}
}
void ParticleEmitter::PlaneModule::drawGizmo(WorldEditor& editor, RenderScene& scene)
{
for (int i = 0; i < m_count; ++i)
{
Entity entity = m_entities[i];
if (m_entities[i] != INVALID_ENTITY) editor.getGizmo().add(entity);
if (entity == INVALID_ENTITY) continue;
if (!m_emitter.m_universe.hasEntity(entity)) continue;
Matrix mtx = m_emitter.m_universe.getMatrix(entity);
Vec3 pos = mtx.getTranslation();
Vec3 right = mtx.getXVector();
Vec3 normal = mtx.getYVector();
Vec3 forward = mtx.getZVector();
uint32 color = 0xffff0000;
for (int i = 0; i < 9; ++i)
{
float w = i / 4.0f - 1.0f;
scene.addDebugLine(pos - right - forward * w, pos + right - forward * w, color, 0);
scene.addDebugLine(pos - right * w - forward, pos - right * w + forward, color, 0);
}
}
}
2015-12-16 21:26:19 +01:00
void ParticleEmitter::PlaneModule::update(float time_delta)
{
if (m_emitter.m_alpha.empty()) return;
Vec3* LUMIX_RESTRICT particle_pos = &m_emitter.m_position[0];
Vec3* LUMIX_RESTRICT particle_vel = &m_emitter.m_velocity[0];
for (int i = 0; i < m_count; ++i)
{
auto entity = m_entities[i];
if (entity == INVALID_ENTITY) continue;
if (!m_emitter.m_universe.hasEntity(entity)) continue;
Vec3 normal = m_emitter.m_universe.getRotation(entity).rotate(Vec3(0, 1, 0));
2015-12-16 21:26:19 +01:00
float D = -dotProduct(normal, m_emitter.m_universe.getPosition(entity));
for (int i = m_emitter.m_position.size() - 1; i >= 0; --i)
{
const auto& pos = particle_pos[i];
if (dotProduct(normal, pos) + D < 0)
{
float NdotV = dotProduct(normal, particle_vel[i]);
particle_vel[i] = (particle_vel[i] - normal * (2 * NdotV)) * m_bounce;
2015-12-16 21:26:19 +01:00
}
}
}
}
void ParticleEmitter::PlaneModule::serialize(OutputBlob& blob)
{
blob.write(m_bounce);
2015-12-16 21:26:19 +01:00
blob.write(m_count);
for (int i = 0; i < m_count; ++i)
{
blob.write(m_entities[i]);
}
}
void ParticleEmitter::PlaneModule::deserialize(InputBlob& blob, int)
2015-12-16 21:26:19 +01:00
{
blob.read(m_bounce);
2015-12-16 21:26:19 +01:00
blob.read(m_count);
for (int i = 0; i < m_count; ++i)
{
blob.read(m_entities[i]);
}
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::PlaneModule::s_type = PropertyRegister::getComponentType("particle_emitter_plane");
2015-12-16 21:26:19 +01:00
ParticleEmitter::SpawnShapeModule::SpawnShapeModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, m_radius(1.0f)
, m_shape(SPHERE)
{
}
void ParticleEmitter::SpawnShapeModule::spawnParticle(int index)
{
// ugly and ~0.1% from uniform distribution, but still faster than the correct solution
float r2 = m_radius * m_radius;
for (int i = 0; i < 10; ++i)
{
2016-01-06 16:11:32 +01:00
Vec3 v(m_radius * Math::randFloat(-1, 1),
m_radius * Math::randFloat(-1, 1),
m_radius * Math::randFloat(-1, 1));
if (v.squaredLength() < r2)
{
m_emitter.m_position[index] += v;
return;
}
}
}
void ParticleEmitter::SpawnShapeModule::serialize(OutputBlob& blob)
{
blob.write(m_shape);
blob.write(m_radius);
}
void ParticleEmitter::SpawnShapeModule::deserialize(InputBlob& blob, int)
{
blob.read(m_shape);
blob.read(m_radius);
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::SpawnShapeModule::s_type =
PropertyRegister::getComponentType("particle_emitter_spawn_shape");
ParticleEmitter::LinearMovementModule::LinearMovementModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
{
}
void ParticleEmitter::LinearMovementModule::spawnParticle(int index)
{
Vec3& velocity = m_emitter.m_velocity[index];
velocity.x = m_x.getRandom();
velocity.y = m_y.getRandom();
velocity.z = m_z.getRandom();
Quat rot = m_emitter.m_universe.getRotation(m_emitter.m_entity);
velocity = rot.rotate(velocity);
}
void ParticleEmitter::LinearMovementModule::serialize(OutputBlob& blob)
{
blob.write(m_x);
blob.write(m_y);
blob.write(m_z);
}
void ParticleEmitter::LinearMovementModule::deserialize(InputBlob& blob, int)
{
blob.read(m_x);
blob.read(m_y);
blob.read(m_z);
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::LinearMovementModule::s_type =
PropertyRegister::getComponentType("particle_emitter_linear_movement");
2015-10-30 21:11:11 +01:00
static void sampleBezier(float max_life, const Array<Vec2>& values, Array<float>& sampled)
{
ASSERT(values.size() >= 6);
ASSERT(values[values.size() - 2].x - values[1].x > 0);
static const int SAMPLES_PER_SECOND = 10;
sampled.resize(int(max_life * SAMPLES_PER_SECOND));
float x_range = values[values.size() - 2].x - values[1].x;
int last_idx = 0;
for (int i = 1; i < values.size() - 3; i += 3)
{
int step_count = int(5 * sampled.size() * ((values[i + 3].x - values[i].x) / x_range));
float t_step = 1.0f / (float)step_count;
for (int i_step = 1; i_step <= step_count; i_step++)
{
float t = t_step * i_step;
float u = 1.0f - t;
float w1 = u * u * u;
float w2 = 3 * u * u * t;
float w3 = 3 * u * t * t;
float w4 = t * t * t;
auto p = values[i] * (w1 + w2) + values[i + 1] * w2 + values[i + 2] * w3 +
values[i + 3] * (w3 + w4);
int idx = int(sampled.size() * ((p.x - values[1].x) / x_range));
ASSERT(idx <= last_idx + 1);
last_idx = idx;
sampled[idx >= sampled.size() ? sampled.size() - 1 : idx] = p.y;
}
}
sampled[0] = values[0].y;
sampled.back() = values[values.size() - 2].y;
}
2015-11-07 13:57:11 +01:00
ParticleEmitter::AlphaModule::AlphaModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, m_values(emitter.getAllocator())
, m_sampled(emitter.getAllocator())
{
2015-12-07 21:49:27 +01:00
m_values.resize(9);
m_values[0].set(-0.2f, 0);
m_values[1].set(0, 0);
m_values[2].set(0.2f, 0.0f);
m_values[3].set(-0.2f, 0.0f);
m_values[4].set(0.5f, 1.0f);
m_values[5].set(0.2f, 0.0f);
m_values[6].set(-0.2f, 0.0f);
m_values[7].set(1, 0);
m_values[8].set(0.2f, 0);
sample();
}
void ParticleEmitter::AlphaModule::serialize(OutputBlob& blob)
{
blob.write(m_values.size());
blob.write(&m_values[0], sizeof(m_values[0]) * m_values.size());
}
void ParticleEmitter::AlphaModule::deserialize(InputBlob& blob, int version)
{
if (version <= (int)ParticleEmitterVersion::SIZE_ALPHA_SAVE) return;
int size;
blob.read(size);
m_values.resize(size);
blob.read(&m_values[0], sizeof(m_values[0]) * m_values.size());
sample();
}
void ParticleEmitter::AlphaModule::sample()
2015-11-07 13:57:11 +01:00
{
sampleBezier(m_emitter.m_initial_life.to, m_values, m_sampled);
2015-11-07 13:57:11 +01:00
}
void ParticleEmitter::AlphaModule::update(float)
2015-11-07 13:57:11 +01:00
{
if(m_emitter.m_alpha.empty()) return;
2015-11-07 13:57:11 +01:00
float* LUMIX_RESTRICT particle_alpha = &m_emitter.m_alpha[0];
float* LUMIX_RESTRICT rel_life = &m_emitter.m_rel_life[0];
int size = m_sampled.size() - 1;
float float_size = (float)size;
for(int i = 0, c = m_emitter.m_size.size(); i < c; ++i)
2015-11-07 13:57:11 +01:00
{
float float_idx = float_size * rel_life[i];
int idx = (int)float_idx;
2016-03-06 12:54:29 +01:00
int next_idx = Math::minimum(idx + 1, size);
float w = float_idx - idx;
particle_alpha[i] = m_sampled[idx] * (1 - w) + m_sampled[next_idx] * w;
2015-11-07 13:57:11 +01:00
}
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::AlphaModule::s_type = PropertyRegister::getComponentType("particle_emitter_alpha");
2015-11-07 13:57:11 +01:00
2015-11-18 20:18:48 +01:00
ParticleEmitter::SizeModule::SizeModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, m_values(emitter.getAllocator())
2015-12-07 00:55:32 +01:00
, m_sampled(emitter.getAllocator())
{
2015-12-07 21:49:27 +01:00
m_values.resize(9);
m_values[0].set(-0.2f, 0);
m_values[1].set(0, 0);
m_values[2].set(0.2f, 0.0f);
m_values[3].set(-0.2f, 0.0f);
m_values[4].set(0.5f, 1.0f);
m_values[5].set(0.2f, 0.0f);
m_values[6].set(-0.2f, 0.0f);
m_values[7].set(1, 0);
m_values[8].set(0.2f, 0);
2015-12-07 00:55:32 +01:00
sample();
}
void ParticleEmitter::SizeModule::serialize(OutputBlob& blob)
{
blob.write(m_values.size());
blob.write(&m_values[0], sizeof(m_values[0]) * m_values.size());
}
void ParticleEmitter::SizeModule::deserialize(InputBlob& blob, int version)
{
if (version <= (int)ParticleEmitterVersion::SIZE_ALPHA_SAVE) return;
int size;
blob.read(size);
m_values.resize(size);
blob.read(&m_values[0], sizeof(m_values[0]) * m_values.size());
sample();
}
2015-12-07 00:55:32 +01:00
void ParticleEmitter::SizeModule::sample()
2015-11-18 20:18:48 +01:00
{
sampleBezier(m_emitter.m_initial_life.to, m_values, m_sampled);
2015-11-18 20:18:48 +01:00
}
void ParticleEmitter::SizeModule::update(float)
{
if (m_emitter.m_size.empty()) return;
float* LUMIX_RESTRICT particle_size = &m_emitter.m_size[0];
float* LUMIX_RESTRICT rel_life = &m_emitter.m_rel_life[0];
2015-12-07 00:55:32 +01:00
int size = m_sampled.size() - 1;
2015-11-18 20:18:48 +01:00
float float_size = (float)size;
for (int i = 0, c = m_emitter.m_size.size(); i < c; ++i)
{
float float_idx = float_size * rel_life[i];
int idx = (int)float_idx;
2016-03-06 12:54:29 +01:00
int next_idx = Math::minimum(idx + 1, size);
2015-11-18 20:18:48 +01:00
float w = float_idx - idx;
2015-12-07 00:55:32 +01:00
particle_size[i] = m_sampled[idx] * (1 - w) + m_sampled[next_idx] * w;
PROFILE_INT("Test", int(particle_size[i] * 1000));
2015-11-18 20:18:48 +01:00
}
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::SizeModule::s_type = PropertyRegister::getComponentType("particle_emitter_size");
2015-11-18 20:18:48 +01:00
2015-11-07 13:57:11 +01:00
ParticleEmitter::RandomRotationModule::RandomRotationModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
{
}
void ParticleEmitter::RandomRotationModule::spawnParticle(int index)
{
2016-01-06 16:11:32 +01:00
m_emitter.m_rotation[index] = Math::randFloat(0, Math::PI * 2);
2015-11-07 13:57:11 +01:00
}
2016-06-22 00:46:48 +02:00
const ComponentType ParticleEmitter::RandomRotationModule::s_type =
PropertyRegister::getComponentType("particle_emitter_random_rotation");
2015-11-07 13:57:11 +01:00
2015-10-30 21:11:11 +01:00
Interval::Interval()
: from(0)
, to(0)
{
}
IntInterval::IntInterval()
{
from = to = 1;
}
int IntInterval::getRandom() const
{
if (from == to) return from;
2016-01-06 16:11:32 +01:00
return Math::rand(from, to);
}
2016-01-12 22:59:11 +01:00
void Interval::checkZero()
{
2016-03-06 12:54:29 +01:00
from = Math::maximum(from, 0.0f);
to = Math::maximum(from, to);
}
2016-01-12 22:59:11 +01:00
void Interval::check()
{
2016-03-06 12:54:29 +01:00
to = Math::maximum(from, to);
2016-01-12 22:59:11 +01:00
}
2015-10-30 21:11:11 +01:00
float Interval::getRandom() const
{
2016-01-06 16:11:32 +01:00
return Math::randFloat(from, to);
2015-10-30 21:11:11 +01:00
}
ParticleEmitter::ParticleEmitter(Entity entity, Universe& universe, IAllocator& allocator)
: m_allocator(allocator)
, m_rel_life(allocator)
2015-10-30 21:11:11 +01:00
, m_life(allocator)
, m_modules(allocator)
, m_position(allocator)
, m_velocity(allocator)
2015-11-07 13:57:11 +01:00
, m_rotation(allocator)
, m_rotational_speed(allocator)
, m_alpha(allocator)
2015-10-30 21:11:11 +01:00
, m_universe(universe)
, m_entity(entity)
, m_size(allocator)
2016-10-02 22:56:47 +02:00
, m_subimage_module(nullptr)
2015-10-30 21:11:11 +01:00
{
init();
2015-10-30 21:11:11 +01:00
}
ParticleEmitter::~ParticleEmitter()
{
setMaterial(nullptr);
2015-10-30 21:11:11 +01:00
for (auto* module : m_modules)
{
LUMIX_DELETE(m_allocator, module);
}
}
void ParticleEmitter::init()
{
m_spawn_period.from = 1;
m_spawn_period.to = 2;
m_initial_life.from = 1;
m_initial_life.to = 2;
m_initial_size.from = 1;
m_initial_size.to = 1;
m_material = nullptr;
m_next_spawn_time = 0;
m_is_valid = true;
}
2015-12-17 13:58:40 +01:00
void ParticleEmitter::reset()
{
m_rel_life.clear();
m_life.clear();
m_size.clear();
m_position.clear();
m_velocity.clear();
m_alpha.clear();
m_rotation.clear();
m_rotational_speed.clear();
}
void ParticleEmitter::setMaterial(Material* material)
{
if (m_material)
{
2016-07-25 01:02:36 +02:00
m_material->getResourceManager().unload(*m_material);
}
m_material = material;
}
2015-10-30 21:11:11 +01:00
void ParticleEmitter::spawnParticle()
{
m_position.push(m_universe.getPosition(m_entity));
2015-11-07 13:57:11 +01:00
m_rotation.push(0);
m_rotational_speed.push(0);
2015-10-30 21:11:11 +01:00
m_life.push(m_initial_life.getRandom());
m_rel_life.push(0.0f);
2015-11-07 13:57:11 +01:00
m_alpha.push(1);
2015-10-30 21:11:11 +01:00
m_velocity.push(Vec3(0, 0, 0));
2015-11-01 20:56:29 +01:00
m_size.push(m_initial_size.getRandom());
2015-10-30 21:11:11 +01:00
for (auto* module : m_modules)
{
module->spawnParticle(m_life.size() - 1);
}
}
2016-06-22 00:46:48 +02:00
ParticleEmitter::ModuleBase* ParticleEmitter::getModule(ComponentType type)
{
for (auto* module : m_modules)
{
if (module->getType() == type) return module;
}
return nullptr;
}
void ParticleEmitter::addModule(ModuleBase* module)
{
2016-10-02 22:56:47 +02:00
if (module->getType() == SubimageModule::s_type) m_subimage_module = static_cast<SubimageModule*>(module);
m_modules.push(module);
}
2015-10-30 21:11:11 +01:00
void ParticleEmitter::destroyParticle(int index)
{
for (auto* module : m_modules)
{
module->destoryParticle(index);
}
m_life.eraseFast(index);
m_rel_life.eraseFast(index);
2015-10-30 21:11:11 +01:00
m_position.eraseFast(index);
m_velocity.eraseFast(index);
2015-11-07 13:57:11 +01:00
m_rotation.eraseFast(index);
m_rotational_speed.eraseFast(index);
m_alpha.eraseFast(index);
2015-10-30 21:11:11 +01:00
m_size.eraseFast(index);
}
void ParticleEmitter::updateLives(float time_delta)
{
for (int i = 0, c = m_rel_life.size(); i < c; ++i)
2015-10-30 21:11:11 +01:00
{
float rel_life = m_rel_life[i];
rel_life += time_delta / m_life[i];
m_rel_life[i] = rel_life;
2015-10-30 21:11:11 +01:00
if (rel_life > 1)
2015-10-30 21:11:11 +01:00
{
destroyParticle(i);
--i;
--c;
}
}
}
void ParticleEmitter::serialize(OutputBlob& blob)
{
blob.write((int)ParticleEmitterVersion::LATEST);
blob.write(m_spawn_count);
blob.write(m_spawn_period);
blob.write(m_initial_life);
blob.write(m_initial_size);
blob.write(m_entity);
blob.writeString(m_material ? m_material->getPath().c_str() : "");
blob.write(m_modules.size());
for (auto* module : m_modules)
{
2016-06-29 12:50:45 +02:00
blob.write(PropertyRegister::getComponentTypeHash(module->getType()));
module->serialize(blob);
}
}
void ParticleEmitter::deserialize(InputBlob& blob, ResourceManager& manager, bool has_version)
{
int version = (int)ParticleEmitterVersion::INVALID;
if (has_version)
{
blob.read(version);
if (version > (int)ParticleEmitterVersion::SPAWN_COUNT) blob.read(m_spawn_count);
}
blob.read(m_spawn_period);
blob.read(m_initial_life);
blob.read(m_initial_size);
blob.read(m_entity);
char path[MAX_PATH_LENGTH];
blob.readString(path, lengthOf(path));
2016-07-24 22:21:43 +02:00
auto material_manager = manager.get(MATERIAL_TYPE);
2016-06-22 00:46:48 +02:00
auto material = static_cast<Material*>(material_manager->load(Path(path)));
setMaterial(material);
int size;
blob.read(size);
for (auto* module : m_modules)
{
LUMIX_DELETE(m_allocator, module);
}
m_modules.clear();
for (int i = 0; i < size; ++i)
{
2016-06-22 00:46:48 +02:00
ParticleEmitter::ModuleBase* module = nullptr;
if (version > (int)ParticleEmitterVersion::COMPONENT_TYPE)
{
2016-06-29 12:50:45 +02:00
uint32 hash;
blob.read(hash);
ComponentType type = PropertyRegister::getComponentTypeFromHash(hash);
2016-06-22 00:46:48 +02:00
module = createModule(type, *this);
}
else
{
uint32 type;
blob.read(type);
static const char* OLD_MODULE_NAMES[] = {"force",
"attractor",
"plane",
"spawn_shape",
"linear_movement",
"alpha",
"size",
2016-10-02 22:56:47 +02:00
"random_rotation",
"subimage"};
2016-06-22 00:46:48 +02:00
for (const char* old_name : OLD_MODULE_NAMES)
{
if (type == crc32(old_name))
{
char tmp[50];
copyString(tmp, "particle_emitter_");
catString(tmp, old_name);
type = crc32(tmp);
module = createModule(PropertyRegister::getComponentTypeFromHash(type), *this);
break;
}
}
ASSERT(module);
}
2016-07-01 23:05:00 +02:00
if (module)
{
m_modules.push(module);
module->deserialize(blob, version);
}
}
}
2015-10-30 21:11:11 +01:00
void ParticleEmitter::updatePositions(float time_delta)
{
for (int i = 0, c = m_position.size(); i < c; ++i)
{
m_position[i] += m_velocity[i] * time_delta;
2015-10-30 21:11:11 +01:00
}
}
2015-11-07 13:57:11 +01:00
void ParticleEmitter::updateRotations(float time_delta)
{
for (int i = 0, c = m_rotation.size(); i < c; ++i)
{
m_rotation[i] += m_rotational_speed[i] * time_delta;
}
}
2015-10-30 21:11:11 +01:00
void ParticleEmitter::update(float time_delta)
{
spawnParticles(time_delta);
updateLives(time_delta);
updatePositions(time_delta);
2015-11-07 13:57:11 +01:00
updateRotations(time_delta);
2015-10-30 21:11:11 +01:00
for (auto* module : m_modules)
{
module->update(time_delta);
}
}
void ParticleEmitter::spawnParticles(float time_delta)
{
m_next_spawn_time -= time_delta;
while (m_next_spawn_time < 0)
{
m_next_spawn_time += m_spawn_period.getRandom();
int spawn_count = m_spawn_count.getRandom();
for (int i = 0; i < spawn_count; ++i)
{
spawnParticle();
}
2015-10-30 21:11:11 +01:00
}
}
struct InitialVelocityModule : public ParticleEmitter::ModuleBase
{
Interval m_x;
Interval m_y;
Interval m_z;
2016-02-05 14:32:21 +01:00
explicit InitialVelocityModule(ParticleEmitter& emitter)
2015-10-30 21:11:11 +01:00
: ModuleBase(emitter)
{
m_z.from = -1;
m_z.to = 1;
2016-02-05 14:32:21 +01:00
m_x.from = m_x.to = m_y.from = m_y.to = 0;
2015-10-30 21:11:11 +01:00
}
void spawnParticle(int index) override
{
Vec3 v;
v.x = m_x.getRandom();
v.y = m_y.getRandom();
v.z = m_z.getRandom();
m_emitter.m_velocity[index] = v;
}
};
} // namespace Lumix