working on adding particle shape types

This commit is contained in:
SamGondelman 2019-03-18 12:05:17 -07:00
parent 840f3a3a2e
commit ea50133146
7 changed files with 138 additions and 55 deletions

View file

@ -307,10 +307,6 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
} }
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
// because the caching system only allows one Geometry per url, and because this url might also be used
// as a visual model, we need to change this url in some way. We add a "collision-hull" query-arg so it
// will end up in a different hash-key in ResourceCache. TODO: It would be better to use the same URL and
// parse it twice.
auto currentCompoundShapeURL = getCompoundShapeURL(); auto currentCompoundShapeURL = getCompoundShapeURL();
ModelEntityItem::setCompoundShapeURL(url); ModelEntityItem::setCompoundShapeURL(url);
if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) { if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) {

View file

@ -9,13 +9,11 @@
// //
#include "RenderableParticleEffectEntityItem.h" #include "RenderableParticleEffectEntityItem.h"
#include <StencilMaskPass.h> #include <StencilMaskPass.h>
#include <GeometryCache.h> #include <GeometryCache.h>
#include <shaders/Shaders.h> #include <shaders/Shaders.h>
using namespace render; using namespace render;
using namespace render::entities; using namespace render::entities;
@ -79,6 +77,14 @@ bool ParticleEffectEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedE
return true; return true;
} }
if (_shapeType != entity->getShapeType()) {
return true;
}
if (_compoundShapeURL != entity->getCompoundShapeURL()) {
return true;
}
return false; return false;
} }
@ -87,11 +93,17 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
if (!newParticleProperties.valid()) { if (!newParticleProperties.valid()) {
qCWarning(entitiesrenderer) << "Bad particle properties"; qCWarning(entitiesrenderer) << "Bad particle properties";
} }
if (resultWithReadLock<bool>([&]{ return _particleProperties != newParticleProperties; })) { if (resultWithReadLock<bool>([&] { return _particleProperties != newParticleProperties; })) {
_timeUntilNextEmit = 0; _timeUntilNextEmit = 0;
withWriteLock([&]{ withWriteLock([&] {
_particleProperties = newParticleProperties; _particleProperties = newParticleProperties;
_shapeType = entity->getShapeType();
QString compoundShapeURL = entity->getCompoundShapeURL();
if (_compoundShapeURL != compoundShapeURL) {
_compoundShapeURL = compoundShapeURL;
fetchGeometryResource();
}
if (!_prevEmitterShouldTrailInitialized) { if (!_prevEmitterShouldTrailInitialized) {
_prevEmitterShouldTrailInitialized = true; _prevEmitterShouldTrailInitialized = true;
_prevEmitterShouldTrail = _particleProperties.emission.shouldTrail; _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
@ -104,10 +116,10 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
}); });
_emitting = entity->getIsEmitting(); _emitting = entity->getIsEmitting();
bool textureEmpty = resultWithReadLock<bool>([&]{ return _particleProperties.textures.isEmpty(); }); bool textureEmpty = resultWithReadLock<bool>([&] { return _particleProperties.textures.isEmpty(); });
if (textureEmpty) { if (textureEmpty) {
if (_networkTexture) { if (_networkTexture) {
withWriteLock([&] { withWriteLock([&] {
_networkTexture.reset(); _networkTexture.reset();
}); });
} }
@ -116,11 +128,11 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
entity->setVisuallyReady(true); entity->setVisuallyReady(true);
}); });
} else { } else {
bool textureNeedsUpdate = resultWithReadLock<bool>([&]{ bool textureNeedsUpdate = resultWithReadLock<bool>([&] {
return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures); return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures);
}); });
if (textureNeedsUpdate) { if (textureNeedsUpdate) {
withWriteLock([&] { withWriteLock([&] {
_networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures); _networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures);
}); });
} }
@ -144,7 +156,7 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
// Fill in Uniforms structure // Fill in Uniforms structure
ParticleUniforms particleUniforms; ParticleUniforms particleUniforms;
withReadLock([&]{ withReadLock([&] {
particleUniforms.radius.start = _particleProperties.radius.range.start; particleUniforms.radius.start = _particleProperties.radius.range.start;
particleUniforms.radius.middle = _particleProperties.radius.gradient.target; particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
particleUniforms.radius.finish = _particleProperties.radius.range.finish; particleUniforms.radius.finish = _particleProperties.radius.range.finish;
@ -183,7 +195,8 @@ Item::Bound ParticleEffectEntityRenderer::getBound() {
static const size_t VERTEX_PER_PARTICLE = 4; static const size_t VERTEX_PER_PARTICLE = 4;
ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties) { ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties,
const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource) {
CpuParticle particle; CpuParticle particle;
const auto& accelerationSpread = particleProperties.emission.acceleration.spread; const auto& accelerationSpread = particleProperties.emission.acceleration.spread;
@ -221,33 +234,53 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
float azimuth; float azimuth;
if (azimuthFinish >= azimuthStart) { if (azimuthFinish >= azimuthStart) {
azimuth = azimuthStart + (azimuthFinish - azimuthStart) * randFloat(); azimuth = azimuthStart + (azimuthFinish - azimuthStart) * randFloat();
} else { } else {
azimuth = azimuthStart + (TWO_PI + azimuthFinish - azimuthStart) * randFloat(); azimuth = azimuthStart + (TWO_PI + azimuthFinish - azimuthStart) * randFloat();
} }
if (emitDimensions == Vectors::ZERO) { if (emitDimensions == Vectors::ZERO || shapeType == ShapeType::SHAPE_TYPE_NONE) {
// Point // Point
emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Vectors::UNIT_Z; emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Vectors::UNIT_Z;
} else { } else {
// Ellipsoid glm::vec3 emitPosition;
float radiusScale = 1.0f; switch (shapeType) {
if (emitRadiusStart < 1.0f) { case ShapeType::SHAPE_TYPE_BOX:
float randRadius =
emitRadiusStart + randFloatInRange(0.0f, particle::MAXIMUM_EMIT_RADIUS_START - emitRadiusStart); case ShapeType::SHAPE_TYPE_CAPSULE_X:
radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f); case ShapeType::SHAPE_TYPE_CAPSULE_Y:
case ShapeType::SHAPE_TYPE_CAPSULE_Z:
case ShapeType::SHAPE_TYPE_CYLINDER_X:
case ShapeType::SHAPE_TYPE_CYLINDER_Y:
case ShapeType::SHAPE_TYPE_CYLINDER_Z:
case ShapeType::SHAPE_TYPE_CIRCLE:
case ShapeType::SHAPE_TYPE_PLANE:
case ShapeType::SHAPE_TYPE_COMPOUND:
case ShapeType::SHAPE_TYPE_SPHERE:
case ShapeType::SHAPE_TYPE_ELLIPSOID:
default: {
float radiusScale = 1.0f;
if (emitRadiusStart < 1.0f) {
float randRadius =
emitRadiusStart + randFloatInRange(0.0f, particle::MAXIMUM_EMIT_RADIUS_START - emitRadiusStart);
radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f);
}
glm::vec3 radii = radiusScale * 0.5f * emitDimensions;
float x = radii.x * glm::cos(elevation) * glm::cos(azimuth);
float y = radii.y * glm::cos(elevation) * glm::sin(azimuth);
float z = radii.z * glm::sin(elevation);
emitPosition = glm::vec3(x, y, z);
emitDirection = glm::normalize(glm::vec3(radii.x > 0.0f ? x / (radii.x * radii.x) : 0.0f,
radii.y > 0.0f ? y / (radii.y * radii.y) : 0.0f,
radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f));
}
} }
glm::vec3 radii = radiusScale * 0.5f * emitDimensions;
float x = radii.x * glm::cos(elevation) * glm::cos(azimuth);
float y = radii.y * glm::cos(elevation) * glm::sin(azimuth);
float z = radii.z * glm::sin(elevation);
glm::vec3 emitPosition = glm::vec3(x, y, z);
emitDirection = glm::normalize(glm::vec3(
radii.x > 0.0f ? x / (radii.x * radii.x) : 0.0f,
radii.y > 0.0f ? y / (radii.y * radii.y) : 0.0f,
radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f
));
particle.relativePosition += emitOrientation * emitPosition; particle.relativePosition += emitOrientation * emitPosition;
} }
} }
@ -267,20 +300,25 @@ void ParticleEffectEntityRenderer::stepSimulation() {
const auto now = usecTimestampNow(); const auto now = usecTimestampNow();
const auto interval = std::min<uint64_t>(USECS_PER_SECOND / 60, now - _lastSimulated); const auto interval = std::min<uint64_t>(USECS_PER_SECOND / 60, now - _lastSimulated);
_lastSimulated = now; _lastSimulated = now;
particle::Properties particleProperties; particle::Properties particleProperties;
withReadLock([&]{ ShapeType shapeType;
GeometryResource::Pointer geometryResource;
withReadLock([&] {
particleProperties = _particleProperties; particleProperties = _particleProperties;
shapeType = _shapeType;
geometryResource = _geometryResource;
}); });
const auto& modelTransform = getModelTransform(); const auto& modelTransform = getModelTransform();
if (_emitting && particleProperties.emitting()) { if (_emitting && particleProperties.emitting() &&
(_shapeType != ShapeType::SHAPE_TYPE_COMPOUND || (_geometryResource && _geometryResource->isLoaded()))) {
uint64_t emitInterval = particleProperties.emitIntervalUsecs(); uint64_t emitInterval = particleProperties.emitIntervalUsecs();
if (emitInterval > 0 && interval >= _timeUntilNextEmit) { if (emitInterval > 0 && interval >= _timeUntilNextEmit) {
auto timeRemaining = interval; auto timeRemaining = interval;
while (timeRemaining > _timeUntilNextEmit) { while (timeRemaining > _timeUntilNextEmit) {
// emit particle // emit particle
_cpuParticles.push_back(createParticle(now, modelTransform, particleProperties)); _cpuParticles.push_back(createParticle(now, modelTransform, particleProperties, shapeType, geometryResource));
_timeUntilNextEmit = emitInterval; _timeUntilNextEmit = emitInterval;
if (emitInterval < timeRemaining) { if (emitInterval < timeRemaining) {
timeRemaining -= emitInterval; timeRemaining -= emitInterval;
@ -297,7 +335,7 @@ void ParticleEffectEntityRenderer::stepSimulation() {
} }
const float deltaTime = (float)interval / (float)USECS_PER_SECOND; const float deltaTime = (float)interval / (float)USECS_PER_SECOND;
// update the particles // update the particles
for (auto& particle : _cpuParticles) { for (auto& particle : _cpuParticles) {
if (_prevEmitterShouldTrail != particleProperties.emission.shouldTrail) { if (_prevEmitterShouldTrail != particleProperties.emission.shouldTrail) {
if (_prevEmitterShouldTrail) { if (_prevEmitterShouldTrail) {
@ -313,7 +351,7 @@ void ParticleEffectEntityRenderer::stepSimulation() {
static GpuParticles gpuParticles; static GpuParticles gpuParticles;
gpuParticles.clear(); gpuParticles.clear();
gpuParticles.reserve(_cpuParticles.size()); // Reserve space gpuParticles.reserve(_cpuParticles.size()); // Reserve space
std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [&particleProperties, &modelTransform](const CpuParticle& particle) { std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [&particleProperties, &modelTransform] (const CpuParticle& particle) {
glm::vec3 position = particle.relativePosition + (particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation()); glm::vec3 position = particle.relativePosition + (particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
return GpuParticle(position, glm::vec2(particle.lifetime, particle.seed)); return GpuParticle(position, glm::vec2(particle.lifetime, particle.seed));
}); });
@ -358,3 +396,12 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
auto numParticles = _particleBuffer->getSize() / sizeof(GpuParticle); auto numParticles = _particleBuffer->getSize() / sizeof(GpuParticle);
batch.drawInstanced((gpu::uint32)numParticles, gpu::TRIANGLE_STRIP, (gpu::uint32)VERTEX_PER_PARTICLE); batch.drawInstanced((gpu::uint32)numParticles, gpu::TRIANGLE_STRIP, (gpu::uint32)VERTEX_PER_PARTICLE);
} }
void ParticleEffectEntityRenderer::fetchGeometryResource() {
QUrl hullURL(_compoundShapeURL);
if (hullURL.isEmpty()) {
_geometryResource.reset();
} else {
_geometryResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL);
}
}

View file

@ -81,7 +81,8 @@ private:
glm::vec2 spare; glm::vec2 spare;
}; };
static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties); static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties,
const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource);
void stepSimulation(); void stepSimulation();
particle::Properties _particleProperties; particle::Properties _particleProperties;
@ -90,11 +91,16 @@ private:
CpuParticles _cpuParticles; CpuParticles _cpuParticles;
bool _emitting { false }; bool _emitting { false };
uint64_t _timeUntilNextEmit { 0 }; uint64_t _timeUntilNextEmit { 0 };
BufferPointer _particleBuffer{ std::make_shared<Buffer>() }; BufferPointer _particleBuffer { std::make_shared<Buffer>() };
BufferView _uniformBuffer; BufferView _uniformBuffer;
quint64 _lastSimulated { 0 }; quint64 _lastSimulated { 0 };
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
ShapeType _shapeType;
QString _compoundShapeURL;
void fetchGeometryResource();
GeometryResource::Pointer _geometryResource;
NetworkTexturePointer _networkTexture; NetworkTexturePointer _networkTexture;
ScenePointer _scene; ScenePointer _scene;

View file

@ -1114,23 +1114,28 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* default, particles emit along the entity's local z-axis, and <code>azimuthStart</code> and <code>azimuthFinish</code> * default, particles emit along the entity's local z-axis, and <code>azimuthStart</code> and <code>azimuthFinish</code>
* are relative to the entity's local x-axis. The default value is a rotation of -90 degrees about the local x-axis, i.e., * are relative to the entity's local x-axis. The default value is a rotation of -90 degrees about the local x-axis, i.e.,
* the particles emit vertically. * the particles emit vertically.
* @property {Vec3} emitDimensions=0,0,0 - The dimensions of the ellipsoid from which particles are emitted. * @property {Vec3} emitDimensions=0,0,0 - The dimensions of the shape from which particles are emitted. The shape is specified with
* @property {number} emitRadiusStart=1 - The starting radius within the ellipsoid at which particles start being emitted; * <code>shapeType</code>.
* range <code>0.0</code> &ndash; <code>1.0</code> for the ellipsoid center to the ellipsoid surface, respectively. * @property {number} emitRadiusStart=1 - The starting radius within the shape at which particles start being emitted;
* Particles are emitted from the portion of the ellipsoid that lies between <code>emitRadiusStart</code> and the * range <code>0.0</code> &ndash; <code>1.0</code> for the center to the surface, respectively.
* ellipsoid's surface. * Particles are emitted from the portion of the shape that lies between <code>emitRadiusStart</code> and the
* shape's surface.
* @property {number} polarStart=0 - The angle in radians from the entity's local z-axis at which particles start being emitted * @property {number} polarStart=0 - The angle in radians from the entity's local z-axis at which particles start being emitted
* within the ellipsoid; range <code>0</code> &ndash; <code>Math.PI</code>. Particles are emitted from the portion of the * within the ellipsoid; range <code>0</code> &ndash; <code>Math.PI</code>. Particles are emitted from the portion of the
* ellipsoid that lies between <code>polarStart<code> and <code>polarFinish</code>. * ellipsoid that lies between <code>polarStart<code> and <code>polarFinish</code>. Only used if <code>shapeType</code> is
* <code>ellipsoid</code>.
* @property {number} polarFinish=0 - The angle in radians from the entity's local z-axis at which particles stop being emitted * @property {number} polarFinish=0 - The angle in radians from the entity's local z-axis at which particles stop being emitted
* within the ellipsoid; range <code>0</code> &ndash; <code>Math.PI</code>. Particles are emitted from the portion of the * within the ellipsoid; range <code>0</code> &ndash; <code>Math.PI</code>. Particles are emitted from the portion of the
* ellipsoid that lies between <code>polarStart<code> and <code>polarFinish</code>. * ellipsoid that lies between <code>polarStart<code> and <code>polarFinish</code>. Only used if <code>shapeType</code> is
* <code>ellipsoid</code>.
* @property {number} azimuthStart=-Math.PI - The angle in radians from the entity's local x-axis about the entity's local * @property {number} azimuthStart=-Math.PI - The angle in radians from the entity's local x-axis about the entity's local
* z-axis at which particles start being emitted; range <code>-Math.PI</code> &ndash; <code>Math.PI</code>. Particles are * z-axis at which particles start being emitted; range <code>-Math.PI</code> &ndash; <code>Math.PI</code>. Particles are
* emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>. * emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>.
* Only used if <code>shapeType</code> is <code>ellipsoid</code>.
* @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local * @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local
* z-axis at which particles stop being emitted; range <code>-Math.PI</code> &ndash; <code>Math.PI</code>. Particles are * z-axis at which particles stop being emitted; range <code>-Math.PI</code> &ndash; <code>Math.PI</code>. Particles are
* emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>. * emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>.
* Only used if <code>shapeType</code> is <code>ellipsoid</code>.
* *
* @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency, * @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency,
* use PNG format. * use PNG format.
@ -1170,7 +1175,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* up in the world. If true, they will point towards the entity's up vector, based on its orientation. * up in the world. If true, they will point towards the entity's up vector, based on its orientation.
* @property {Entities.Pulse} pulse - The pulse-related properties. Deprecated. * @property {Entities.Pulse} pulse - The pulse-related properties. Deprecated.
* *
* @property {ShapeType} shapeType="none" - <em>Currently not used.</em> <em>Read-only.</em> * @property {ShapeType} shapeType="ellipsoid" - The shape of the collision hull used if collisions are enabled.
* @property {string} compoundShapeURL="" - The model file to use for the compound shape if <code>shapeType</code> is
* <code>"compound"</code>.
* *
* @example <caption>Create a ball of green smoke.</caption> * @example <caption>Create a ball of green smoke.</caption>
* particles = Entities.addEntity({ * particles = Entities.addEntity({
@ -1658,6 +1665,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
// Particles only // Particles only
if (_type == EntityTypes::ParticleEffect) { if (_type == EntityTypes::ParticleEffect) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
@ -3104,6 +3112,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
if (properties.getType() == EntityTypes::ParticleEffect) { if (properties.getType() == EntityTypes::ParticleEffect) {
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType()));
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
_staticPulse.setProperties(properties); _staticPulse.setProperties(properties);
@ -3584,6 +3593,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
if (properties.getType() == EntityTypes::ParticleEffect) { if (properties.getType() == EntityTypes::ParticleEffect) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);

View file

@ -410,6 +410,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropert
EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class 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(shapeType, getShapeType);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
withReadLock([&] { withReadLock([&] {
@ -464,6 +465,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); 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(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
withWriteLock([&] { withWriteLock([&] {
@ -540,6 +542,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
const unsigned char* dataAt = data; const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); 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_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
withWriteLock([&] { withWriteLock([&] {
@ -598,6 +601,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_SHAPE_TYPE;
requestedProperties += PROP_COMPOUND_SHAPE_URL;
requestedProperties += PROP_COLOR; requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA; requestedProperties += PROP_ALPHA;
requestedProperties += _pulseProperties.getEntityProperties(params); requestedProperties += _pulseProperties.getEntityProperties(params);
@ -656,6 +660,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
bool successPropertyFits = true; bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); 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_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
withReadLock([&] { withReadLock([&] {
@ -726,6 +731,24 @@ void ParticleEffectEntityItem::setShapeType(ShapeType type) {
}); });
} }
ShapeType ParticleEffectEntityItem::getShapeType() const {
return resultWithReadLock<ShapeType>([&] {
return _shapeType;
});
}
void ParticleEffectEntityItem::setCompoundShapeURL(const QString& compoundShapeURL) {
withWriteLock([&] {
_compoundShapeURL = compoundShapeURL;
});
}
QString ParticleEffectEntityItem::getCompoundShapeURL() const {
return resultWithReadLock<QString>([&] {
return _compoundShapeURL;
});
}
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
withWriteLock([&] { withWriteLock([&] {
_particleProperties.maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES); _particleProperties.maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES);

View file

@ -79,6 +79,7 @@ namespace particle {
static const QString DEFAULT_TEXTURES = ""; static const QString DEFAULT_TEXTURES = "";
static const bool DEFAULT_EMITTER_SHOULD_TRAIL = false; static const bool DEFAULT_EMITTER_SHOULD_TRAIL = false;
static const bool DEFAULT_ROTATE_WITH_ENTITY = false; static const bool DEFAULT_ROTATE_WITH_ENTITY = false;
static const ShapeType DEFAULT_SHAPE_TYPE = ShapeType::SHAPE_TYPE_ELLIPSOID;
template <typename T> template <typename T>
struct Range { struct Range {
@ -255,7 +256,10 @@ public:
float getAlphaSpread() const { return _particleProperties.alpha.gradient.spread; } float getAlphaSpread() const { return _particleProperties.alpha.gradient.spread; }
void setShapeType(ShapeType type) override; void setShapeType(ShapeType type) override;
virtual ShapeType getShapeType() const override { return _shapeType; } virtual ShapeType getShapeType() const override;
QString getCompoundShapeURL() const;
virtual void setCompoundShapeURL(const QString& url);
virtual void debugDump() const override; virtual void debugDump() const override;
@ -349,7 +353,8 @@ protected:
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
bool _isEmitting { true }; bool _isEmitting { true };
ShapeType _shapeType { SHAPE_TYPE_NONE }; ShapeType _shapeType{ particle::DEFAULT_SHAPE_TYPE };
QString _compoundShapeURL { "" };
}; };
#endif // hifi_ParticleEffectEntityItem_h #endif // hifi_ParticleEffectEntityItem_h

View file

@ -13,7 +13,6 @@
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include <QDebug> #include <QDebug>
#include <QUrlQuery>
#include <ByteCountCoding.h> #include <ByteCountCoding.h>
@ -463,9 +462,6 @@ void ZoneEntityItem::fetchCollisionGeometryResource() {
if (hullURL.isEmpty()) { if (hullURL.isEmpty()) {
_shapeResource.reset(); _shapeResource.reset();
} else { } else {
QUrlQuery queryArgs(hullURL);
queryArgs.addQueryItem("collision-hull", "");
hullURL.setQuery(queryArgs);
_shapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL); _shapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL);
} }
} }