From 45ff118249e1f60eb7b538d00b38447d5bbc6ec4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Sep 2015 12:43:36 -0700 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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 cb9468c311ba542649bf266fa0c67df658e5bc92 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 7 Sep 2015 16:27:42 -0700 Subject: [PATCH 14/19] 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 cdd5e68815c6094a31dd9c05614e92d0a27b9848 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Sep 2015 11:28:53 -0700 Subject: [PATCH 15/19] 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 c728cd4c4c3fa026aa5af087ed5f105211816125 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 8 Sep 2015 11:57:35 -0700 Subject: [PATCH 16/19] Fix for RenderableParticleffectEntityItem assert. When a particle system had no living particles, PendingChanges::updateItem would assert, due to the access to _vertices[0]. In release this might be harmless as this memory is never accessed, but different implementations of std::vector might do different things here. So, let's be safe and early return when the number of particles is 0. --- .../src/RenderableParticleEffectEntityItem.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f683083ed1..9c839bfaad 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -219,6 +219,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // update vertex buffer auto vertexBuffer = payload.getVertexBuffer(); size_t numBytes = sizeof(Vertex) * _vertices.size(); + + if (numBytes == 0) { + vertexBuffer->resize(0); + auto indexBuffer = payload.getIndexBuffer(); + indexBuffer->resize(0); + return; + } + vertexBuffer->resize(numBytes); gpu::Byte* data = vertexBuffer->editData(); memcpy(data, &(_vertices[0]), numBytes); @@ -284,7 +292,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { payload.setPipeline(_untexturedPipeline); } }); - + _scene->enqueuePendingChanges(pendingChanges); } From 57c27f70490ec1d3dbeaa0bee3ae387f70c4a3c4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 8 Sep 2015 13:06:20 -0700 Subject: [PATCH 17/19] 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 18/19] 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; } From 5f1affaff94454b4a79bf3d69f0ff070b88c0468 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 8 Sep 2015 00:51:54 -0700 Subject: [PATCH 19/19] Procedural skybox work --- cmake/macros/AutoScribeShader.cmake | 2 +- cmake/macros/SetupHifiLibrary.cmake | 6 +- examples/shaders/exampleSkyboxUserDataV2.json | 6 + .../shaders/shadertoys/relentlessSkybox.fs | 144 +++++++++ interface/CMakeLists.txt | 2 +- libraries/entities-renderer/CMakeLists.txt | 2 +- .../src/EntityTreeRenderer.cpp | 18 +- .../src/RenderableBoxEntityItem.cpp | 13 +- .../src/RenderableBoxEntityItem.h | 9 +- .../src/RenderableProceduralItem.h | 60 ---- .../src/RenderableSphereEntityItem.cpp | 13 +- .../src/RenderableSphereEntityItem.h | 10 +- libraries/gpu-networking/CMakeLists.txt | 11 + .../gpu-networking/GpuNetworkingLogging.cpp | 11 + .../src/gpu-networking/GpuNetworkingLogging.h | 11 + .../src/gpu-networking}/ShaderCache.cpp | 0 .../src/gpu-networking}/ShaderCache.h | 0 .../src/gpu-networking}/TextureCache.cpp | 21 +- .../src/gpu-networking/TextureCache.h | 167 +++++++++++ libraries/gpu/CMakeLists.txt | 4 + libraries/model/CMakeLists.txt | 2 +- libraries/model/src/model/Skybox.cpp | 71 +++-- libraries/model/src/model/Skybox.h | 9 +- libraries/model/src/model/Skybox.slf | 18 +- libraries/procedural/CMakeLists.txt | 10 + .../src/procedural/Procedural.cpp} | 130 ++++----- .../procedural/src/procedural/Procedural.h | 60 ++++ .../src/procedural/ProceduralShaders.h | 276 ++++++++++++++++++ libraries/render-utils/CMakeLists.txt | 2 +- libraries/render-utils/src/TextureCache.h | 173 +---------- libraries/render-utils/src/simple.slf | 37 ++- libraries/script-engine/CMakeLists.txt | 2 +- tests/gpu-test/CMakeLists.txt | 2 +- 33 files changed, 937 insertions(+), 365 deletions(-) create mode 100644 examples/shaders/exampleSkyboxUserDataV2.json create mode 100644 examples/shaders/shadertoys/relentlessSkybox.fs delete mode 100644 libraries/entities-renderer/src/RenderableProceduralItem.h create mode 100644 libraries/gpu-networking/CMakeLists.txt create mode 100644 libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp create mode 100644 libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h rename libraries/{render-utils/src => gpu-networking/src/gpu-networking}/ShaderCache.cpp (100%) rename libraries/{render-utils/src => gpu-networking/src/gpu-networking}/ShaderCache.h (100%) rename libraries/{render-utils/src => gpu-networking/src/gpu-networking}/TextureCache.cpp (97%) create mode 100644 libraries/gpu-networking/src/gpu-networking/TextureCache.h create mode 100644 libraries/procedural/CMakeLists.txt rename libraries/{entities-renderer/src/RenderableProceduralItem.cpp => procedural/src/procedural/Procedural.cpp} (66%) create mode 100644 libraries/procedural/src/procedural/Procedural.h create mode 100644 libraries/procedural/src/procedural/ProceduralShaders.h diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index bec80d55b7..90a304ac50 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -73,7 +73,7 @@ endfunction() macro(AUTOSCRIBE_SHADER_LIB) - + message("Autoscribe running for ${TARGET_NAME}") file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") foreach(HIFI_LIBRARY ${ARGN}) #if (NOT TARGET ${HIFI_LIBRARY}) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index aba8d500a5..2e943f9b12 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -9,7 +9,8 @@ macro(SETUP_HIFI_LIBRARY) - project(${TARGET_NAME}) + project(${TARGET_NAME}) + message("Setting up project ${TARGET_NAME}") # grab the implemenation and header files file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c") @@ -33,5 +34,8 @@ macro(SETUP_HIFI_LIBRARY) foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES}) target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) endforeach() + + # Don't make scribed shaders cumulative + set(AUTOSCRIBE_SHADER_LIB_SRC "") endmacro(SETUP_HIFI_LIBRARY) \ No newline at end of file diff --git a/examples/shaders/exampleSkyboxUserDataV2.json b/examples/shaders/exampleSkyboxUserDataV2.json new file mode 100644 index 0000000000..2839baea4c --- /dev/null +++ b/examples/shaders/exampleSkyboxUserDataV2.json @@ -0,0 +1,6 @@ +{ + "ProceduralEntity": + { + "shaderUrl": "https://s3.amazonaws.com/Oculus/shadertoys/relentlessSkybox.fs" + } +} \ No newline at end of file diff --git a/examples/shaders/shadertoys/relentlessSkybox.fs b/examples/shaders/shadertoys/relentlessSkybox.fs new file mode 100644 index 0000000000..79e38bf9aa --- /dev/null +++ b/examples/shaders/shadertoys/relentlessSkybox.fs @@ -0,0 +1,144 @@ +// 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); +} + + + +vec3 getSkyboxColor() { + vec3 rd = normalize(_normal); + vec3 ro = vec3(0, 0, 1); + 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; + } + } + + inten *= 0.4 + (sin(time) * 0.5 + 0.5) * 0.6; + + vec3 ct = vec3(0.6, 0.8, 9.0); + // find a color for the computed intensity + vec3 col = pow(vec3(inten), ct); + return col; +} diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d7ee9228f4..05a937eef8 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -113,7 +113,7 @@ endif() target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES}) # link required hifi libraries -link_hifi_libraries(shared octree environment gpu model render fbx networking entities avatars +link_hifi_libraries(shared octree environment gpu gpu-networking procedural model render fbx networking entities avatars audio audio-client animation script-engine physics render-utils entities-renderer ui auto-updater plugins display-plugins input-plugins) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index c4dddb8971..3787beb32b 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -26,4 +26,4 @@ find_package(PolyVox REQUIRED) target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) -link_hifi_libraries(shared gpu script-engine render render-utils) +link_hifi_libraries(shared gpu gpu-networking procedural script-engine render render-utils) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 72400dcefb..fa8c0eb633 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "EntityTreeRenderer.h" @@ -454,13 +455,24 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrendOverrideEnvironmentData(); auto stage = scene->getSkyStage(); if (zone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) { - stage->getSkybox()->setColor(zone->getSkyboxProperties().getColorVec3()); + auto skybox = stage->getSkybox(); + skybox->setColor(zone->getSkyboxProperties().getColorVec3()); + static QString userData; + if (userData != zone->getUserData()) { + userData = zone->getUserData(); + QSharedPointer procedural(new Procedural(userData)); + if (procedural->_enabled) { + skybox->setProcedural(procedural); + } else { + skybox->setProcedural(QSharedPointer()); + } + } if (zone->getSkyboxProperties().getURL().isEmpty()) { - stage->getSkybox()->setCubemap(gpu::TexturePointer()); + skybox->setCubemap(gpu::TexturePointer()); } else { // Update the Texture of the Skybox with the one pointed by this zone auto cubeMap = DependencyManager::get()->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE); - stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); + skybox->setCubemap(cubeMap->getGPUTexture()); } stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); } else { diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 738c677104..525226b0e8 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -21,6 +21,8 @@ #include #include "RenderableDebugableEntityItem.h" +#include "../render-utils/simple_vert.h" +#include "../render-utils/simple_frag.h" EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); @@ -42,11 +44,18 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); if (!_procedural) { - _procedural.reset(new ProceduralInfo(this)); + _procedural.reset(new Procedural(this->getUserData())); + _procedural->_vertexSource = simple_vert; + _procedural->_fragmentSource = simple_frag; + _procedural->_state->setCullMode(gpu::State::CULL_NONE); + _procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL); + _procedural->_state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } if (_procedural->ready()) { - _procedural->prepare(batch); + _procedural->prepare(batch, this->getDimensions()); DependencyManager::get()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor)); } else { DependencyManager::get()->renderSolidCube(batch, 1.0f, cubeColor); diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.h b/libraries/entities-renderer/src/RenderableBoxEntityItem.h index e317163683..838022c7d4 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.h @@ -13,10 +13,11 @@ #define hifi_RenderableBoxEntityItem_h #include -#include "RenderableEntityItem.h" -#include "RenderableProceduralItem.h" +#include -class RenderableBoxEntityItem : public BoxEntityItem, RenderableProceduralItem { +#include "RenderableEntityItem.h" + +class RenderableBoxEntityItem : public BoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -28,6 +29,8 @@ public: virtual void setUserData(const QString& value); SIMPLE_RENDERABLE() +private: + QSharedPointer _procedural; }; diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.h b/libraries/entities-renderer/src/RenderableProceduralItem.h deleted file mode 100644 index 37e827d304..0000000000 --- a/libraries/entities-renderer/src/RenderableProceduralItem.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/09/05 -// Copyright 2013-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 -// - -#pragma once -#ifndef hifi_RenderableProcedrualItem_h -#define hifi_RenderableProcedrualItem_h - -#include -#include -#include -#include - -#include -#include -#include -#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; - gpu::ShaderPointer _shader; - QString _shaderSource; - QString _shaderPath; - QUrl _shaderUrl; - quint64 _shaderModified{ 0 }; - bool _pipelineDirty{ true }; - int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION }; - int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION }; - uint64_t _start{ 0 }; - NetworkShaderPointer _networkShader; - EntityItem* _entity; - QJsonObject _uniforms; - }; - - QSharedPointer _procedural; -}; - -#endif diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 3b58397a82..82257c67fb 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -21,6 +21,8 @@ #include #include "RenderableDebugableEntityItem.h" +#include "../render-utils/simple_vert.h" +#include "../render-utils/simple_frag.h" EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); @@ -47,12 +49,19 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { static const int SLICES = 15, STACKS = 15; if (!_procedural) { - _procedural.reset(new ProceduralInfo(this)); + _procedural.reset(new Procedural(getUserData())); + _procedural->_vertexSource = simple_vert; + _procedural->_fragmentSource = simple_frag; + _procedural->_state->setCullMode(gpu::State::CULL_NONE); + _procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL); + _procedural->_state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha()); if (_procedural->ready()) { - _procedural->prepare(batch); + _procedural->prepare(batch, getDimensions()); DependencyManager::get()->renderSphere(batch, 0.5f, SLICES, STACKS, _procedural->getColor(sphereColor)); } else { DependencyManager::get()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor); diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.h b/libraries/entities-renderer/src/RenderableSphereEntityItem.h index 5036354c04..293ae79029 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.h +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.h @@ -13,10 +13,11 @@ #define hifi_RenderableSphereEntityItem_h #include -#include "RenderableEntityItem.h" -#include "RenderableProceduralItem.h" +#include -class RenderableSphereEntityItem : public SphereEntityItem, RenderableProceduralItem { +#include "RenderableEntityItem.h" + +class RenderableSphereEntityItem : public SphereEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -28,6 +29,9 @@ public: virtual void setUserData(const QString& value); SIMPLE_RENDERABLE(); + +private: + QSharedPointer _procedural; }; diff --git a/libraries/gpu-networking/CMakeLists.txt b/libraries/gpu-networking/CMakeLists.txt new file mode 100644 index 0000000000..836afac371 --- /dev/null +++ b/libraries/gpu-networking/CMakeLists.txt @@ -0,0 +1,11 @@ +set(TARGET_NAME gpu-networking) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library() + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + +link_hifi_libraries(shared networking gpu) + diff --git a/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp new file mode 100644 index 0000000000..38da22969b --- /dev/null +++ b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp @@ -0,0 +1,11 @@ +// +// Created by Bradley Austin Davis on 2015/08/07 +// Copyright 2013-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 +// + +#include "GpuNetworkingLogging.h" + +Q_LOGGING_CATEGORY(gpunetwork, "hifi.gpu-network") diff --git a/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h new file mode 100644 index 0000000000..7499340a9b --- /dev/null +++ b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h @@ -0,0 +1,11 @@ +// +// Created by Bradley Austin Davis on 2015/08/07 +// Copyright 2013-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 +// + +#include + +Q_DECLARE_LOGGING_CATEGORY(gpunetwork) diff --git a/libraries/render-utils/src/ShaderCache.cpp b/libraries/gpu-networking/src/gpu-networking/ShaderCache.cpp similarity index 100% rename from libraries/render-utils/src/ShaderCache.cpp rename to libraries/gpu-networking/src/gpu-networking/ShaderCache.cpp diff --git a/libraries/render-utils/src/ShaderCache.h b/libraries/gpu-networking/src/gpu-networking/ShaderCache.h similarity index 100% rename from libraries/render-utils/src/ShaderCache.h rename to libraries/gpu-networking/src/gpu-networking/ShaderCache.h diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp similarity index 97% rename from libraries/render-utils/src/TextureCache.cpp rename to libraries/gpu-networking/src/gpu-networking/TextureCache.cpp index c4fb4c9989..e2462946a4 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp @@ -1,7 +1,4 @@ // -// TextureCache.cpp -// interface/src/renderer -// // Created by Andrzej Kapolka on 8/6/13. // Copyright 2013 High Fidelity, Inc. // @@ -21,13 +18,11 @@ #include #include #include -#include "PathUtils.h" +#include #include - - -#include "RenderUtilsLogging.h" +#include "GpuNetworkingLogging.h" TextureCache::TextureCache() { const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; @@ -255,7 +250,7 @@ void listSupportedImageFormats() { foreach(const QByteArray& f, supportedFormats) { formats += QString(f) + ","; } - qCDebug(renderutils) << "List of supported Image formats:" << formats; + qCDebug(gpunetwork) << "List of supported Image formats:" << formats; }); } @@ -323,9 +318,9 @@ void ImageReader::run() { if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { - qCDebug(renderutils) << "QImage failed to create from content, no file extension:" << _url; + qCDebug(gpunetwork) << "QImage failed to create from content, no file extension:" << _url; } else { - qCDebug(renderutils) << "QImage failed to create from content" << _url; + qCDebug(gpunetwork) << "QImage failed to create from content" << _url; } return; } @@ -333,7 +328,7 @@ void ImageReader::run() { int imageArea = image.width() * image.height(); auto ntex = dynamic_cast(&*texture); if (ntex && (ntex->getType() == CUBE_TEXTURE)) { - qCDebug(renderutils) << "Cube map size:" << _url << image.width() << image.height(); + qCDebug(gpunetwork) << "Cube map size:" << _url << image.width() << image.height(); } int opaquePixels = 0; @@ -384,7 +379,7 @@ void ImageReader::run() { } } if (opaquePixels == imageArea) { - qCDebug(renderutils) << "Image with alpha channel is completely opaque:" << _url; + qCDebug(gpunetwork) << "Image with alpha channel is completely opaque:" << _url; image = image.convertToFormat(QImage::Format_RGB888); } @@ -532,7 +527,7 @@ void ImageReader::run() { faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror)); } else { - qCDebug(renderutils) << "Failed to find a known cube map layout from this image:" << _url; + qCDebug(gpunetwork) << "Failed to find a known cube map layout from this image:" << _url; return; } diff --git a/libraries/gpu-networking/src/gpu-networking/TextureCache.h b/libraries/gpu-networking/src/gpu-networking/TextureCache.h new file mode 100644 index 0000000000..f0abda8e66 --- /dev/null +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.h @@ -0,0 +1,167 @@ +// +// Created by Andrzej Kapolka on 8/6/13. +// Copyright 2013 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 +// + +#ifndef hifi_TextureCache_h +#define hifi_TextureCache_h + +#include + +#include +#include +#include + +#include +#include + +namespace gpu { +class Batch; +} +class NetworkTexture; + +typedef QSharedPointer NetworkTexturePointer; + +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE }; + +/// Stores cached textures, including render-to-texture targets. +class TextureCache : public ResourceCache, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture + /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and + /// the second, a set of random unit vectors to be used as noise gradients. + const gpu::TexturePointer& getPermutationNormalTexture(); + + /// Returns an opaque white texture (useful for a default). + const gpu::TexturePointer& getWhiteTexture(); + + /// Returns an opaque gray texture (useful for a default). + const gpu::TexturePointer& getGrayTexture(); + + /// Returns the a pale blue texture (useful for a normal map). + const gpu::TexturePointer& getBlueTexture(); + + /// Returns the a black texture (useful for a default). + const gpu::TexturePointer& getBlackTexture(); + + // Returns a map used to compress the normals through a fitting scale algorithm + const gpu::TexturePointer& getNormalFittingTexture(); + + /// Returns a texture version of an image file + static gpu::TexturePointer getImageTexture(const QString& path); + + /// Loads a texture from the specified URL. + NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false, + const QByteArray& content = QByteArray()); + +protected: + + virtual QSharedPointer createResource(const QUrl& url, + const QSharedPointer& fallback, bool delayLoad, const void* extra); + +private: + TextureCache(); + virtual ~TextureCache(); + friend class DilatableNetworkTexture; + + gpu::TexturePointer _permutationNormalTexture; + gpu::TexturePointer _whiteTexture; + gpu::TexturePointer _grayTexture; + gpu::TexturePointer _blueTexture; + gpu::TexturePointer _blackTexture; + gpu::TexturePointer _normalFittingTexture; + + QHash > _dilatableNetworkTextures; +}; + +/// A simple object wrapper for an OpenGL texture. +class Texture { +public: + friend class TextureCache; + friend class DilatableNetworkTexture; + Texture(); + ~Texture(); + + const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } + +protected: + gpu::TexturePointer _gpuTexture; + +private: +}; + +/// A texture loaded from the network. + +class NetworkTexture : public Resource, public Texture { + Q_OBJECT + +public: + + NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content); + + /// Checks whether it "looks like" this texture is translucent + /// (majority of pixels neither fully opaque or fully transparent). + bool isTranslucent() const { return _translucent; } + + /// Returns the lazily-computed average texture color. + const QColor& getAverageColor() const { return _averageColor; } + + int getOriginalWidth() const { return _originalWidth; } + int getOriginalHeight() const { return _originalHeight; } + int getWidth() const { return _width; } + int getHeight() const { return _height; } + TextureType getType() const { return _type; } +protected: + + virtual void downloadFinished(QNetworkReply* reply); + + Q_INVOKABLE void loadContent(const QByteArray& content); + // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... + Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth, + int originalHeight); + + virtual void imageLoaded(const QImage& image); + + TextureType _type; + +private: + bool _translucent; + QColor _averageColor; + int _originalWidth; + int _originalHeight; + int _width; + int _height; +}; + +/// Caches derived, dilated textures. +class DilatableNetworkTexture : public NetworkTexture { + Q_OBJECT + +public: + + DilatableNetworkTexture(const QUrl& url, const QByteArray& content); + + /// Returns a pointer to a texture with the requested amount of dilation. + QSharedPointer getDilatedTexture(float dilation); + +protected: + + virtual void imageLoaded(const QImage& image); + virtual void reinsert(); + +private: + + QImage _image; + int _innerRadius; + int _outerRadius; + + QMap > _dilatedTextures; +}; + +#endif // hifi_TextureCache_h diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 7a88580f7f..38fe5cb22f 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -7,6 +7,10 @@ setup_hifi_library() link_hifi_libraries(shared) +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + add_dependency_external_projects(glew) find_package(GLEW REQUIRED) add_definitions(-DGLEW_STATIC) diff --git a/libraries/model/CMakeLists.txt b/libraries/model/CMakeLists.txt index 701c132e61..8acb4b0a71 100755 --- a/libraries/model/CMakeLists.txt +++ b/libraries/model/CMakeLists.txt @@ -9,4 +9,4 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared gpu octree) +link_hifi_libraries(shared networking gpu gpu-networking procedural octree) diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 314492881f..c17bf1df72 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -10,10 +10,12 @@ // #include "Skybox.h" -#include "gpu/Batch.h" -#include "gpu/Context.h" -#include "ViewFrustum.h" +#include +#include +#include +#include + #include "Skybox_vert.h" #include "Skybox_frag.h" @@ -38,19 +40,54 @@ void Skybox::setColor(const Color& color) { _color = color; } +void Skybox::setProcedural(QSharedPointer procedural) { + _procedural = procedural; + if (_procedural) { + _procedural->_vertexSource = Skybox_vert; + _procedural->_fragmentSource = Skybox_frag; + // No pipeline state customization + } +} + void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { _cubemap = cubemap; } + void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) { + static gpu::BufferPointer theBuffer; + static gpu::Stream::FormatPointer theFormat; - if (skybox.getCubemap()) { - if (skybox.getCubemap()->isDefined()) { + if (skybox._procedural || skybox.getCubemap()) { + if (!theBuffer) { + const float CLIP = 1.0f; + const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } }; + theBuffer = std::make_shared(sizeof(vertices), (const gpu::Byte*) vertices); + theFormat = std::make_shared(); + theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); + } - static gpu::PipelinePointer thePipeline; - static gpu::BufferPointer theBuffer; - static gpu::Stream::FormatPointer theFormat; + glm::mat4 projMat; + viewFrustum.evalProjectionMatrix(projMat); + + Transform viewTransform; + viewFrustum.evalViewTransform(viewTransform); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewTransform); + batch.setModelTransform(Transform()); // only for Mac + batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); + batch.setInputFormat(theFormat); + + if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) { + if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { + batch.setResourceTexture(0, skybox.getCubemap()); + } + + skybox._procedural->prepare(batch, glm::vec3(1)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } else if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { static gpu::BufferPointer theConstants; + static gpu::PipelinePointer thePipeline; static int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader if (!thePipeline) { auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert))); @@ -72,23 +109,10 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); - const float CLIP = 1.0f; - const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; - theBuffer = std::make_shared(sizeof(vertices), (const gpu::Byte*) vertices); - - theFormat = std::make_shared(); - theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); - auto color = glm::vec4(1.0f); theConstants = std::make_shared(sizeof(color), (const gpu::Byte*) &color); } - glm::mat4 projMat; - viewFrustum.evalProjectionMatrix(projMat); - - Transform viewTransform; - viewFrustum.evalViewTransform(viewTransform); - if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) { auto color = glm::vec4(1.0f); theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color); @@ -96,13 +120,8 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor()); } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewTransform); - batch.setModelTransform(Transform()); // only for Mac batch.setPipeline(thePipeline); - batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize()); - batch.setInputFormat(theFormat); batch.setResourceTexture(0, skybox.getCubemap()); batch.draw(gpu::TRIANGLE_STRIP, 4); } diff --git a/libraries/model/src/model/Skybox.h b/libraries/model/src/model/Skybox.h index 7a4550d75a..809ec7e3b0 100755 --- a/libraries/model/src/model/Skybox.h +++ b/libraries/model/src/model/Skybox.h @@ -11,12 +11,13 @@ #ifndef hifi_model_Skybox_h #define hifi_model_Skybox_h -#include "gpu/Texture.h" +#include +#include #include "Light.h" class ViewFrustum; -//class Transform; +struct Procedural; namespace gpu { class Batch; } namespace model { @@ -35,11 +36,13 @@ public: void setCubemap(const gpu::TexturePointer& cubemap); const gpu::TexturePointer& getCubemap() const { return _cubemap; } + void setProcedural(QSharedPointer procedural); + static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox); protected: gpu::TexturePointer _cubemap; - + QSharedPointer _procedural; Color _color{1.0f, 1.0f, 1.0f}; }; typedef std::shared_ptr< Skybox > SkyboxPointer; diff --git a/libraries/model/src/model/Skybox.slf b/libraries/model/src/model/Skybox.slf index 47444b21bd..382801f52d 100755 --- a/libraries/model/src/model/Skybox.slf +++ b/libraries/model/src/model/Skybox.slf @@ -22,13 +22,29 @@ uniform skyboxBuffer { }; in vec3 _normal; - out vec4 _fragColor; +//PROCEDURAL_COMMON_BLOCK + +#line 1001 +//PROCEDURAL_BLOCK + +#line 2033 void main(void) { + +#ifdef PROCEDURAL + + vec3 color = getSkyboxColor(); + _fragColor = vec4(color, 0.0); + +#else + vec3 coord = normalize(_normal); vec3 texel = texture(cubeMap, coord).rgb; vec3 color = texel * _skybox._color.rgb; vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction _fragColor = vec4(pixel, 0.0); + +#endif + } diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt new file mode 100644 index 0000000000..bd53f0abb9 --- /dev/null +++ b/libraries/procedural/CMakeLists.txt @@ -0,0 +1,10 @@ +set(TARGET_NAME procedural) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library() + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + +link_hifi_libraries(shared gpu networking gpu-networking) diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.cpp b/libraries/procedural/src/procedural/Procedural.cpp similarity index 66% rename from libraries/entities-renderer/src/RenderableProceduralItem.cpp rename to libraries/procedural/src/procedural/Procedural.cpp index c88d1410a5..c8433ef341 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItem.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -6,7 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "RenderableProceduralItem.h" +#include "Procedural.h" #include #include @@ -14,14 +14,12 @@ #include #include -#include -#include -#include -#include +#include #include +#include +#include -#include "RenderableProceduralItemShader.h" -#include "../render-utils/simple_vert.h" +#include "ProceduralShaders.h" static const char* const UNIFORM_TIME_NAME= "iGlobalTime"; static const char* const UNIFORM_SCALE_NAME = "iWorldScale"; @@ -30,43 +28,46 @@ 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"; +static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK"; +static const std::string PROCEDURAL_COMMON_BLOCK = "//PROCEDURAL_COMMON_BLOCK"; +static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; -RenderableProceduralItem::ProceduralInfo::ProceduralInfo(EntityItem* entity) : _entity(entity) { - parse(); + +// Example +//{ +// "ProceduralEntity": { +// "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs", +// } +//} +QJsonValue Procedural::getProceduralData(const QString& proceduralJson) { + if (proceduralJson.isEmpty()) { + return QJsonValue(); + } + + QJsonParseError parseError; + auto doc = QJsonDocument::fromJson(proceduralJson.toUtf8(), &parseError); + if (parseError.error != QJsonParseError::NoError) { + return QJsonValue(); + } + + return doc.object()[PROCEDURAL_USER_DATA_KEY]; } -void RenderableProceduralItem::ProceduralInfo::parse() { + +Procedural::Procedural(const QString& userDataJson) { + parse(userDataJson); + _state = std::make_shared(); +} + +void Procedural::parse(const QString& userDataJson) { _enabled = false; - QJsonObject userData; - { - const QString& userDataJson = _entity->getUserData(); - if (userDataJson.isEmpty()) { - return; - } - QJsonParseError parseError; - auto doc = QJsonDocument::fromJson(userDataJson.toUtf8(), &parseError); - if (parseError.error != QJsonParseError::NoError) { - return; - } - userData = doc.object(); + auto proceduralData = getProceduralData(userDataJson); + if (proceduralData.isObject()) { + parse(proceduralData.toObject()); } - - // Example - //{ - // "ProceduralEntity": { - // "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs", - // "color" : "#FFFFFF" - // } - //} - auto proceduralData = userData[PROCEDURAL_USER_DATA_KEY]; - if (proceduralData.isNull()) { - return; - } - - parse(proceduralData.toObject()); } -void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& proceduralData) { +void Procedural::parse(const QJsonObject& proceduralData) { // grab the version number { auto version = proceduralData[VERSION_KEY]; @@ -106,7 +107,7 @@ void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& procedur _enabled = true; } -bool RenderableProceduralItem::ProceduralInfo::ready() { +bool Procedural::ready() { if (!_enabled) { return false; } @@ -122,7 +123,7 @@ bool RenderableProceduralItem::ProceduralInfo::ready() { return false; } -void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { +void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) { if (_shaderUrl.isLocalFile()) { auto lastModified = QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { @@ -139,31 +140,33 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { if (!_pipeline || _pipelineDirty) { _pipelineDirty = true; if (!_vertexShader) { - _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); + _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(_vertexSource)); } - QString framentShaderSource; - switch (_version) { - case 1: - framentShaderSource = SHADER_TEMPLATE_V1.arg(_shaderSource); - break; - default: - case 2: - framentShaderSource = SHADER_TEMPLATE_V2.arg(_shaderSource); - break; + // Build the fragment shader + std::string fragmentShaderSource = _fragmentSource; + size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK); + if (replaceIndex != std::string::npos) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), SHADER_COMMON); } - _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(framentShaderSource.toLocal8Bit().data()))); + + replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION); + if (replaceIndex != std::string::npos) { + if (_version == 1) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1"); + } else if (_version == 2) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1"); + } + } + replaceIndex = fragmentShaderSource.find(PROCEDURAL_BLOCK); + if (replaceIndex != std::string::npos) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data()); + } + qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str(); + _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource)); _shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader)); - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - gpu::Shader::makeProgram(*_shader, slotBindings); - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_NONE); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, state)); + gpu::Shader::makeProgram(*_shader); + _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state)); _timeSlot = _shader->getUniforms().findLocation(UNIFORM_TIME_NAME); _scaleSlot = _shader->getUniforms().findLocation(UNIFORM_SCALE_NAME); _start = usecTimestampNow(); @@ -221,15 +224,12 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { // 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()); + batch._glUniform3f(_scaleSlot, size.x, size.y, size.z); } -glm::vec4 RenderableProceduralItem::ProceduralInfo::getColor(const glm::vec4& entityColor) { +glm::vec4 Procedural::getColor(const glm::vec4& entityColor) { if (_version == 1) { return glm::vec4(1); } diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h new file mode 100644 index 0000000000..bb6a0ad44d --- /dev/null +++ b/libraries/procedural/src/procedural/Procedural.h @@ -0,0 +1,60 @@ +// +// Created by Bradley Austin Davis on 2015/09/05 +// Copyright 2013-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 +// + +#pragma once +#ifndef hifi_RenderableProcedrualItem_h +#define hifi_RenderableProcedrualItem_h + +#include +#include +#include +#include + +#include +#include +#include +#include + + +// FIXME better encapsulation +// FIXME better mechanism for extending to things rendered using shaders other than simple.slv +struct Procedural { + static QJsonValue getProceduralData(const QString& proceduralJson); + + Procedural(const QString& userDataJson); + void parse(const QString& userDataJson); + void parse(const QJsonObject&); + bool ready(); + void prepare(gpu::Batch& batch, const glm::vec3& size); + glm::vec4 getColor(const glm::vec4& entityColor); + + bool _enabled{ false }; + uint8_t _version{ 1 }; + + std::string _vertexSource; + std::string _fragmentSource; + + QString _shaderSource; + QString _shaderPath; + QUrl _shaderUrl; + quint64 _shaderModified{ 0 }; + bool _pipelineDirty{ true }; + int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION }; + int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION }; + uint64_t _start{ 0 }; + NetworkShaderPointer _networkShader; + QJsonObject _uniforms; + + gpu::PipelinePointer _pipeline; + gpu::ShaderPointer _vertexShader; + gpu::ShaderPointer _fragmentShader; + gpu::ShaderPointer _shader; + gpu::StatePointer _state; +}; + +#endif diff --git a/libraries/procedural/src/procedural/ProceduralShaders.h b/libraries/procedural/src/procedural/ProceduralShaders.h new file mode 100644 index 0000000000..9943a322cc --- /dev/null +++ b/libraries/procedural/src/procedural/ProceduralShaders.h @@ -0,0 +1,276 @@ +// +// Created by Bradley Austin Davis on 2015/09/05 +// Copyright 2013-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 +// + +// Shader includes portions of webgl-noise: +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + + +const std::string SHADER_COMMON = R"SHADER( + +float mod289(float x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec2 mod289(vec2 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 mod289(vec4 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +float permute(float x) { + return mod289(((x*34.0)+1.0)*x); +} + +vec3 permute(vec3 x) { + return mod289(((x*34.0)+1.0)*x); +} + +vec4 permute(vec4 x) { + return mod289(((x*34.0)+1.0)*x); +} + +float taylorInvSqrt(float r) { + return 1.79284291400159 - 0.85373472095314 * r; +} + +vec4 taylorInvSqrt(vec4 r) { + return 1.79284291400159 - 0.85373472095314 * r; +} + +vec4 grad4(float j, vec4 ip) { + const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); + vec4 p, s; + + p.xyz = floor(fract(vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; + p.w = 1.5 - dot(abs(p.xyz), ones.xyz); + s = vec4(lessThan(p, vec4(0.0))); + p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www; + + return p; +} + +// (sqrt(5) - 1)/4 = F4, used once below +#define F4 0.309016994374947451 + +float snoise(vec4 v) { + const vec4 C = vec4(0.138196601125011, // (5 - sqrt(5))/20 G4 + 0.276393202250021, // 2 * G4 + 0.414589803375032, // 3 * G4 + -0.447213595499958); // -1 + 4 * G4 + + // First corner + vec4 i = floor(v + dot(v, vec4(F4))); + vec4 x0 = v - i + dot(i, C.xxxx); + + // Other corners + + // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) + vec4 i0; + vec3 isX = step(x0.yzw, x0.xxx); + vec3 isYZ = step(x0.zww, x0.yyz); + i0.x = isX.x + isX.y + isX.z; + i0.yzw = 1.0 - isX; + i0.y += isYZ.x + isYZ.y; + i0.zw += 1.0 - isYZ.xy; + i0.z += isYZ.z; + i0.w += 1.0 - isYZ.z; + + // i0 now contains the unique values 0,1,2,3 in each channel + vec4 i3 = clamp(i0, 0.0, 1.0); + vec4 i2 = clamp(i0 - 1.0, 0.0, 1.0); + vec4 i1 = clamp(i0 - 2.0, 0.0, 1.0); + + vec4 x1 = x0 - i1 + C.xxxx; + vec4 x2 = x0 - i2 + C.yyyy; + vec4 x3 = x0 - i3 + C.zzzz; + vec4 x4 = x0 + C.wwww; + + // Permutations + i = mod289(i); + float j0 = permute(permute(permute(permute(i.w) + i.z) + i.y) + i.x); + vec4 j1 = permute( + permute( + permute( + permute(i.w + vec4(i1.w, i2.w, i3.w, 1.0)) + i.z + + vec4(i1.z, i2.z, i3.z, 1.0)) + i.y + + vec4(i1.y, i2.y, i3.y, 1.0)) + i.x + + vec4(i1.x, i2.x, i3.x, 1.0)); + + // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope + // 7*7*6 = 294, which is close to the ring size 17*17 = 289. + vec4 ip = vec4(1.0 / 294.0, 1.0 / 49.0, 1.0 / 7.0, 0.0); + + vec4 p0 = grad4(j0, ip); + vec4 p1 = grad4(j1.x, ip); + vec4 p2 = grad4(j1.y, ip); + vec4 p3 = grad4(j1.z, ip); + vec4 p4 = grad4(j1.w, ip); + + // Normalise gradients + vec4 norm = taylorInvSqrt( + vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + p4 *= taylorInvSqrt(dot(p4, p4)); + + // Mix contributions from the five corners + vec3 m0 = max(0.6 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2)), 0.0); + vec2 m1 = max(0.6 - vec2(dot(x3, x3), dot(x4, x4)), 0.0); + m0 = m0 * m0; + m1 = m1 * m1; + return 49.0 + * (dot(m0 * m0, vec3(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + + dot(m1 * m1, vec2(dot(p3, x3), dot(p4, x4)))); + +} + +float snoise(vec3 v) { + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = mod289(i); + vec4 p = permute( + permute( + permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + + vec4(0.0, i1.y, i2.y, 1.0)) + i.x + + vec4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt( + vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), + 0.0); + m = m * m; + return 42.0 + * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); +} + +float snoise(vec2 v) { + const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 + 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) + -0.577350269189626, // -1.0 + 2.0 * C.x + 0.024390243902439); // 1.0 / 41.0 + // First corner + vec2 i = floor(v + dot(v, C.yy)); + vec2 x0 = v - i + dot(i, C.xx); + + // Other corners + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + // Permutations + i = mod289(i); // Avoid truncation effects in permutation + vec3 p = permute( + permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); + + vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), + 0.0); + m = m * m; + m = m * m; + + // Gradients: 41 points uniformly over a line, mapped onto a diamond. + // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Approximation of: m *= inversesqrt( a0*a0 + h*h ); + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + + // Compute final noise value at P + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} + +// TODO add more uniforms +uniform float iGlobalTime; // shader playback time (in seconds) +uniform vec3 iWorldScale; // the dimensions of the object being rendered + +// TODO add support for textures +// TODO document available inputs other than the uniforms +// TODO provide world scale in addition to the untransformed position + +#define PROCEDURAL 1 + +//PROCEDURAL_VERSION +)SHADER"; diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 0ea71e54e3..4d33c6f1c1 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -40,4 +40,4 @@ add_dependency_external_projects(oglplus) find_package(OGLPLUS REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS}) -link_hifi_libraries(animation fbx shared gpu model render environment) +link_hifi_libraries(shared gpu gpu-networking procedural model render environment animation fbx) diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index eeb17f07b9..23ac11d7b0 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -1,171 +1,2 @@ -// -// TextureCache.h -// interface/src/renderer -// -// Created by Andrzej Kapolka on 8/6/13. -// Copyright 2013 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 -// - -#ifndef hifi_TextureCache_h -#define hifi_TextureCache_h - -#include -#include - -#include -#include -#include - -#include -#include - -namespace gpu { -class Batch; -} -class NetworkTexture; - -typedef QSharedPointer NetworkTexturePointer; - -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE }; - -/// Stores cached textures, including render-to-texture targets. -class TextureCache : public ResourceCache, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - -public: - /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture - /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and - /// the second, a set of random unit vectors to be used as noise gradients. - const gpu::TexturePointer& getPermutationNormalTexture(); - - /// Returns an opaque white texture (useful for a default). - const gpu::TexturePointer& getWhiteTexture(); - - /// Returns an opaque gray texture (useful for a default). - const gpu::TexturePointer& getGrayTexture(); - - /// Returns the a pale blue texture (useful for a normal map). - const gpu::TexturePointer& getBlueTexture(); - - /// Returns the a black texture (useful for a default). - const gpu::TexturePointer& getBlackTexture(); - - // Returns a map used to compress the normals through a fitting scale algorithm - const gpu::TexturePointer& getNormalFittingTexture(); - - /// Returns a texture version of an image file - static gpu::TexturePointer getImageTexture(const QString& path); - - /// Loads a texture from the specified URL. - NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false, - const QByteArray& content = QByteArray()); - -protected: - - virtual QSharedPointer createResource(const QUrl& url, - const QSharedPointer& fallback, bool delayLoad, const void* extra); - -private: - TextureCache(); - virtual ~TextureCache(); - friend class DilatableNetworkTexture; - - gpu::TexturePointer _permutationNormalTexture; - gpu::TexturePointer _whiteTexture; - gpu::TexturePointer _grayTexture; - gpu::TexturePointer _blueTexture; - gpu::TexturePointer _blackTexture; - gpu::TexturePointer _normalFittingTexture; - - QHash > _dilatableNetworkTextures; -}; - -/// A simple object wrapper for an OpenGL texture. -class Texture { -public: - friend class TextureCache; - friend class DilatableNetworkTexture; - Texture(); - ~Texture(); - - const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } - -protected: - gpu::TexturePointer _gpuTexture; - -private: -}; - -/// A texture loaded from the network. - -class NetworkTexture : public Resource, public Texture { - Q_OBJECT - -public: - - NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content); - - /// Checks whether it "looks like" this texture is translucent - /// (majority of pixels neither fully opaque or fully transparent). - bool isTranslucent() const { return _translucent; } - - /// Returns the lazily-computed average texture color. - const QColor& getAverageColor() const { return _averageColor; } - - int getOriginalWidth() const { return _originalWidth; } - int getOriginalHeight() const { return _originalHeight; } - int getWidth() const { return _width; } - int getHeight() const { return _height; } - TextureType getType() const { return _type; } -protected: - - virtual void downloadFinished(QNetworkReply* reply); - - Q_INVOKABLE void loadContent(const QByteArray& content); - // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... - Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth, - int originalHeight); - - virtual void imageLoaded(const QImage& image); - - TextureType _type; - -private: - bool _translucent; - QColor _averageColor; - int _originalWidth; - int _originalHeight; - int _width; - int _height; -}; - -/// Caches derived, dilated textures. -class DilatableNetworkTexture : public NetworkTexture { - Q_OBJECT - -public: - - DilatableNetworkTexture(const QUrl& url, const QByteArray& content); - - /// Returns a pointer to a texture with the requested amount of dilation. - QSharedPointer getDilatedTexture(float dilation); - -protected: - - virtual void imageLoaded(const QImage& image); - virtual void reinsert(); - -private: - - QImage _image; - int _innerRadius; - int _outerRadius; - - QMap > _dilatedTextures; -}; - -#endif // hifi_TextureCache_h +// Compatibility +#include diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 31d33a73e4..5901a72838 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -18,12 +18,39 @@ // the interpolated normal in vec3 _normal; in vec3 _color; +in vec2 _texCoord0; +in vec4 _position; +//PROCEDURAL_COMMON_BLOCK + +#line 1001 +//PROCEDURAL_BLOCK + +#line 2030 void main(void) { Material material = getMaterial(); - packDeferredFragment( - normalize(_normal.xyz), - glowIntensity, - _color.rgb, - DEFAULT_SPECULAR, DEFAULT_SHININESS); + vec3 normal = normalize(_normal.xyz); + vec3 diffuse = _color.rgb; + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; + float emissiveAmount = 0.0; + +#ifdef PROCEDURAL + +#ifdef PROCEDURAL_V1 + specular = getProceduralColor().rgb; + emissiveAmount = 1.0; +#else + emissiveAmount = getProceduralColors(diffuse, specular, shininess); +#endif + +#endif + + if (emissiveAmount > 0.0) { + packDeferredFragmentLightmap( + normal, glowIntensity, diffuse, specular, shininess, specular); + } else { + packDeferredFragment( + normal, glowIntensity, diffuse, specular, shininess); + } } diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 139b99e426..1acfb57829 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -7,4 +7,4 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared octree gpu model fbx entities animation audio physics) +link_hifi_libraries(shared networking octree gpu gpu-networking procedural model fbx entities animation audio physics) diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index abdbfc07f9..3d42364132 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -10,6 +10,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") #include_oglplus() # link in the shared libraries -link_hifi_libraries(render-utils gpu shared networking fbx model animation script-engine) +link_hifi_libraries(networking gpu gpu-networking procedural shared fbx model animation script-engine render-utils ) copy_dlls_beside_windows_executable() \ No newline at end of file