Files
BMagnu fcaa9dd998 Allow trail particles to be parented to their spawner (#7528)
* Adapt particle at runtime

* Refactor EffectHosts

* fix issues

* cleanup

* Remove live transitive particles

* paticle hosts now do local correctly

* Fix effecthostparticle local mode

* again

* Set particle host orientation

* I don't like mixed local and global vectors

* agaiiin

* Fix validity check

* parent foo

* Fix bugs, hopefully finally

* refactor

* Flip new table option for intuitiveness

* Fix support for GCC9 due to issues with LWG3052

* Address feedback
2026-07-15 15:10:15 +09:00

82 lines
3.3 KiB
C++

#include "EffectHostParticle.h"
#include <utility>
#include "math/vecmat.h"
#include "math/curve.h"
#include "freespace.h"
#include "particle/ParticleEffect.h"
EffectHostParticle::EffectHostParticle(particle::WeakParticlePtr particle, matrix orientationOverride, bool orientationOverrideRelative) :
EffectHost(orientationOverride, orientationOverrideRelative), m_particle(std::move(particle)) {}
std::pair<vec3d, matrix> EffectHostParticle::getPositionAndOrientation(bool relativeToParent, float interp, const std::optional<vec3d>& tabled_offset) const {
const auto& particle = m_particle.lock();
vec3d pos;
if (interp != 0.0f) {
float vel_scalar = particle->parent_effect.getParticleEffect().m_lifetime_curves.get_output(particle::ParticleEffect::ParticleLifetimeCurvesOutput::VELOCITY_MULT, std::forward_as_tuple(*particle, vm_vec_mag_quick(&particle->velocity)));
vec3d pos_last = particle->pos - (particle->velocity * vel_scalar * flFrametime);
vm_vec_linear_interpolate(&pos, &particle->pos, &pos_last, interp);
} else {
pos = particle->pos;
}
vec3d particle_dir = particle->attachment.local_vel_to_global(particle->velocity);
vm_vec_normalize_safe(&particle_dir);
matrix orientation;
pos = particle->attachment.local_pos_to_global(pos, interp);
if (!relativeToParent) {
orientation = m_orientationOverrideRelative ? m_orientationOverride * *vm_vector_2_matrix(&orientation, &particle_dir) : m_orientationOverride;
} else {
const auto& parent = getParentAttachment();
pos = parent.global_pos_to_local(pos);
const auto& [parent_pos, parent_orient] = parent.get_frame(interp);
vm_vec_rotate(&particle_dir, &particle_dir, &parent_orient);
if (m_orientationOverrideRelative) {
orientation = m_orientationOverride * *vm_vector_2_matrix(&orientation, &particle_dir);
} else {
matrix parent_orient_transpose;
orientation = m_orientationOverride * *vm_copy_transpose(&parent_orient_transpose, &parent_orient);
}
}
if (tabled_offset)
pos += particle_dir * tabled_offset->xyz.z;
return { pos, orientation };
}
vec3d EffectHostParticle::getVelocity() const {
return m_particle.lock()->velocity;
}
effects::EffectAttachment EffectHostParticle::getParentAttachment() const {
Assertion(isValid(), "Tried to query particle attachment on an invalid particle");
return effects::EffectAttachment(effects::attachment_particle{m_particle}).resolve_true_parent();
}
float EffectHostParticle::getLifetime() const {
const auto& particle = m_particle.lock();
return particle->max_life - particle->age;
}
float EffectHostParticle::getScale() const {
const auto& particle = m_particle.lock();
//For anything apart from the velocity curve, "Post-Curves Velocity" is well defined. This is needed to facilitate complex but common particle scaling and appearance curves.
const auto& curve_input = std::forward_as_tuple(*particle,
vm_vec_mag_quick(&particle->velocity) * particle->parent_effect.getParticleEffect().m_lifetime_curves.get_output(particle::ParticleEffect::ParticleLifetimeCurvesOutput::VELOCITY_MULT, std::forward_as_tuple(*particle, vm_vec_mag_quick(&particle->velocity))));
return particle->radius * particle->parent_effect.getParticleEffect().m_lifetime_curves.get_output(particle::ParticleEffect::ParticleLifetimeCurvesOutput::RADIUS_MULT, curve_input);
}
bool EffectHostParticle::isValid() const {
return !m_particle.expired();
}