From 45ff118249e1f60eb7b538d00b38447d5bbc6ec4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Sep 2015 12:43:36 -0700 Subject: [PATCH 01/21] Add new radiusSpread entity particle property --- .../RenderableParticleEffectEntityItem.cpp | 47 ++++++++++++------- .../entities/src/EntityItemProperties.cpp | 8 +++- libraries/entities/src/EntityItemProperties.h | 2 + libraries/entities/src/EntityPropertyFlags.h | 1 + .../entities/src/ParticleEffectEntityItem.cpp | 28 ++++++++--- .../entities/src/ParticleEffectEntityItem.h | 10 ++-- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + 8 files changed, 69 insertions(+), 30 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f683083ed1..146dea8ea0 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -168,52 +168,63 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) { updateRenderItem(); } -static glm::vec3 zSortAxis; -static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) { - return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis); -} - uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24); } +class PositionAndRadius { +public: + PositionAndRadius(glm::vec3 position, float radius) : position(position), radius(radius) { } + + glm::vec3 position; + float radius; +}; + +static glm::vec3 zSortAxis; +static bool zSort(const PositionAndRadius& rhs, const PositionAndRadius& lhs) { + return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis); +} + void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; } - float particleRadius = getParticleRadius(); + //float particleRadius = _particleRadiuses[i]; auto xcolor = getXColor(); auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); - // make a copy of each particle position - std::vector positions; - positions.reserve(getLivingParticleCount()); + // make a copy of each particle position and radius + std::vector positionsAndRadiuses; + positionsAndRadiuses.reserve(getLivingParticleCount()); for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { - positions.push_back(_particlePositions[i]); + positionsAndRadiuses.push_back(PositionAndRadius(_particlePositions[i], _particleRadiuses[i])); } // sort particles back to front // NOTE: this is view frustum might be one frame out of date. auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum(); ::zSortAxis = frustum->getDirection(); - qSort(positions.begin(), positions.end(), zSort); + qSort(positionsAndRadiuses.begin(), positionsAndRadiuses.end(), zSort); // allocate vertices _vertices.clear(); // build vertices from particle positions - const glm::vec3 upOffset = frustum->getUp() * particleRadius; - const glm::vec3 rightOffset = frustum->getRight() * particleRadius; - for (auto&& pos : positions) { + const glm::vec3 up = frustum->getUp(); + const glm::vec3 right = frustum->getRight(); + for (auto&& particle : positionsAndRadiuses) { + glm::vec3 upOffset = up * particle.radius; + glm::vec3 rightOffset = right * particle.radius; // generate corners of quad aligned to face the camera. - _vertices.emplace_back(pos + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba); - _vertices.emplace_back(pos - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba); - _vertices.emplace_back(pos - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba); - _vertices.emplace_back(pos + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba); + _vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba); + _vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba); + _vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba); + _vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba); } + render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { // update vertex buffer diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index c6c02f248c..e7204e33d8 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -89,6 +89,7 @@ CONSTRUCT_PROPERTY(velocitySpread, ParticleEffectEntityItem::DEFAULT_VELOCITY_SP CONSTRUCT_PROPERTY(emitAcceleration, ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION), CONSTRUCT_PROPERTY(accelerationSpread, ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), +CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD), CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR), CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY), @@ -355,6 +356,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration); CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); + CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); CHECK_PROPERTY_CHANGE(PROP_NAME, name); CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor); @@ -458,6 +460,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration); COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); + COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); COPY_PROPERTY_TO_QSCRIPTVALUE(name); COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL); @@ -579,6 +582,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration); COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius); + COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID); COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL); @@ -821,7 +825,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius()); - + APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); } if (properties.getType() == EntityTypes::Zone) { @@ -1091,6 +1095,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); } if (properties.getType() == EntityTypes::Zone) { @@ -1223,6 +1228,7 @@ void EntityItemProperties::markAllChanged() { _emitAccelerationChanged = true; _accelerationSpreadChanged = true; _particleRadiusChanged = true; + _radiusSpreadChanged = true; _marketplaceIDChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6d95faa9b1..0c4d963fc5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -136,6 +136,7 @@ public: DEFINE_PROPERTY(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3); DEFINE_PROPERTY(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); + DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); @@ -316,6 +317,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index abb8241d8f..8d1ad12a8d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -138,6 +138,7 @@ enum EntityPropertyList { // used by particles PROP_VELOCITY_SPREAD, PROP_ACCELERATION_SPREAD, + PROP_RADIUS_SPREAD, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 7dab825adc..202bb82051 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -54,6 +54,7 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_VELOCITY_SPREAD(3.0f, 0.0f, 3. const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f); const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f); const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f; +const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; @@ -72,6 +73,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _emitAcceleration(DEFAULT_EMIT_ACCELERATION), _accelerationSpread(DEFAULT_ACCELERATION_SPREAD), _particleRadius(DEFAULT_PARTICLE_RADIUS), + _radiusSpread(DEFAULT_RADIUS_SPREAD), _lastAnimated(usecTimestampNow()), _animationLoop(), _animationSettings(), @@ -82,6 +84,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleAccelerations(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), + _particleRadiuses(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _timeUntilNextEmit(0.0f), _particleHeadIndex(0), _particleTailIndex(0), @@ -111,7 +114,6 @@ void ParticleEffectEntityItem::setVelocitySpread(const glm::vec3& velocitySpread computeAndUpdateDimensions(); } - void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) { _emitAcceleration = emitAcceleration; computeAndUpdateDimensions(); @@ -126,6 +128,10 @@ void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } +void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) { + _radiusSpread = radiusSpread; +} + void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error @@ -163,9 +169,9 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitVelocity, getEmitVelocity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration); COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); return properties; @@ -185,11 +191,12 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitVelocity, setEmitVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread); 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(textures, setTextures); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread); if (somethingChanged) { bool wantDebug = false; @@ -257,6 +264,10 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); } + if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_SPREAD) { + READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); + } + return bytesRead; } @@ -280,6 +291,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_PARTICLE_RADIUS; requestedProperties += PROP_TEXTURES; requestedProperties += PROP_VELOCITY_SPREAD; + requestedProperties += PROP_RADIUS_SPREAD; return requestedProperties; } @@ -308,6 +320,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY_SPREAD, getVelocitySpread()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread()); } bool ParticleEffectEntityItem::isAnimatingSomething() const { @@ -514,7 +527,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } } - // emit new particles, but only if animaiton is playing + // emit new particles, but only if animation is playing if (getAnimationIsPlaying()) { float timeLeftInFrame = deltaTime; @@ -527,12 +540,12 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { quint32 i = _particleTailIndex; _particleLifetimes[i] = _lifespan; - + _particleRadiuses[i] = _particleRadius + (2.0f * randFloat() - 1) * _radiusSpread; + glm::vec3 spreadOffset; spreadOffset.x = -_velocitySpread.x + randFloat() * (_velocitySpread.x * 2.0f); spreadOffset.y = -_velocitySpread.y + randFloat() * (_velocitySpread.y * 2.0f); spreadOffset.z = -_velocitySpread.z + randFloat() * (_velocitySpread.z * 2.0f); - // set initial conditions _particlePositions[i] = getPosition(); @@ -571,8 +584,9 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _particleLifetimes.resize(_maxParticles); _particlePositions.resize(_maxParticles); _particleVelocities.resize(_maxParticles); + _particleRadiuses.resize(_maxParticles); - // effectivly clear all particles and start emitting new ones from scratch. + // effectively clear all particles and start emitting new ones from scratch. _particleHeadIndex = 0; _particleTailIndex = 0; _timeUntilNextEmit = 0.0f; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 4ed9216e85..844348a667 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -102,12 +102,10 @@ public: void setEmitVelocity(const glm::vec3& emitVelocity); const glm::vec3& getEmitVelocity() const { return _emitVelocity; } - static const glm::vec3 DEFAULT_VELOCITY_SPREAD; void setVelocitySpread(const glm::vec3& velocitySpread); const glm::vec3& getVelocitySpread() const { return _velocitySpread; } - static const glm::vec3 DEFAULT_EMIT_ACCELERATION; void setEmitAcceleration(const glm::vec3& emitAcceleration); const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; } @@ -119,7 +117,11 @@ public: static const float DEFAULT_PARTICLE_RADIUS; void setParticleRadius(float particleRadius); float getParticleRadius() const { return _particleRadius; } - + + static const float DEFAULT_RADIUS_SPREAD; + void setRadiusSpread(float radiusSpread); + float getRadiusSpread() const { return _radiusSpread; } + void computeAndUpdateDimensions(); @@ -155,6 +157,7 @@ protected: glm::vec3 _emitAcceleration; glm::vec3 _accelerationSpread; float _particleRadius; + float _radiusSpread; quint64 _lastAnimated; AnimationLoop _animationLoop; QString _animationSettings; @@ -167,6 +170,7 @@ protected: QVector _particlePositions; QVector _particleVelocities; QVector _particleAccelerations; + QVector _particleRadiuses; float _timeUntilNextEmit; // particle arrays are a ring buffer, use these indicies diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index ac72f1bd68..da84a7cec8 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_PARTICLE_MODIFICATIONS; + return VERSION_ENTITIES_PARTICLE_RADIUS_SPREAD; case AvatarData: return 13; default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index fa6178b627..ce58273f43 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -144,5 +144,6 @@ const PacketVersion VERSION_POLYVOX_TEXTURES = 36; const PacketVersion VERSION_ENTITIES_POLYLINE = 37; const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39; +const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_SPREAD = 40; #endif // hifi_PacketHeaders_h \ No newline at end of file From 2bc2582797de5d8ef4a0bc8daceb902b53282bf4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Sep 2015 12:44:13 -0700 Subject: [PATCH 02/21] Fix missing entity property gets for velocity and acceleration spread --- libraries/entities/src/ParticleEffectEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 202bb82051..da19f64361 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -169,7 +169,9 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitVelocity, getEmitVelocity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocitySpread, getVelocitySpread); 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(textures, getTextures); From 341e1dcf684f88c6ce203684c61f0f4d5c136c2b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Sep 2015 12:44:29 -0700 Subject: [PATCH 03/21] Add particleTest.js script to demo / test entity particle properties --- examples/example/entities/particlesTest.js | 117 +++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 examples/example/entities/particlesTest.js diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js new file mode 100644 index 0000000000..f2c80b6895 --- /dev/null +++ b/examples/example/entities/particlesTest.js @@ -0,0 +1,117 @@ +// +// particlesTest.js +// examples/example/entities +// +// Created by David Rowe on 2 Sep 2015. +// Copyright 2015 High Fidelity, Inc. +// +// Click on the box entity to display different particle effects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function () { + var box, + particles, + particleExample = -1, + NUM_PARTICLE_EXAMPLES = 4; + + function onClickDownOnEntity(entityID) { + if (entityID === box || entityID === particles) { + particleExample = (particleExample + 1) % NUM_PARTICLE_EXAMPLES; + + switch (particleExample) { + case 0: + print("Simple animation"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + radiusSpread: 0.0, + animationIsPlaying: true + }); + break; + case 1: + print("Velocity spread"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.1, y: 0.0, z: 0.1 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + radiusSpread: 0.0, + animationIsPlaying: true + }); + break; + case 2: + print("Acceleration spread"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 }, + radiusSpread: 0.0, + animationIsPlaying: true + }); + break; + case 3: + print("Radius spread"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + radiusSpread: 0.035, + animationIsPlaying: true + }); + break; + } + } + } + + function setUp() { + var spawnPoint = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation()))), + animation = { + fps: 30, + frameIndex: 0, + running: true, + firstFrame: 0, + lastFrame: 30, + loop: true + }; + + box = Entities.addEntity({ + type: "Box", + position: spawnPoint, + dimensions: { x: 0.3, y: 0.3, z: 0.3 }, + color: { red: 128, green: 128, blue: 128 }, + lifetime: 3600 // 1 hour; just in case + }); + + particles = Entities.addEntity({ + type: "ParticleEffect", + position: spawnPoint, + particleRadius: 0.04, + particleRadiusSpread: 0.0, + emitRate: 2.0, + emitVelocity: { x: 0.0, y: 1.0, z: 0.0 }, + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + emitAcceleration: { x: 0.0, y: -0.3, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png", + color: { red: 255, green: 255, blue: 255 }, + lifespan: 5.0, + visible: true, + locked: false, + animationSettings: animation, + animationIsPlaying: false, + lifetime: 3600 // 1 hour; just in case + }); + + Entities.clickDownOnEntity.connect(onClickDownOnEntity); + + print("Click on the box to cycle through particle examples"); + } + + function tearDown() { + Entities.clickDownOnEntity.disconnect(onClickDownOnEntity); + Entities.deleteEntity(particles); + Entities.deleteEntity(box); + } + + setUp(); + Script.scriptEnding.connect(tearDown); +}()); \ No newline at end of file From c910da7179ae225a1964588a1f50451db12ad924 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 4 Sep 2015 12:27:18 -0700 Subject: [PATCH 04/21] Add radiusStart and radiusFinish entity particle properties --- examples/example/entities/particlesTest.js | 28 ++++++++- .../RenderableParticleEffectEntityItem.cpp | 4 +- .../entities/src/EntityItemProperties.cpp | 14 +++++ libraries/entities/src/EntityItemProperties.h | 4 ++ libraries/entities/src/EntityPropertyFlags.h | 2 + .../entities/src/ParticleEffectEntityItem.cpp | 62 ++++++++++++++----- .../entities/src/ParticleEffectEntityItem.h | 28 +++++++-- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 2 +- 9 files changed, 120 insertions(+), 26 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index f2c80b6895..e23e64677f 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -15,7 +15,8 @@ var box, particles, particleExample = -1, - NUM_PARTICLE_EXAMPLES = 4; + NUM_PARTICLE_EXAMPLES = 6, + PARTICLE_RADIUS = 0.04; function onClickDownOnEntity(entityID) { if (entityID === box || entityID === particles) { @@ -58,6 +59,27 @@ animationIsPlaying: true }); break; + case 4: + print("Radius start and finish"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + radiusStart: 0.0, + radiusFinish: 0.0, + radiusSpread: 0.0, + animationIsPlaying: true + }); + break; + case 5: + print("Stop animation"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + radiusStart: PARTICLE_RADIUS, + radiusFinish: PARTICLE_RADIUS, + animationIsPlaying: false + }); + break; } } } @@ -84,8 +106,8 @@ particles = Entities.addEntity({ type: "ParticleEffect", position: spawnPoint, - particleRadius: 0.04, - particleRadiusSpread: 0.0, + particleRadius: PARTICLE_RADIUS, + radiusSpread: 0.0, emitRate: 2.0, emitVelocity: { x: 0.0, y: 1.0, z: 0.0 }, velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 146dea8ea0..424ea2b810 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -190,7 +190,6 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { return; } - //float particleRadius = _particleRadiuses[i]; auto xcolor = getXColor(); auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); @@ -211,7 +210,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // allocate vertices _vertices.clear(); - // build vertices from particle positions + // build vertices from particle positions and radiuses const glm::vec3 up = frustum->getUp(); const glm::vec3 right = frustum->getRight(); for (auto&& particle : positionsAndRadiuses) { @@ -224,7 +223,6 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { _vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba); } - render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { // update vertex buffer diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index e7204e33d8..0d7d7852f2 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -89,6 +89,8 @@ CONSTRUCT_PROPERTY(velocitySpread, ParticleEffectEntityItem::DEFAULT_VELOCITY_SP CONSTRUCT_PROPERTY(emitAcceleration, ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION), CONSTRUCT_PROPERTY(accelerationSpread, ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), +CONSTRUCT_PROPERTY(radiusStart, ParticleEffectEntityItem::DEFAULT_RADIUS_START), +CONSTRUCT_PROPERTY(radiusFinish, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH), CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD), CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR), @@ -356,6 +358,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration); CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); + CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); + CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); CHECK_PROPERTY_CHANGE(PROP_NAME, name); @@ -460,6 +464,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration); COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); + COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); COPY_PROPERTY_TO_QSCRIPTVALUE(name); @@ -582,6 +588,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration); COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius); + COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart); + COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID); COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); @@ -825,6 +833,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); } @@ -1095,6 +1105,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); } @@ -1228,6 +1240,8 @@ void EntityItemProperties::markAllChanged() { _emitAccelerationChanged = true; _accelerationSpreadChanged = true; _particleRadiusChanged = true; + _radiusStartChanged = true; + _radiusFinishChanged = true; _radiusSpreadChanged = true; _marketplaceIDChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 0c4d963fc5..bcdfbd0289 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -136,6 +136,8 @@ public: DEFINE_PROPERTY(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3); DEFINE_PROPERTY(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); + DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float); + DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); @@ -317,6 +319,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 8d1ad12a8d..7eafc25427 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -139,6 +139,8 @@ enum EntityPropertyList { PROP_VELOCITY_SPREAD, PROP_ACCELERATION_SPREAD, PROP_RADIUS_SPREAD, + PROP_RADIUS_START, + PROP_RADIUS_FINISH, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index da19f64361..ff534ff03b 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -54,6 +54,9 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_VELOCITY_SPREAD(3.0f, 0.0f, 3. const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f); const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f); const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f; +const float ParticleEffectEntityItem::RADIUS_UNINITIALIZED = -1.0f; +const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = RADIUS_UNINITIALIZED; +const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = RADIUS_UNINITIALIZED; const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; @@ -73,6 +76,8 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _emitAcceleration(DEFAULT_EMIT_ACCELERATION), _accelerationSpread(DEFAULT_ACCELERATION_SPREAD), _particleRadius(DEFAULT_PARTICLE_RADIUS), + _radiusStart(DEFAULT_RADIUS_START), + _radiusFinish(DEFAULT_RADIUS_FINISH), _radiusSpread(DEFAULT_RADIUS_SPREAD), _lastAnimated(usecTimestampNow()), _animationLoop(), @@ -85,6 +90,9 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleAccelerations(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleRadiuses(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _timeUntilNextEmit(0.0f), _particleHeadIndex(0), _particleTailIndex(0), @@ -100,10 +108,6 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() { } -void ParticleEffectEntityItem::setLifespan(float lifespan) { - _lifespan = lifespan; -} - void ParticleEffectEntityItem::setEmitVelocity(const glm::vec3& emitVelocity) { _emitVelocity = emitVelocity; computeAndUpdateDimensions(); @@ -124,14 +128,6 @@ void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerati computeAndUpdateDimensions(); } -void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { - _particleRadius = particleRadius; -} - -void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) { - _radiusSpread = radiusSpread; -} - void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error @@ -173,6 +169,8 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { 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(radiusStart, getRadiusStart); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); @@ -197,6 +195,8 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert 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(radiusStart, setRadiusStart); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); @@ -266,8 +266,10 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); } - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_SPREAD) { + if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS) { READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); + READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); } return bytesRead; @@ -294,6 +296,8 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_TEXTURES; requestedProperties += PROP_VELOCITY_SPREAD; requestedProperties += PROP_RADIUS_SPREAD; + requestedProperties += PROP_RADIUS_START; + requestedProperties += PROP_RADIUS_FINISH; return requestedProperties; } @@ -323,6 +327,8 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY_SPREAD, getVelocitySpread()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish()); } bool ParticleEffectEntityItem::isAnimatingSomething() const { @@ -492,6 +498,15 @@ QString ParticleEffectEntityItem::getAnimationSettings() const { return jsonByteString; } +void ParticleEffectEntityItem::updateRadius(quint32 index) { + float age = 2.0f * (1.0f - _particleLifetimes[index] / _lifespan); // 0.0 .. 2.0 + if (age < 1.0f) { + _particleRadiuses[index] = cosineInterpolate(_radiusStarts[index], _radiusMiddles[index], age); + } else { + _particleRadiuses[index] = cosineInterpolate(_radiusMiddles[index], _radiusFinishes[index], age - 1.0f); + } +} + void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) { _particleMinBound.x = glm::min(_particleMinBound.x, point.x); _particleMinBound.y = glm::min(_particleMinBound.y, point.y); @@ -524,6 +539,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; } else { + updateRadius(i); integrateParticle(i, deltaTime); extendBounds(_particlePositions[i]); } @@ -542,8 +558,14 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { quint32 i = _particleTailIndex; _particleLifetimes[i] = _lifespan; - _particleRadiuses[i] = _particleRadius + (2.0f * randFloat() - 1) * _radiusSpread; + // Radius + float spreadMultiplier = 1.0 + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius; + _radiusStarts[i] = spreadMultiplier * getRadiusStart(); + _radiusMiddles[i] = spreadMultiplier * _particleRadius; + _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); + updateRadius(i); + // Velocity and acceleration glm::vec3 spreadOffset; spreadOffset.x = -_velocitySpread.x + randFloat() * (_velocitySpread.x * 2.0f); spreadOffset.y = -_velocitySpread.y + randFloat() * (_velocitySpread.y * 2.0f); @@ -587,6 +609,9 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _particlePositions.resize(_maxParticles); _particleVelocities.resize(_maxParticles); _particleRadiuses.resize(_maxParticles); + _radiusStarts.resize(_maxParticles); + _radiusMiddles.resize(_maxParticles); + _radiusFinishes.resize(_maxParticles); // effectively clear all particles and start emitting new ones from scratch. _particleHeadIndex = 0; @@ -603,3 +628,12 @@ quint32 ParticleEffectEntityItem::getLivingParticleCount() const { return (_maxParticles - _particleHeadIndex) + _particleTailIndex; } } + +float ParticleEffectEntityItem::cosineInterpolate(float y1, float y2, float u) { + if (y1 == y2) { + return y1; + } + + float uy = (1 - cos(u * PI)) / 2; + return y1 * (1 - uy) + y2 * uy; +} diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 844348a667..cac0af39a4 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -91,7 +91,7 @@ public: quint32 getMaxParticles() const { return _maxParticles; } static const float DEFAULT_LIFESPAN; - void setLifespan(float lifespan); + void setLifespan(float lifespan) { _lifespan = lifespan; } float getLifespan() const { return _lifespan; } static const float DEFAULT_EMIT_RATE; @@ -115,11 +115,21 @@ public: const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; } static const float DEFAULT_PARTICLE_RADIUS; - void setParticleRadius(float particleRadius); + void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } float getParticleRadius() const { return _particleRadius; } + static const float RADIUS_UNINITIALIZED; + + static const float DEFAULT_RADIUS_START; + void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; } + float getRadiusStart() const { return _radiusStart == RADIUS_UNINITIALIZED ? _particleRadius : _radiusStart; } + + static const float DEFAULT_RADIUS_FINISH; + void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; } + float getRadiusFinish() const { return _radiusFinish == RADIUS_UNINITIALIZED ? _particleRadius : _radiusFinish; } + static const float DEFAULT_RADIUS_SPREAD; - void setRadiusSpread(float radiusSpread); + void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; } float getRadiusSpread() const { return _radiusSpread; } void computeAndUpdateDimensions(); @@ -143,6 +153,7 @@ protected: bool isAnimatingSomething() const; void stepSimulation(float deltaTime); + void updateRadius(quint32 index); void extendBounds(const glm::vec3& point); void integrateParticle(quint32 index, float deltaTime); quint32 getLivingParticleCount() const; @@ -157,6 +168,8 @@ protected: glm::vec3 _emitAcceleration; glm::vec3 _accelerationSpread; float _particleRadius; + float _radiusStart; + float _radiusFinish; float _radiusSpread; quint64 _lastAnimated; AnimationLoop _animationLoop; @@ -171,9 +184,13 @@ protected: QVector _particleVelocities; QVector _particleAccelerations; QVector _particleRadiuses; + QVector _radiusStarts; + QVector _radiusMiddles; + QVector _radiusFinishes; + float _timeUntilNextEmit; - // particle arrays are a ring buffer, use these indicies + // particle arrays are a ring buffer, use these indices // to keep track of the living particles. quint32 _particleHeadIndex; quint32 _particleTailIndex; @@ -181,6 +198,9 @@ protected: // bounding volume glm::vec3 _particleMaxBound; glm::vec3 _particleMinBound; + +private: + float cosineInterpolate(float y1, float y2, float u); }; #endif // hifi_ParticleEffectEntityItem_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index da84a7cec8..8ac183da6f 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_PARTICLE_RADIUS_SPREAD; + return VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS; case AvatarData: return 13; default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index ce58273f43..00bce90c9a 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -144,6 +144,6 @@ const PacketVersion VERSION_POLYVOX_TEXTURES = 36; const PacketVersion VERSION_ENTITIES_POLYLINE = 37; const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39; -const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_SPREAD = 40; +const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS = 40; #endif // hifi_PacketHeaders_h \ No newline at end of file From e86581ab64b17d9ed809a6484d562452b0b6c136 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 4 Sep 2015 13:51:25 -0700 Subject: [PATCH 05/21] Update scripts to use HiFi smoke particle --- examples/example/entities/particlesTest.js | 2 +- examples/particles.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index e23e64677f..48d5ca246a 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -113,7 +113,7 @@ velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, emitAcceleration: { x: 0.0, y: -0.3, z: 0.0 }, accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, - textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png", + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", color: { red: 255, green: 255, blue: 255 }, lifespan: 5.0, visible: true, diff --git a/examples/particles.js b/examples/particles.js index fc1a936a72..ad232dd781 100644 --- a/examples/particles.js +++ b/examples/particles.js @@ -43,7 +43,7 @@ emitVelocity: {x: 0, y: 5, z: 0}, velocitySpread: {x: 2, y: 0, z: 2}, emitAcceleration: {x: 0, y: -9.8, z: 0}, - textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png", + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", color: color, lifespan: 1.0, visible: true, From c9cf426dba909010a8e55d0778ce40ac923d7600 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 4 Sep 2015 15:31:21 -0700 Subject: [PATCH 06/21] Fix EntityPropertyList merge --- libraries/entities/src/EntityPropertyFlags.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 4cf8b4064a..7ea471d851 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -138,9 +138,6 @@ enum EntityPropertyList { // used by particles PROP_VELOCITY_SPREAD, PROP_ACCELERATION_SPREAD, - PROP_RADIUS_SPREAD, - PROP_RADIUS_START, - PROP_RADIUS_FINISH, PROP_X_N_NEIGHBOR_ID, // used by PolyVox PROP_Y_N_NEIGHBOR_ID, // used by PolyVox @@ -149,6 +146,11 @@ enum EntityPropertyList { PROP_Y_P_NEIGHBOR_ID, // used by PolyVox PROP_Z_P_NEIGHBOR_ID, // used by PolyVox + // Used by particles + PROP_RADIUS_SPREAD, + PROP_RADIUS_START, + PROP_RADIUS_FINISH, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, From 68a4f4ac5ebed788948e9e17058f8a618e0132b8 Mon Sep 17 00:00:00 2001 From: Seiji Emery Date: Fri, 4 Sep 2015 17:36:09 -0700 Subject: [PATCH 07/21] Added js benchmark scripts Adds a small declarative benchmarking library and some sample tests to examples/utils/tests. --- examples/utilities/tests/allPerfTests.js | 11 ++ examples/utilities/tests/entityPerfTest.js | 107 ++++++++++++++ examples/utilities/tests/forLoopPerfTest.js | 140 ++++++++++++++++++ examples/utilities/tests/mathPerfTest.js | 127 ++++++++++++++++ examples/utilities/tests/perfTest.js | 155 ++++++++++++++++++++ 5 files changed, 540 insertions(+) create mode 100644 examples/utilities/tests/allPerfTests.js create mode 100644 examples/utilities/tests/entityPerfTest.js create mode 100644 examples/utilities/tests/forLoopPerfTest.js create mode 100644 examples/utilities/tests/mathPerfTest.js create mode 100644 examples/utilities/tests/perfTest.js diff --git a/examples/utilities/tests/allPerfTests.js b/examples/utilities/tests/allPerfTests.js new file mode 100644 index 0000000000..d389d78104 --- /dev/null +++ b/examples/utilities/tests/allPerfTests.js @@ -0,0 +1,11 @@ +// +// Created by Seiji Emery on 9/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("entityPerfTest.js"); +Script.include("mathPerfTest.js"); +Script.include("forLoopPerfTest.js"); \ No newline at end of file diff --git a/examples/utilities/tests/entityPerfTest.js b/examples/utilities/tests/entityPerfTest.js new file mode 100644 index 0000000000..181afcf360 --- /dev/null +++ b/examples/utilities/tests/entityPerfTest.js @@ -0,0 +1,107 @@ +// +// Created by Seiji Emery on 9/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("perfTest.js"); + +function makeEntity () { + return Entities.addEntity({ + type: "Box", + position: Vec3.sum(MyAvatar.position, { + x: 0.0, y: 0.0, z: 1.0 + }), + dimensions: { x: 0.1, y: 0.1, z: 0.1 }, + userData: "fooooooooooooooooooooooo" + }); +} + +// Create + run tests +(function () { + var entityTests = new TestRunner(); + + entityTests.addTestCase('getEntityProperties') + .before(function () { + this.entity = makeEntity(); + }) + .after(function() { + Entities.deleteEntity(this.entity); + }) + .run(function() { + var properties = Entities.getEntityProperties(this.entity); + var foo = properties.userData; + }); + + entityTests.addTestCase('add + delete entity') + .run(function() { + var entity = makeEntity(); + Entities.deleteEntity(entity); + }); + entityTests.addTestCase('update entity') + .before(function () { + this.entity = makeEntity(); + }) + .after(function () { + Entities.deleteEntity(this.entity); + }) + .run(function() { + Entities.editEntity(this.entity, { userData: "barrrrrrr" }); + }); + + TestCase.prototype.withEntityOp = function(op) { + this.before(function(){ + this.entity = makeEntity(); + }) + this.after(function(){ + Entities.deleteEntity(this.entity); + }) + this.run(op); + } + entityTests.addTestCase('find closest entity') + .withEntityOp(function() { + Entities.findClosestEntity(this.entity, MyAvatar.position, 100.0); + }) + entityTests.addTestCase('findEntities') + .withEntityOp(function(){ + Entities.findEntities(this.entity, MyAvatar.position, 10.0); + }) + entityTests.addTestCase('findEntitiesInBox') + .withEntityOp(function(){ + Entities.findEntitiesInBox(this.entity, MyAvatar.position, {x: 10.0, y: 10.0, z: 10.0}); + }) + + TestCase.prototype.withRay = function(op) { + this.before(function(){ + this.ray = Camera.computePickRay(500, 200); + }); + this.run(op); + } + entityTests.addTestCase('findRayIntersection, precisionPicking=true') + .withRay(function(){ + Entities.findRayIntersection(this.ray, true); + }) + entityTests.addTestCase('findRayIntersection, precisionPicking=false') + .withRay(function(){ + Entities.findRayIntersection(this.ray, false); + }); + entityTests.addTestCase('findRayIntersectionBlocking, precisionPicking=true') + .withRay(function(){ + Entities.findRayIntersectionBlocking(this.ray, true); + }) + entityTests.addTestCase('findRayIntersectionBlocking, precisionPicking=false') + .withRay(function(){ + Entities.findRayIntersectionBlocking(this.ray, false); + }) + entityTests.addTestCase('no-op') + .run(function(){}); + + print("Running entity tests"); + entityTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10); + entityTests.writeResultsToLog(); +})(); + + + diff --git a/examples/utilities/tests/forLoopPerfTest.js b/examples/utilities/tests/forLoopPerfTest.js new file mode 100644 index 0000000000..4d960ac2a5 --- /dev/null +++ b/examples/utilities/tests/forLoopPerfTest.js @@ -0,0 +1,140 @@ +// +// Created by Seiji Emery on 9/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Checks various types of js iteration (for loops, for/in loops, Array.forEach, and Object.keys) +// for speed + efficiency. Mostly a sanity check for my own code. +// + +Script.include("perfTest.js"); + +(function () { + var input1 = []; + var input2 = []; + var N = 1000; + for (var i = 0; i < N; ++i) { + input1.push(Math.random()); + input2.push(Math.random()); + } + TestCase.prototype.withArray = function(n, func) { + this.before(function () { + this.array = []; + for (var i = 0; i < n; ++i) { + this.array.push(0); + } + }); + this.run(fcn); + } + + print("For loop test -- prelim tests"); + var prelimTests = new TestRunner(); + prelimTests.addTestCase('Array.push (test component)') + .before(function () { + this.array = []; + }) + .run(function () { + this.array.push(1); + }); + prelimTests.addTestCase('Array.push with mul op (test component)') + .before(function() { + this.array = []; + }) + .run(function (i) { + this.array.push(input1[i] * Math.PI); + }) + prelimTests.runAllTestsWithIterations([1e4, 1e5, 1e6], 1e6, 10); + + print("For loop test (n = " + N + ")"); + var loopTests = new TestRunner(); + loopTests.addTestCase('for (var i = 0; i < n; ++i) { ... }') + .before(function () { + this.array = []; + }) + .run(function () { + for (var i = 0; i < N; ++i) { + this.array.push(input1[i] * Math.PI); + } + }) + loopTests.addTestCase('while (n --> 0) { ... } (reversed)') + .before(function () { + this.array = []; + }) + .run(function () { + var n = N; + while (n --> 0) { + this.array.push(input1[n] * Math.PI); + } + }) + loopTests.addTestCase('Array.forEach(function(v, i) { ... })') + .before(function () { + this.array = []; + }) + .run(function () { + input1.forEach(function(v) { + this.array.push(v * Math.PI); + }, this); + }) + loopTests.addTestCase('Array.map(function(v, i) { ... })') + .run(function () { + this.array = input1.map(function (v) { + return v * Math.PI; + }, this); + }); + loopTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10); + + + // Test iteration on object keys + + // http://stackoverflow.com/questions/10726909/random-alpha-numeric-string-in-javascript + function makeRandomString(length, chars) { + var result = ''; + for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))]; + return result; + } + function randomString () { + var n = Math.floor(Math.random() * 18) + 12; + return makeRandomString(n, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'); + } + + var obj = {}, numKeys = 1000; + while (numKeys --> 0) { + obj[randomString()] = Math.floor(Math.random() * 255); + } + print("Object iter tests (object has " + Object.keys(obj).length + " keys)"); + var iterTests = new TestRunner(); + iterTests.addTestCase('for (var k in obj) { foo(obj[k]); }') + .before(function () { + this.x = 0; + }) + .run(function () { + for (var k in obj) { + this.x = (this.x + obj[k]) % 256; + } + }); + iterTests.addTestCase('for (var k in obj) { if (Object.hasOwnProperty(obj, k)) { foo(obj[k]); } }') + .before(function () { + this.x = 0; + }) + .run(function () { + for (var k in obj) { + if (Object.hasOwnProperty(obj, k)) { + this.x = (this.x + obj[k]) % 256; + } + } + }) + iterTests.addTestCase('Object.keys(obj).forEach(function(k) { foo(obj[k]); }') + .before(function () { + this.x = 0; + }) + .run(function () { + Object.keys(obj).forEach(function (k) { + this.x = (this.x + obj[k]) % 256; + }) + }) + + iterTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10); +})(); + diff --git a/examples/utilities/tests/mathPerfTest.js b/examples/utilities/tests/mathPerfTest.js new file mode 100644 index 0000000000..b4df45aa41 --- /dev/null +++ b/examples/utilities/tests/mathPerfTest.js @@ -0,0 +1,127 @@ +// +// Created by Seiji Emery on 9/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("perfTest.js"); + +// Native vec3 (for comparison) +var Native = {}; +(function () { + Native.Vec3 = function (x, y, z) { + this.x = x || 0.0; + this.y = y || 0.0; + this.z = z || 0.0; + } + Native.Vec3.prototype.add = function (other) { + this.x += other.x; + this.y += other.y; + this.z += other.z; + } + Native.Vec3.prototype.distance = function (other) { + var rx = this.x - other.x; + var ry = this.y - other.y; + var rz = this.z - other.z; + return Math.sqrt(rx * rx + ry * ry + rz * rz); + } + Native.Vec3.prototype.dist2 = function (other) { + var rx = this.x - other.x; + var ry = this.y - other.y; + var rz = this.z - other.z; + return rx * rx + ry * ry + rz * rz; + } + + Native.Quaternion = function (x, y, z, w) { + this.x = x || 0.0; + this.y = y || 0.0; + this.z = z || 0.0; + this.w = w || 0.0; + } + // Pulled from THREE.js + Native.Quaternion.prototype.multiply = function(quat2) { + var qax = this.x, qay = this.y, qaz = this.z, qaw = this.w, + qbx = quat2.x, qby = quat2.y, qbz = quat2.z, qbw = quat2.w; + this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + return this; + } +})(); + +// Create + run tests +(function () { + var mathTests = new TestRunner(); + var foo; + + print("math tests:"); + var iterations = [ 1000, 10000, 100000, 1000000 ]; + + print("builtin Vec3 + Quat (wrapped glm::vec3 + glm::quat)"); + var builtinTests = new TestRunner(); + builtinTests.addTestCase('Vec3.sum') + .run(function () { + foo = Vec3.sum({x: 10, y: 12, z: 3}, {x: 1, y: 2, z: 4}); + }) + builtinTests.addTestCase('Vec3.distance') + .run(function () { + foo = Vec3.distance({x: 1209, y: 298, z: 238}, {x: 239, y: 20, z: 23}) + }) + builtinTests.addTestCase('Quat.multiply') + .run(function () { + foo = Quat.multiply({x: 2190.0, y: 2109.0, z: 1209.0, w: 829.0}, {x: -1293.0, y: 1029.1, z: 2190.1, w: 129.0}) + }); + builtinTests.runAllTestsWithIterations([ 1e3, 1e4, 1e5 ], 1e3, 10); + + print(""); + print("native JS Vec3 + Quaternion"); + var nativeTests = new TestRunner(); + nativeTests.addTestCase('Native Vec3.sum') + .run(function () { + foo = new Native.Vec3(10, 12, 3).add(new Native.Vec3(1, 2, 4)); + }) + nativeTests.addTestCase('Native Vec3.distance') + .run(function () { + foo = new Native.Vec3(1209, 298, 238).distance(new Native.Vec3(239, 20, 23)); + }) + nativeTests.addTestCase('Native Vec3.dist2') + .run(function () { + foo = new Native.Vec3(1209, 298, 238).dist2(new Native.Vec3(239, 20, 23)); + }) + nativeTests.addTestCase('Native Quat.multiply') + .run(function () { + foo = new Native.Quaternion(2190.0, 2109.0, 1209.0, 829.0).multiply(new Native.Quaternion(-1293.0, 1029.1, 2190.1, 129.0)); + }); + nativeTests.runAllTestsWithIterations([ 1e3, 1e4, 1e5, 1e6 ], 1e6, 10); + + print(""); + print("no-ops (for test assignment / construction overhead)") + mathTests.addTestCase('no-op') + .run(function(){}); + mathTests.addTestCase('assign null') + .run(function () { + foo = null; + }); + mathTests.addTestCase('assign object') + .run(function () { + foo = { x: 1902, y: 129, z: 21 }; + }); + mathTests.addTestCase('Native Vec3.construct -- 3 args') + .run(function () { + foo = new Native.Vec3(1209, 298, 238); + }); + mathTests.addTestCase('Native Vec3.construct -- 2 args') + .run(function () { + foo = new Native.Vec3(1209, 298); + }); + mathTests.addTestCase('Native Vec3.construct -- no args') + .run(function() { + foo = new Native.Vec3(); + }); + + mathTests.runAllTestsWithIterations([1e3, 1e4, 1e5, 1e6], 1e6, 10); + mathTests.writeResultsToLog(); +})(); \ No newline at end of file diff --git a/examples/utilities/tests/perfTest.js b/examples/utilities/tests/perfTest.js new file mode 100644 index 0000000000..814cee8ac0 --- /dev/null +++ b/examples/utilities/tests/perfTest.js @@ -0,0 +1,155 @@ +// +// Created by Seiji Emery on 9/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Simple benchmarking library. See the test scripts for example usage. +// + +(function () { + // Runs multiple 'test cases' (benchmarks that get invoked w/ varying iteration counts) + function TestRunner () { + this._testCases = {}; + this._testResults = []; + } + this.TestRunner = TestRunner; + + // Add a test case. Define behavior by declaratively calling .before, .after, and .run w/ impls. + TestRunner.prototype.addTestCase = function (name) { + var testcase = new TestCase(name); + this._testCases[name] = testcase; + return testcase; + } + + // Runs a function n times. Uses context object so it runs sandboxed. + function runTimedWithIterations (f, context, numIterations) { + var start = new Date().getTime(); + while (numIterations --> 0) { + f.apply(context); + } + var end = new Date().getTime(); + return end - start; + } + + function fmtSecs (secs) { + if (secs >= 1.0) { + return ""+secs.toFixed(3)+" secs"; + } else if (secs >= 1e-3) { + return ""+(secs * 1e3).toFixed(3)+" ms"; + } else if (secs >= 1e-6) { + return ""+(secs * 1e6).toFixed(3)+" µs"; + } else { + return ""+(secs * 1e9).toFixed(3)+" ns"; + } + } + function avg(samples) { + return samples.length ? + samples.reduce(function(a, b){return a+b;}, 0.0) / samples.length : 0.0; + } + + // Runs a named performance test for multiple iterations, and optionally calculates an average. + // @param name: the test name registered with addTest + // @param iterations: a list of iteration sequences. eg. [10, 100, 1000] => runs for 10, then 100, then 1000 iterations + // and prints the timing info for each (in ms) + // @param iterationsForAvg: optional + // @param samplesForAvg: optional + // After running iterations, will compute an average if iterationsForAvg and samplesForAvg are both set: + // average := + // collects n samples by running the testcase n times with i iterations + // where n = samplesForAvg, i = iterationsForAvg + // we then average the samples, and print that. + // + TestRunner.prototype.runPerfTestWithIterations = function (name, iterations, iterationsForAvg, samplesForAvg) { + if (!this._testCases[name]) { + print("No test case with name '" + name + "'!"); + } + var testcase = this._testCases[name]; + + var runAverages = []; // secs + + var noErrors = true; + iterations.forEach(function(n, i) { + var sandbox = {}; + try { + if (testcase.setupFunction) { + testcase.setupFunction.apply(sandbox); + } + + var dt = runTimedWithIterations(testcase.runFunction, sandbox, n); + + if (testcase.teardownFunction) { + testcase.teardownFunction.apply(sandbox); + } + + this._testResults.push(""+name+" with "+n+" iterations: "+dt+" ms"); + } catch (e) { + this._testResults.push("Testcase '"+name+"':"+i+" ("+n+") failed with error: "+e); + noErrors = false; + } + }, this); + this.writeResultsToLog(); + if (noErrors && iterationsForAvg && samplesForAvg) { + try { + var samples = []; + for (var n = samplesForAvg; n --> 0; ) { + var sandbox = {}; + if (testcase.setupFunction) { + testcase.setupFunction.apply(sandbox); + } + + var dt = runTimedWithIterations(testcase.runFunction, sandbox, iterationsForAvg); + + if (testcase.teardownFunction) { + testcase.teardownFunction.apply(sandbox); + } + samples.push(dt / iterationsForAvg * 1e-3); // dt in ms + } + print(" average: " + ((avg(samples) * 1e6).toFixed(3)) + " µs") + // print("\t(" + samplesForAvg + " samples with " + iterationsForAvg + " iterations)"); + } catch (e) { + print("Error while calculating average: " + e); + return; + } + } + } + // Runs all registered tests w/ iteration + average parameters + TestRunner.prototype.runAllTestsWithIterations = function (iterations, iterationsForAvg, samplesForAvg) { + Object.keys(this._testCases).forEach(function(name) { + this.runPerfTestWithIterations(name, iterations, iterationsForAvg, samplesForAvg); + }, this); + } + + // Dump results to the debug log. You don't need to call this. + TestRunner.prototype.writeResultsToLog = function () { + var s = ' ' + this._testResults.join('\n '); + this._testResults = []; + // print(s); + s.split('\n').forEach(function(line) { + print(line); + }); + } + + // Implements a benchmark test case, that has optional setup = teardown code, and a (non-optional) run function. + // setup + teardown get called once, and run gets called for n sequential iterations (see TestRunner.runTestWithIterations) + // setup, run, and teardown all get applied to the same sandboxed this object, so use that for storing test data for each run. + function TestCase (name) { + this.name = name; + this.setupFunction = null; + this.runFunction = null; + this.teardownFunction = null; + } + this.TestCase = TestCase; + TestCase.prototype.before = function (f) { + this.setupFunction = f; + return this; + } + TestCase.prototype.after = function (f) { + this.teardownFunction = f; + return this; + } + TestCase.prototype.run = function (f) { + this.runFunction = f; + } +})(); \ No newline at end of file From 12b8a5a1d52c478feb6c88b2eb308e15e948f6e9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Sep 2015 10:23:27 -0700 Subject: [PATCH 08/21] Add alpha property support to ParticleEffect entities Add at same "level" as color so that it's available for other entity types to use in the future. --- examples/example/entities/particlesTest.js | 18 +++++++++-- .../RenderableParticleEffectEntityItem.cpp | 32 +++++++++---------- .../entities/src/EntityItemProperties.cpp | 8 ++++- libraries/entities/src/EntityItemProperties.h | 2 ++ .../src/EntityItemPropertiesDefaults.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 2 ++ .../entities/src/ParticleEffectEntityItem.cpp | 13 +++++++- .../entities/src/ParticleEffectEntityItem.h | 5 +++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- 10 files changed, 63 insertions(+), 23 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index 48d5ca246a..88e1c8d919 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -15,7 +15,7 @@ var box, particles, particleExample = -1, - NUM_PARTICLE_EXAMPLES = 6, + NUM_PARTICLE_EXAMPLES = 7, PARTICLE_RADIUS = 0.04; function onClickDownOnEntity(entityID) { @@ -24,7 +24,7 @@ switch (particleExample) { case 0: - print("Simple animation"); + print("Simple emitter"); Entities.editEntity(particles, { velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, @@ -71,12 +71,24 @@ }); break; case 5: - print("Stop animation"); + print("Alpha 0.5"); Entities.editEntity(particles, { velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, radiusStart: PARTICLE_RADIUS, radiusFinish: PARTICLE_RADIUS, + alpha: 0.5, + animationIsPlaying: true + }); + break; + case 6: + print("Stop emitting"); + Entities.editEntity(particles, { + velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, + radiusStart: PARTICLE_RADIUS, + radiusFinish: PARTICLE_RADIUS, + alpha: 1.0, animationIsPlaying: false }); break; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 424ea2b810..be9c28a80d 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -172,16 +172,17 @@ uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24); } -class PositionAndRadius { +class ParticleDetails { public: - PositionAndRadius(glm::vec3 position, float radius) : position(position), radius(radius) { } + ParticleDetails(glm::vec3 position, float radius, uint32_t rgba) : position(position), radius(radius), rgba(rgba) { } glm::vec3 position; float radius; + uint32_t rgba; }; static glm::vec3 zSortAxis; -static bool zSort(const PositionAndRadius& rhs, const PositionAndRadius& lhs) { +static bool zSort(const ParticleDetails& rhs, const ParticleDetails& lhs) { return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis); } @@ -190,22 +191,21 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { return; } + // make a copy of each particle's details + std::vector particleDetails; + particleDetails.reserve(getLivingParticleCount()); auto xcolor = getXColor(); - auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); - auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); - - // make a copy of each particle position and radius - std::vector positionsAndRadiuses; - positionsAndRadiuses.reserve(getLivingParticleCount()); for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { - positionsAndRadiuses.push_back(PositionAndRadius(_particlePositions[i], _particleRadiuses[i])); + auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); + auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); + particleDetails.push_back(ParticleDetails(_particlePositions[i], _particleRadiuses[i], rgba)); } // sort particles back to front // NOTE: this is view frustum might be one frame out of date. auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum(); ::zSortAxis = frustum->getDirection(); - qSort(positionsAndRadiuses.begin(), positionsAndRadiuses.end(), zSort); + qSort(particleDetails.begin(), particleDetails.end(), zSort); // allocate vertices _vertices.clear(); @@ -213,14 +213,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // build vertices from particle positions and radiuses const glm::vec3 up = frustum->getUp(); const glm::vec3 right = frustum->getRight(); - for (auto&& particle : positionsAndRadiuses) { + for (auto&& particle : particleDetails) { glm::vec3 upOffset = up * particle.radius; glm::vec3 rightOffset = right * particle.radius; // generate corners of quad aligned to face the camera. - _vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba); - _vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba); - _vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba); - _vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba); + _vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), particle.rgba); + _vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), particle.rgba); + _vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), particle.rgba); + _vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), particle.rgba); } render::PendingChanges pendingChanges; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a07eaacdb9..f838b7a17e 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -55,6 +55,7 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), +CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA), CONSTRUCT_PROPERTY(modelURL, ""), CONSTRUCT_PROPERTY(compoundShapeURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), @@ -331,6 +332,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); + CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); @@ -445,6 +447,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE(color); + COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); @@ -578,6 +581,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL); @@ -915,11 +919,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths()); } - APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -1192,6 +1196,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); return valid; } @@ -1248,6 +1253,7 @@ void EntityItemProperties::markAllChanged() { _nameChanged = true; _visibleChanged = true; _colorChanged = true; + _alphaChanged = true; _modelURLChanged = true; _compoundShapeURLChanged = true; _animationURLChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 95f9757f20..520e2c1224 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -103,6 +103,7 @@ public: DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); + DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); @@ -294,6 +295,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 0cdfe73040..a4aca0b344 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -27,6 +27,7 @@ const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString(""); const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid(); +const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f; const bool ENTITY_ITEM_DEFAULT_VISIBLE = true; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 7ea471d851..bfef04ab57 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -151,6 +151,8 @@ enum EntityPropertyList { PROP_RADIUS_START, PROP_RADIUS_FINISH, + PROP_ALPHA, // Supported by some derived classes + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index ff534ff03b..0f8df954bf 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -85,6 +85,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _textures(DEFAULT_TEXTURES), _texturesChangedFlag(false), _shapeType(SHAPE_TYPE_NONE), + _alpha(ENTITY_ITEM_DEFAULT_ALPHA), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), _particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), @@ -93,6 +94,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _particleAlphas(DEFAULT_MAX_PARTICLES, ENTITY_ITEM_DEFAULT_ALPHA), _timeUntilNextEmit(0.0f), _particleHeadIndex(0), _particleTailIndex(0), @@ -155,6 +157,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS); @@ -181,6 +184,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS); @@ -266,10 +270,11 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); } - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS) { + if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) { 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_ALPHA, float, setAlpha); } return bytesRead; @@ -298,6 +303,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_RADIUS_SPREAD; requestedProperties += PROP_RADIUS_START; requestedProperties += PROP_RADIUS_FINISH; + requestedProperties += PROP_ALPHA; return requestedProperties; } @@ -329,6 +335,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, 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_ALPHA, getAlpha()); } bool ParticleEffectEntityItem::isAnimatingSomething() const { @@ -584,6 +591,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { integrateParticle(i, timeLeftInFrame); extendBounds(_particlePositions[i]); + // Alpha + _particleAlphas[i] = _alpha; + _particleTailIndex = (_particleTailIndex + 1) % _maxParticles; // overflow! move head forward by one. @@ -612,6 +622,7 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _radiusStarts.resize(_maxParticles); _radiusMiddles.resize(_maxParticles); _radiusFinishes.resize(_maxParticles); + _particleAlphas.resize(_maxParticles); // effectively clear all particles and start emitting new ones from scratch. _particleHeadIndex = 0; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index cac0af39a4..81d88e5a41 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -56,6 +56,9 @@ public: _color[BLUE_INDEX] = value.blue; } + void setAlpha(float alpha) { _alpha = alpha; } + float getAlpha() const { return _alpha; } + void updateShapeType(ShapeType type); virtual ShapeType getShapeType() const { return _shapeType; } @@ -160,6 +163,7 @@ protected: // the properties of this entity rgbColor _color; + float _alpha; quint32 _maxParticles; float _lifespan; float _emitRate; @@ -187,6 +191,7 @@ protected: QVector _radiusStarts; QVector _radiusMiddles; QVector _radiusFinishes; + QVector _particleAlphas; float _timeUntilNextEmit; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 8ac183da6f..3a2013d367 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS; + return VERSION_ENTITIES_PARTICLE_ALPHA_PROPERTIES; case AvatarData: return 13; default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index a68d3adbad..e63f7f410b 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -145,6 +145,7 @@ const PacketVersion VERSION_ENTITIES_POLYLINE = 37; const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39; const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40; -const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS = 41; +const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41; +const PacketVersion VERSION_ENTITIES_PARTICLE_ALPHA_PROPERTIES = 42; #endif // hifi_PacketHeaders_h From 8d85309925fd5d04b06dcc664bc268a628b26e82 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Sep 2015 10:50:05 -0700 Subject: [PATCH 09/21] Use cubic interpolation instead of cosine --- .../entities/src/ParticleEffectEntityItem.cpp | 29 ++++++++++++++----- .../entities/src/ParticleEffectEntityItem.h | 2 +- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 0f8df954bf..1b58e92ef1 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -507,11 +507,22 @@ QString ParticleEffectEntityItem::getAnimationSettings() const { void ParticleEffectEntityItem::updateRadius(quint32 index) { float age = 2.0f * (1.0f - _particleLifetimes[index] / _lifespan); // 0.0 .. 2.0 + float y0, y1, y2, y3; + if (age < 1.0f) { - _particleRadiuses[index] = cosineInterpolate(_radiusStarts[index], _radiusMiddles[index], age); + y1 = _radiusStarts[index]; + y2 = _radiusMiddles[index]; + y3 = _radiusFinishes[index]; + y0 = 2.0f * y1 - y2; } else { - _particleRadiuses[index] = cosineInterpolate(_radiusMiddles[index], _radiusFinishes[index], age - 1.0f); + y0 = _radiusStarts[index]; + y1 = _radiusMiddles[index]; + y2 = _radiusFinishes[index]; + 2.0f * y2 - y1; + age -= 1.0f; } + + _particleRadiuses[index] = cubicInterpolate(y0, y1, y2, y3, age); } void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) { @@ -640,11 +651,13 @@ quint32 ParticleEffectEntityItem::getLivingParticleCount() const { } } -float ParticleEffectEntityItem::cosineInterpolate(float y1, float y2, float u) { - if (y1 == y2) { - return y1; - } +float ParticleEffectEntityItem::cubicInterpolate(float y0, float y1, float y2, float y3, float u) { + float a0, a1, a2, a3, uu; + uu = u * u; + a0 = y3 - y2 - y0 + y1; + a1 = y0 - y1 - a0; + a2 = y2 - y0; + a3 = y1; - float uy = (1 - cos(u * PI)) / 2; - return y1 * (1 - uy) + y2 * uy; + return (a0 * u * uu + a1 * uu + a2 * u + a3); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 81d88e5a41..5d751d7b1c 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -205,7 +205,7 @@ protected: glm::vec3 _particleMinBound; private: - float cosineInterpolate(float y1, float y2, float u); + float cubicInterpolate(float y0, float y1, float y2, float y3, float u); }; #endif // hifi_ParticleEffectEntityItem_h From 8b296f53e612a95be36467c8c2c83693b5ccee4d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Sep 2015 11:13:48 -0700 Subject: [PATCH 10/21] Short-circuit radius values and interpolation when can --- .../entities/src/ParticleEffectEntityItem.cpp | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 1b58e92ef1..b3859f10f0 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -506,23 +506,27 @@ QString ParticleEffectEntityItem::getAnimationSettings() const { } void ParticleEffectEntityItem::updateRadius(quint32 index) { - float age = 2.0f * (1.0f - _particleLifetimes[index] / _lifespan); // 0.0 .. 2.0 - float y0, y1, y2, y3; - - if (age < 1.0f) { - y1 = _radiusStarts[index]; - y2 = _radiusMiddles[index]; - y3 = _radiusFinishes[index]; - y0 = 2.0f * y1 - y2; + if (_radiusStarts[index] == _radiusMiddles[index] && _radiusMiddles[index] == _radiusFinishes[index]) { + _particleRadiuses[index] = _radiusMiddles[index]; } else { - y0 = _radiusStarts[index]; - y1 = _radiusMiddles[index]; - y2 = _radiusFinishes[index]; - 2.0f * y2 - y1; - age -= 1.0f; - } + float age = 2.0f * (1.0f - _particleLifetimes[index] / _lifespan); // 0.0 .. 2.0 + float y0, y1, y2, y3; - _particleRadiuses[index] = cubicInterpolate(y0, y1, y2, y3, age); + if (age < 1.0f) { + y1 = _radiusStarts[index]; + y2 = _radiusMiddles[index]; + y3 = _radiusFinishes[index]; + y0 = 2.0f * y1 - y2; + } else { + y0 = _radiusStarts[index]; + y1 = _radiusMiddles[index]; + y2 = _radiusFinishes[index]; + y3 = 2.0f * y2 - y1; + age -= 1.0f; + } + + _particleRadiuses[index] = cubicInterpolate(y0, y1, y2, y3, age); + } } void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) { @@ -577,10 +581,16 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleLifetimes[i] = _lifespan; // Radius - float spreadMultiplier = 1.0 + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius; - _radiusStarts[i] = spreadMultiplier * getRadiusStart(); - _radiusMiddles[i] = spreadMultiplier * _particleRadius; - _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); + if (_radiusSpread == 0.0f) { + _radiusStarts[i] = getRadiusStart(); + _radiusMiddles[i] =_particleRadius; + _radiusFinishes[i] = getRadiusFinish(); + } else { + float spreadMultiplier = 1.0 + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius; + _radiusStarts[i] = spreadMultiplier * getRadiusStart(); + _radiusMiddles[i] = spreadMultiplier * _particleRadius; + _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); + } updateRadius(i); // Velocity and acceleration From 1b3d125cb33ebdcfe9dc7937e07e03426335afb1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Sep 2015 14:39:10 -0700 Subject: [PATCH 11/21] Add alphaSpread entity particle property --- examples/example/entities/particlesTest.js | 37 +++++++------------ .../entities/src/EntityItemProperties.cpp | 7 ++++ libraries/entities/src/EntityItemProperties.h | 2 + libraries/entities/src/EntityPropertyFlags.h | 3 ++ .../entities/src/ParticleEffectEntityItem.cpp | 14 ++++++- .../entities/src/ParticleEffectEntityItem.h | 5 +++ 6 files changed, 43 insertions(+), 25 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index 88e1c8d919..d6406b18ca 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -15,7 +15,7 @@ var box, particles, particleExample = -1, - NUM_PARTICLE_EXAMPLES = 7, + NUM_PARTICLE_EXAMPLES = 8, PARTICLE_RADIUS = 0.04; function onClickDownOnEntity(entityID) { @@ -35,10 +35,7 @@ case 1: print("Velocity spread"); Entities.editEntity(particles, { - velocitySpread: { x: 0.1, y: 0.0, z: 0.1 }, - accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, - radiusSpread: 0.0, - animationIsPlaying: true + velocitySpread: { x: 0.1, y: 0.0, z: 0.1 } }); break; case 2: @@ -46,49 +43,43 @@ Entities.editEntity(particles, { velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 }, - radiusSpread: 0.0, - animationIsPlaying: true }); break; case 3: print("Radius spread"); Entities.editEntity(particles, { - velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, - radiusSpread: 0.035, - animationIsPlaying: true + radiusSpread: 0.035 }); break; case 4: print("Radius start and finish"); Entities.editEntity(particles, { - velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, - accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, - radiusStart: 0.0, - radiusFinish: 0.0, radiusSpread: 0.0, - animationIsPlaying: true + radiusStart: 0.0, + radiusFinish: 0.0 }); break; case 5: print("Alpha 0.5"); Entities.editEntity(particles, { - velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, - accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, radiusStart: PARTICLE_RADIUS, radiusFinish: PARTICLE_RADIUS, - alpha: 0.5, - animationIsPlaying: true + alpha: 0.5 }); break; case 6: + print("Alpha spread"); + Entities.editEntity(particles, { + alpha: 0.5, + alphaSpread: 0.5 + }); + break; + case 7: print("Stop emitting"); Entities.editEntity(particles, { - velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, - accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, - radiusStart: PARTICLE_RADIUS, - radiusFinish: PARTICLE_RADIUS, alpha: 1.0, + alphaSpread: 0.0, animationIsPlaying: false }); break; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f838b7a17e..d633ed787a 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -56,6 +56,7 @@ CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA), +CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD), CONSTRUCT_PROPERTY(modelURL, ""), CONSTRUCT_PROPERTY(compoundShapeURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), @@ -333,6 +334,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); + CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); @@ -448,6 +450,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE(color); COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); + COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); @@ -582,6 +585,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); + COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL); @@ -869,6 +873,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); } if (properties.getType() == EntityTypes::Zone) { @@ -1147,6 +1152,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); } if (properties.getType() == EntityTypes::Zone) { @@ -1290,6 +1296,7 @@ void EntityItemProperties::markAllChanged() { _radiusStartChanged = true; _radiusFinishChanged = true; _radiusSpreadChanged = true; + _alphaSpreadChanged = true; _marketplaceIDChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 520e2c1224..6cd735149e 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -104,6 +104,7 @@ public: DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float); + DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); @@ -296,6 +297,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index bfef04ab57..e8763cf565 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -153,6 +153,9 @@ enum EntityPropertyList { PROP_ALPHA, // Supported by some derived classes + //Used by particles + PROP_ALPHA_SPREAD, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index b3859f10f0..8ab31aa0c4 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -43,6 +43,7 @@ #include "ParticleEffectEntityItem.h" const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; +const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f; @@ -79,6 +80,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStart(DEFAULT_RADIUS_START), _radiusFinish(DEFAULT_RADIUS_FINISH), _radiusSpread(DEFAULT_RADIUS_SPREAD), + _alphaSpread(DEFAULT_ALPHA_SPREAD), _lastAnimated(usecTimestampNow()), _animationLoop(), _animationSettings(), @@ -175,6 +177,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); return properties; @@ -202,6 +205,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); if (somethingChanged) { @@ -304,6 +308,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_RADIUS_START; requestedProperties += PROP_RADIUS_FINISH; requestedProperties += PROP_ALPHA; + requestedProperties += PROP_ALPHA_SPREAD; return requestedProperties; } @@ -586,7 +591,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _radiusMiddles[i] =_particleRadius; _radiusFinishes[i] = getRadiusFinish(); } else { - float spreadMultiplier = 1.0 + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius; + float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius; _radiusStarts[i] = spreadMultiplier * getRadiusStart(); _radiusMiddles[i] = spreadMultiplier * _particleRadius; _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); @@ -613,7 +618,12 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { extendBounds(_particlePositions[i]); // Alpha - _particleAlphas[i] = _alpha; + if (_alphaSpread == 0.0f) { + _particleAlphas[i] = _alpha; + + } else { + _particleAlphas[i] = glm::clamp(_alpha + (2.0f * randFloat() - 1) * _alphaSpread, 0.0f, 1.0f); + } _particleTailIndex = (_particleTailIndex + 1) % _maxParticles; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 5d751d7b1c..55ae724fe6 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -59,6 +59,10 @@ public: void setAlpha(float alpha) { _alpha = alpha; } float getAlpha() const { return _alpha; } + static const float DEFAULT_ALPHA_SPREAD; + void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; } + float getAlphaSpread() const { return _alphaSpread; } + void updateShapeType(ShapeType type); virtual ShapeType getShapeType() const { return _shapeType; } @@ -164,6 +168,7 @@ protected: // the properties of this entity rgbColor _color; float _alpha; + float _alphaSpread; quint32 _maxParticles; float _lifespan; float _emitRate; From 042384b5b08b8fb5e283f048ffa36b86acf535e2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Sep 2015 14:51:48 -0700 Subject: [PATCH 12/21] Tidy and finish alpha and alphaSpread --- libraries/entities/src/ParticleEffectEntityItem.cpp | 9 ++++++--- libraries/entities/src/ParticleEffectEntityItem.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 8ab31aa0c4..4e0ece15fc 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -43,6 +43,7 @@ #include "ParticleEffectEntityItem.h" const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; +const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f; const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; @@ -80,14 +81,14 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStart(DEFAULT_RADIUS_START), _radiusFinish(DEFAULT_RADIUS_FINISH), _radiusSpread(DEFAULT_RADIUS_SPREAD), - _alphaSpread(DEFAULT_ALPHA_SPREAD), _lastAnimated(usecTimestampNow()), _animationLoop(), _animationSettings(), _textures(DEFAULT_TEXTURES), _texturesChangedFlag(false), _shapeType(SHAPE_TYPE_NONE), - _alpha(ENTITY_ITEM_DEFAULT_ALPHA), + _alpha(DEFAULT_ALPHA), + _alphaSpread(DEFAULT_ALPHA_SPREAD), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), _particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), @@ -96,7 +97,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), - _particleAlphas(DEFAULT_MAX_PARTICLES, ENTITY_ITEM_DEFAULT_ALPHA), + _particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _timeUntilNextEmit(0.0f), _particleHeadIndex(0), _particleTailIndex(0), @@ -279,6 +280,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); + READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); } return bytesRead; @@ -341,6 +343,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); } bool ParticleEffectEntityItem::isAnimatingSomething() const { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 55ae724fe6..ad8ed8b386 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -56,6 +56,7 @@ public: _color[BLUE_INDEX] = value.blue; } + static const float DEFAULT_ALPHA; void setAlpha(float alpha) { _alpha = alpha; } float getAlpha() const { return _alpha; } From 47b27a32808196027704d923dc1ef237da92531b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Sep 2015 16:30:01 -0700 Subject: [PATCH 13/21] Add alphaStart and alphaFinish entity particle properties --- examples/example/entities/particlesTest.js | 16 +++- .../entities/src/EntityItemProperties.cpp | 14 +++ libraries/entities/src/EntityItemProperties.h | 4 + libraries/entities/src/EntityPropertyFlags.h | 2 + .../entities/src/ParticleEffectEntityItem.cpp | 89 +++++++++++++------ .../entities/src/ParticleEffectEntityItem.h | 19 +++- 6 files changed, 114 insertions(+), 30 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index d6406b18ca..f1ae210373 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -15,7 +15,7 @@ var box, particles, particleExample = -1, - NUM_PARTICLE_EXAMPLES = 8, + NUM_PARTICLE_EXAMPLES = 9, PARTICLE_RADIUS = 0.04; function onClickDownOnEntity(entityID) { @@ -42,7 +42,7 @@ print("Acceleration spread"); Entities.editEntity(particles, { velocitySpread: { x: 0.0, y: 0.0, z: 0.0 }, - accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 }, + accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 } }); break; case 3: @@ -76,10 +76,20 @@ }); break; case 7: + print("Alpha start and finish"); + Entities.editEntity(particles, { + alphaSpread: 0.0, + alpha: 1.0, + alphaStart: 0.0, + alphaFinish: 0.0 + }); + break; + case 8: print("Stop emitting"); Entities.editEntity(particles, { alpha: 1.0, - alphaSpread: 0.0, + alphaStart: 1.0, + alphaFinish: 1.0, animationIsPlaying: false }); break; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d633ed787a..6d68483388 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -56,6 +56,8 @@ CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA), +CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START), +CONSTRUCT_PROPERTY(alphaFinish, ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH), CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD), CONSTRUCT_PROPERTY(modelURL, ""), CONSTRUCT_PROPERTY(compoundShapeURL, ""), @@ -334,6 +336,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); + CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); + CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish); CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); @@ -450,6 +454,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE(color); COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); + COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL); @@ -585,6 +591,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); + COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); + COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); @@ -873,6 +881,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); } @@ -1152,6 +1162,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); } @@ -1296,6 +1308,8 @@ void EntityItemProperties::markAllChanged() { _radiusStartChanged = true; _radiusFinishChanged = true; _radiusSpreadChanged = true; + _alphaStartChanged = true; + _alphaFinishChanged = true; _alphaSpreadChanged = true; _marketplaceIDChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6cd735149e..3721e0d9ca 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -104,6 +104,8 @@ public: DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float); + DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float); + DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); @@ -297,6 +299,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index e8763cf565..146f4126a7 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -155,6 +155,8 @@ enum EntityPropertyList { //Used by particles PROP_ALPHA_SPREAD, + PROP_ALPHA_START, + PROP_ALPHA_FINISH, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 4e0ece15fc..a85a83a4ac 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -44,6 +44,9 @@ const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f; +const float ParticleEffectEntityItem::ALPHA_UNINITIALIZED = -1.0f; +const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = ALPHA_UNINITIALIZED; +const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = ALPHA_UNINITIALIZED; const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; @@ -88,6 +91,8 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _texturesChangedFlag(false), _shapeType(SHAPE_TYPE_NONE), _alpha(DEFAULT_ALPHA), + _alphaStart(DEFAULT_ALPHA_START), + _alphaFinish(DEFAULT_ALPHA_FINISH), _alphaSpread(DEFAULT_ALPHA_SPREAD), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), _particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), @@ -97,6 +102,9 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), + _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _timeUntilNextEmit(0.0f), _particleHeadIndex(0), @@ -178,6 +186,8 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); @@ -206,6 +216,8 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); @@ -281,6 +293,8 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); + READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); + READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); } return bytesRead; @@ -311,6 +325,8 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_RADIUS_FINISH; requestedProperties += PROP_ALPHA; requestedProperties += PROP_ALPHA_SPREAD; + requestedProperties += PROP_ALPHA_START; + requestedProperties += PROP_ALPHA_FINISH; return requestedProperties; } @@ -344,6 +360,8 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish()); } bool ParticleEffectEntityItem::isAnimatingSomething() const { @@ -513,28 +531,13 @@ QString ParticleEffectEntityItem::getAnimationSettings() const { return jsonByteString; } -void ParticleEffectEntityItem::updateRadius(quint32 index) { - if (_radiusStarts[index] == _radiusMiddles[index] && _radiusMiddles[index] == _radiusFinishes[index]) { - _particleRadiuses[index] = _radiusMiddles[index]; - } else { - float age = 2.0f * (1.0f - _particleLifetimes[index] / _lifespan); // 0.0 .. 2.0 - float y0, y1, y2, y3; +void ParticleEffectEntityItem::updateRadius(quint32 index, float age) { + _particleRadiuses[index] = interpolate(_radiusStarts[index], _radiusMiddles[index], _radiusFinishes[index], age); +} - if (age < 1.0f) { - y1 = _radiusStarts[index]; - y2 = _radiusMiddles[index]; - y3 = _radiusFinishes[index]; - y0 = 2.0f * y1 - y2; - } else { - y0 = _radiusStarts[index]; - y1 = _radiusMiddles[index]; - y2 = _radiusFinishes[index]; - y3 = 2.0f * y2 - y1; - age -= 1.0f; - } - - _particleRadiuses[index] = cubicInterpolate(y0, y1, y2, y3, age); - } +void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) { + _particleAlphas[index] = glm::clamp(interpolate(_alphaStarts[index], _alphaMiddles[index], _alphaFinishes[index], age), + 0.0f, 1.0f); } void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) { @@ -569,7 +572,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; } else { - updateRadius(i); + float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0 + updateRadius(i, age); + updateAlpha(i, age); integrateParticle(i, deltaTime); extendBounds(_particlePositions[i]); } @@ -599,7 +604,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _radiusMiddles[i] = spreadMultiplier * _particleRadius; _radiusFinishes[i] = spreadMultiplier * getRadiusFinish(); } - updateRadius(i); + updateRadius(i, 0.0f); // Velocity and acceleration glm::vec3 spreadOffset; @@ -622,11 +627,16 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { // Alpha if (_alphaSpread == 0.0f) { - _particleAlphas[i] = _alpha; - + _alphaStarts[i] = getAlphaStart(); + _alphaMiddles[i] = _alpha; + _alphaFinishes[i] = getAlphaFinish(); } else { - _particleAlphas[i] = glm::clamp(_alpha + (2.0f * randFloat() - 1) * _alphaSpread, 0.0f, 1.0f); + float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _alphaSpread / _alpha; + _alphaStarts[i] = spreadMultiplier * getAlphaStart(); + _alphaMiddles[i] = spreadMultiplier * _alpha; + _alphaFinishes[i] = spreadMultiplier * getAlphaFinish(); } + updateAlpha(i, 0.0f); _particleTailIndex = (_particleTailIndex + 1) % _maxParticles; @@ -657,6 +667,9 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _radiusMiddles.resize(_maxParticles); _radiusFinishes.resize(_maxParticles); _particleAlphas.resize(_maxParticles); + _alphaStarts.resize(_maxParticles); + _alphaMiddles.resize(_maxParticles); + _alphaFinishes.resize(_maxParticles); // effectively clear all particles and start emitting new ones from scratch. _particleHeadIndex = 0; @@ -684,3 +697,27 @@ float ParticleEffectEntityItem::cubicInterpolate(float y0, float y1, float y2, f return (a0 * u * uu + a1 * uu + a2 * u + a3); } + +float ParticleEffectEntityItem::interpolate(float start, float middle, float finish, float age) { + if (start == middle && middle == finish) { + return middle; + } else { + float y0, y1, y2, y3, u; + + if (age <= 0.5f) { + y1 = start; + y2 = middle; + y3 = finish; + y0 = 2.0f * y1 - y2; + u = 2.0f * age; + } else { + y0 = start; + y1 = middle; + y2 = finish; + y3 = 2.0f * y2 - y1; + u = 2.0f * age - 1.0f; + } + + return cubicInterpolate(y0, y1, y2, y3, u); + } +} diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index ad8ed8b386..efdedc715d 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -60,6 +60,16 @@ public: void setAlpha(float alpha) { _alpha = alpha; } float getAlpha() const { return _alpha; } + static const float ALPHA_UNINITIALIZED; + + static const float DEFAULT_ALPHA_START; + void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; } + float getAlphaStart() const { return _alphaStart == ALPHA_UNINITIALIZED ? _alpha : _alphaStart; } + + static const float DEFAULT_ALPHA_FINISH; + void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; } + float getAlphaFinish() const { return _alphaFinish == ALPHA_UNINITIALIZED ? _alpha : _alphaFinish; } + static const float DEFAULT_ALPHA_SPREAD; void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; } float getAlphaSpread() const { return _alphaSpread; } @@ -161,7 +171,8 @@ protected: bool isAnimatingSomething() const; void stepSimulation(float deltaTime); - void updateRadius(quint32 index); + void updateRadius(quint32 index, float age); + void updateAlpha(quint32 index, float age); void extendBounds(const glm::vec3& point); void integrateParticle(quint32 index, float deltaTime); quint32 getLivingParticleCount() const; @@ -169,6 +180,8 @@ protected: // the properties of this entity rgbColor _color; float _alpha; + float _alphaStart; + float _alphaFinish; float _alphaSpread; quint32 _maxParticles; float _lifespan; @@ -198,6 +211,9 @@ protected: QVector _radiusMiddles; QVector _radiusFinishes; QVector _particleAlphas; + QVector _alphaStarts; + QVector _alphaMiddles; + QVector _alphaFinishes; float _timeUntilNextEmit; @@ -212,6 +228,7 @@ protected: private: float cubicInterpolate(float y0, float y1, float y2, float y3, float u); + float interpolate(float start, float middle, float finish, float age); }; #endif // hifi_ParticleEffectEntityItem_h From fe13d591464220b1bc34bd39777a4f3027e7f67b Mon Sep 17 00:00:00 2001 From: Rudi Chen Date: Sun, 6 Sep 2015 16:53:26 -0400 Subject: [PATCH 14/21] Troubleshooting tip for repeated build failures with cmake. --- BUILD.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILD.md b/BUILD.md index ad365fcde2..ae4a67c2ee 100644 --- a/BUILD.md +++ b/BUILD.md @@ -53,6 +53,8 @@ Create a build directory in the root of your checkout and then run the CMake bui cd build cmake .. +If cmake gives you the same error message repeatedly after the build fails (e.g. you had a typo in the QT_CMAKE_PREFIX_PATH that you fixed but the `.cmake` files still cannot be found), try removing `CMakeCache.txt`. + ####Variables Any variables that need to be set for CMake to find dependencies can be set as ENV variables in your shell profile, or passed directly to CMake with a `-D` flag appended to the `cmake ..` command. From f2fdb97f1600f76fcfa7e8787fb0f54affa74641 Mon Sep 17 00:00:00 2001 From: Rudi Chen Date: Sun, 6 Sep 2015 17:31:37 -0400 Subject: [PATCH 15/21] Add additional linux dependencies. It is a dependency of libjack-dev but without manually specifying it, I would get the error message (on Linux Mint 17.2): ``` The following packages have unmet dependencies: libjack-dev : Depends: libjack0 (= 1:0.121.3+20120418git75e3e20b-2.1ubuntu1) but it is not going to be installed ``` libudev-dev is used in linking the interface executable. --- BUILD_LINUX.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 38f5628c64..55cd647f66 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -1,6 +1,6 @@ -Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file. +Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file. ###Qt5 Dependencies Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required: - libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev libxrandr-dev + libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev From b703ce01fb61094d0c651ba9ef2148ae43106edf Mon Sep 17 00:00:00 2001 From: Rudi Chen Date: Sun, 6 Sep 2015 21:08:50 -0400 Subject: [PATCH 16/21] Make sure libdl is linked after libcrypto. Fixes a `undefined reference to symbol 'dlclose@@GLIBC_2.2.5' error I was running into on Linux Mint 17.2. --- assignment-client/CMakeLists.txt | 4 ---- domain-server/CMakeLists.txt | 5 +++++ libraries/networking/CMakeLists.txt | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index c9fd769822..84a36c6c51 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -13,10 +13,6 @@ link_hifi_libraries( physics ) -if (UNIX) - target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) -endif (UNIX) - include_application_version() copy_dlls_beside_windows_executable() diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index e4fa1d874d..ce683df698 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -31,5 +31,10 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") # append OpenSSL to our list of libraries to link target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) +# libcrypto uses dlopen in libdl +if (UNIX) + target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) +endif (UNIX) + include_application_version() copy_dlls_beside_windows_executable() diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 400fc5446a..274dae7420 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -27,6 +27,11 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") # append OpenSSL to our list of libraries to link target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES}) +# libcrypto uses dlopen in libdl +if (UNIX) + target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) +endif (UNIX) + # append tbb includes to our list of includes to bubble target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS}) include_application_version() From cb9468c311ba542649bf266fa0c67df658e5bc92 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 7 Sep 2015 16:27:42 -0700 Subject: [PATCH 17/21] Add colorSpread entity particle property --- examples/example/entities/particlesTest.js | 14 +++++++++- .../RenderableParticleEffectEntityItem.cpp | 2 +- .../entities/src/EntityItemProperties.cpp | 7 +++++ libraries/entities/src/EntityItemProperties.h | 2 ++ libraries/entities/src/EntityPropertyFlags.h | 1 + .../entities/src/ParticleEffectEntityItem.cpp | 26 ++++++++++++++++++- .../entities/src/ParticleEffectEntityItem.h | 6 +++++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 2 +- 9 files changed, 57 insertions(+), 5 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index f1ae210373..5c0a13c371 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -15,7 +15,7 @@ var box, particles, particleExample = -1, - NUM_PARTICLE_EXAMPLES = 9, + NUM_PARTICLE_EXAMPLES = 10, PARTICLE_RADIUS = 0.04; function onClickDownOnEntity(entityID) { @@ -85,11 +85,23 @@ }); break; case 8: + print("Color spread"); + Entities.editEntity(particles, { + alpha: 1.0, + alphaStart: 1.0, + alphaFinish: 1.0, + color: { red: 128, green: 128, blue: 128 }, + colorSpread: { red: 128, green: 0, blue: 0 } + }); + break; + case 9: print("Stop emitting"); Entities.editEntity(particles, { alpha: 1.0, alphaStart: 1.0, alphaFinish: 1.0, + color: { red: 255, green: 255, blue: 255 }, + colorSpread: { red: 0, green: 0, blue: 0 }, animationIsPlaying: false }); break; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index be9c28a80d..40648fe26f 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -194,8 +194,8 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // make a copy of each particle's details std::vector particleDetails; particleDetails.reserve(getLivingParticleCount()); - auto xcolor = getXColor(); for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { + auto xcolor = _particleColors[i]; auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); particleDetails.push_back(ParticleDetails(_particlePositions[i], _particleRadiuses[i], rgba)); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 6d68483388..99008c5da0 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -55,6 +55,7 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), +CONSTRUCT_PROPERTY(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD), CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA), CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START), CONSTRUCT_PROPERTY(alphaFinish, ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH), @@ -335,6 +336,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); + CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread); CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish); @@ -453,6 +455,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE(color); + COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish); @@ -590,6 +593,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); @@ -881,6 +885,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); @@ -1162,6 +1167,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); @@ -1308,6 +1314,7 @@ void EntityItemProperties::markAllChanged() { _radiusStartChanged = true; _radiusFinishChanged = true; _radiusSpreadChanged = true; + _colorSpreadChanged = true; _alphaStartChanged = true; _alphaFinishChanged = true; _alphaSpreadChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3721e0d9ca..43573c0744 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -103,6 +103,7 @@ public: DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); + DEFINE_PROPERTY(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor); DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float); DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float); DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); @@ -298,6 +299,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 146f4126a7..4bd6a1cd96 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -154,6 +154,7 @@ enum EntityPropertyList { PROP_ALPHA, // Supported by some derived classes //Used by particles + PROP_COLOR_SPREAD, PROP_ALPHA_SPREAD, PROP_ALPHA_START, PROP_ALPHA_FINISH, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index a85a83a4ac..9ae80f098b 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -43,6 +43,7 @@ #include "ParticleEffectEntityItem.h" const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; +const xColor ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD = { 0, 0, 0 }; const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f; const float ParticleEffectEntityItem::ALPHA_UNINITIALIZED = -1.0f; const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = ALPHA_UNINITIALIZED; @@ -90,6 +91,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _textures(DEFAULT_TEXTURES), _texturesChangedFlag(false), _shapeType(SHAPE_TYPE_NONE), + _colorSpread(DEFAULT_COLOR_SPREAD), _alpha(DEFAULT_ALPHA), _alphaStart(DEFAULT_ALPHA_START), _alphaFinish(DEFAULT_ALPHA_FINISH), @@ -102,7 +104,8 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), - _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), + _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), @@ -186,6 +189,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread); @@ -216,6 +220,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread); @@ -291,6 +296,10 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); + } + + if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) { + READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread); READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); @@ -323,6 +332,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_RADIUS_SPREAD; requestedProperties += PROP_RADIUS_START; requestedProperties += PROP_RADIUS_FINISH; + requestedProperties += PROP_COLOR_SPREAD; requestedProperties += PROP_ALPHA; requestedProperties += PROP_ALPHA_SPREAD; requestedProperties += PROP_ALPHA_START; @@ -358,6 +368,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, 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_ALPHA, getAlpha()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart()); @@ -625,6 +636,18 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { integrateParticle(i, timeLeftInFrame); extendBounds(_particlePositions[i]); + // Color + if (_colorSpread == xColor(xColor{ 0, 0, 0 })) { + _particleColors[i] = getXColor(); + } else { + float spread = 2.0f * randFloat() - 1.0f; + xColor color = getXColor(); + color.red = (int)glm::clamp((float)color.red + spread * (float)_colorSpread.red, 0.0f, 255.0f); + color.green = (int)glm::clamp((float)color.green + spread * (float)_colorSpread.green, 0.0f, 255.0f); + color.blue = (int)glm::clamp((float)color.blue + spread * (float)_colorSpread.blue, 0.0f, 255.0f); + _particleColors[i] = color; + } + // Alpha if (_alphaSpread == 0.0f) { _alphaStarts[i] = getAlphaStart(); @@ -666,6 +689,7 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _radiusStarts.resize(_maxParticles); _radiusMiddles.resize(_maxParticles); _radiusFinishes.resize(_maxParticles); + _particleColors.resize(_maxParticles); _particleAlphas.resize(_maxParticles); _alphaStarts.resize(_maxParticles); _alphaMiddles.resize(_maxParticles); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index efdedc715d..7f117ca5cd 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -56,6 +56,10 @@ public: _color[BLUE_INDEX] = value.blue; } + static const xColor DEFAULT_COLOR_SPREAD; + void setColorSpread(const xColor colorSpread) { _colorSpread = colorSpread; } + xColor getColorSpread() const { return _colorSpread; } + static const float DEFAULT_ALPHA; void setAlpha(float alpha) { _alpha = alpha; } float getAlpha() const { return _alpha; } @@ -179,6 +183,7 @@ protected: // the properties of this entity rgbColor _color; + xColor _colorSpread; float _alpha; float _alphaStart; float _alphaFinish; @@ -210,6 +215,7 @@ protected: QVector _radiusStarts; QVector _radiusMiddles; QVector _radiusFinishes; + QVector _particleColors; QVector _particleAlphas; QVector _alphaStarts; QVector _alphaMiddles; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 3a2013d367..bb120ce198 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_PARTICLE_ALPHA_PROPERTIES; + return VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES; case AvatarData: return 13; default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e63f7f410b..eb48bc8019 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -146,6 +146,6 @@ const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39; const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40; const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41; -const PacketVersion VERSION_ENTITIES_PARTICLE_ALPHA_PROPERTIES = 42; +const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42; #endif // hifi_PacketHeaders_h From 743d79335dd27ffcd4a2aa58cc5935ba802938a6 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 5 Sep 2015 23:00:17 -0700 Subject: [PATCH 18/21] Procedural shaders V2 --- examples/shaders/example.fs | 55 ++++ examples/shaders/exampleFloor.fs | 49 ++++ examples/shaders/exampleSphere.fs | 22 ++ examples/shaders/exampleSphereDisco.fs | 17 ++ examples/shaders/exampleUserDataV2.json | 25 ++ examples/shaders/exampleV2.fs | 40 +++ examples/shaders/noise.fs | 39 +++ examples/shaders/scratch.fs | 136 +++++++++ examples/shaders/shadertoyWrapper.fs | 32 +++ examples/shaders/shadertoys/clock.fs | 231 +++++++++++++++ examples/shaders/shadertoys/relentless.fs | 269 ++++++++++++++++++ examples/shaders/shadertoys/topologica.fs | 136 +++++++++ .../src/RenderableBoxEntityItem.cpp | 6 +- .../src/RenderableProceduralItem.cpp | 138 +++++++-- .../src/RenderableProceduralItem.h | 11 +- .../src/RenderableProceduralItemShader.h | 78 +++-- .../src/RenderableSphereEntityItem.cpp | 4 +- libraries/gpu/src/gpu/Batch.h | 2 + libraries/gpu/src/gpu/GLBackend.cpp | 31 ++ libraries/gpu/src/gpu/GLBackend.h | 1 + 20 files changed, 1275 insertions(+), 47 deletions(-) create mode 100644 examples/shaders/example.fs create mode 100644 examples/shaders/exampleFloor.fs create mode 100644 examples/shaders/exampleSphere.fs create mode 100644 examples/shaders/exampleSphereDisco.fs create mode 100644 examples/shaders/exampleUserDataV2.json create mode 100644 examples/shaders/exampleV2.fs create mode 100644 examples/shaders/noise.fs create mode 100644 examples/shaders/scratch.fs create mode 100644 examples/shaders/shadertoyWrapper.fs create mode 100644 examples/shaders/shadertoys/clock.fs create mode 100644 examples/shaders/shadertoys/relentless.fs create mode 100644 examples/shaders/shadertoys/topologica.fs diff --git a/examples/shaders/example.fs b/examples/shaders/example.fs new file mode 100644 index 0000000000..171b692ac5 --- /dev/null +++ b/examples/shaders/example.fs @@ -0,0 +1,55 @@ +#line 2 + +////////////////////////////////// +// +// Available inputs +// +// Uniforms: constant across the whole surface +// +// float iGlobalTime; +// vec3 iWorldScale; +// +// Varyings: Per-pixel attributes that change for every pixel +// +// vec3 _normal +// vec4 _position +// vec2 _texCoord0 // reserved for future use, currently always vec2(0) +// vec3 _color // reserved for future user, currently always vec3(1) +// +///////////////////////////////// + +////////////////////////////////// +// +// Available functions +// +// All GLSL functions from GLSL version 4.10 and usable in fragment shaders +// See Page 8 of this document: https://www.khronos.org/files/opengl41-quick-reference-card.pdf +// +// Additionally the snoise functions defined in WebGL-noise are available +// See https://github.com/ashima/webgl-noise/tree/master/src +// +// float snoise(vec2) +// float snoise(vec3) +// float snoise(vec4) +// + +// Fade from black to white and back again +vec4 getProceduralColor() { + // set intensity to a sine wave with a frequency of 1 Hz + float intensity = sin(iGlobalTime * 3.14159 * 2.0); + + // Raise the wave to move between 0 and 2 + intensity += 1.0; + + // Reducce the amplitude to between 0 and 1 + intensity /= 2.0; + + // Set the base color to blue + vec3 color = vec3(0.0, 0.0, 1.0); + + // Multiply by the intensity + color *= intensity; + + // return the color as a vec 4 + return vec4(color, 1.0); +} diff --git a/examples/shaders/exampleFloor.fs b/examples/shaders/exampleFloor.fs new file mode 100644 index 0000000000..b2fbb34ad2 --- /dev/null +++ b/examples/shaders/exampleFloor.fs @@ -0,0 +1,49 @@ +#line 2 + +// Created by inigo quilez - iq/2014 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +// { 2d cell id, distance to border, distnace to center ) +vec4 hexagon(vec2 p) { + vec2 q = vec2(p.x * 2.0 * 0.5773503, p.y + p.x * 0.5773503); + + vec2 pi = floor(q); + vec2 pf = fract(q); + + float v = mod(pi.x + pi.y, 3.0); + + float ca = step(1.0, v); + float cb = step(2.0, v); + vec2 ma = step(pf.xy, pf.yx); + + // distance to borders + float e = dot(ma, + 1.0 - pf.yx + ca * (pf.x + pf.y - 1.0) + cb * (pf.yx - 2.0 * pf.xy)); + + // distance to center + p = vec2(q.x + floor(0.5 + p.y / 1.5), 4.0 * p.y / 3.0) * 0.5 + 0.5; + float f = length((fract(p) - 0.5) * vec2(1.0, 0.85)); + + return vec4(pi + ca - cb * ma, e, f); +} + + +float hash1(vec2 p) { + float n = dot(p, vec2(127.1, 311.7)); + return fract(sin(n) * 43758.5453); +} + +vec4 getProceduralColor() { + vec2 uv = _position.xz + 0.5; + vec2 pos = _position.xz * iWorldScale.xz; + // gray + vec4 h = hexagon(8.0 * pos + 0.5); + float n = snoise(vec3(0.3 * h.xy + iGlobalTime * 0.1, iGlobalTime)); + vec3 col = 0.15 + 0.15 * hash1(h.xy + 1.2) * vec3(1.0); + col *= smoothstep(0.10, 0.11, h.z); + col *= smoothstep(0.10, 0.11, h.w); + col *= 1.0 + 0.15 * sin(40.0 * h.z); + col *= 0.75 + 0.5 * h.z * n; + col *= pow(16.0 * uv.x * (1.0 - uv.x) * uv.y * (1.0 - uv.y), 0.1); + return vec4(col, 1.0); +} diff --git a/examples/shaders/exampleSphere.fs b/examples/shaders/exampleSphere.fs new file mode 100644 index 0000000000..ccf11d5d02 --- /dev/null +++ b/examples/shaders/exampleSphere.fs @@ -0,0 +1,22 @@ +#line 2 + +const vec3 RED = vec3(1.0, 0.0, 0.0); +const vec3 GREEN = vec3(0.0, 1.0, 0.0); +const vec3 BLUE = vec3(0.0, 0.0, 1.0); +const vec3 YELLOW = vec3(1.0, 1.0, 0.0); +const vec3 WHITE = vec3(1.0, 1.0, 1.0); + +vec4 getProceduralColor() { + float intensity = 0.0; + for (int i = 0; i < 2; ++i) { + float modifier = pow(2, i); + float noise = snoise(vec4(_position.xyz * 10.0 * modifier, iGlobalTime)); + noise /= modifier; + intensity += noise; + } + intensity /= 2.0; + intensity += 0.5; + vec3 color = (intensity * BLUE) + (1.0 - intensity) * YELLOW; + return vec4(color, 1.0); +} + diff --git a/examples/shaders/exampleSphereDisco.fs b/examples/shaders/exampleSphereDisco.fs new file mode 100644 index 0000000000..ea54b35b42 --- /dev/null +++ b/examples/shaders/exampleSphereDisco.fs @@ -0,0 +1,17 @@ +#line 2 + +float noise(vec3 v) { + return snoise(vec4(v, iGlobalTime)); +} + +vec3 noise3_3(vec3 p) { + float fx = noise(p); + float fy = noise(p + vec3(1345.67, 0, 45.67)); + float fz = noise(p + vec3(0, 134.67, 3245.67)); + return vec3(fx, fy, fz); +} + +vec4 getProceduralColor() { + vec3 color = noise3_3(_position.xyz * 10.0); + return vec4(color, 1.0); +} \ No newline at end of file diff --git a/examples/shaders/exampleUserDataV2.json b/examples/shaders/exampleUserDataV2.json new file mode 100644 index 0000000000..d15ef905b3 --- /dev/null +++ b/examples/shaders/exampleUserDataV2.json @@ -0,0 +1,25 @@ + { + "ProceduralEntity": { + "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/exampleV2.fs", + // V2 and onwards, shaders must include a version identifier, or they will default + // to V1 behavior + "version": 2, + // Any values specified here will be passed on to uniforms with matching names in + // the shader. Only numbers and arrays of length 1-4 of numbers are supported. + // + // The size of the data must match the size of the uniform: + // a number or 1 value array = 'uniform float' + // 2 value array = 'uniform vec2' + // 3 value array = 'uniform vec3' + // 4 value array = 'uniform vec4' + // + // Uniforms should always be declared in the shader with a default value + // or failure to specify the value here will result in undefined behavior. + "uniforms": { + // uniform float iSpeed = 1.0; + "iSpeed": 2.0, + // uniform vec3 iSize = vec3(1.0); + "iSize": [1.0, 2.0, 4.0] + } + } + } \ No newline at end of file diff --git a/examples/shaders/exampleV2.fs b/examples/shaders/exampleV2.fs new file mode 100644 index 0000000000..8967df09e2 --- /dev/null +++ b/examples/shaders/exampleV2.fs @@ -0,0 +1,40 @@ +const vec3 BLUE = vec3(0.0, 0.0, 1.0); +const vec3 YELLOW = vec3(1.0, 1.0, 0.0); + +uniform float iSpeed = 1.0; +uniform vec3 iSize = vec3(1.0, 1.0, 1.0); + +vec3 getNoiseColor() { + float intensity = 0.0; + vec3 position = _position.xyz; + //position = normalize(position); + float time = iGlobalTime * iSpeed; + for (int i = 0; i < 4; ++i) { + float modifier = pow(2, i); + vec3 noisePosition = position * iSize * 10.0 * modifier; + float noise = snoise(vec4(noisePosition, time)); + noise /= modifier; + intensity += noise; + } + intensity /= 2.0; intensity += 0.5; + return (intensity * BLUE) + (1.0 - intensity) * YELLOW; +} + +// Produce a lit procedural surface +float getProceduralColorsLit(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + vec3 noiseColor = getNoiseColor(); + diffuse = noiseColor; + return 0.0; +} + +// Produce an unlit procedural surface: emulates old behavior +float getProceduralColorsUnlit(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + vec3 noiseColor = getNoiseColor(); + diffuse = vec3(1.0); + specular = noiseColor; + return 1.0; +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return getProceduralColorsLit(diffuse, specular, shininess); +} \ No newline at end of file diff --git a/examples/shaders/noise.fs b/examples/shaders/noise.fs new file mode 100644 index 0000000000..ae7a8bf081 --- /dev/null +++ b/examples/shaders/noise.fs @@ -0,0 +1,39 @@ +#line 2 + +////////////////////////////////// +// +// Available inputs +// +// Uniforms: constant across the whole surface +// +// float iGlobalTime; +// vec3 iWorldScale; +// +// Varyings: Per-pixel attributes that change for every pixel +// +// vec3 _normal +// vec4 _position +// vec2 _texCoord0 // reserved for future use, currently always vec2(0) +// vec3 _color // reserved for future user, currently always vec3(1) +// +///////////////////////////////// + +////////////////////////////////// +// +// Available functions +// +// All GLSL functions from GLSL version 4.10 and usable in fragment shaders +// See Page 8 of this document: https://www.khronos.org/files/opengl41-quick-reference-card.pdf +// +// Additionally the snoise functions defined in WebGL-noise are available +// See https://github.com/ashima/webgl-noise/tree/master/src +// +// float snoise(vec2) +// float snoise(vec3) +// float snoise(vec4) +// + +// Fade from black to white and back again +vec4 getProceduralColor() { + return vec4(vec3(abs((sin(iGlobalTime * 3.14159) + 1.0) / 2.0)), 1); // vec4(color, 1.0); +} diff --git a/examples/shaders/scratch.fs b/examples/shaders/scratch.fs new file mode 100644 index 0000000000..c402524e6d --- /dev/null +++ b/examples/shaders/scratch.fs @@ -0,0 +1,136 @@ +#line 2 +vec2 iResolution = iWorldScale.xz; +vec2 iMouse = vec2(0); + +// From https://www.shadertoy.com/view/4djXzz + +/*-------------------------------------------------------------------------------------- + License CC0 - http://creativecommons.org/publicdomain/zero/1.0/ + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. + ---------------------------------------------------------------------------------------- + ^ This means do ANYTHING YOU WANT with this code. Because we are programmers, not lawyers. + -Otavio Good + */ + +// various noise functions +float Hash2d(vec2 uv) +{ + float f = uv.x + uv.y * 47.0; + return fract(cos(f*3.333)*100003.9); +} +float Hash3d(vec3 uv) { + float f = uv.x + uv.y * 37.0 + uv.z * 521.0; + return fract(cos(f * 3.333) * 100003.9); +} +float mixP(float f0, float f1, float a) { + return mix(f0, f1, a * a * (3.0 - 2.0 * a)); +} +const vec2 zeroOne = vec2(0.0, 1.0); +float noise2d(vec2 uv) { + vec2 fr = fract(uv.xy); + vec2 fl = floor(uv.xy); + float h00 = Hash2d(fl); + float h10 = Hash2d(fl + zeroOne.yx); + float h01 = Hash2d(fl + zeroOne); + float h11 = Hash2d(fl + zeroOne.yy); + return mixP(mixP(h00, h10, fr.x), mixP(h01, h11, fr.x), fr.y); +} + +float noise(vec3 uv) { + vec3 fr = fract(uv.xyz); + vec3 fl = floor(uv.xyz); + float h000 = Hash3d(fl); + float h100 = Hash3d(fl + zeroOne.yxx); + float h010 = Hash3d(fl + zeroOne.xyx); + float h110 = Hash3d(fl + zeroOne.yyx); + float h001 = Hash3d(fl + zeroOne.xxy); + float h101 = Hash3d(fl + zeroOne.yxy); + float h011 = Hash3d(fl + zeroOne.xyy); + float h111 = Hash3d(fl + zeroOne.yyy); + return mixP(mixP(mixP(h000, h100, fr.x), mixP(h010, h110, fr.x), fr.y), + mixP(mixP(h001, h101, fr.x), mixP(h011, h111, fr.x), fr.y), fr.z); +} + +float PI = 3.14159265; + +vec3 saturate(vec3 a) { + return clamp(a, 0.0, 1.0); +} +vec2 saturate(vec2 a) { + return clamp(a, 0.0, 1.0); +} +float saturate(float a) { + return clamp(a, 0.0, 1.0); +} + +float Density(vec3 p) { + //float ws = 0.06125*0.125; + //vec3 warp = vec3(noise(p*ws), noise(p*ws + 111.11), noise(p*ws + 7111.11)); + float final = noise(p * 0.06125); // + sin(iGlobalTime)*0.5-1.95 + warp.x*4.0; + float other = noise(p * 0.06125 + 1234.567); + other -= 0.5; + final -= 0.5; + final = 0.1 / (abs(final * final * other)); + final += 0.5; + return final * 0.0001; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // ---------------- First, set up the camera rays for ray marching ---------------- + vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;// - 0.5; + + // Camera up vector. + vec3 camUp=vec3(0,1,0);// vuv + + // Camera lookat. + vec3 camLookat=vec3(0,0.0,0);// vrp + + float mx=iMouse.x/iResolution.x*PI*2.0 + iGlobalTime * 0.01; + float my=-iMouse.y/iResolution.y*10.0 + sin(iGlobalTime * 0.03)*0.2+0.2;//*PI/2.01; + vec3 camPos=vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(200.2);// prp + + // Camera setup. + vec3 camVec=normalize(camLookat - camPos);//vpn + vec3 sideNorm=normalize(cross(camUp, camVec));// u + vec3 upNorm=cross(camVec, sideNorm);//v + vec3 worldFacing=(camPos + camVec);//vcv + vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;//scrCoord + vec3 relVec = normalize(worldPix - camPos);//scp + + // -------------------------------------------------------------------------------- + float t = 0.0; + float inc = 0.02; + float maxDepth = 70.0; + vec3 pos = vec3(0,0,0); + float density = 0.0; + // ray marching time + for (int i = 0; i < 37; i++)// This is the count of how many times the ray actually marches. + { + if ((t > maxDepth)) break; + pos = camPos + relVec * t; + float temp = Density(pos); + //temp *= saturate(t-1.0); + + inc = 1.9 + temp*0.05;// add temp because this makes it look extra crazy! + density += temp * inc; + t += inc; + } + + // -------------------------------------------------------------------------------- + // Now that we have done our ray marching, let's put some color on this. + vec3 finalColor = vec3(0.01,0.1,1.0)* density*0.2; + + // output the final color with sqrt for "gamma correction" + fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0); +} + +vec4 getProceduralColor() { + vec4 result; + vec2 position = _position.xz; + position += 0.5; + + mainImage(result, position * iWorldScale.xz); + + return result; +} diff --git a/examples/shaders/shadertoyWrapper.fs b/examples/shaders/shadertoyWrapper.fs new file mode 100644 index 0000000000..f1f7e3d54f --- /dev/null +++ b/examples/shaders/shadertoyWrapper.fs @@ -0,0 +1,32 @@ +vec2 iResolution = iWorldScale.xz; +vec2 iMouse = vec2(0); + +//////////////////////////////////////////////////////////////////////////////////// +// +// REPLACE BELOW +// +// Replace the contents of this section with a shadertoy that includes a mainImage +// function +// +//////////////////////////////////////////////////////////////////////////////////// + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + fragColor = vec4(0, 0, 1, 1); +} + +//////////////////////////////////////////////////////////////////////////////////// +// +// REPLACE ABOVE +// +//////////////////////////////////////////////////////////////////////////////////// + + +vec4 getProceduralColor() { + vec4 result; + vec2 position = _position.xz; + position += 0.5; + + mainImage(result, position * iWorldScale.xz); + + return result; +} \ No newline at end of file diff --git a/examples/shaders/shadertoys/clock.fs b/examples/shaders/shadertoys/clock.fs new file mode 100644 index 0000000000..5698cb9130 --- /dev/null +++ b/examples/shaders/shadertoys/clock.fs @@ -0,0 +1,231 @@ +vec2 iResolution = iWorldScale.xz; + +// from https://www.shadertoy.com/view/Xd2XWR + +// Created by Daniel Burke - burito/2014 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +// Inspiration from Dr Who (2005) S7E13 - The Name of the Doctor + +vec2 rot(vec2 p, float a) +{ + float c = cos(a); + float s = sin(a); + return vec2(p.x*c + p.y*s, + -p.x*s + p.y*c); +} + +float circle(vec2 pos, float radius) +{ + return clamp(((1.0-abs(length(pos)-radius))-0.99)*100.0, 0.0, 1.0); + +} + +float circleFill(vec2 pos, float radius) +{ + return clamp(((1.0-(length(pos)-radius))-0.99)*100.0, 0.0, 1.0); +} + +// Thanks Iñigo Quilez! +float line( in vec2 p, in vec2 a, in vec2 b ) +{ + vec2 pa = -p - a; + vec2 ba = b - a; + float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); + float d = length( pa - ba*h ); + + return clamp(((1.0 - d)-0.99)*100.0, 0.0, 1.0); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + vec2 p = -1.0 + 2.0 * uv; + p.x *= iResolution.x / iResolution.y; + + vec3 colour = vec3(0); + vec3 white = vec3(1); + + + + float c = circle(p, 0.2); + c += circle(p, 0.1); + c += circle(p, 0.18); + c += circleFill(p, 0.005); + +// c += circle(p, 1.3); + c += circle(p, 1.0); + if(p.x > 0.0)c += circle(p, 0.4); + if(p.x > 0.0)c += circle(p, 0.42); + if(p.x < 0.0)c += circle(p, 0.47); + c += circleFill(p+vec2(0.47, 0.0), 0.02); + c += circleFill(p+vec2(0.84147*0.47, 0.54030*0.47), 0.02); + c += circleFill(p+vec2(0.84147*0.47, -0.54030*0.47), 0.02); + c += circleFill(p+vec2(0.41614*0.47, 0.90929*0.47), 0.02); + c += circleFill(p+vec2(0.41614*0.47, -0.90929*0.47), 0.02); + + float t = iGlobalTime; + float t2 = t * -0.01; + float t3 = t * 0.03; + + vec2 angle1 = vec2(sin(t), cos(t)); + vec2 a = angle1 * 0.7; + + t *= 0.5; + vec2 angle2 = vec2(sin(t), cos(t)); + vec2 b = angle2 * 0.8; + + vec2 angle3 = vec2(sin(t2), cos(t2)); + vec2 d = b + angle3* 0.4; + + vec2 angle4 = vec2(sin(t3), cos(t3)); + vec2 e = angle4 * 0.9; + + vec2 angle5 = vec2(sin(t3+4.0), cos(t3+4.0)); + vec2 f = angle5 * 0.8; + + vec2 angle6 = vec2(sin(t*-0.1+5.0), cos(t*-0.1+5.0)); + vec2 h = angle6 * 0.8; + + + + + + float tt = t * 1.4; + + float tm = mod(tt, 0.5); + float tmt = tt - tm; + if( tm > 0.4) tmt += (tm-0.4)*5.0; + vec2 tangle1 = vec2(sin(tmt), cos(tmt)); + + tt *= 0.8; + tm = mod(tt, 0.6); + float tmt2 = tt - tm; + if( tm > 0.2) tmt2 += (tm-0.2)*1.5; + + vec2 tangle2 = vec2(sin(tmt2*-4.0), cos(tmt2*-4.0)); + + vec2 tangle3 = vec2(sin(tmt2), cos(tmt2)); + + tt = t+3.0; + tm = mod(tt, 0.2); + tmt = tt - tm; + if( tm > 0.1) tmt += (tm-0.1)*2.0; + vec2 tangle4 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.9; + vec2 tangle41 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5; + vec2 tangle42 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5; + vec2 tangle43 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5; + vec2 tangle44 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5; + vec2 tangle45 = vec2(sin(-tmt), cos(-tmt)); + + tt = iGlobalTime+0.001; + tm = mod(tt, 1.0); + tmt = tt - tm; + if( tm > 0.9) tmt += (tm-0.9)*10.0; + + vec2 tangle51 = 0.17*vec2(sin(-tmt), cos(-tmt)); tmt += 1.0471975511965976; + vec2 tangle52 = 0.17*vec2(sin(-tmt), cos(-tmt)); tmt += 1.0471975511965976; + vec2 tangle53 = 0.17*vec2(sin(-tmt), cos(-tmt)); + + c += line(p, tangle51, -tangle53); + c += line(p, tangle52, tangle51); + c += line(p, tangle53, tangle52); + c += line(p, -tangle51, tangle53); + c += line(p, -tangle52, -tangle51); + c += line(p, -tangle53, -tangle52); + + c += circleFill(p+tangle51, 0.01); + c += circleFill(p+tangle52, 0.01); + c += circleFill(p+tangle53, 0.01); + c += circleFill(p-tangle51, 0.01); + c += circleFill(p-tangle52, 0.01); + c += circleFill(p-tangle53, 0.01); + + + + c += circle(p+a, 0.2); + c += circle(p+a, 0.14); + c += circle(p+a, 0.1); + c += circleFill(p+a, 0.04); + c += circleFill(p+a+tangle3*0.2, 0.025); + + + c += circle(p+a, 0.14); + + + c += circle(p+b, 0.2); + c += circle(p+b, 0.03); + c += circle(p+b, 0.15); + c += circle(p+b, 0.45); + c += circleFill(p+b+tangle1*0.05, 0.01); + c += circleFill(p+b+tangle1*0.09, 0.02); + c += circleFill(p+b+tangle1*0.15, 0.03); + c += circle(p+b+tangle1*-0.15, 0.03); + c += circle(p+b+tangle1*-0.07, 0.015); + + c += circle(p+d, 0.08); + + + c += circle(p+e, 0.08); + + + c += circle(p+f, 0.12); + c += circle(p+f, 0.10); + c += circleFill(p+f+tangle2*0.05, 0.01); + c += circleFill(p+f+tangle2*0.10, 0.01); + c += circle(p+f-tangle2*0.03, 0.01); + c += circleFill(p+f+vec2(0.085), 0.005); + c += circleFill(p+f, 0.005); + + + vec2 g = tangle4 * 0.16; + c += circle(p+h, 0.05); + c += circle(p+h, 0.1); + c += circle(p+h, 0.17); + c += circle(p+h, 0.2); + c += circleFill(p+h+tangle41 *0.16, 0.01); + c += circleFill(p+h+tangle42 *0.16, 0.01); + c += circleFill(p+h+tangle43 *0.16, 0.01); + c += circleFill(p+h+tangle44 *0.16, 0.01); + c += circleFill(p+h+tangle45 *0.16, 0.01); + c += circleFill(p+h+angle1 *0.06, 0.02); + c += circleFill(p+h+tangle43*-0.16, 0.01); + + + c += line(p, vec2(0.0), a); + c += circleFill(p+b, 0.005); + c += circleFill(p+d, 0.005); + c += circleFill(p+e, 0.005); + + c += line(p, b, a); + c += line(p, d, e); + c += line(p, b+tangle1*0.15, e); + c += line(p, e, f+vec2(0.085)); + + c += line(p, h+angle1*0.06, f); + c += line(p, h+tangle43*-0.16, d); + c += line(p, h+tangle42*0.16, e); + + + // of course I'd write a line function that + // doesn't handle perfectly vertical lines + c += line(p, vec2(0.001, -0.5), vec2(0.0001, 0.5)); + c += circleFill(p+vec2(0.001, -0.5), 0.005); + c += circleFill(p+vec2(0.001, 0.5), 0.005); + + c = clamp(c, 0.0, 1.0); + colour = white * c; + + + fragColor = vec4(colour, 1.0); +} + + +vec4 getProceduralColor() { + vec4 result; + vec2 position = _position.xz; + position += 0.5; + + mainImage(result, position * iWorldScale.xz); + return result; +} \ No newline at end of file diff --git a/examples/shaders/shadertoys/relentless.fs b/examples/shaders/shadertoys/relentless.fs new file mode 100644 index 0000000000..c3d4aeb762 --- /dev/null +++ b/examples/shaders/shadertoys/relentless.fs @@ -0,0 +1,269 @@ +vec2 iResolution = iWorldScale.xz; +vec2 iMouse = vec2(0); + +// From https://www.shadertoy.com/view/lss3WS + +// srtuss, 2013 + +// collecting some design ideas for a new game project. +// no raymarching is used. + +// if i could add a custom soundtrack, it'd use this one (essential for desired sensation) +// http://www.youtube.com/watch?v=1uFAu65tZpo + +//#define GREEN_VERSION + +// ** improved camera shaking +// ** cleaned up code +// ** added stuff to the gates + +// ******************************************************************************************* +// Please do NOT use this shader in your own productions/videos/games without my permission! +// If you'd still like to do so, please drop me a mail (stral@aon.at) +// ******************************************************************************************* + +float time = iGlobalTime; + +vec2 rotate(vec2 p, float a) { + return vec2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a)); +} +float box(vec2 p, vec2 b, float r) { + return length(max(abs(p) - b, 0.0)) - r; +} + +// iq's ray-plane-intersection code +vec3 intersect(in vec3 o, in vec3 d, vec3 c, vec3 u, vec3 v) +{ + vec3 q = o - c; + return vec3( + dot(cross(u, v), q), + dot(cross(q, u), d), + dot(cross(v, q), d)) / dot(cross(v, u), d); +} + +// some noise functions for fast developing +float rand11(float p) { + return fract(sin(p * 591.32) * 43758.5357); +} +float rand12(vec2 p) { + return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5357); +} +vec2 rand21(float p) { + return fract(vec2(sin(p * 591.32), cos(p * 391.32))); +} +vec2 rand22(in vec2 p) +{ + return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077))); +} + +float noise11(float p) { + float fl = floor(p); + return mix(rand11(fl), rand11(fl + 1.0), fract(p)); //smoothstep(0.0, 1.0, fract(p))); +} +float fbm11(float p) { + return noise11(p) * 0.5 + noise11(p * 2.0) * 0.25 + noise11(p * 5.0) * 0.125; +} +vec3 noise31(float p) { + return vec3(noise11(p), noise11(p + 18.952), noise11(p - 11.372)) * 2.0 - 1.0; +} + +// something that looks a bit like godrays coming from the surface +float sky(vec3 p) { + float a = atan(p.x, p.z); + float t = time * 0.1; + float v = rand11(floor(a * 4.0 + t)) * 0.5 + rand11(floor(a * 8.0 - t)) * 0.25 + + rand11(floor(a * 16.0 + t)) * 0.125; + return v; +} + +vec3 voronoi(in vec2 x) +{ + vec2 n = floor(x); // grid cell id + vec2 f = fract(x);// grid internal position + vec2 mg;// shortest distance... + vec2 mr;// ..and second shortest distance + float md = 8.0, md2 = 8.0; + for(int j = -1; j <= 1; j ++) + { + for(int i = -1; i <= 1; i ++) + { + vec2 g = vec2(float(i), float(j)); // cell id + vec2 o = rand22(n + g);// offset to edge point + vec2 r = g + o - f; + + float d = max(abs(r.x), abs(r.y));// distance to the edge + + if(d < md) + { md2 = md; md = d; mr = r; mg = g;} + else if(d < md2) + { md2 = d;} + } + } + return vec3(n + mg, md2 - md); +} + +#define A2V(a) vec2(sin((a) * 6.28318531 / 100.0), cos((a) * 6.28318531 / 100.0)) + +float circles(vec2 p) { + float v, w, l, c; + vec2 pp; + l = length(p); + + pp = rotate(p, time * 3.0); + c = max(dot(pp, normalize(vec2(-0.2, 0.5))), + -dot(pp, normalize(vec2(0.2, 0.5)))); + c = min(c, + max(dot(pp, normalize(vec2(0.5, -0.5))), + -dot(pp, normalize(vec2(0.2, -0.5))))); + c = min(c, + max(dot(pp, normalize(vec2(0.3, 0.5))), + -dot(pp, normalize(vec2(0.2, 0.5))))); + + // innerest stuff + v = abs(l - 0.5) - 0.03; + v = max(v, -c); + v = min(v, abs(l - 0.54) - 0.02); + v = min(v, abs(l - 0.64) - 0.05); + + pp = rotate(p, time * -1.333); + c = max(dot(pp, A2V(-5.0)), -dot(pp, A2V(5.0))); + c = min(c, max(dot(pp, A2V(25.0 - 5.0)), -dot(pp, A2V(25.0 + 5.0)))); + c = min(c, max(dot(pp, A2V(50.0 - 5.0)), -dot(pp, A2V(50.0 + 5.0)))); + c = min(c, max(dot(pp, A2V(75.0 - 5.0)), -dot(pp, A2V(75.0 + 5.0)))); + + w = abs(l - 0.83) - 0.09; + v = min(v, max(w, c)); + + return v; +} + +float shade1(float d) { + float v = 1.0 - smoothstep(0.0, mix(0.012, 0.2, 0.0), d); + float g = exp(d * -20.0); + return v + g * 0.5; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + uv = uv * 2.0 - 1.0; + uv.x *= iResolution.x / iResolution.y; + + // using an iq styled camera this time :) + // ray origin + vec3 ro = 0.7 * vec3(cos(0.2 * time), 0.0, sin(0.2 * time)); + ro.y = cos(0.6 * time) * 0.3 + 0.65; + // camera look at + vec3 ta = vec3(0.0, 0.2, 0.0); + + // camera shake intensity + float shake = clamp(3.0 * (1.0 - length(ro.yz)), 0.3, 1.0); + float st = mod(time, 10.0) * 143.0; + + // build camera matrix + vec3 ww = normalize(ta - ro + noise31(st) * shake * 0.01); + vec3 uu = normalize(cross(ww, normalize(vec3(0.0, 1.0, 0.2 * sin(time))))); + vec3 vv = normalize(cross(uu, ww)); + // obtain ray direction + vec3 rd = normalize(uv.x * uu + uv.y * vv + 1.0 * ww); + + // shaking and movement + ro += noise31(-st) * shake * 0.015; + ro.x += time * 2.0; + + float inten = 0.0; + + // background + float sd = dot(rd, vec3(0.0, 1.0, 0.0)); + inten = pow(1.0 - abs(sd), 20.0) + pow(sky(rd), 5.0) * step(0.0, rd.y) * 0.2; + + vec3 its; + float v, g; + + // voronoi floor layers + for(int i = 0; i < 4; i ++) + { + float layer = float(i); + its = intersect(ro, rd, vec3(0.0, -5.0 - layer * 5.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0)); + if(its.x > 0.0) + { + vec3 vo = voronoi((its.yz) * 0.05 + 8.0 * rand21(float(i))); + v = exp(-100.0 * (vo.z - 0.02)); + + float fx = 0.0; + + // add some special fx to lowest layer + if(i == 3) + { + float crd = 0.0; //fract(time * 0.2) * 50.0 - 25.0; + float fxi = cos(vo.x * 0.2 + time * 1.5);//abs(crd - vo.x); + fx = clamp(smoothstep(0.9, 1.0, fxi), 0.0, 0.9) * 1.0 * rand12(vo.xy); + fx *= exp(-3.0 * vo.z) * 2.0; + } + inten += v * 0.1 + fx; + } + } + + // draw the gates, 4 should be enough + float gatex = floor(ro.x / 8.0 + 0.5) * 8.0 + 4.0; + float go = -16.0; + for(int i = 0; i < 4; i ++) + { + its = intersect(ro, rd, vec3(gatex + go, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); + if(dot(its.yz, its.yz) < 2.0 && its.x > 0.0) + { + v = circles(its.yz); + inten += shade1(v); + } + + go += 8.0; + } + + // draw the stream + for(int j = 0; j < 20; j ++) + { + float id = float(j); + + vec3 bp = vec3(0.0, (rand11(id) * 2.0 - 1.0) * 0.25, 0.0); + vec3 its = intersect(ro, rd, bp, vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0)); + + if(its.x > 0.0) + { + vec2 pp = its.yz; + float spd = (1.0 + rand11(id) * 3.0) * 2.5; + pp.y += time * spd; + pp += (rand21(id) * 2.0 - 1.0) * vec2(0.3, 1.0); + float rep = rand11(id) + 1.5; + pp.y = mod(pp.y, rep * 2.0) - rep; + float d = box(pp, vec2(0.02, 0.3), 0.1); + float foc = 0.0; + float v = 1.0 - smoothstep(0.0, 0.03, abs(d) - 0.001); + float g = min(exp(d * -20.0), 2.0); + + inten += (v + g * 0.7) * 0.5; + + } + } + + inten *= 0.4 + (sin(time) * 0.5 + 0.5) * 0.6; + + // find a color for the computed intensity +#ifdef GREEN_VERSION + vec3 col = pow(vec3(inten), vec3(2.0, 0.15, 9.0)); +#else + vec3 col = pow(vec3(inten), 1.5 * vec3(0.15, 2.0, 9.0)); +#endif + + fragColor = vec4(col, 1.0); +} + +vec4 getProceduralColor() { + vec4 result; + vec2 position = _position.xz; + position += 0.5; + position.y = 1.0 - position.y; + + mainImage(result, position * iWorldScale.xz); + + return result; +} diff --git a/examples/shaders/shadertoys/topologica.fs b/examples/shaders/shadertoys/topologica.fs new file mode 100644 index 0000000000..c402524e6d --- /dev/null +++ b/examples/shaders/shadertoys/topologica.fs @@ -0,0 +1,136 @@ +#line 2 +vec2 iResolution = iWorldScale.xz; +vec2 iMouse = vec2(0); + +// From https://www.shadertoy.com/view/4djXzz + +/*-------------------------------------------------------------------------------------- + License CC0 - http://creativecommons.org/publicdomain/zero/1.0/ + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. + ---------------------------------------------------------------------------------------- + ^ This means do ANYTHING YOU WANT with this code. Because we are programmers, not lawyers. + -Otavio Good + */ + +// various noise functions +float Hash2d(vec2 uv) +{ + float f = uv.x + uv.y * 47.0; + return fract(cos(f*3.333)*100003.9); +} +float Hash3d(vec3 uv) { + float f = uv.x + uv.y * 37.0 + uv.z * 521.0; + return fract(cos(f * 3.333) * 100003.9); +} +float mixP(float f0, float f1, float a) { + return mix(f0, f1, a * a * (3.0 - 2.0 * a)); +} +const vec2 zeroOne = vec2(0.0, 1.0); +float noise2d(vec2 uv) { + vec2 fr = fract(uv.xy); + vec2 fl = floor(uv.xy); + float h00 = Hash2d(fl); + float h10 = Hash2d(fl + zeroOne.yx); + float h01 = Hash2d(fl + zeroOne); + float h11 = Hash2d(fl + zeroOne.yy); + return mixP(mixP(h00, h10, fr.x), mixP(h01, h11, fr.x), fr.y); +} + +float noise(vec3 uv) { + vec3 fr = fract(uv.xyz); + vec3 fl = floor(uv.xyz); + float h000 = Hash3d(fl); + float h100 = Hash3d(fl + zeroOne.yxx); + float h010 = Hash3d(fl + zeroOne.xyx); + float h110 = Hash3d(fl + zeroOne.yyx); + float h001 = Hash3d(fl + zeroOne.xxy); + float h101 = Hash3d(fl + zeroOne.yxy); + float h011 = Hash3d(fl + zeroOne.xyy); + float h111 = Hash3d(fl + zeroOne.yyy); + return mixP(mixP(mixP(h000, h100, fr.x), mixP(h010, h110, fr.x), fr.y), + mixP(mixP(h001, h101, fr.x), mixP(h011, h111, fr.x), fr.y), fr.z); +} + +float PI = 3.14159265; + +vec3 saturate(vec3 a) { + return clamp(a, 0.0, 1.0); +} +vec2 saturate(vec2 a) { + return clamp(a, 0.0, 1.0); +} +float saturate(float a) { + return clamp(a, 0.0, 1.0); +} + +float Density(vec3 p) { + //float ws = 0.06125*0.125; + //vec3 warp = vec3(noise(p*ws), noise(p*ws + 111.11), noise(p*ws + 7111.11)); + float final = noise(p * 0.06125); // + sin(iGlobalTime)*0.5-1.95 + warp.x*4.0; + float other = noise(p * 0.06125 + 1234.567); + other -= 0.5; + final -= 0.5; + final = 0.1 / (abs(final * final * other)); + final += 0.5; + return final * 0.0001; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // ---------------- First, set up the camera rays for ray marching ---------------- + vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;// - 0.5; + + // Camera up vector. + vec3 camUp=vec3(0,1,0);// vuv + + // Camera lookat. + vec3 camLookat=vec3(0,0.0,0);// vrp + + float mx=iMouse.x/iResolution.x*PI*2.0 + iGlobalTime * 0.01; + float my=-iMouse.y/iResolution.y*10.0 + sin(iGlobalTime * 0.03)*0.2+0.2;//*PI/2.01; + vec3 camPos=vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(200.2);// prp + + // Camera setup. + vec3 camVec=normalize(camLookat - camPos);//vpn + vec3 sideNorm=normalize(cross(camUp, camVec));// u + vec3 upNorm=cross(camVec, sideNorm);//v + vec3 worldFacing=(camPos + camVec);//vcv + vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;//scrCoord + vec3 relVec = normalize(worldPix - camPos);//scp + + // -------------------------------------------------------------------------------- + float t = 0.0; + float inc = 0.02; + float maxDepth = 70.0; + vec3 pos = vec3(0,0,0); + float density = 0.0; + // ray marching time + for (int i = 0; i < 37; i++)// This is the count of how many times the ray actually marches. + { + if ((t > maxDepth)) break; + pos = camPos + relVec * t; + float temp = Density(pos); + //temp *= saturate(t-1.0); + + inc = 1.9 + temp*0.05;// add temp because this makes it look extra crazy! + density += temp * inc; + t += inc; + } + + // -------------------------------------------------------------------------------- + // Now that we have done our ray marching, let's put some color on this. + vec3 finalColor = vec3(0.01,0.1,1.0)* density*0.2; + + // output the final color with sqrt for "gamma correction" + fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0); +} + +vec4 getProceduralColor() { + vec4 result; + vec2 position = _position.xz; + position += 0.5; + + mainImage(result, position * iWorldScale.xz); + + return result; +} diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 000a8a5f96..738c677104 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -39,16 +39,16 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well - + glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); + if (!_procedural) { _procedural.reset(new ProceduralInfo(this)); } if (_procedural->ready()) { _procedural->prepare(batch); - DependencyManager::get()->renderUnitCube(batch); + DependencyManager::get()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor)); } else { - glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); DependencyManager::get()->renderSolidCube(batch, 1.0f, cubeColor); } diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.cpp b/libraries/entities-renderer/src/RenderableProceduralItem.cpp index bec2b57a71..c88d1410a5 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItem.cpp +++ b/libraries/entities-renderer/src/RenderableProceduralItem.cpp @@ -8,10 +8,11 @@ #include "RenderableProceduralItem.h" -#include -#include #include #include +#include +#include +#include #include #include @@ -26,10 +27,19 @@ static const char* const UNIFORM_TIME_NAME= "iGlobalTime"; static const char* const UNIFORM_SCALE_NAME = "iWorldScale"; static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; +static const QString URL_KEY = "shaderUrl"; +static const QString VERSION_KEY = "version"; +static const QString UNIFORMS_KEY = "uniforms"; + RenderableProceduralItem::ProceduralInfo::ProceduralInfo(EntityItem* entity) : _entity(entity) { + parse(); +} + +void RenderableProceduralItem::ProceduralInfo::parse() { + _enabled = false; QJsonObject userData; { - const QString& userDataJson = entity->getUserData(); + const QString& userDataJson = _entity->getUserData(); if (userDataJson.isEmpty()) { return; } @@ -48,30 +58,51 @@ RenderableProceduralItem::ProceduralInfo::ProceduralInfo(EntityItem* entity) : _ // "color" : "#FFFFFF" // } //} - auto proceduralData = userData[PROCEDURAL_USER_DATA_KEY]; if (proceduralData.isNull()) { return; } - auto proceduralDataObject = proceduralData.toObject(); - QString shaderUrl = proceduralDataObject["shaderUrl"].toString(); - _shaderUrl = QUrl(shaderUrl); - if (!_shaderUrl.isValid()) { - qWarning() << "Invalid shader URL: " << shaderUrl; - return; + + parse(proceduralData.toObject()); +} + +void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& proceduralData) { + // grab the version number + { + auto version = proceduralData[VERSION_KEY]; + if (version.isDouble()) { + _version = (uint8_t)(floor(version.toDouble())); + } } - if (_shaderUrl.isLocalFile()) { - _shaderPath = _shaderUrl.toLocalFile(); - qDebug() << "Shader path: " << _shaderPath; - if (!QFile(_shaderPath).exists()) { + // Get the path to the shader + { + QString shaderUrl = proceduralData[URL_KEY].toString(); + _shaderUrl = QUrl(shaderUrl); + if (!_shaderUrl.isValid()) { + qWarning() << "Invalid shader URL: " << shaderUrl; return; } - } else { - qDebug() << "Shader url: " << _shaderUrl; - _networkShader = ShaderCache::instance().getShader(_shaderUrl); + + if (_shaderUrl.isLocalFile()) { + _shaderPath = _shaderUrl.toLocalFile(); + qDebug() << "Shader path: " << _shaderPath; + if (!QFile(_shaderPath).exists()) { + return; + } + } else { + qDebug() << "Shader url: " << _shaderUrl; + _networkShader = ShaderCache::instance().getShader(_shaderUrl); + } } + // Grab any custom uniforms + { + auto uniforms = proceduralData[UNIFORMS_KEY]; + if (uniforms.isObject()) { + _uniforms = uniforms.toObject();; + } + } _enabled = true; } @@ -106,11 +137,21 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { } if (!_pipeline || _pipelineDirty) { - _pipelineDirty = false; + _pipelineDirty = true; if (!_vertexShader) { _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); } - QString framentShaderSource = SHADER_TEMPLATE.arg(_shaderSource); + QString framentShaderSource; + switch (_version) { + case 1: + framentShaderSource = SHADER_TEMPLATE_V1.arg(_shaderSource); + break; + + default: + case 2: + framentShaderSource = SHADER_TEMPLATE_V2.arg(_shaderSource); + break; + } _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(framentShaderSource.toLocal8Bit().data()))); _shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader)); gpu::Shader::BindingSet slotBindings; @@ -129,9 +170,68 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { } batch.setPipeline(_pipeline); + + if (_pipelineDirty) { + _pipelineDirty = false; + // Set any userdata specified uniforms + foreach(QString key, _uniforms.keys()) { + std::string uniformName = key.toLocal8Bit().data(); + int32_t slot = _shader->getUniforms().findLocation(uniformName); + if (gpu::Shader::INVALID_LOCATION == slot) { + continue; + } + QJsonValue value = _uniforms[key]; + if (value.isDouble()) { + batch._glUniform1f(slot, value.toDouble()); + } else if (value.isArray()) { + auto valueArray = value.toArray(); + switch (valueArray.size()) { + case 0: + break; + + case 1: + batch._glUniform1f(slot, valueArray[0].toDouble()); + break; + case 2: + batch._glUniform2f(slot, + valueArray[0].toDouble(), + valueArray[1].toDouble()); + break; + case 3: + batch._glUniform3f(slot, + valueArray[0].toDouble(), + valueArray[0].toDouble(), + valueArray[1].toDouble()); + break; + case 4: + default: + batch._glUniform4f(slot, + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble()); + break; + + } + valueArray.size(); + } + } + } + + // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; batch._glUniform1f(_timeSlot, time); + + // FIXME move into the 'set once' section, since this doesn't change over time auto scale = _entity->getDimensions(); batch._glUniform3f(_scaleSlot, scale.x, scale.y, scale.z); batch.setResourceTexture(DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT, DependencyManager::get()->getNormalFittingTexture()); } + + +glm::vec4 RenderableProceduralItem::ProceduralInfo::getColor(const glm::vec4& entityColor) { + if (_version == 1) { + return glm::vec4(1); + } + return entityColor; +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.h b/libraries/entities-renderer/src/RenderableProceduralItem.h index e42cc81b64..37e827d304 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItem.h +++ b/libraries/entities-renderer/src/RenderableProceduralItem.h @@ -10,9 +10,10 @@ #ifndef hifi_RenderableProcedrualItem_h #define hifi_RenderableProcedrualItem_h +#include #include #include -#include +#include #include #include @@ -20,15 +21,22 @@ #include class EntityItem; +class QJsonObject; class RenderableProceduralItem { protected: + // FIXME better encapsulation + // FIXME better mechanism for extending to things rendered using shaders other than simple.slv struct ProceduralInfo { ProceduralInfo(EntityItem* entity); + void parse(); + void parse(const QJsonObject&); bool ready(); void prepare(gpu::Batch& batch); + glm::vec4 getColor(const glm::vec4& entityColor); bool _enabled{ false }; + uint8_t _version{ 1 }; gpu::PipelinePointer _pipeline; gpu::ShaderPointer _vertexShader; gpu::ShaderPointer _fragmentShader; @@ -43,6 +51,7 @@ protected: uint64_t _start{ 0 }; NetworkShaderPointer _networkShader; EntityItem* _entity; + QJsonObject _uniforms; }; QSharedPointer _procedural; diff --git a/libraries/entities-renderer/src/RenderableProceduralItemShader.h b/libraries/entities-renderer/src/RenderableProceduralItemShader.h index 82ba91cc42..8c9e7c77dd 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItemShader.h +++ b/libraries/entities-renderer/src/RenderableProceduralItemShader.h @@ -16,17 +16,17 @@ // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise // -const QString SHADER_TEMPLATE = R"SCRIBE(#version 410 core + + +const QString SHADER_COMMON = R"SHADER(#version 410 core layout(location = 0) out vec4 _fragColor0; layout(location = 1) out vec4 _fragColor1; layout(location = 2) out vec4 _fragColor2; // the glow intensity uniform float glowIntensity; - // the alpha threshold uniform float alphaThreshold; - uniform sampler2D normalFittingMap; vec3 bestFitNormal(vec3 normal) { @@ -45,18 +45,6 @@ vec3 bestFitNormal(vec3 normal) { } -const vec3 DEFAULT_SPECULAR = vec3(0.1); -const float DEFAULT_SHININESS = 10; - -void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) { - if (alpha != glowIntensity) { - discard; - } - - _fragColor0 = vec4(diffuse.rgb, alpha); - _fragColor1 = vec4(bestFitNormal(normal), 0.5); - _fragColor2 = vec4(emissive, shininess / 128.0); -} float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; @@ -314,16 +302,62 @@ uniform vec3 iWorldScale; // the dimensions of the object being rende // TODO document available inputs other than the uniforms // TODO provide world scale in addition to the untransformed position +const vec3 DEFAULT_SPECULAR = vec3(0.1); +const float DEFAULT_SHININESS = 10; + +)SHADER"; + +// V1 shaders, only support emissive +// vec4 getProceduralColor() +const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE( + +#line 1001 %1 +#line 317 void main(void) { - vec4 texel = getProceduralColor(); + vec4 emissive = getProceduralColor(); + + float alpha = glowIntensity * emissive.a; + if (alpha != glowIntensity) { + discard; + } + + vec4 diffuse = vec4(_color.rgb, alpha); + vec4 normal = vec4(normalize(bestFitNormal(_normal)), 0.5); + + _fragColor0 = diffuse; + _fragColor1 = normal; + _fragColor2 = vec4(emissive.rgb, DEFAULT_SHININESS / 128.0); +} + +)SCRIBE"; + +// void getProceduralDiffuseAndEmissive(out vec4 diffuse, out vec4 emissive) +const QString SHADER_TEMPLATE_V2 = SHADER_COMMON + R"SCRIBE( +// FIXME should we be doing the swizzle here? +vec3 iResolution = iWorldScale.xzy; + +// FIXME Mouse X,Y coordinates, and Z,W are for the click position if clicked (not supported in High Fidelity at the moment) +vec4 iMouse = vec4(0); + +// FIXME We set the seconds (iDate.w) of iDate to iGlobalTime, which contains the current date in seconds +vec4 iDate = vec4(0, 0, 0, iGlobalTime); + + +#line 1001 +%1 +#line 351 + +void main(void) { + vec3 diffuse = _color.rgb; + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; - packDeferredFragmentLightmap( - normalize(_normal), - glowIntensity * texel.a, - _color.rgb, - DEFAULT_SPECULAR, DEFAULT_SHININESS, - texel.rgb); + float emissiveAmount = getProceduralColors(diffuse, specular, shininess); + + _fragColor0 = vec4(diffuse.rgb, 1.0); + _fragColor1 = vec4(bestFitNormal(normalize(_normal.xyz)), 1.0 - (emissiveAmount / 2.0)); + _fragColor2 = vec4(specular, shininess / 128.0); } )SCRIBE"; diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 5a93a418f7..3b58397a82 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -50,11 +50,11 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { _procedural.reset(new ProceduralInfo(this)); } + glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha()); if (_procedural->ready()) { _procedural->prepare(batch); - DependencyManager::get()->renderSphere(batch, 0.5f, SLICES, STACKS, vec3(1)); + DependencyManager::get()->renderSphere(batch, 0.5f, SLICES, STACKS, _procedural->getColor(sphereColor)); } else { - glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha()); DependencyManager::get()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index ca74032c5e..0ecfde44f1 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -144,6 +144,7 @@ public: void _glUniform1f(int location, float v0); void _glUniform2f(int location, float v0, float v1); void _glUniform3f(int location, float v0, float v1, float v2); + void _glUniform4f(int location, float v0, float v1, float v2, float v3); void _glUniform3fv(int location, int count, const float* value); void _glUniform4fv(int location, int count, const float* value); void _glUniform4iv(int location, int count, const int* value); @@ -192,6 +193,7 @@ public: COMMAND_glUniform1f, COMMAND_glUniform2f, COMMAND_glUniform3f, + COMMAND_glUniform4f, COMMAND_glUniform3fv, COMMAND_glUniform4fv, COMMAND_glUniform4iv, diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 2270c0dce7..a8c21125b5 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -56,6 +56,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glUniform1f), (&::gpu::GLBackend::do_glUniform2f), (&::gpu::GLBackend::do_glUniform3f), + (&::gpu::GLBackend::do_glUniform4f), (&::gpu::GLBackend::do_glUniform3fv), (&::gpu::GLBackend::do_glUniform4fv), (&::gpu::GLBackend::do_glUniform4iv), @@ -458,6 +459,36 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } + +void Batch::_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + ADD_COMMAND_GL(glUniform4f); + + _params.push_back(v3); + _params.push_back(v2); + _params.push_back(v1); + _params.push_back(v0); + _params.push_back(location); + + DO_IT_NOW(_glUniform4f, 1); +} + + +void GLBackend::do_glUniform4f(Batch& batch, uint32 paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + glUniform4f( + batch._params[paramOffset + 4]._int, + batch._params[paramOffset + 3]._float, + batch._params[paramOffset + 2]._float, + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 0]._float); + (void)CHECK_GL_ERROR(); +} + void Batch::_glUniform3fv(GLint location, GLsizei count, const GLfloat* value) { ADD_COMMAND_GL(glUniform3fv); diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index c97ea4e615..6d806a7f06 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -457,6 +457,7 @@ protected: void do_glUniform1f(Batch& batch, uint32 paramOffset); void do_glUniform2f(Batch& batch, uint32 paramOffset); void do_glUniform3f(Batch& batch, uint32 paramOffset); + void do_glUniform4f(Batch& batch, uint32 paramOffset); void do_glUniform3fv(Batch& batch, uint32 paramOffset); void do_glUniform4fv(Batch& batch, uint32 paramOffset); void do_glUniform4iv(Batch& batch, uint32 paramOffset); From cdd5e68815c6094a31dd9c05614e92d0a27b9848 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Sep 2015 11:28:53 -0700 Subject: [PATCH 19/21] Add colorStart and colorFinish entity particle properties --- examples/example/entities/particlesTest.js | 16 +++-- .../entities/src/EntityItemProperties.cpp | 14 ++++ libraries/entities/src/EntityItemProperties.h | 6 +- libraries/entities/src/EntityPropertyFlags.h | 2 + .../entities/src/ParticleEffectEntityItem.cpp | 64 +++++++++++++++++-- .../entities/src/ParticleEffectEntityItem.h | 14 ++++ 6 files changed, 103 insertions(+), 13 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index 5c0a13c371..0d1ea60005 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -15,7 +15,7 @@ var box, particles, particleExample = -1, - NUM_PARTICLE_EXAMPLES = 10, + NUM_PARTICLE_EXAMPLES = 11, PARTICLE_RADIUS = 0.04; function onClickDownOnEntity(entityID) { @@ -95,13 +95,19 @@ }); break; case 9: - print("Stop emitting"); + print("Color start and finish"); Entities.editEntity(particles, { - alpha: 1.0, - alphaStart: 1.0, - alphaFinish: 1.0, color: { red: 255, green: 255, blue: 255 }, colorSpread: { red: 0, green: 0, blue: 0 }, + colorStart: { red: 255, green: 0, blue: 0 }, + colorFinish: { red: 0, green: 255, blue: 0 } + }); + break; + case 10: + print("Stop emitting"); + Entities.editEntity(particles, { + colorStart: { red: 255, green: 255, blue: 255 }, + colorFinish: { red: 255, green: 255, blue: 255 }, animationIsPlaying: false }); break; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 99008c5da0..66153342e7 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -55,6 +55,8 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), +CONSTRUCT_PROPERTY(colorStart, ParticleEffectEntityItem::DEFAULT_COLOR), +CONSTRUCT_PROPERTY(colorFinish, ParticleEffectEntityItem::DEFAULT_COLOR), CONSTRUCT_PROPERTY(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD), CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA), CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START), @@ -336,6 +338,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); + CHECK_PROPERTY_CHANGE(PROP_COLOR_START, colorStart); + CHECK_PROPERTY_CHANGE(PROP_COLOR_FINISH, colorFinish); CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread); CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); @@ -455,6 +459,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE(color); + COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart); @@ -593,6 +599,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart); + COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, xColor, setColorFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); @@ -885,6 +893,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish()); APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); @@ -1167,6 +1177,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, xColor, setColorStart); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, xColor, setColorFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); @@ -1314,6 +1326,8 @@ void EntityItemProperties::markAllChanged() { _radiusStartChanged = true; _radiusFinishChanged = true; _radiusSpreadChanged = true; + _colorStartChanged = true; + _colorFinishChanged = true; _colorSpreadChanged = true; _alphaStartChanged = true; _alphaFinishChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 43573c0744..1c5913fc88 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -103,7 +103,9 @@ public: DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); - DEFINE_PROPERTY(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor); + DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, xColor); + DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor); + DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor); DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float); DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float); DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); @@ -299,6 +301,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorStart, colorStart, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorFinish, colorFinish, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 4bd6a1cd96..d4f880ed8f 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -155,6 +155,8 @@ enum EntityPropertyList { //Used by particles PROP_COLOR_SPREAD, + PROP_COLOR_START, + PROP_COLOR_FINISH, PROP_ALPHA_SPREAD, PROP_ALPHA_START, PROP_ALPHA_FINISH, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 9ae80f098b..0686c3a996 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -91,6 +91,10 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _textures(DEFAULT_TEXTURES), _texturesChangedFlag(false), _shapeType(SHAPE_TYPE_NONE), + _isColorStartInitialized(false), + _isColorFinishInitialized(false), + _colorStart(DEFAULT_COLOR), + _colorFinish(DEFAULT_COLOR), _colorSpread(DEFAULT_COLOR_SPREAD), _alpha(DEFAULT_ALPHA), _alphaStart(DEFAULT_ALPHA_START), @@ -104,6 +108,9 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _colorStarts(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), + _colorMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), + _colorFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), _particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), @@ -189,6 +196,8 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); @@ -220,6 +229,8 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); @@ -300,6 +311,8 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) { READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread); + READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart); + READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish); READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); @@ -333,6 +346,8 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_RADIUS_START; requestedProperties += PROP_RADIUS_FINISH; requestedProperties += PROP_COLOR_SPREAD; + requestedProperties += PROP_COLOR_START; + requestedProperties += PROP_COLOR_FINISH; requestedProperties += PROP_ALPHA; requestedProperties += PROP_ALPHA_SPREAD; requestedProperties += PROP_ALPHA_START; @@ -369,6 +384,8 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, 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, getAlpha()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart()); @@ -546,6 +563,18 @@ void ParticleEffectEntityItem::updateRadius(quint32 index, float age) { _particleRadiuses[index] = interpolate(_radiusStarts[index], _radiusMiddles[index], _radiusFinishes[index], age); } +void ParticleEffectEntityItem::updateColor(quint32 index, float age) { + _particleColors[index].red = + (int)glm::clamp(interpolate(_colorStarts[index].red, _colorMiddles[index].red, _colorFinishes[index].red, age), + 0.0f, 255.0f); + _particleColors[index].green = + (int)glm::clamp(interpolate(_colorStarts[index].green, _colorMiddles[index].green, _colorFinishes[index].green, age), + 0.0f, 255.0f); + _particleColors[index].blue = + (int)glm::clamp(interpolate(_colorStarts[index].blue, _colorMiddles[index].blue, _colorFinishes[index].blue, age), + 0.0f, 255.0f); +} + void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) { _particleAlphas[index] = glm::clamp(interpolate(_alphaStarts[index], _alphaMiddles[index], _alphaFinishes[index], age), 0.0f, 1.0f); @@ -585,6 +614,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { else { float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0 updateRadius(i, age); + updateColor(i, age); updateAlpha(i, age); integrateParticle(i, deltaTime); extendBounds(_particlePositions[i]); @@ -637,16 +667,33 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { extendBounds(_particlePositions[i]); // Color - if (_colorSpread == xColor(xColor{ 0, 0, 0 })) { - _particleColors[i] = getXColor(); + if (_colorSpread == xColor{ 0, 0, 0 }) { + _colorStarts[i] = getColorStart(); + _colorMiddles[i] = getXColor(); + _colorFinishes[i] = getColorFinish(); } else { + xColor startColor = getColorStart(); + xColor middleColor = getXColor(); + xColor finishColor = getColorFinish(); + float spread = 2.0f * randFloat() - 1.0f; - xColor color = getXColor(); - color.red = (int)glm::clamp((float)color.red + spread * (float)_colorSpread.red, 0.0f, 255.0f); - color.green = (int)glm::clamp((float)color.green + spread * (float)_colorSpread.green, 0.0f, 255.0f); - color.blue = (int)glm::clamp((float)color.blue + spread * (float)_colorSpread.blue, 0.0f, 255.0f); - _particleColors[i] = color; + float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red; + float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green; + float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue; + + _colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); + _colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); + _colorStarts[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); + + _colorMiddles[i].red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); + _colorMiddles[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); + _colorMiddles[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); + + _colorFinishes[i].red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); + _colorFinishes[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); + _colorFinishes[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); } + updateColor(i, 0.0f); // Alpha if (_alphaSpread == 0.0f) { @@ -690,6 +737,9 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _radiusMiddles.resize(_maxParticles); _radiusFinishes.resize(_maxParticles); _particleColors.resize(_maxParticles); + _colorStarts.resize(_maxParticles); + _colorMiddles.resize(_maxParticles); + _colorFinishes.resize(_maxParticles); _particleAlphas.resize(_maxParticles); _alphaStarts.resize(_maxParticles); _alphaMiddles.resize(_maxParticles); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 7f117ca5cd..9511dde152 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -56,6 +56,14 @@ public: _color[BLUE_INDEX] = value.blue; } + bool _isColorStartInitialized; + void setColorStart(xColor colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; } + xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); } + + bool _isColorFinishInitialized; + void setColorFinish(xColor colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; } + xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); } + static const xColor DEFAULT_COLOR_SPREAD; void setColorSpread(const xColor colorSpread) { _colorSpread = colorSpread; } xColor getColorSpread() const { return _colorSpread; } @@ -176,6 +184,7 @@ protected: bool isAnimatingSomething() const; void stepSimulation(float deltaTime); void updateRadius(quint32 index, float age); + void updateColor(quint32 index, float age); void updateAlpha(quint32 index, float age); void extendBounds(const glm::vec3& point); void integrateParticle(quint32 index, float deltaTime); @@ -183,6 +192,8 @@ protected: // the properties of this entity rgbColor _color; + xColor _colorStart; + xColor _colorFinish; xColor _colorSpread; float _alpha; float _alphaStart; @@ -216,6 +227,9 @@ protected: QVector _radiusMiddles; QVector _radiusFinishes; QVector _particleColors; + QVector _colorStarts; + QVector _colorMiddles; + QVector _colorFinishes; QVector _particleAlphas; QVector _alphaStarts; QVector _alphaMiddles; From 57c27f70490ec1d3dbeaa0bee3ae387f70c4a3c4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 8 Sep 2015 13:06:20 -0700 Subject: [PATCH 20/21] added an example script that detects being touched by avatars hand --- examples/entityScripts/detectTouchExample.js | 76 ++++++++++++++++++++ examples/libraries/utils.js | 6 ++ 2 files changed, 82 insertions(+) create mode 100644 examples/entityScripts/detectTouchExample.js diff --git a/examples/entityScripts/detectTouchExample.js b/examples/entityScripts/detectTouchExample.js new file mode 100644 index 0000000000..6129dac558 --- /dev/null +++ b/examples/entityScripts/detectTouchExample.js @@ -0,0 +1,76 @@ +// +// detectTouchExample.js +// examples/entityScripts +// +// Created by Brad Hefta-Gaub on 9/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// This is an example of an entity script which when assigned to an entity, will detect when the entity is being touched by the avatars hands +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + Script.include("../libraries/utils.js"); + + var _this; + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + DetectTouched = function() { + _this = this; + }; + + DetectTouched.prototype = { + + // update() will be called regulary, because we've hooked the update signal in our preload() function. + // we will check the avatars hand positions and if either hand is in our bounding box, we will notice that + update: function() { + // because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID + var entityID = _this.entityID; + + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var props = Entities.getEntityProperties(entityID); + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + + if (pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint) || pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint)) { + + // remember we're being grabbed so we can detect being released + _this.beingTouched = true; + + // print out that we're being grabbed + print("I'm being touched..."); + + } else if (_this.beingTouched) { + + // if we are not being grabbed, and we previously were, then we were just released, remember that + // and print out a message + _this.beingTouched = false; + print("I'm am no longer being touched..."); + } + }, + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * connecting to the update signal so we can check our grabbed state + preload: function(entityID) { + print("preload!"); + this.entityID = entityID; + Script.update.connect(this.update); + }, + + // unload() will be called when our entity is no longer available. It may be because we were deleted, + // or because we've left the domain or quit the application. In all cases we want to unhook our connection + // to the update signal + unload: function(entityID) { + Script.update.disconnect(this.update); + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new DetectTouched(); +}) diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index c6143a51a8..10694b11f5 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -146,3 +146,9 @@ getEyeRelativePosition = function(v) { getAvatarRelativeRotation = function(q) { return Quat.multiply(MyAvatar.orientation, q); } + +pointInExtents = function(point, minPoint, maxPoint) { + return (point.x >= minPoint.x && point.x <= maxPoint.x) && + (point.y >= minPoint.y && point.y <= maxPoint.y) && + (point.z >= minPoint.z && point.z <= maxPoint.z); +} \ No newline at end of file From 99c1e06201df8c20d7b094de0498a98d394876e5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Sep 2015 13:25:15 -0700 Subject: [PATCH 21/21] Code tidying --- .../entities/src/EntityItemProperties.cpp | 42 +++++----- libraries/entities/src/EntityItemProperties.h | 12 +-- .../entities/src/ParticleEffectEntityItem.cpp | 76 ++++++++++--------- .../entities/src/ParticleEffectEntityItem.h | 30 ++++---- 4 files changed, 82 insertions(+), 78 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 66153342e7..eec872153d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -55,13 +55,13 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), +CONSTRUCT_PROPERTY(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD), CONSTRUCT_PROPERTY(colorStart, ParticleEffectEntityItem::DEFAULT_COLOR), CONSTRUCT_PROPERTY(colorFinish, ParticleEffectEntityItem::DEFAULT_COLOR), -CONSTRUCT_PROPERTY(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD), CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA), +CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD), CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START), CONSTRUCT_PROPERTY(alphaFinish, ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH), -CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD), CONSTRUCT_PROPERTY(modelURL, ""), CONSTRUCT_PROPERTY(compoundShapeURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), @@ -96,9 +96,9 @@ CONSTRUCT_PROPERTY(velocitySpread, ParticleEffectEntityItem::DEFAULT_VELOCITY_SP CONSTRUCT_PROPERTY(emitAcceleration, ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION), CONSTRUCT_PROPERTY(accelerationSpread, ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), +CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD), CONSTRUCT_PROPERTY(radiusStart, ParticleEffectEntityItem::DEFAULT_RADIUS_START), CONSTRUCT_PROPERTY(radiusFinish, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH), -CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD), CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR), CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY), @@ -338,13 +338,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); + CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread); CHECK_PROPERTY_CHANGE(PROP_COLOR_START, colorStart); CHECK_PROPERTY_CHANGE(PROP_COLOR_FINISH, colorFinish); - CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread); CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); + CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish); - CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); @@ -379,9 +379,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration); CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); + CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); - CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); CHECK_PROPERTY_CHANGE(PROP_NAME, name); CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor); @@ -459,13 +459,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE(color); + COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart); COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); + COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); @@ -498,9 +498,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration); COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); + COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart); COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); COPY_PROPERTY_TO_QSCRIPTVALUE(name); COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL); @@ -599,13 +599,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, xColor, setColorFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); + COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL); @@ -637,9 +637,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration); COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius); + COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID); COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL); @@ -890,15 +890,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread()); APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart()); APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); } if (properties.getType() == EntityTypes::Zone) { @@ -1174,15 +1174,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, xColor, setColorStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, xColor, setColorFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); } if (properties.getType() == EntityTypes::Zone) { @@ -1323,15 +1323,15 @@ void EntityItemProperties::markAllChanged() { _emitAccelerationChanged = true; _accelerationSpreadChanged = true; _particleRadiusChanged = true; + _radiusSpreadChanged = true; _radiusStartChanged = true; _radiusFinishChanged = true; - _radiusSpreadChanged = true; + _colorSpreadChanged = true; _colorStartChanged = true; _colorFinishChanged = true; - _colorSpreadChanged = true; + _alphaSpreadChanged = true; _alphaStartChanged = true; _alphaFinishChanged = true; - _alphaSpreadChanged = true; _marketplaceIDChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 1c5913fc88..2731ab19d5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -103,13 +103,13 @@ public: DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); + DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor); DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, xColor); DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor); - DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor); DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float); + DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float); DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); - DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); @@ -143,9 +143,9 @@ public: DEFINE_PROPERTY(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3); DEFINE_PROPERTY(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); + DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float); DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float); DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); - DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); @@ -301,13 +301,13 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorStart, colorStart, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorFinish, colorFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, ""); @@ -339,9 +339,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, ""); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 0686c3a996..dce4445336 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -45,10 +45,9 @@ const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; const xColor ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD = { 0, 0, 0 }; const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f; -const float ParticleEffectEntityItem::ALPHA_UNINITIALIZED = -1.0f; -const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = ALPHA_UNINITIALIZED; -const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = ALPHA_UNINITIALIZED; const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f; +const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA; +const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f; @@ -60,10 +59,9 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_VELOCITY_SPREAD(3.0f, 0.0f, 3. const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f); const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f); const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f; -const float ParticleEffectEntityItem::RADIUS_UNINITIALIZED = -1.0f; -const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = RADIUS_UNINITIALIZED; -const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = RADIUS_UNINITIALIZED; const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; +const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; +const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; @@ -82,24 +80,26 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _emitAcceleration(DEFAULT_EMIT_ACCELERATION), _accelerationSpread(DEFAULT_ACCELERATION_SPREAD), _particleRadius(DEFAULT_PARTICLE_RADIUS), + _radiusSpread(DEFAULT_RADIUS_SPREAD), _radiusStart(DEFAULT_RADIUS_START), _radiusFinish(DEFAULT_RADIUS_FINISH), - _radiusSpread(DEFAULT_RADIUS_SPREAD), _lastAnimated(usecTimestampNow()), _animationLoop(), _animationSettings(), _textures(DEFAULT_TEXTURES), _texturesChangedFlag(false), _shapeType(SHAPE_TYPE_NONE), - _isColorStartInitialized(false), - _isColorFinishInitialized(false), + _colorSpread(DEFAULT_COLOR_SPREAD), _colorStart(DEFAULT_COLOR), _colorFinish(DEFAULT_COLOR), - _colorSpread(DEFAULT_COLOR_SPREAD), + _isColorStartInitialized(false), + _isColorFinishInitialized(false), _alpha(DEFAULT_ALPHA), + _alphaSpread(DEFAULT_ALPHA_SPREAD), _alphaStart(DEFAULT_ALPHA_START), _alphaFinish(DEFAULT_ALPHA_FINISH), - _alphaSpread(DEFAULT_ALPHA_SPREAD), + _isAlphaStartInitialized(false), + _isAlphaFinishInitialized(false), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), _particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), _particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), @@ -108,14 +108,14 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), + _particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), _colorStarts(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), _colorMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), _colorFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), - _particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), + _particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), - _particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _timeUntilNextEmit(0.0f), _particleHeadIndex(0), _particleTailIndex(0), @@ -193,15 +193,15 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const { 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(radiusSpread, getRadiusSpread); + 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(colorSpread, getColorSpread); + 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(alphaSpread, getAlphaSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); return properties; @@ -226,15 +226,15 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert 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(radiusSpread, setRadiusSpread); + 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(colorSpread, setColorSpread); + 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(alphaSpread, setAlphaSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); if (somethingChanged) { @@ -773,25 +773,29 @@ float ParticleEffectEntityItem::cubicInterpolate(float y0, float y1, float y2, f } float ParticleEffectEntityItem::interpolate(float start, float middle, float finish, float age) { - if (start == middle && middle == finish) { - return middle; - } else { - float y0, y1, y2, y3, u; + float y0, y1, y2, y3, u; - if (age <= 0.5f) { - y1 = start; - y2 = middle; - y3 = finish; - y0 = 2.0f * y1 - y2; - u = 2.0f * age; - } else { - y0 = start; - y1 = middle; - y2 = finish; - y3 = 2.0f * y2 - y1; - u = 2.0f * age - 1.0f; + if (age <= 0.5f) { + if (start == middle) { + return middle; } - return cubicInterpolate(y0, y1, y2, y3, u); + y1 = start; + y2 = middle; + y3 = finish; + y0 = 2.0f * y1 - y2; + u = 2.0f * age; + } else { + if (middle == finish) { + return middle; + } + + y0 = start; + y1 = middle; + y2 = finish; + y3 = 2.0f * y2 - y1; + u = 2.0f * age - 1.0f; } + + return cubicInterpolate(y0, y1, y2, y3, u); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 9511dde152..4e3c4b57b9 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -57,30 +57,30 @@ public: } bool _isColorStartInitialized; - void setColorStart(xColor colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; } + void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; } xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); } bool _isColorFinishInitialized; - void setColorFinish(xColor colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; } + void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; } xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); } static const xColor DEFAULT_COLOR_SPREAD; - void setColorSpread(const xColor colorSpread) { _colorSpread = colorSpread; } + void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; } xColor getColorSpread() const { return _colorSpread; } static const float DEFAULT_ALPHA; void setAlpha(float alpha) { _alpha = alpha; } float getAlpha() const { return _alpha; } - static const float ALPHA_UNINITIALIZED; - static const float DEFAULT_ALPHA_START; - void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; } - float getAlphaStart() const { return _alphaStart == ALPHA_UNINITIALIZED ? _alpha : _alphaStart; } + bool _isAlphaStartInitialized; + void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; } + float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; } static const float DEFAULT_ALPHA_FINISH; - void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; } - float getAlphaFinish() const { return _alphaFinish == ALPHA_UNINITIALIZED ? _alpha : _alphaFinish; } + bool _isAlphaFinishInitialized; + void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; } + float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; } static const float DEFAULT_ALPHA_SPREAD; void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; } @@ -148,15 +148,15 @@ public: void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } float getParticleRadius() const { return _particleRadius; } - static const float RADIUS_UNINITIALIZED; - static const float DEFAULT_RADIUS_START; - void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; } - float getRadiusStart() const { return _radiusStart == RADIUS_UNINITIALIZED ? _particleRadius : _radiusStart; } + bool _isRadiusStartInitialized; + void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; } + float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; } static const float DEFAULT_RADIUS_FINISH; - void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; } - float getRadiusFinish() const { return _radiusFinish == RADIUS_UNINITIALIZED ? _particleRadius : _radiusFinish; } + bool _isRadiusFinishInitialized; + void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; } + float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; } static const float DEFAULT_RADIUS_SPREAD; void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; }