overte-Armored-Dragon/libraries/entities/src/ParticleEffectEntityItem.cpp

1131 lines
No EOL
44 KiB
C++

//
// ParticleEffectEntityItem.cpp
// libraries/entities/src
//
// Some starter code for a particle simulation entity, which could ideally be used for a variety of effects.
// This is some really early and rough stuff here. It was enough for now to just get it up and running in the interface.
//
// Todo's and other notes:
// - The simulation should restart when the AnimationLoop's max frame is reached (or passed), but there doesn't seem
// to be a good way to set that max frame to something reasonable right now.
// - There seems to be a bug whereby entities on the edge of screen will just pop off or on. This is probably due
// to my lack of understanding of how entities in the octree are picked for rendering. I am updating the entity
// dimensions based on the bounds of the sim, but maybe I need to update a dirty flag or something.
// - This should support some kind of pre-roll of the simulation.
// - Just to get this out the door, I just did forward Euler integration. There are better ways.
// - Gravity always points along the Y axis. Support an actual gravity vector.
// - Add the ability to add arbitrary forces to the simulation.
// - Add drag.
// - Add some kind of support for collisions.
// - There's no synchronization of the simulation across clients at all. In fact, it's using rand() under the hood, so
// there's no gaurantee that different clients will see simulations that look anything like the other.
//
// Created by Jason Rickwald on 3/2/15.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ParticleEffectEntityItem.h"
#include <glm/gtx/transform.hpp>
#include <QtCore/QJsonDocument>
#include <ByteCountCoding.h>
#include <GeometryUtil.h>
#include <Interpolate.h>
#include "EntityTree.h"
#include "EntityTreeElement.h"
#include "EntitiesLogging.h"
#include "EntityScriptingInterface.h"
using namespace particle;
template <typename T>
bool operator==(const Range<T>& a, const Range<T>& b) {
return (a.start == b.start && a.finish == b.finish);
}
template <typename T>
bool operator==(const Gradient<T>& a, const Gradient<T>& b) {
return (a.target == b.target && a.spread == b.spread);
}
template <typename T>
bool operator==(const RangeGradient<T>& a, const RangeGradient<T>& b) {
return (a.gradient == b.gradient && a.range == b.range);
}
template <typename T>
bool operator!=(const Range<T>& a, const Range<T>& b) {
return !(a == b);
}
template <typename T>
bool operator!=(const Gradient<T>& a, const Gradient<T>& b) {
return !(a == b);
}
template <typename T>
bool operator!=(const RangeGradient<T>& a, const RangeGradient<T>& b) {
return !(a == b);
}
bool operator==(const EmitProperties& a, const EmitProperties& b) {
return
(a.rate == b.rate) &&
(a.speed == b.speed) &&
(a.acceleration == b.acceleration) &&
(a.orientation == b.orientation) &&
(a.dimensions == b.dimensions) &&
(a.shouldTrail == b.shouldTrail);
}
bool operator!=(const EmitProperties& a, const EmitProperties& b) {
return !(a == b);
}
bool operator==(const Properties& a, const Properties& b) {
return
(a.color == b.color) &&
(a.alpha == b.alpha) &&
(a.radiusStart == b.radiusStart) &&
(a.radius == b.radius) &&
(a.spin == b.spin) &&
(a.rotateWithEntity == b.rotateWithEntity) &&
(a.lifespan == b.lifespan) &&
(a.maxParticles == b.maxParticles) &&
(a.emission == b.emission) &&
(a.polar == b.polar) &&
(a.azimuth == b.azimuth) &&
(a.textures == b.textures);
}
bool operator!=(const Properties& a, const Properties& b) {
return !(a == b);
}
bool Properties::valid() const {
if (glm::any(glm::isnan(emission.orientation))) {
qCWarning(entities) << "Bad particle data";
return false;
}
return
(alpha.gradient.target == glm::clamp(alpha.gradient.target, MINIMUM_ALPHA, MAXIMUM_ALPHA)) &&
(alpha.range.start == glm::clamp(alpha.range.start, MINIMUM_ALPHA, MAXIMUM_ALPHA)) &&
(alpha.range.finish == glm::clamp(alpha.range.finish, MINIMUM_ALPHA, MAXIMUM_ALPHA)) &&
(alpha.gradient.spread == glm::clamp(alpha.gradient.spread, MINIMUM_ALPHA, MAXIMUM_ALPHA)) &&
(radiusStart == glm::clamp(radiusStart, MINIMUM_EMIT_RADIUS_START, MAXIMUM_EMIT_RADIUS_START)) &&
(radius.gradient.target == glm::clamp(radius.gradient.target, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
(radius.range.start == glm::clamp(radius.range.start, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
(radius.range.finish == glm::clamp(radius.range.finish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
(radius.gradient.spread == glm::clamp(radius.gradient.spread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
(spin.gradient.target == glm::clamp(spin.gradient.target, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
(spin.range.start == glm::clamp(spin.range.start, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
(spin.range.finish == glm::clamp(spin.range.finish, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
(spin.gradient.spread == glm::clamp(spin.gradient.spread, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
(lifespan == glm::clamp(lifespan, MINIMUM_LIFESPAN, MAXIMUM_LIFESPAN)) &&
(maxParticles == glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES)) &&
(emission.rate == glm::clamp(emission.rate, MINIMUM_EMIT_RATE, MAXIMUM_EMIT_RATE)) &&
(emission.speed.target == glm::clamp(emission.speed.target, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED)) &&
(emission.speed.spread == glm::clamp(emission.speed.spread, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED)) &&
(emission.acceleration.target == glm::clamp(emission.acceleration.target, vec3(MINIMUM_EMIT_ACCELERATION), vec3(MAXIMUM_EMIT_ACCELERATION))) &&
(emission.acceleration.spread == glm::clamp(emission.acceleration.spread, vec3(MINIMUM_ACCELERATION_SPREAD), vec3(MAXIMUM_ACCELERATION_SPREAD)) &&
(emission.dimensions == glm::clamp(emission.dimensions, vec3(MINIMUM_EMIT_DIMENSION), vec3(MAXIMUM_EMIT_DIMENSION))) &&
(polar.start == glm::clamp(polar.start, MINIMUM_POLAR, MAXIMUM_POLAR)) &&
(polar.finish == glm::clamp(polar.finish, MINIMUM_POLAR, MAXIMUM_POLAR)) &&
(azimuth.start == glm::clamp(azimuth.start, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH)) &&
(azimuth.finish == glm::clamp(azimuth.finish, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH)));
}
bool Properties::emitting() const {
return emission.rate > 0.0f && lifespan > 0.0f && polar.start <= polar.finish;
}
uint64_t Properties::emitIntervalUsecs() const {
if (emission.rate > 0.0f) {
return (uint64_t)(USECS_PER_SECOND / emission.rate);
}
return 0;
}
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
std::shared_ptr<ParticleEffectEntityItem> entity(new ParticleEffectEntityItem(entityID), [](ParticleEffectEntityItem* ptr) { ptr->deleteLater(); });
entity->setProperties(properties);
return entity;
}
// our non-pure virtual subclass for now...
ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID) :
EntityItem(entityItemID)
{
_type = EntityTypes::ParticleEffect;
_visuallyReady = false;
}
void ParticleEffectEntityItem::setAlpha(float alpha) {
alpha = glm::clamp(alpha, MINIMUM_ALPHA, MAXIMUM_ALPHA);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.alpha.gradient.target != alpha;
_particleProperties.alpha.gradient.target = alpha;
});
}
float ParticleEffectEntityItem::getAlpha() const {
return resultWithReadLock<float>([&] {
return _particleProperties.alpha.gradient.target;
});
}
void ParticleEffectEntityItem::setAlphaStart(float alphaStart) {
alphaStart = glm::isnan(alphaStart) ? alphaStart : glm::clamp(alphaStart, MINIMUM_ALPHA, MAXIMUM_ALPHA);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.alpha.range.start != alphaStart;
_particleProperties.alpha.range.start = alphaStart;
});
}
float ParticleEffectEntityItem::getAlphaStart() const {
return resultWithReadLock<float>([&] {
return _particleProperties.alpha.range.start;
});
}
void ParticleEffectEntityItem::setAlphaFinish(float alphaFinish) {
alphaFinish = glm::isnan(alphaFinish) ? alphaFinish : glm::clamp(alphaFinish, MINIMUM_ALPHA, MAXIMUM_ALPHA);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.alpha.range.finish != alphaFinish;
_particleProperties.alpha.range.finish = alphaFinish;
});
}
float ParticleEffectEntityItem::getAlphaFinish() const {
return resultWithReadLock<float>([&] {
return _particleProperties.alpha.range.finish;
});
}
void ParticleEffectEntityItem::setAlphaSpread(float alphaSpread) {
alphaSpread = glm::clamp(alphaSpread, MINIMUM_ALPHA, MAXIMUM_ALPHA);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.alpha.gradient.spread != alphaSpread;
_particleProperties.alpha.gradient.spread = alphaSpread;
});
}
float ParticleEffectEntityItem::getAlphaSpread() const {
return resultWithReadLock<float>([&] {
return _particleProperties.alpha.gradient.spread;
});
}
void ParticleEffectEntityItem::setLifespan(float lifespan) {
lifespan = glm::clamp(lifespan, MINIMUM_LIFESPAN, MAXIMUM_LIFESPAN);
bool changed;
withWriteLock([&] {
changed = _particleProperties.lifespan != lifespan;
_needsRenderUpdate |= changed;
_particleProperties.lifespan = lifespan;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getLifespan() const {
return resultWithReadLock<float>([&] {
return _particleProperties.lifespan;
});
}
void ParticleEffectEntityItem::setEmitRate(float emitRate) {
emitRate = glm::clamp(emitRate, MINIMUM_EMIT_RATE, MAXIMUM_EMIT_RATE);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.emission.rate != emitRate;
_particleProperties.emission.rate = emitRate;
});
}
float ParticleEffectEntityItem::getEmitRate() const {
return resultWithReadLock<float>([&] {
return _particleProperties.emission.rate;
});
}
void ParticleEffectEntityItem::setEmitSpeed(float emitSpeed) {
emitSpeed = glm::clamp(emitSpeed, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED);
bool changed;
withWriteLock([&] {
changed = _particleProperties.emission.speed.target != emitSpeed;
_needsRenderUpdate |= changed;
_particleProperties.emission.speed.target = emitSpeed;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getEmitSpeed() const {
return resultWithReadLock<float>([&] {
return _particleProperties.emission.speed.target;
});
}
void ParticleEffectEntityItem::setSpeedSpread(float speedSpread) {
speedSpread = glm::clamp(speedSpread, MINIMUM_EMIT_SPEED, MAXIMUM_EMIT_SPEED);
bool changed;
withWriteLock([&] {
changed = _particleProperties.emission.speed.spread != speedSpread;
_needsRenderUpdate |= changed;
_particleProperties.emission.speed.spread = speedSpread;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getSpeedSpread() const {
return resultWithReadLock<float>([&] {
return _particleProperties.emission.speed.spread;
});
}
void ParticleEffectEntityItem::setEmitOrientation(const glm::quat& emitOrientation_) {
auto emitOrientation = glm::normalize(emitOrientation_);
bool changed;
withWriteLock([&] {
changed = _particleProperties.emission.orientation != emitOrientation;
_needsRenderUpdate |= changed;
_particleProperties.emission.orientation = emitOrientation;
});
if (changed) {
computeAndUpdateDimensions();
}
}
glm::quat ParticleEffectEntityItem::getEmitOrientation() const {
return resultWithReadLock<glm::quat>([&] {
return _particleProperties.emission.orientation;
});
}
void ParticleEffectEntityItem::setEmitDimensions(const glm::vec3& emitDimensions_) {
auto emitDimensions = glm::clamp(emitDimensions_, vec3(MINIMUM_EMIT_DIMENSION), vec3(MAXIMUM_EMIT_DIMENSION));
bool changed;
withWriteLock([&] {
changed = _particleProperties.emission.dimensions != emitDimensions;
_needsRenderUpdate |= changed;
_particleProperties.emission.dimensions = emitDimensions;
});
if (changed) {
computeAndUpdateDimensions();
}
}
glm::vec3 ParticleEffectEntityItem::getEmitDimensions() const {
return resultWithReadLock<glm::vec3>([&] {
return _particleProperties.emission.dimensions;
});
}
void ParticleEffectEntityItem::setEmitRadiusStart(float emitRadiusStart) {
emitRadiusStart = glm::clamp(emitRadiusStart, MINIMUM_EMIT_RADIUS_START, MAXIMUM_EMIT_RADIUS_START);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.radiusStart != emitRadiusStart;
_particleProperties.radiusStart = emitRadiusStart;
});
}
float ParticleEffectEntityItem::getEmitRadiusStart() const {
return resultWithReadLock<float>([&] {
return _particleProperties.radiusStart;
});
}
void ParticleEffectEntityItem::setPolarStart(float polarStart) {
polarStart = glm::clamp(polarStart, MINIMUM_POLAR, MAXIMUM_POLAR);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.polar.start != polarStart;
_particleProperties.polar.start = polarStart;
});
}
float ParticleEffectEntityItem::getPolarStart() const {
return resultWithReadLock<float>([&] {
return _particleProperties.polar.start;
});
}
void ParticleEffectEntityItem::setPolarFinish(float polarFinish) {
polarFinish = glm::clamp(polarFinish, MINIMUM_POLAR, MAXIMUM_POLAR);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.polar.finish != polarFinish;
_particleProperties.polar.finish = polarFinish;
});
}
float ParticleEffectEntityItem::getPolarFinish() const {
return resultWithReadLock<float>([&] {
return _particleProperties.polar.finish;
});
}
void ParticleEffectEntityItem::setAzimuthStart(float azimuthStart) {
azimuthStart = glm::clamp(azimuthStart, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.azimuth.start != azimuthStart;
_particleProperties.azimuth.start = azimuthStart;
});
}
float ParticleEffectEntityItem::getAzimuthStart() const {
return resultWithReadLock<float>([&] {
return _particleProperties.azimuth.start;
});
}
void ParticleEffectEntityItem::setAzimuthFinish(float azimuthFinish) {
azimuthFinish = glm::clamp(azimuthFinish, MINIMUM_AZIMUTH, MAXIMUM_AZIMUTH);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.azimuth.finish != azimuthFinish;
_particleProperties.azimuth.finish = azimuthFinish;
});
}
float ParticleEffectEntityItem::getAzimuthFinish() const {
return resultWithReadLock<float>([&] {
return _particleProperties.azimuth.finish;
});
}
void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration_) {
auto emitAcceleration = glm::clamp(emitAcceleration_, vec3(MINIMUM_EMIT_ACCELERATION), vec3(MAXIMUM_EMIT_ACCELERATION));
bool changed;
withWriteLock([&] {
changed = _particleProperties.emission.acceleration.target != emitAcceleration;
_needsRenderUpdate |= changed;
_particleProperties.emission.acceleration.target = emitAcceleration;
});
if (changed) {
computeAndUpdateDimensions();
}
}
glm::vec3 ParticleEffectEntityItem::getEmitAcceleration() const {
return resultWithReadLock<glm::vec3>([&] {
return _particleProperties.emission.acceleration.target;
});
}
void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerationSpread_){
auto accelerationSpread = glm::clamp(accelerationSpread_, vec3(MINIMUM_ACCELERATION_SPREAD), vec3(MAXIMUM_ACCELERATION_SPREAD));
bool changed;
withWriteLock([&] {
changed = _particleProperties.emission.acceleration.spread != accelerationSpread;
_needsRenderUpdate |= changed;
_particleProperties.emission.acceleration.spread = accelerationSpread;
});
if (changed) {
computeAndUpdateDimensions();
}
}
glm::vec3 ParticleEffectEntityItem::getAccelerationSpread() const {
return resultWithReadLock<glm::vec3>([&] {
return _particleProperties.emission.acceleration.spread;
});
}
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
particleRadius = glm::clamp(particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
bool changed;
withWriteLock([&] {
changed = _particleProperties.radius.gradient.target != particleRadius;
_needsRenderUpdate |= changed;
_particleProperties.radius.gradient.target = particleRadius;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getParticleRadius() const {
return resultWithReadLock<float>([&] {
return _particleProperties.radius.gradient.target;
});
}
void ParticleEffectEntityItem::setRadiusStart(float radiusStart) {
radiusStart = glm::isnan(radiusStart) ? radiusStart : glm::clamp(radiusStart, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
bool changed;
withWriteLock([&] {
changed = _particleProperties.radius.range.start != radiusStart;
_needsRenderUpdate |= changed;
_particleProperties.radius.range.start = radiusStart;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getRadiusStart() const {
return resultWithReadLock<float>([&] {
return _particleProperties.radius.range.start;
});
}
void ParticleEffectEntityItem::setRadiusFinish(float radiusFinish) {
radiusFinish = glm::isnan(radiusFinish) ? radiusFinish : glm::clamp(radiusFinish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
bool changed;
withWriteLock([&] {
changed = _particleProperties.radius.range.finish != radiusFinish;
_needsRenderUpdate |= changed;
_particleProperties.radius.range.finish = radiusFinish;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getRadiusFinish() const {
return resultWithReadLock<float>([&] {
return _particleProperties.radius.range.finish;
});
}
void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) {
radiusSpread = glm::clamp(radiusSpread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
bool changed;
withWriteLock([&] {
changed = _particleProperties.radius.gradient.spread != radiusSpread;
_needsRenderUpdate |= changed;
_particleProperties.radius.gradient.spread = radiusSpread;
});
if (changed) {
computeAndUpdateDimensions();
}
}
float ParticleEffectEntityItem::getRadiusSpread() const {
return resultWithReadLock<float>([&] {
return _particleProperties.radius.gradient.spread;
});
}
void ParticleEffectEntityItem::setParticleSpin(float particleSpin) {
particleSpin = glm::clamp(particleSpin, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.spin.gradient.target != particleSpin;
_particleProperties.spin.gradient.target = particleSpin;
});
}
float ParticleEffectEntityItem::getParticleSpin() const {
return resultWithReadLock<float>([&] {
return _particleProperties.spin.gradient.target;
});
}
void ParticleEffectEntityItem::setSpinStart(float spinStart) {
spinStart =
glm::isnan(spinStart) ? spinStart : glm::clamp(spinStart, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.spin.range.start != spinStart;
_particleProperties.spin.range.start = spinStart;
});
}
float ParticleEffectEntityItem::getSpinStart() const {
return resultWithReadLock<float>([&] {
return _particleProperties.spin.range.start;
});
}
void ParticleEffectEntityItem::setSpinFinish(float spinFinish) {
spinFinish =
glm::isnan(spinFinish) ? spinFinish : glm::clamp(spinFinish, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.spin.range.finish != spinFinish;
_particleProperties.spin.range.finish = spinFinish;
});
}
float ParticleEffectEntityItem::getSpinFinish() const {
return resultWithReadLock<float>([&] {
return _particleProperties.spin.range.finish;
});
}
void ParticleEffectEntityItem::setSpinSpread(float spinSpread) {
spinSpread = glm::clamp(spinSpread, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.spin.gradient.spread != spinSpread;
_particleProperties.spin.gradient.spread = spinSpread;
});
}
float ParticleEffectEntityItem::getSpinSpread() const {
return resultWithReadLock<float>([&] {
return _particleProperties.spin.gradient.spread;
});
}
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
particle::Properties particleProperties;
withReadLock([&] {
particleProperties = _particleProperties;
});
const float time = particleProperties.lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error
glm::vec3 direction = particleProperties.emission.orientation * Vectors::UNIT_Z;
glm::vec3 velocity = particleProperties.emission.speed.target * direction;
glm::vec3 velocitySpread = particleProperties.emission.speed.spread * direction;
glm::vec3 maxVelocity = glm::abs(velocity) + velocitySpread;
glm::vec3 maxAccleration = glm::abs(particleProperties.emission.acceleration.target) + particleProperties.emission.acceleration.spread;
float maxRadius = particleProperties.radius.gradient.target;
if (!glm::isnan(particleProperties.radius.range.start)) {
maxRadius = glm::max(maxRadius, particleProperties.radius.range.start);
}
if (!glm::isnan(particleProperties.radius.range.finish)) {
maxRadius = glm::max(maxRadius, particleProperties.radius.range.finish);
}
glm::vec3 maxDistance = 0.5f * particleProperties.emission.dimensions + time * maxVelocity + (0.5f * time * time) * maxAccleration + vec3(maxRadius + particleProperties.radius.gradient.spread);
if (isNaN(maxDistance)) {
qCWarning(entities) << "Bad particle data";
return;
}
float maxDistanceValue = glm::compMax(maxDistance);
//times 2 because dimensions are diameters not radii
glm::vec3 dims(2.0f * maxDistanceValue);
EntityItem::setScaledDimensions(dims);
}
EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
withReadLock([&] {
_pulseProperties.getProperties(properties);
});
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(isEmitting, getIsEmitting);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitSpeed, getEmitSpeed);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(speedSpread, getSpeedSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitOrientation, getEmitOrientation);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitDimensions, getEmitDimensions);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRadiusStart, getEmitRadiusStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(polarStart, getPolarStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(polarFinish, getPolarFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(azimuthStart, getAzimuthStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(azimuthFinish, getAzimuthFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(accelerationSpread, getAccelerationSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleSpin, getParticleSpin);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinSpread, getSpinSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinStart, getSpinStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinFinish, getSpinFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotateWithEntity, getRotateWithEntity);
return properties;
}
bool ParticleEffectEntityItem::setSubClassProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
withWriteLock([&] {
bool pulsePropertiesChanged = _pulseProperties.setProperties(properties);
somethingChanged |= pulsePropertiesChanged;
_needsRenderUpdate |= pulsePropertiesChanged;
});
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isEmitting, setIsEmitting);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitSpeed, setEmitSpeed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(speedSpread, setSpeedSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitOrientation, setEmitOrientation);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitDimensions, setEmitDimensions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRadiusStart, setEmitRadiusStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(polarStart, setPolarStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(polarFinish, setPolarFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(azimuthStart, setAzimuthStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(azimuthFinish, setAzimuthFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitAcceleration, setEmitAcceleration);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(accelerationSpread, setAccelerationSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleSpin, setParticleSpin);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinSpread, setSpinSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinStart, setSpinStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinFinish, setSpinFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotateWithEntity, setRotateWithEntity);
return somethingChanged;
}
void ParticleEffectEntityItem::setColor(const glm::u8vec3& value) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.color.gradient.target != glm::vec3(value);
_particleProperties.color.gradient.target = value;
});
}
glm::u8vec3 ParticleEffectEntityItem::getColor() const {
return resultWithReadLock<glm::u8vec3>([&] {
return _particleProperties.color.gradient.target;
});
}
int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
withWriteLock([&] {
int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData,
somethingChanged);
bytesRead += bytesFromPulse;
dataAt += bytesFromPulse;
});
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles);
READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan);
READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting);
READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate);
READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed);
READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread);
READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, quat, setEmitOrientation);
READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions);
READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart);
READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart);
READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish);
READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart);
READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish);
READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius);
READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread);
READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart);
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, u8vec3Color, setColorSpread);
READ_ENTITY_PROPERTY(PROP_COLOR_START, vec3Color, setColorStart);
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, vec3Color, setColorFinish);
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish);
READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
READ_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, float, setParticleSpin);
READ_ENTITY_PROPERTY(PROP_SPIN_SPREAD, float, setSpinSpread);
READ_ENTITY_PROPERTY(PROP_SPIN_START, float, setSpinStart);
READ_ENTITY_PROPERTY(PROP_SPIN_FINISH, float, setSpinFinish);
READ_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, bool, setRotateWithEntity);
return bytesRead;
}
EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_SHAPE_TYPE;
requestedProperties += PROP_COMPOUND_SHAPE_URL;
requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA;
requestedProperties += _pulseProperties.getEntityProperties(params);
requestedProperties += PROP_TEXTURES;
requestedProperties += PROP_MAX_PARTICLES;
requestedProperties += PROP_LIFESPAN;
requestedProperties += PROP_EMITTING_PARTICLES;
requestedProperties += PROP_EMIT_RATE;
requestedProperties += PROP_EMIT_SPEED;
requestedProperties += PROP_SPEED_SPREAD;
requestedProperties += PROP_EMIT_ORIENTATION;
requestedProperties += PROP_EMIT_DIMENSIONS;
requestedProperties += PROP_EMIT_RADIUS_START;
requestedProperties += PROP_POLAR_START;
requestedProperties += PROP_POLAR_FINISH;
requestedProperties += PROP_AZIMUTH_START;
requestedProperties += PROP_AZIMUTH_FINISH;
requestedProperties += PROP_EMIT_ACCELERATION;
requestedProperties += PROP_ACCELERATION_SPREAD;
requestedProperties += PROP_PARTICLE_RADIUS;
requestedProperties += PROP_RADIUS_SPREAD;
requestedProperties += PROP_RADIUS_START;
requestedProperties += PROP_RADIUS_FINISH;
requestedProperties += PROP_COLOR_SPREAD;
requestedProperties += PROP_COLOR_START;
requestedProperties += PROP_COLOR_FINISH;
requestedProperties += PROP_ALPHA_SPREAD;
requestedProperties += PROP_ALPHA_START;
requestedProperties += PROP_ALPHA_FINISH;
requestedProperties += PROP_EMITTER_SHOULD_TRAIL;
requestedProperties += PROP_PARTICLE_SPIN;
requestedProperties += PROP_SPIN_SPREAD;
requestedProperties += PROP_SPIN_START;
requestedProperties += PROP_SPIN_FINISH;
requestedProperties += PROP_PARTICLE_ROTATE_WITH_ENTITY;
return requestedProperties;
}
void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
withReadLock([&] {
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
});
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, getIsEmitting());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_SPEED, getEmitSpeed());
APPEND_ENTITY_PROPERTY(PROP_SPEED_SPREAD, getSpeedSpread());
APPEND_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, getEmitOrientation());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, getEmitDimensions());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, getEmitRadiusStart());
APPEND_ENTITY_PROPERTY(PROP_POLAR_START, getPolarStart());
APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish());
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart());
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish());
APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, getEmitAcceleration());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, getAccelerationSpread());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish());
APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread());
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart());
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish());
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, getParticleSpin());
APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, getSpinSpread());
APPEND_ENTITY_PROPERTY(PROP_SPIN_START, getSpinStart());
APPEND_ENTITY_PROPERTY(PROP_SPIN_FINISH, getSpinFinish());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, getRotateWithEntity());
}
void ParticleEffectEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " color:" <<
_particleProperties.color.gradient.target.r << "," <<
_particleProperties.color.gradient.target.g << "," <<
_particleProperties.color.gradient.target.b;
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}
void ParticleEffectEntityItem::setShapeType(ShapeType type) {
switch (type) {
case SHAPE_TYPE_NONE:
case SHAPE_TYPE_CAPSULE_X:
case SHAPE_TYPE_CAPSULE_Y:
case SHAPE_TYPE_CAPSULE_Z:
case SHAPE_TYPE_HULL:
case SHAPE_TYPE_SIMPLE_HULL:
case SHAPE_TYPE_SIMPLE_COMPOUND:
case SHAPE_TYPE_STATIC_MESH:
// these types are unsupported for ParticleEffectEntity
type = particle::DEFAULT_SHAPE_TYPE;
break;
default:
break;
}
withWriteLock([&] {
_needsRenderUpdate |= _shapeType != type;
_shapeType = type;
});
}
ShapeType ParticleEffectEntityItem::getShapeType() const {
return resultWithReadLock<ShapeType>([&] {
return _shapeType;
});
}
void ParticleEffectEntityItem::setCompoundShapeURL(const QString& compoundShapeURL) {
withWriteLock([&] {
_needsRenderUpdate |= _compoundShapeURL != compoundShapeURL;
_compoundShapeURL = compoundShapeURL;
});
}
QString ParticleEffectEntityItem::getCompoundShapeURL() const {
return resultWithReadLock<QString>([&] {
return _compoundShapeURL;
});
}
void ParticleEffectEntityItem::setIsEmitting(bool isEmitting) {
withWriteLock([&] {
_needsRenderUpdate |= _isEmitting != isEmitting;
_isEmitting = isEmitting;
});
}
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES);
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.maxParticles != maxParticles;
_particleProperties.maxParticles = maxParticles;
});
}
quint32 ParticleEffectEntityItem::getMaxParticles() const {
return resultWithReadLock<quint32>([&] {
return _particleProperties.maxParticles;
});
}
void ParticleEffectEntityItem::setTextures(const QString& textures) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.textures != textures;
_particleProperties.textures = textures;
});
}
QString ParticleEffectEntityItem::getTextures() const {
return resultWithReadLock<QString>([&] {
return _particleProperties.textures;
});
}
void ParticleEffectEntityItem::setColorStart(const vec3& colorStart) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.color.range.start != colorStart;
_particleProperties.color.range.start = colorStart;
});
}
glm::vec3 ParticleEffectEntityItem::getColorStart() const {
return resultWithReadLock<glm::vec3>([&] {
return _particleProperties.color.range.start;
});
}
void ParticleEffectEntityItem::setColorFinish(const vec3& colorFinish) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.color.range.finish != colorFinish;
_particleProperties.color.range.finish = colorFinish;
});
}
glm::vec3 ParticleEffectEntityItem::getColorFinish() const {
return resultWithReadLock<glm::vec3>([&] {
return _particleProperties.color.range.finish;
});
}
void ParticleEffectEntityItem::setColorSpread(const glm::u8vec3& value) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.color.gradient.spread != glm::vec3(value);
_particleProperties.color.gradient.spread = value;
});
}
glm::u8vec3 ParticleEffectEntityItem::getColorSpread() const {
return resultWithReadLock<glm::vec3>([&] {
return _particleProperties.color.gradient.spread;
});
}
void ParticleEffectEntityItem::setEmitterShouldTrail(bool emitterShouldTrail) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.emission.shouldTrail != emitterShouldTrail;
_particleProperties.emission.shouldTrail = emitterShouldTrail;
});
}
void ParticleEffectEntityItem::setRotateWithEntity(bool rotateWithEntity) {
withWriteLock([&] {
_needsRenderUpdate |= _particleProperties.rotateWithEntity != rotateWithEntity;
_particleProperties.rotateWithEntity = rotateWithEntity;
});
}
particle::Properties ParticleEffectEntityItem::getParticleProperties() const {
particle::Properties result;
withReadLock([&] {
result = _particleProperties;
});
// Special case the properties that get treated differently if they're unintialized
if (glm::any(glm::isnan(result.color.range.start))) {
result.color.range.start = getColor();
}
if (glm::any(glm::isnan(result.color.range.finish))) {
result.color.range.finish = getColor();
}
if (glm::isnan(result.alpha.range.start)) {
result.alpha.range.start = getAlpha();
}
if (glm::isnan(result.alpha.range.finish)) {
result.alpha.range.finish = getAlpha();
}
if (glm::isnan(result.radius.range.start)) {
result.radius.range.start = getParticleRadius();
}
if (glm::isnan(result.radius.range.finish)) {
result.radius.range.finish = getParticleRadius();
}
if (glm::isnan(result.spin.range.start)) {
result.spin.range.start = getParticleSpin();
}
if (glm::isnan(result.spin.range.finish)) {
result.spin.range.finish = getParticleSpin();
}
if (!result.valid()) {
qCWarning(entities) << "failed validation";
}
return result;
}
PulsePropertyGroup ParticleEffectEntityItem::getPulseProperties() const {
return resultWithReadLock<PulsePropertyGroup>([&] {
return _pulseProperties;
});
}