From abf8e83c335e297a9044c5a884656f090d09c5b2 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sun, 5 Jan 2014 11:09:16 -0800 Subject: [PATCH 01/24] change Voxels JS interface to be more clear --- examples/gun.js | 46 +++++++++---------- interface/src/Application.cpp | 4 +- libraries/script-engine/src/ScriptEngine.cpp | 2 - .../voxels/src/VoxelsScriptingInterface.cpp | 14 +++--- .../voxels/src/VoxelsScriptingInterface.h | 10 ++-- 5 files changed, 37 insertions(+), 39 deletions(-) diff --git a/examples/gun.js b/examples/gun.js index e9b1472700..c9554594c2 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -24,7 +24,7 @@ function checkController() { var numberOfTriggers = Controller.getNumberOfTriggers(); var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; - + // this is expected for hydras if (numberOfTriggers == 2 && controllersPerTrigger == 2) { for (var t = 0; t < numberOfTriggers; t++) { @@ -43,38 +43,38 @@ function checkController() { shootABullet = true; } } - + if (shootABullet) { - var palmController = t * controllersPerTrigger; + var palmController = t * controllersPerTrigger; var palmPosition = Controller.getSpatialControlPosition(palmController); - var fingerTipController = palmController + 1; + var fingerTipController = palmController + 1; var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController); - + var bulletSize = 0.25/TREE_SCALE; - var palmInParticleSpace = - { x: palmPosition.x/TREE_SCALE, - y: palmPosition.y/TREE_SCALE, + var palmInParticleSpace = + { x: palmPosition.x/TREE_SCALE, + y: palmPosition.y/TREE_SCALE, z: palmPosition.z/TREE_SCALE }; - - var tipInParticleSpace = - { x: fingerTipPosition.x/TREE_SCALE, - y: fingerTipPosition.y/TREE_SCALE, + + var tipInParticleSpace = + { x: fingerTipPosition.x/TREE_SCALE, + y: fingerTipPosition.y/TREE_SCALE, z: fingerTipPosition.z/TREE_SCALE }; - var palmToFingerTipVector = + var palmToFingerTipVector = { x: (tipInParticleSpace.x - palmInParticleSpace.x), y: (tipInParticleSpace.y - palmInParticleSpace.y), z: (tipInParticleSpace.z - palmInParticleSpace.z) }; - + // just off the front of the finger tip - var position = { x: tipInParticleSpace.x + palmToFingerTipVector.x/2, - y: tipInParticleSpace.y + palmToFingerTipVector.y/2, - z: tipInParticleSpace.z + palmToFingerTipVector.z/2}; + var position = { x: tipInParticleSpace.x + palmToFingerTipVector.x/2, + y: tipInParticleSpace.y + palmToFingerTipVector.y/2, + z: tipInParticleSpace.z + palmToFingerTipVector.z/2}; var linearVelocity = 50; // 50 meters per second - + var velocity = { x: palmToFingerTipVector.x * linearVelocity, y: palmToFingerTipVector.y * linearVelocity, z: palmToFingerTipVector.z * linearVelocity }; @@ -85,7 +85,7 @@ function checkController() { var inHand = false; // This is the script for the particles that this gun shoots. - var script = + var script = " function collisionWithVoxel(voxel) { " + " print('collisionWithVoxel(voxel)... '); " + " print('myID=' + Particle.getID() + '\\n'); " + @@ -96,17 +96,17 @@ function checkController() { " Particle.setColor(voxelColor); " + " var voxelAt = voxel.getPosition();" + " var voxelScale = voxel.getScale();" + - " Voxels.queueVoxelDelete(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + - " print('Voxels.queueVoxelDelete(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + + " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + + " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " } " + " Particle.collisionWithVoxel.connect(collisionWithVoxel); "; - + Particles.queueParticleAdd(position, bulletSize, color, velocity, gravity, damping, inHand, script); } } } } - + // register the call back so it fires before each data send Agent.willSendVisualDataCallback.connect(checkController); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 64a50a5b99..40de415c94 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1561,8 +1561,8 @@ void Application::shootParticle() { " Particle.setColor(voxelColor); " " var voxelAt = voxel.getPosition();" " var voxelScale = voxel.getScale();" - " Voxels.queueVoxelDelete(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " - " print('Voxels.queueVoxelDelete(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " " } " " Particle.collisionWithVoxel.connect(collisionWithVoxel); " ); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 86b6e8884e..3410b59d86 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -145,7 +145,6 @@ void ScriptEngine::evaluate() { } QScriptValue result = _engine.evaluate(_scriptContents); - qDebug() << "Evaluated script.\n"; if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); @@ -160,7 +159,6 @@ void ScriptEngine::run() { _isRunning = true; QScriptValue result = _engine.evaluate(_scriptContents); - qDebug() << "Evaluated script.\n"; if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index b17e40c036..df5dad8231 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -12,28 +12,28 @@ void VoxelsScriptingInterface::queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDet getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails); } -void VoxelsScriptingInterface::queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { +void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { // setup a VoxelDetail struct with the data VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; - + // queue the packet queueVoxelAdd(PACKET_TYPE_VOXEL_SET, addVoxelDetail); } -void VoxelsScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z, float scale, +void VoxelsScriptingInterface::destructiveSetVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { // setup a VoxelDetail struct with the data VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; - + // queue the destructive add queueVoxelAdd(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, addVoxelDetail); } -void VoxelsScriptingInterface::queueVoxelDelete(float x, float y, float z, float scale) { - +void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale) { + // setup a VoxelDetail struct with data VoxelDetail deleteVoxelDetail = {x, y, z, scale, 0, 0, 0}; - + getVoxelPacketSender()->queueVoxelEditMessages(PACKET_TYPE_VOXEL_ERASE, 1, &deleteVoxelDetail); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index c725b93493..ea9f6a4205 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -33,8 +33,8 @@ public slots: /// \param red the R value for RGB color of voxel /// \param green the G value for RGB color of voxel /// \param blue the B value for RGB color of voxel - void queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - + void setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); + /// queues the destructive creation of a voxel which will be sent by calling process on the PacketSender /// \param x the x-coordinate of the voxel (in VS space) /// \param y the y-coordinate of the voxel (in VS space) @@ -43,14 +43,14 @@ public slots: /// \param red the R value for RGB color of voxel /// \param green the G value for RGB color of voxel /// \param blue the B value for RGB color of voxel - void queueDestructiveVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - + void destructiveSetVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); + /// queues the deletion of a voxel, sent by calling process on the PacketSender /// \param x the x-coordinate of the voxel (in VS space) /// \param y the y-coordinate of the voxel (in VS space) /// \param z the z-coordinate of the voxel (in VS space) /// \param scale the scale of the voxel (in VS space) - void queueVoxelDelete(float x, float y, float z, float scale); + void eraseVoxel(float x, float y, float z, float scale); private: void queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails); From 43da1edadbe55bbce26465aa09450e91aace058e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 17 Jan 2014 11:35:35 -0800 Subject: [PATCH 02/24] more particle work --- libraries/particles/src/Particle.cpp | 209 +++++++++++++++++++++++++++ libraries/particles/src/Particle.h | 34 +++++ 2 files changed, 243 insertions(+) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 3323dec88b..38ef50f21a 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -611,3 +611,212 @@ void Particle::copyChangedProperties(const Particle& other) { *this = other; setLifetime(lifetime); } + + +QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const { + QScriptValue properties = engine->newObject(); + + QScriptValue position = vec3toScriptValue(engine, _position); + properties.setProperty("position", position); + + QScriptValue color = xColortoScriptValue(engine, _color); + properties.setProperty("color", color); + + properties.setProperty("radius", _radius); + + QScriptValue velocity = vec3toScriptValue(engine, _velocity); + properties.setProperty("velocity", velocity); + + QScriptValue gravity = vec3toScriptValue(engine, _gravity); + properties.setProperty("gravity", gravity); + + properties.setProperty("damping", _damping); + properties.setProperty("script", _script); + properties.setProperty("inHand", _inHand); + properties.setProperty("shouldDie", _shouldDie); + + return properties; +} + +void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { + + QScriptValue position = object.property("position"); + if (position.isValid()) { + QScriptValue x = position.property("x"); + QScriptValue y = position.property("y"); + QScriptValue z = position.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + glm::vec3 newPosition; + newPosition.x = x.toVariant().toFloat(); + newPosition.y = x.toVariant().toFloat(); + newPosition.z = x.toVariant().toFloat(); + if (newPosition != _position) { + _position = newPosition; + _positionChanged = true; + } + } + } + + QScriptValue color = object.property("color"); + if (color.isValid()) { + QScriptValue red = color.property("red"); + QScriptValue green = color.property("green"); + QScriptValue blue = color.property("blue"); + if (red.isValid() && green.isValid() && blue.isValid()) { + xColor newColor; + newColor.red = red.toVariant().toInt(); + newColor.green = green.toVariant().toInt(); + newColor.blue = blue.toVariant().toInt(); + if (newColor.red != _color.red || + newColor.green != _color.green || + newColor.blue != _color.blue) { + _color = newColor; + _colorChanged = true; + } + } + } + + QScriptValue radius = object.property("radius"); + if (radius.isValid()) { + float newRadius; + newRadius = radius.toVariant().toFloat(); + if (newRadius != _radius) { + _radius = newRadius; + _radiusChanged = true; + } + } + + QScriptValue velocity = object.property("velocity"); + if (velocity.isValid()) { + QScriptValue x = velocity.property("x"); + QScriptValue y = velocity.property("y"); + QScriptValue z = velocity.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + glm::vec3 newVelocity; + newVelocity.x = x.toVariant().toFloat(); + newVelocity.y = x.toVariant().toFloat(); + newVelocity.z = x.toVariant().toFloat(); + if (newVelocity != _velocity) { + _velocity = newVelocity; + _velocityChanged = true; + } + } + } + + QScriptValue gravity = object.property("gravity"); + if (gravity.isValid()) { + QScriptValue x = gravity.property("x"); + QScriptValue y = gravity.property("y"); + QScriptValue z = gravity.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + glm::vec3 newGravity; + newGravity.x = x.toVariant().toFloat(); + newGravity.y = x.toVariant().toFloat(); + newGravity.z = x.toVariant().toFloat(); + if (newGravity != _gravity) { + _gravity = newGravity; + _gravityChanged = true; + } + } + } + + QScriptValue damping = object.property("damping"); + if (damping.isValid()) { + float newDamping; + newDamping = damping.toVariant().toFloat(); + if (newDamping != _damping) { + _damping = newDamping; + _dampingChanged = true; + } + } + + QScriptValue script = object.property("script"); + if (script.isValid()) { + QString newScript; + newScript = script.toVariant().toString(); + if (newScript != _script) { + _script = newScript; + _scriptChanged = true; + } + } + + QScriptValue inHand = object.property("inHand"); + if (inHand.isValid()) { + bool newInHand; + newInHand = inHand.toVariant().toBool(); + if (newInHand != _inHand) { + _inHand = newInHand; + _inHandChanged = true; + } + } + + QScriptValue shouldDie = object.property("shouldDie"); + if (shouldDie.isValid()) { + bool newShouldDie; + newShouldDie = shouldDie.toVariant().toBool(); + if (newShouldDie != _shouldDie) { + _shouldDie = newShouldDie; + _shouldDieChanged = true; + } + } +} + +void ParticleProperties::copyToParticle(Particle& particle) const { + if (_positionChanged) { + particle.setPosition(_position); + } + + if (_colorChanged) { + particle.setColor(_color); + } + + if (_radiusChanged) { + particle.setRadius(_radius); + } + + if (_velocityChanged) { + particle.setVelocity(_velocity); + } + + if (_gravityChanged) { + particle.setGravity(_gravity); + } + + if (_dampingChanged) { + particle.setDamping(_damping); + } + + if (_scriptChanged) { + particle.setScript(_script); + } + + if (_inHandChanged) { + particle.setInHand(_inHand); + } + + if (_shouldDieChanged) { + particle.setShouldDie(_shouldDie); + } +} + +void ParticleProperties::copyFromParticle(const Particle& particle) { + _position = particle.getPosition(); + _color = particle.getXColor(); + _radius = particle.getRadius(); + _velocity = particle.getVelocity(); + _gravity = particle.getGravity(); + _damping = particle.getDamping(); + _script = particle.getScript(); + _inHand = particle.getInHand(); + _shouldDie = particle.getShouldDie(); + + _positionChanged = false; + _colorChanged = false; + _radiusChanged = false; + _velocityChanged = false; + _gravityChanged = false; + _dampingChanged = false; + _scriptChanged = false; + _inHandChanged = false; + _shouldDieChanged = false; +} diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index e93790eab7..0e81fa2bf2 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -207,4 +207,38 @@ private: }; +class ParticleProperties : public QObject { + Q_OBJECT +public: + ParticleProperties(); + + QScriptValue copyToScriptValue(QScriptEngine* engine) const; + void copyFromScriptValue(const QScriptValue& object); + + void copyToParticle(Particle& particle) const; + void copyFromParticle(const Particle& particle); + +private: + glm::vec3 _position; + xColor _color; + float _radius; + glm::vec3 _velocity; + glm::vec3 _gravity; + float _damping; + QString _script; + bool _inHand; + bool _shouldDie; + + bool _positionChanged; + bool _colorChanged; + bool _radiusChanged; + bool _velocityChanged; + bool _gravityChanged; + bool _dampingChanged; + bool _scriptChanged; + bool _inHandChanged; + bool _shouldDieChanged; +}; + + #endif /* defined(__hifi__Particle__) */ From 1e0f1adb16397aad8b196d90e879ed56d9cb2150 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 17 Jan 2014 14:59:40 -0800 Subject: [PATCH 03/24] added lifetime to particles --- interface/src/Application.cpp | 13 +-- interface/src/Application.h | 2 +- interface/src/avatar/Hand.cpp | 5 ++ interface/src/avatar/MyAvatar.cpp | 2 - libraries/particles/src/Particle.cpp | 86 ++++++++++++++----- libraries/particles/src/Particle.h | 21 +++-- .../particles/src/ParticleCollisionSystem.cpp | 17 ++-- .../particles/src/ParticleEditHandle.cpp | 10 +-- libraries/particles/src/ParticleEditHandle.h | 10 +-- .../src/ParticlesScriptingInterface.cpp | 12 +-- .../src/ParticlesScriptingInterface.h | 10 +-- libraries/shared/src/PacketHeaders.cpp | 26 +++--- 12 files changed, 135 insertions(+), 79 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d1a375c7f2..30b298332c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1513,8 +1513,9 @@ void Application::shootParticle() { const float radius = 0.125 / TREE_SCALE; xColor color = { 0, 255, 255}; glm::vec3 velocity = lookingAt - position; - glm::vec3 gravity = DEFAULT_GRAVITY * 0.f; + glm::vec3 gravity = DEFAULT_GRAVITY * 0.01f; float damping = DEFAULT_DAMPING * 0.01f; + float lifetime = 5.0f; // bullets have 5 second lifetime QString script( " function collisionWithVoxel(voxel) { " " print('collisionWithVoxel(voxel)... '); " @@ -1533,7 +1534,7 @@ void Application::shootParticle() { ParticleEditHandle* particleEditHandle = makeParticle(position / (float)TREE_SCALE, radius, color, - velocity / (float)TREE_SCALE, gravity, damping, NOT_IN_HAND, script); + velocity / (float)TREE_SCALE, gravity, damping, lifetime, NOT_IN_HAND, script); // If we wanted to be able to edit this particle after shooting, then we could store this value // and use it for editing later. But we don't care about that for "shooting" and therefore we just @@ -1550,10 +1551,10 @@ ParticleEditHandle* Application::newParticleEditHandle(uint32_t id) { // Caller is responsible for managing this EditableParticle ParticleEditHandle* Application::makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, bool inHand, QString updateScript) { + glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { ParticleEditHandle* particleEditHandle = newParticleEditHandle(); - particleEditHandle->createParticle(position, radius, color, velocity, gravity, damping, inHand, updateScript); + particleEditHandle->createParticle(position, radius, color, velocity, gravity, damping, lifetime, inHand, updateScript); return particleEditHandle; } @@ -2089,14 +2090,14 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& glm::vec3 rayOrigin, rayDirection; _viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection); lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE; - + } else if (!_lookatTargetAvatar) { if (_isHoverVoxel) { // Look at the hovered voxel lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); } else { - // Just look in direction of the mouse ray + // Just look in direction of the mouse ray lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE; } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 7e78cced4c..1b465d9a59 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,7 +126,7 @@ public: void shootParticle(); // shoots a particle in the direction you're looking ParticleEditHandle* newParticleEditHandle(uint32_t id = NEW_PARTICLE); ParticleEditHandle* makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, bool inHand, QString updateScript); + glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript); void makeVoxel(glm::vec3 position, float scale, diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 0b399c4287..e1cdcae58d 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -24,6 +24,7 @@ const float FINGERTIP_VOXEL_SIZE = 0.05f; const int TOY_BALL_HAND = 1; const float TOY_BALL_RADIUS = 0.05f; const float TOY_BALL_DAMPING = 0.1f; +const float TOY_BALL_LIFETIME = 30.0f; // toy balls live for 30 seconds const glm::vec3 NO_VELOCITY = glm::vec3(0,0,0); const glm::vec3 NO_GRAVITY = glm::vec3(0,0,0); const float NO_DAMPING = 0.f; @@ -113,6 +114,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f newVelocity, NO_GRAVITY, NO_DAMPING, + DEFAULT_LIFETIME, IN_HAND, // we just grabbed it! closestParticle->getScript()); @@ -156,6 +158,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f NO_VELOCITY / (float)TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_DAMPING, + TOY_BALL_LIFETIME, IN_HAND, TOY_BALL_UPDATE_SCRIPT); // Play a new ball sound @@ -178,6 +181,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f NO_VELOCITY / (float)TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_DAMPING, + TOY_BALL_LIFETIME, IN_HAND, TOY_BALL_UPDATE_SCRIPT); } @@ -204,6 +208,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f ballVelocity / (float)TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_DAMPING, + TOY_BALL_LIFETIME, NOT_IN_HAND, TOY_BALL_UPDATE_SCRIPT); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3c5fdb243f..3bbba8b749 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -175,8 +175,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { // Compute instantaneous acceleration float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; - const float ACCELERATION_PITCH_DECAY = 0.4f; - const float ACCELERATION_PULL_THRESHOLD = 0.2f; const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; const int OCULUS_YAW_OFFSET_THRESHOLD = 10; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 346e77c71c..d989bcb01b 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -29,22 +29,22 @@ ParticleEditPacketSender* Particle::_particleEditSender = NULL; Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, - float damping, bool inHand, QString updateScript, uint32_t id) { + float damping, float lifetime, bool inHand, QString updateScript, uint32_t id) { - init(position, radius, color, velocity, gravity, damping, inHand, updateScript, id); + init(position, radius, color, velocity, gravity, damping, lifetime, inHand, updateScript, id); } Particle::Particle() { rgbColor noColor = { 0, 0, 0 }; init(glm::vec3(0,0,0), 0, noColor, glm::vec3(0,0,0), - DEFAULT_GRAVITY, DEFAULT_DAMPING, NOT_IN_HAND, DEFAULT_SCRIPT, NEW_PARTICLE); + DEFAULT_GRAVITY, DEFAULT_DAMPING, DEFAULT_LIFETIME, NOT_IN_HAND, DEFAULT_SCRIPT, NEW_PARTICLE); } Particle::~Particle() { } void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, - float damping, bool inHand, QString updateScript, uint32_t id) { + float damping, float lifetime, bool inHand, QString updateScript, uint32_t id) { if (id == NEW_PARTICLE) { _id = _nextID; _nextID++; @@ -54,7 +54,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 uint64_t now = usecTimestampNow(); _lastEdited = now; _lastUpdated = now; - _created = now; // will get updated as appropriate in setLifetime() + _created = now; // will get updated as appropriate in setAge() _position = position; _radius = radius; @@ -62,6 +62,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 memcpy(_color, color, sizeof(_color)); _velocity = velocity; _damping = damping; + _lifetime = lifetime; _gravity = gravity; _script = updateScript; _inHand = inHand; @@ -81,7 +82,7 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { //printf("Particle::appendParticleData()... getID()=%d\n", getID()); if (success) { - success = packetData->appendValue(getLifetime()); + success = packetData->appendValue(getAge()); } if (success) { success = packetData->appendValue(getLastUpdated()); @@ -107,6 +108,9 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { if (success) { success = packetData->appendValue(getDamping()); } + if (success) { + success = packetData->appendValue(getLifetime()); + } if (success) { success = packetData->appendValue(getInHand()); } @@ -122,7 +126,7 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { int Particle::expectedBytes() { int expectedBytes = sizeof(uint32_t) // id - + sizeof(float) // lifetime + + sizeof(float) // age + sizeof(uint64_t) // last updated + sizeof(uint64_t) // lasted edited + sizeof(float) // radius @@ -131,6 +135,7 @@ int Particle::expectedBytes() { + sizeof(glm::vec3) // velocity + sizeof(glm::vec3) // gravity + sizeof(float) // damping + + sizeof(float) // lifetime + sizeof(bool); // inhand // potentially more... return expectedBytes; @@ -145,6 +150,7 @@ int Particle::expectedEditMessageBytes() { + sizeof(glm::vec3) // velocity + sizeof(glm::vec3) // gravity + sizeof(float) // damping + + sizeof(float) // lifetime + sizeof(bool); // inhand // potentially more... return expectedBytes; @@ -162,12 +168,12 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef dataAt += sizeof(_id); bytesRead += sizeof(_id); - // lifetime - float lifetime; - memcpy(&lifetime, dataAt, sizeof(lifetime)); - dataAt += sizeof(lifetime); - bytesRead += sizeof(lifetime); - setLifetime(lifetime); + // age + float age; + memcpy(&age, dataAt, sizeof(age)); + dataAt += sizeof(age); + bytesRead += sizeof(age); + setAge(age); // _lastUpdated memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated)); @@ -211,6 +217,11 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef dataAt += sizeof(_damping); bytesRead += sizeof(_damping); + // lifetime + memcpy(&_lifetime, dataAt, sizeof(_lifetime)); + dataAt += sizeof(_lifetime); + bytesRead += sizeof(_lifetime); + // inHand memcpy(&_inHand, dataAt, sizeof(_inHand)); dataAt += sizeof(_inHand); @@ -262,7 +273,7 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe newParticle.setCreatorTokenID(creatorTokenID); newParticle._newlyCreated = true; - newParticle.setLifetime(0); // this guy is new! + newParticle.setAge(0); // this guy is new! } else { newParticle._id = editID; @@ -304,6 +315,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe dataAt += sizeof(newParticle._damping); processedBytes += sizeof(newParticle._damping); + // lifetime + memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime)); + dataAt += sizeof(newParticle._lifetime); + processedBytes += sizeof(newParticle._lifetime); + // inHand memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand)); dataAt += sizeof(newParticle._inHand); @@ -331,7 +347,7 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe void Particle::debugDump() const { printf("Particle id :%u\n", _id); - printf(" lifetime:%f\n", getLifetime()); + printf(" age:%f\n", getAge()); printf(" edited ago:%f\n", getEditedAgo()); printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z); printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z); @@ -414,6 +430,11 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, copyAt += sizeof(details[i].damping); sizeOut += sizeof(details[i].damping); + // damping + memcpy(copyAt, &details[i].lifetime, sizeof(details[i].lifetime)); + copyAt += sizeof(details[i].lifetime); + sizeOut += sizeof(details[i].lifetime); + // inHand memcpy(copyAt, &details[i].inHand, sizeof(details[i].inHand)); copyAt += sizeof(details[i].inHand); @@ -486,9 +507,11 @@ void Particle::update() { const float STILL_MOVING = 0.05f / static_cast(TREE_SCALE); bool isStillMoving = (velocityScalar > STILL_MOVING); const float REALLY_OLD = 30.0f; // 30 seconds - bool isReallyOld = (getLifetime() > REALLY_OLD); + bool isReallyOld = (getAge() > REALLY_OLD); bool isInHand = getInHand(); - bool shouldDie = getShouldDie() || (!isInHand && !isStillMoving && isReallyOld); + + // Lifetime - even if you're moving, or in hand, if you're age is greater than your requested lifetime, you are going to die + bool shouldDie = getShouldDie() || (getAge() > getLifetime()) || (!isInHand && !isStillMoving && isReallyOld); setShouldDie(shouldDie); runUpdateScript(); // allow the javascript to alter our state @@ -607,15 +630,15 @@ void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) { -void Particle::setLifetime(float lifetime) { - uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND; - _created = usecTimestampNow() - lifetimeInUsecs; +void Particle::setAge(float age) { + uint64_t ageInUsecs = age * USECS_PER_SECOND; + _created = usecTimestampNow() - ageInUsecs; } void Particle::copyChangedProperties(const Particle& other) { - float lifetime = getLifetime(); + float age = getAge(); *this = other; - setLifetime(lifetime); + setAge(age); } @@ -625,7 +648,7 @@ QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const QScriptValue position = vec3toScriptValue(engine, _position); properties.setProperty("position", position); - QScriptValue color = xColortoScriptValue(engine, _color); + QScriptValue color = xColorToScriptValue(engine, _color); properties.setProperty("color", color); properties.setProperty("radius", _radius); @@ -637,6 +660,7 @@ QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const properties.setProperty("gravity", gravity); properties.setProperty("damping", _damping); + properties.setProperty("lifetime", _lifetime); properties.setProperty("script", _script); properties.setProperty("inHand", _inHand); properties.setProperty("shouldDie", _shouldDie); @@ -736,6 +760,16 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { } } + QScriptValue lifetime = object.property("lifetime"); + if (lifetime.isValid()) { + float newLifetime; + newLifetime = lifetime.toVariant().toFloat(); + if (newLifetime != _lifetime) { + _lifetime = newLifetime; + _lifetimeChanged = true; + } + } + QScriptValue script = object.property("script"); if (script.isValid()) { QString newScript; @@ -792,6 +826,10 @@ void ParticleProperties::copyToParticle(Particle& particle) const { particle.setDamping(_damping); } + if (_lifetimeChanged) { + particle.setLifetime(_lifetime); + } + if (_scriptChanged) { particle.setScript(_script); } @@ -812,6 +850,7 @@ void ParticleProperties::copyFromParticle(const Particle& particle) { _velocity = particle.getVelocity(); _gravity = particle.getGravity(); _damping = particle.getDamping(); + _lifetime = particle.getLifetime(); _script = particle.getScript(); _inHand = particle.getInHand(); _shouldDie = particle.getShouldDie(); @@ -822,6 +861,7 @@ void ParticleProperties::copyFromParticle(const Particle& particle) { _velocityChanged = false; _gravityChanged = false; _dampingChanged = false; + _lifetimeChanged = false; _scriptChanged = false; _inHandChanged = false; _shouldDieChanged = false; diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index f32d12a1cd..1c1c47dbe9 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -38,11 +38,13 @@ public: glm::vec3 velocity; glm::vec3 gravity; float damping; + float lifetime; bool inHand; QString updateScript; uint32_t creatorTokenID; }; +const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default const float DEFAULT_DAMPING = 0.99f; const glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0); const QString DEFAULT_SCRIPT(""); @@ -54,16 +56,16 @@ class Particle { public: Particle(); Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, - glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND, - QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); + glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, float lifetime = DEFAULT_LIFETIME, + bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); /// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes); virtual ~Particle(); virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, - glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND, - QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); + glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, float lifetime = DEFAULT_LIFETIME, + bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); const glm::vec3& getPosition() const { return _position; } const rgbColor& getColor() const { return _color; } @@ -74,6 +76,7 @@ public: const glm::vec3& getGravity() const { return _gravity; } bool getInHand() const { return _inHand; } float getDamping() const { return _damping; } + float getLifetime() const { return _lifetime; } /// The last updated/simulated time of this particle from the time perspective of the authoritative server/source uint64_t getLastUpdated() const { return _lastUpdated; } @@ -82,7 +85,7 @@ public: uint64_t getLastEdited() const { return _lastEdited; } /// lifetime of the particle in seconds - float getLifetime() const { return static_cast(usecTimestampNow() - _created) / static_cast(USECS_PER_SECOND); } + float getAge() const { return static_cast(usecTimestampNow() - _created) / static_cast(USECS_PER_SECOND); } float getEditedAgo() const { return static_cast(usecTimestampNow() - _lastEdited) / static_cast(USECS_PER_SECOND); } uint32_t getID() const { return _id; } bool getShouldDie() const { return _shouldDie; } @@ -104,6 +107,7 @@ public: void setInHand(bool inHand) { _inHand = inHand; } void setDamping(float value) { _damping = value; } void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; } + void setLifetime(float value) { _lifetime = value; } void setScript(QString updateScript) { _script = updateScript; } void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; } @@ -146,7 +150,7 @@ protected: static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color); static void xColorFromScriptValue(const QScriptValue &object, xColor& color); - void setLifetime(float lifetime); + void setAge(float age); glm::vec3 _position; rgbColor _color; @@ -158,6 +162,7 @@ protected: bool _shouldDie; glm::vec3 _gravity; float _damping; + float _lifetime; QString _script; bool _inHand; @@ -189,6 +194,7 @@ public slots: float getDamping() const { return _particle->getDamping(); } float getRadius() const { return _particle->getRadius(); } bool getShouldDie() { return _particle->getShouldDie(); } + float getAge() const { return _particle->getAge(); } float getLifetime() const { return _particle->getLifetime(); } void setPosition(glm::vec3 value) { _particle->setPosition(value); } @@ -199,6 +205,7 @@ public slots: void setRadius(float value) { _particle->setRadius(value); } void setShouldDie(bool value) { _particle->setShouldDie(value); } void setScript(const QString& script) { _particle->setScript(script); } + void setLifetime(float value) const { return _particle->setLifetime(value); } signals: void update(); @@ -228,6 +235,7 @@ private: glm::vec3 _velocity; glm::vec3 _gravity; float _damping; + float _lifetime; QString _script; bool _inHand; bool _shouldDie; @@ -238,6 +246,7 @@ private: bool _velocityChanged; bool _gravityChanged; bool _dampingChanged; + bool _lifetimeChanged; bool _scriptChanged; bool _inHandChanged; bool _shouldDieChanged; diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index ed62da8791..12af1a0b69 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -121,14 +121,16 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) particleA->setVelocity(particleA->getVelocity() - axialVelocity * (2.0f * massB / totalMass)); ParticleEditHandle particleEditHandle(_packetSender, _particles, particleA->getID()); - particleEditHandle.updateParticle(particleA->getPosition(), particleA->getRadius(), particleA->getXColor(), particleA->getVelocity(), - particleA->getGravity(), particleA->getDamping(), particleA->getInHand(), particleA->getScript()); + particleEditHandle.updateParticle(particleA->getPosition(), particleA->getRadius(), particleA->getXColor(), + particleA->getVelocity(), particleA->getGravity(), particleA->getDamping(), particleA->getLifetime(), + particleA->getInHand(), particleA->getScript()); particleB->setVelocity(particleB->getVelocity() + axialVelocity * (2.0f * massA / totalMass)); ParticleEditHandle penetratedparticleEditHandle(_packetSender, _particles, particleB->getID()); - penetratedparticleEditHandle.updateParticle(particleB->getPosition(), particleB->getRadius(), particleB->getXColor(), particleB->getVelocity(), - particleB->getGravity(), particleB->getDamping(), particleB->getInHand(), particleB->getScript()); + penetratedparticleEditHandle.updateParticle(particleB->getPosition(), particleB->getRadius(), + particleB->getXColor(), particleB->getVelocity(), particleB->getGravity(), particleB->getDamping(), + particleB->getLifetime(), particleB->getInHand(), particleB->getScript()); penetration /= (float)(TREE_SCALE); updateCollisionSound(particleA, penetration, COLLISION_FREQUENCY); @@ -160,7 +162,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { collision._penetration /= (float)(TREE_SCALE); collision._addedVelocity /= (float)(TREE_SCALE); updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY); - applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); + applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); } } } @@ -178,7 +180,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { collision._penetration /= (float)(TREE_SCALE); collision._addedVelocity /= (float)(TREE_SCALE); updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY); - applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); + applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); } } } @@ -224,7 +226,8 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm:: ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID()); particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity, - particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getScript()); + particle->getGravity(), particle->getDamping(), particle->getLifetime(), + particle->getInHand(), particle->getScript()); } diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index 88d3143a0f..d3a8dd56be 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -41,13 +41,13 @@ ParticleEditHandle::~ParticleEditHandle() { } void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, bool inHand, QString updateScript) { + glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, - velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; + velocity, gravity, damping, lifetime, inHand, updateScript, _creatorTokenID }; // queue the packet _packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &addParticleDetail); @@ -63,7 +63,7 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor } bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, bool inHand, QString updateScript) { + glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { if (!isKnownID()) { return false; // not allowed until we know the id @@ -73,7 +73,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor uint64_t now = usecTimestampNow(); ParticleDetail newParticleDetail = { _id, now, position, radius, {color.red, color.green, color.blue }, - velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; + velocity, gravity, damping, lifetime, inHand, updateScript, _creatorTokenID }; // queue the packet _packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &newParticleDetail); @@ -84,7 +84,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor // if we have a local tree, also update it... if (_localTree) { rgbColor rcolor = {color.red, color.green, color.blue }; - Particle tempParticle(position, radius, rcolor, velocity, gravity, damping, inHand, updateScript, _id); + Particle tempParticle(position, radius, rcolor, velocity, gravity, damping, lifetime, inHand, updateScript, _id); _localTree->storeParticle(tempParticle); } diff --git a/libraries/particles/src/ParticleEditHandle.h b/libraries/particles/src/ParticleEditHandle.h index 186dc47944..f0a9191f35 100644 --- a/libraries/particles/src/ParticleEditHandle.h +++ b/libraries/particles/src/ParticleEditHandle.h @@ -34,12 +34,12 @@ public: bool isKnownID() const { return _isKnownID; } - void createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, bool inHand, QString updateScript); + void createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, + glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript); + + bool updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, + glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript); - bool updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, bool inHand, QString updateScript); - static void handleAddResponse(unsigned char* packetData , int packetLength); private: uint32_t _creatorTokenID; diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 7f8c435a12..553293a9a8 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -14,8 +14,8 @@ void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, P getParticlePacketSender()->queueParticleEditMessages(packetType, 1, &particleDetails); } -unsigned int ParticlesScriptingInterface::queueParticleAdd(glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script) { +unsigned int ParticlesScriptingInterface::addParticle(glm::vec3 position, float radius, + xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { // The application will keep track of creatorTokenID uint32_t creatorTokenID = _nextCreatorTokenID; @@ -25,7 +25,7 @@ unsigned int ParticlesScriptingInterface::queueParticleAdd(glm::vec3 position, f uint64_t now = usecTimestampNow(); ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, velocity, - gravity, damping, inHand, script, creatorTokenID }; + gravity, damping, lifetime, inHand, script, creatorTokenID }; // queue the packet queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); @@ -34,14 +34,14 @@ unsigned int ParticlesScriptingInterface::queueParticleAdd(glm::vec3 position, f } -void ParticlesScriptingInterface::queueParticleEdit(unsigned int particleID, glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script) { +void ParticlesScriptingInterface::editParticle(unsigned int particleID, glm::vec3 position, float radius, + xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); ParticleDetail editParticleDetail = { particleID, now, position, radius, {color.red, color.green, color.blue }, velocity, - gravity, damping, inHand, script, UNKNOWN_TOKEN }; + gravity, damping, lifetime, inHand, script, UNKNOWN_TOKEN }; // queue the packet queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail); diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index 265f5a7ca4..0fe2de5190 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -26,15 +26,15 @@ public: public slots: /// queues the creation of a Particle which will be sent by calling process on the PacketSender /// returns the creatorTokenID for the newly created particle - unsigned int queueParticleAdd(glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script); + unsigned int addParticle(glm::vec3 position, float radius, + xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script); - void queueParticleEdit(unsigned int particleID, glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString script); + void editParticle(unsigned int particleID, glm::vec3 position, float radius, + xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script); private: void queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails); - + uint32_t _nextCreatorTokenID; }; diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 0d468f0e1d..d329171459 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -18,21 +18,21 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO: case PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO: return 2; - + case PACKET_TYPE_HEAD_DATA: return 14; - + case PACKET_TYPE_AVATAR_URLS: return 2; case PACKET_TYPE_OCTREE_STATS: return 2; - + case PACKET_TYPE_DOMAIN: case PACKET_TYPE_DOMAIN_LIST_REQUEST: case PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY: return 2; - + case PACKET_TYPE_VOXEL_QUERY: return 2; @@ -43,19 +43,19 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_VOXEL_DATA: return 1; - + case PACKET_TYPE_JURISDICTION: return 1; - - case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: - return 2; + + case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: + return 3; case PACKET_TYPE_PARTICLE_DATA: - return 5; - + return 6; + case PACKET_TYPE_PING_REPLY: return 1; - + default: return 0; } @@ -75,7 +75,7 @@ bool packetVersionMatch(unsigned char* packetHeader) { int populateTypeAndVersion(unsigned char* destinationHeader, PACKET_TYPE type) { destinationHeader[0] = type; destinationHeader[1] = versionForPacketType(type); - + // return the number of bytes written for pointer pushing return 2; } @@ -99,7 +99,7 @@ int numBytesForPacketVersion(const unsigned char* packetVersion) { int numBytesForPacketHeader(const unsigned char* packetHeader) { // int numBytesType = numBytesForPacketType(packetHeader); // return numBytesType + numBytesForPacketVersion(packetHeader + numBytesType); - + // currently this need not be dynamic - there are 2 bytes for each packet header return 2; } From 99f9ae9d3a60527e34b4d9df1ce1e62f53ef235c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 17 Jan 2014 16:02:58 -0800 Subject: [PATCH 04/24] implement new setProperties() getProperties() for Particle to allow setting all properties at once using a JS hash --- examples/gun.js | 3 +- interface/src/Application.cpp | 12 +-- libraries/particles/src/Particle.cpp | 42 +++++++++++ libraries/particles/src/Particle.h | 79 +++++++++++--------- libraries/script-engine/src/ScriptEngine.cpp | 1 + libraries/shared/src/RegisteredMetaTypes.cpp | 1 + 6 files changed, 98 insertions(+), 40 deletions(-) diff --git a/examples/gun.js b/examples/gun.js index 7e486ee92d..b93131c0f7 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -92,7 +92,8 @@ function checkController() { " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " + " var myColor = Particle.getColor();" + " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " + - " Particle.setColor(voxelColor); " + + " var newProps = { color: voxelColor }; " + + " Particle.setProperties(newProps); " + " var voxelAt = voxel.getPosition();" + " var voxelScale = voxel.getScale();" + " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30b298332c..5d30d8b991 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1519,16 +1519,18 @@ void Application::shootParticle() { QString script( " function collisionWithVoxel(voxel) { " " print('collisionWithVoxel(voxel)... '); " - " print('myID=' + Particle.getID() + '\\n'); " + " print('myID=' + Particle.getID()); " " var voxelColor = voxel.getColor();" - " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " + " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue ); " " var myColor = Particle.getColor();" - " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " - " Particle.setColor(voxelColor); " + " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue ); " + " var newProps = { color: voxelColor }; " + " print('about to call Particle.setProperties()'); " + " Particle.setProperties(newProps); " " var voxelAt = voxel.getPosition();" " var voxelScale = voxel.getScale();" " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " - " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')...'); " " } " " Particle.collisionWithVoxel.connect(collisionWithVoxel); " ); diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index d989bcb01b..e3c1247176 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -641,6 +641,40 @@ void Particle::copyChangedProperties(const Particle& other) { setAge(age); } +ParticleProperties Particle::getProperties() const { + ParticleProperties properties; + properties.copyFromParticle(*this); + return properties; +} + +void Particle::setProperties(const ParticleProperties& properties) { + properties.copyToParticle(*this); +} + +ParticleProperties::ParticleProperties() : + _position(0), + _color(), + _radius(0), + _velocity(0), + _gravity(DEFAULT_GRAVITY), + _damping(DEFAULT_DAMPING), + _lifetime(DEFAULT_LIFETIME), + _script(""), + _inHand(false), + _shouldDie(false), + + _positionChanged(false), + _colorChanged(false), + _radiusChanged(false), + _velocityChanged(false), + _gravityChanged(false), + _dampingChanged(false), + _lifetimeChanged(false), + _scriptChanged(false), + _inHandChanged(false), + _shouldDieChanged(false) +{ +} QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const { QScriptValue properties = engine->newObject(); @@ -866,3 +900,11 @@ void ParticleProperties::copyFromParticle(const Particle& particle) { _inHandChanged = false; _shouldDieChanged = false; } + +QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties) { + return properties.copyToScriptValue(engine); +} + +void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties) { + properties.copyFromScriptValue(object); +} diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 1c1c47dbe9..5eace8daff 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -23,7 +23,8 @@ class VoxelsScriptingInterface; class ParticlesScriptingInterface; class VoxelEditPacketSender; class ParticleEditPacketSender; - +class ParticleProperties; +class Particle; const uint32_t NEW_PARTICLE = 0xFFFFFFFF; const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; @@ -51,6 +52,42 @@ const QString DEFAULT_SCRIPT(""); const bool IN_HAND = true; // it's in a hand const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand +/// Used in scripting to set/get the complete set of particle properties via JavaScript hashes/QScriptValues +class ParticleProperties { +public: + ParticleProperties(); + + QScriptValue copyToScriptValue(QScriptEngine* engine) const; + void copyFromScriptValue(const QScriptValue& object); + + void copyToParticle(Particle& particle) const; + void copyFromParticle(const Particle& particle); + +private: + glm::vec3 _position; + xColor _color; + float _radius; + glm::vec3 _velocity; + glm::vec3 _gravity; + float _damping; + float _lifetime; + QString _script; + bool _inHand; + bool _shouldDie; + + bool _positionChanged; + bool _colorChanged; + bool _radiusChanged; + bool _velocityChanged; + bool _gravityChanged; + bool _dampingChanged; + bool _lifetimeChanged; + bool _scriptChanged; + bool _inHandChanged; + bool _shouldDieChanged; +}; + + class Particle { public: @@ -77,6 +114,7 @@ public: bool getInHand() const { return _inHand; } float getDamping() const { return _damping; } float getLifetime() const { return _lifetime; } + ParticleProperties getProperties() const; /// The last updated/simulated time of this particle from the time perspective of the authoritative server/source uint64_t getLastUpdated() const { return _lastUpdated; } @@ -110,6 +148,7 @@ public: void setLifetime(float value) { _lifetime = value; } void setScript(QString updateScript) { _script = updateScript; } void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; } + void setProperties(const ParticleProperties& properties); bool appendParticleData(OctreePacketData* packetData) const; int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); @@ -196,6 +235,7 @@ public slots: bool getShouldDie() { return _particle->getShouldDie(); } float getAge() const { return _particle->getAge(); } float getLifetime() const { return _particle->getLifetime(); } + ParticleProperties getProperties() const { return _particle->getProperties(); } void setPosition(glm::vec3 value) { _particle->setPosition(value); } void setVelocity(glm::vec3 value) { _particle->setVelocity(value); } @@ -206,6 +246,7 @@ public slots: void setShouldDie(bool value) { _particle->setShouldDie(value); } void setScript(const QString& script) { _particle->setScript(script); } void setLifetime(float value) const { return _particle->setLifetime(value); } + void setProperties(const ParticleProperties& properties) { return _particle->setProperties(properties); } signals: void update(); @@ -216,41 +257,11 @@ private: Particle* _particle; }; +Q_DECLARE_METATYPE(ParticleProperties); -class ParticleProperties : public QObject { - Q_OBJECT -public: - ParticleProperties(); - QScriptValue copyToScriptValue(QScriptEngine* engine) const; - void copyFromScriptValue(const QScriptValue& object); - - void copyToParticle(Particle& particle) const; - void copyFromParticle(const Particle& particle); - -private: - glm::vec3 _position; - xColor _color; - float _radius; - glm::vec3 _velocity; - glm::vec3 _gravity; - float _damping; - float _lifetime; - QString _script; - bool _inHand; - bool _shouldDie; - - bool _positionChanged; - bool _colorChanged; - bool _radiusChanged; - bool _velocityChanged; - bool _gravityChanged; - bool _dampingChanged; - bool _lifetimeChanged; - bool _scriptChanged; - bool _inHandChanged; - bool _shouldDieChanged; -}; +QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties); +void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties); #endif /* defined(__hifi__Particle__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a98a8654e4..28fd07d158 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -99,6 +99,7 @@ void ScriptEngine::init() { // register meta-type for glm::vec3 conversions registerMetaTypes(&_engine); + qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); QScriptValue agentValue = _engine.newQObject(this); _engine.globalObject().setProperty("Agent", agentValue); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 9a099b4171..9d2eec6b40 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -56,3 +56,4 @@ void xColorFromScriptValue(const QScriptValue &object, xColor& color) { color.green = object.property("green").toVariant().toInt(); color.blue = object.property("blue").toVariant().toInt(); } + From a7fd1e4565c8277f737ff70ffd33e96070e69ed9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 17 Jan 2014 16:50:56 -0800 Subject: [PATCH 05/24] first cut at having particle JS api return ParticleID types --- libraries/particles/src/Particle.cpp | 23 +++++++ libraries/particles/src/Particle.h | 39 +++++++++-- .../src/ParticlesScriptingInterface.cpp | 64 ++++++++++++++++--- .../src/ParticlesScriptingInterface.h | 11 ++-- 4 files changed, 118 insertions(+), 19 deletions(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index e3c1247176..dfd170aca0 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -556,6 +556,8 @@ void Particle::runUpdateScript() { particleScriptable.emitUpdate(); + // it seems like we may need to send out particle edits if the state of our particle was changed. + if (_voxelEditSender) { _voxelEditSender->releaseQueuedMessages(); } @@ -586,6 +588,8 @@ void Particle::collisionWithParticle(Particle* other) { ParticleScriptObject otherParticleScriptable(other); particleScriptable.emitCollisionWithParticle(&otherParticleScriptable); + // it seems like we may need to send out particle edits if the state of our particle was changed. + if (_voxelEditSender) { _voxelEditSender->releaseQueuedMessages(); } @@ -619,6 +623,8 @@ void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) { VoxelDetailScriptObject voxelDetailsScriptable(voxelDetails); particleScriptable.emitCollisionWithVoxel(&voxelDetailsScriptable); + // it seems like we may need to send out particle edits if the state of our particle was changed. + if (_voxelEditSender) { _voxelEditSender->releaseQueuedMessages(); } @@ -908,3 +914,20 @@ QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const Partic void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties) { properties.copyFromScriptValue(object); } + + +QScriptValue ParticleIDtoScriptValue(QScriptEngine* engine, const ParticleID& id) { + QScriptValue obj = engine->newObject(); + obj.setProperty("id", id.id); + obj.setProperty("creatorTokenID", id.creatorTokenID); + obj.setProperty("isKnownID", id.isKnownID); + return obj; +} + +void ParticleIDFromScriptValue(const QScriptValue &object, ParticleID& id) { + id.id = object.property("id").toVariant().toUInt(); + id.creatorTokenID = object.property("creatorTokenID").toVariant().toUInt(); + id.isKnownID = object.property("isKnownID").toVariant().toBool(); +} + + diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 5eace8daff..9d006f935c 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -63,6 +63,17 @@ public: void copyToParticle(Particle& particle) const; void copyFromParticle(const Particle& particle); + const glm::vec3& getPosition() const { return _position; } + xColor getColor() const { return _color; } + float getRadius() const { return _radius; } + const glm::vec3& getVelocity() const { return _velocity; } + const glm::vec3& getGravity() const { return _gravity; } + float getDamping() const { return _damping; } + float getLifetime() const { return _lifetime; } + QString getScript() const { return _script; } + bool getInHand() const { return _inHand; } + bool getShouldDie() const { return _shouldDie; } + private: glm::vec3 _position; xColor _color; @@ -86,6 +97,29 @@ private: bool _inHandChanged; bool _shouldDieChanged; }; +Q_DECLARE_METATYPE(ParticleProperties); +QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties); +void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties); + + +/// used in Particle JS API +class ParticleID { +public: + ParticleID() : + id(NEW_PARTICLE), creatorTokenID(UNKNOWN_TOKEN), isKnownID(false) { }; + + ParticleID(uint32_t id, uint32_t creatorTokenID, bool isKnownID) : + id(id), creatorTokenID(creatorTokenID), isKnownID(isKnownID) { }; + + uint32_t id; + uint32_t creatorTokenID; + bool isKnownID; +}; + +Q_DECLARE_METATYPE(ParticleID); +QScriptValue ParticleIDToScriptValue(QScriptEngine* engine, const ParticleID& properties); +void ParticleIDFromScriptValue(const QScriptValue &object, ParticleID& properties); + class Particle { @@ -257,11 +291,6 @@ private: Particle* _particle; }; -Q_DECLARE_METATYPE(ParticleProperties); - - -QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties); -void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties); #endif /* defined(__hifi__Particle__) */ diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 553293a9a8..8b4f25a3c1 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -14,35 +14,79 @@ void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, P getParticlePacketSender()->queueParticleEditMessages(packetType, 1, &particleDetails); } -unsigned int ParticlesScriptingInterface::addParticle(glm::vec3 position, float radius, +ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { // The application will keep track of creatorTokenID uint32_t creatorTokenID = _nextCreatorTokenID; _nextCreatorTokenID++; - + // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); ParticleDetail addParticleDetail = { NEW_PARTICLE, now, - position, radius, {color.red, color.green, color.blue }, velocity, + position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, script, creatorTokenID }; - + // queue the packet queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); - - return creatorTokenID; + + ParticleID id(NEW_PARTICLE, creatorTokenID, false ); + return id; } -void ParticlesScriptingInterface::editParticle(unsigned int particleID, glm::vec3 position, float radius, +void ParticlesScriptingInterface::editParticle(ParticleID particleID, glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); - ParticleDetail editParticleDetail = { particleID, now, - position, radius, {color.red, color.green, color.blue }, velocity, + ParticleDetail editParticleDetail = { particleID.id , now, + position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, script, UNKNOWN_TOKEN }; - + // queue the packet queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail); } + +ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& properties) { + // The application will keep track of creatorTokenID + uint32_t creatorTokenID = _nextCreatorTokenID; + _nextCreatorTokenID++; + + // setup a ParticleDetail struct with the data + uint64_t now = usecTimestampNow(); + xColor color = properties.getColor(); + ParticleDetail addParticleDetail = { NEW_PARTICLE, now, + properties.getPosition(), properties.getRadius(), + {color.red, color.green, color.blue }, properties.getVelocity(), + properties.getGravity(), properties.getDamping(), properties.getLifetime(), + properties.getInHand(), properties.getScript(), + creatorTokenID }; + + // queue the packet + queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); + + ParticleID id(NEW_PARTICLE, creatorTokenID, false ); + return id; +} + +void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) { + // setup a ParticleDetail struct with the data + uint64_t now = usecTimestampNow(); + + xColor color = properties.getColor(); + ParticleDetail editParticleDetail = { particleID.id, now, + properties.getPosition(), properties.getRadius(), + {color.red, color.green, color.blue }, properties.getVelocity(), + properties.getGravity(), properties.getDamping(), properties.getLifetime(), + properties.getInHand(), properties.getScript(), + UNKNOWN_TOKEN }; + + + // queue the packet + queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail); +} + + +void ParticlesScriptingInterface::deleteParticle(ParticleID particleID) { +} diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index 0fe2de5190..c8e0d45234 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -24,14 +24,17 @@ public: virtual OctreeEditPacketSender* createPacketSender() { return new ParticleEditPacketSender(); } public slots: - /// queues the creation of a Particle which will be sent by calling process on the PacketSender - /// returns the creatorTokenID for the newly created particle - unsigned int addParticle(glm::vec3 position, float radius, + ParticleID addParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script); - void editParticle(unsigned int particleID, glm::vec3 position, float radius, + void editParticle(ParticleID particleID, glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script); + ParticleID addParticle(const ParticleProperties& properties); + + void editParticle(ParticleID particleID, const ParticleProperties& properties); + void deleteParticle(ParticleID particleID); + private: void queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails); From ab9e01ce7fd1deacdb37d8261cab20690b3def59 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 20 Jan 2014 09:11:47 -0800 Subject: [PATCH 06/24] add ParticleID class --- libraries/particles/src/Particle.cpp | 2 +- libraries/particles/src/Particle.h | 4 ++-- libraries/particles/src/ParticlesScriptingInterface.cpp | 7 +++++++ libraries/script-engine/src/ScriptEngine.cpp | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index dfd170aca0..188c506006 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -924,7 +924,7 @@ QScriptValue ParticleIDtoScriptValue(QScriptEngine* engine, const ParticleID& id return obj; } -void ParticleIDFromScriptValue(const QScriptValue &object, ParticleID& id) { +void ParticleIDfromScriptValue(const QScriptValue &object, ParticleID& id) { id.id = object.property("id").toVariant().toUInt(); id.creatorTokenID = object.property("creatorTokenID").toVariant().toUInt(); id.isKnownID = object.property("isKnownID").toVariant().toBool(); diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 9d006f935c..d7be4f29b4 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -117,8 +117,8 @@ public: }; Q_DECLARE_METATYPE(ParticleID); -QScriptValue ParticleIDToScriptValue(QScriptEngine* engine, const ParticleID& properties); -void ParticleIDFromScriptValue(const QScriptValue &object, ParticleID& properties); +QScriptValue ParticleIDtoScriptValue(QScriptEngine* engine, const ParticleID& properties); +void ParticleIDfromScriptValue(const QScriptValue &object, ParticleID& properties); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 8b4f25a3c1..7466370df8 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -71,6 +71,13 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr } void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) { + // expected behavior... + // + // if !particleID.isKnownID + // try to lookup the particle + // do nothing + + // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 28fd07d158..57b22cc3d2 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -100,6 +100,7 @@ void ScriptEngine::init() { // register meta-type for glm::vec3 conversions registerMetaTypes(&_engine); qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); + qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); QScriptValue agentValue = _engine.newQObject(this); _engine.globalObject().setProperty("Agent", agentValue); From b4b3720fcfeeefa97cd60f66f115c0872cdb4f97 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 20 Jan 2014 12:56:35 -0800 Subject: [PATCH 07/24] move creatorTokenID management into Particle static members --- interface/src/Application.cpp | 6 ++- libraries/particles/src/Particle.cpp | 44 +++++++++++++++++-- libraries/particles/src/Particle.h | 22 +++++++++- .../particles/src/ParticleEditHandle.cpp | 29 ++++++------ .../src/ParticlesScriptingInterface.cpp | 43 +++++++++++++----- 5 files changed, 110 insertions(+), 34 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3d8669eb4c..cdf917e73b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4178,8 +4178,12 @@ void Application::processDatagrams() { break; case PACKET_TYPE_PARTICLE_ADD_RESPONSE: - // look up our ParticleEditHanders.... + + // This will make sure our local ParticleEditHandle are handles correctly ParticleEditHandle::handleAddResponse(_incomingPacket, bytesReceived); + + // this will keep creatorTokenIDs to IDs mapped correctly + Particle::handleAddParticleResponse(_incomingPacket, bytesReceived); break; case PACKET_TYPE_PARTICLE_DATA: diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 188c506006..dbf6fde300 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -27,6 +27,41 @@ uint32_t Particle::_nextID = 0; VoxelEditPacketSender* Particle::_voxelEditSender = NULL; ParticleEditPacketSender* Particle::_particleEditSender = NULL; +// for locally created particles +std::map Particle::_tokenIDsToIDs; +uint32_t Particle::_nextCreatorTokenID = 0; + +uint32_t Particle::getIDfromCreatorTokenID(uint32_t creatorTokenID) { + if (_tokenIDsToIDs.find(creatorTokenID) != _tokenIDsToIDs.end()) { + return _tokenIDsToIDs[creatorTokenID]; + } + return UNKNOWN_PARTICLE_ID; +} + +uint32_t Particle::getNextCreatorTokenID() { + uint32_t creatorTokenID = _nextCreatorTokenID; + _nextCreatorTokenID++; + return creatorTokenID; +} + +void Particle::handleAddParticleResponse(unsigned char* packetData , int packetLength) { + unsigned char* dataAt = packetData; + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + dataAt += numBytesPacketHeader; + + uint32_t creatorTokenID; + memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID)); + dataAt += sizeof(creatorTokenID); + + uint32_t particleID; + memcpy(&particleID, dataAt, sizeof(particleID)); + dataAt += sizeof(particleID); + + // add our token to id mapping + _tokenIDsToIDs[creatorTokenID] = particleID; +} + + Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript, uint32_t id) { @@ -335,10 +370,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe dataAt += scriptLength; processedBytes += scriptLength; - const bool wantDebugging = false; + const bool wantDebugging = true; if (wantDebugging) { - printf("Particle::fromEditPacket()...\n"); - printf(" Particle id in packet:%u\n", editID); + qDebug("Particle::fromEditPacket()..."); + qDebug(" Particle id in packet:%u", editID); + //qDebug() << " position: " << newParticle._position; newParticle.debugDump(); } @@ -660,7 +696,7 @@ void Particle::setProperties(const ParticleProperties& properties) { ParticleProperties::ParticleProperties() : _position(0), _color(), - _radius(0), + _radius(DEFAULT_RADIUS), _velocity(0), _gravity(DEFAULT_GRAVITY), _damping(DEFAULT_DAMPING), diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index d7be4f29b4..e52cfd90a5 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -28,6 +28,7 @@ class Particle; const uint32_t NEW_PARTICLE = 0xFFFFFFFF; const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; +const uint32_t UNKNOWN_PARTICLE_ID = 0xFFFFFFFF; class ParticleDetail { public: @@ -47,12 +48,15 @@ public: const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default const float DEFAULT_DAMPING = 0.99f; +const float DEFAULT_RADIUS = 0.1f / TREE_SCALE; // really shouldn't be a default? const glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0); const QString DEFAULT_SCRIPT(""); const bool IN_HAND = true; // it's in a hand const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand -/// Used in scripting to set/get the complete set of particle properties via JavaScript hashes/QScriptValues +/// A collection of properties of a particle used in the scripting API. Translates between the actual properties of a particle +/// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of +/// particle properties via JavaScript hashes/QScriptValues class ParticleProperties { public: ParticleProperties(); @@ -102,7 +106,9 @@ QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const Partic void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties); -/// used in Particle JS API +/// Abstract ID for editing particles. Used in Particle JS API - When particles are created in the JS api, they are given a +/// local creatorTokenID, the actual id for the particle is not known until the server responds to the creator with the +/// correct mapping. This class works with the scripting API an allows the developer to edit particles they created. class ParticleID { public: ParticleID() : @@ -122,6 +128,7 @@ void ParticleIDfromScriptValue(const QScriptValue &object, ParticleID& propertie +/// Particle class - this is the actual particle class. class Particle { public: @@ -213,6 +220,11 @@ public: { _particleEditSender = senderInterface; } + // these methods allow you to create particles, and later edit them. + static uint32_t getIDfromCreatorTokenID(uint32_t creatorTokenID); + static uint32_t getNextCreatorTokenID(); + static void handleAddParticleResponse(unsigned char* packetData , int packetLength); + protected: static VoxelEditPacketSender* _voxelEditSender; static ParticleEditPacketSender* _particleEditSender; @@ -247,8 +259,14 @@ protected: // this doesn't go on the wire, we send it as lifetime uint64_t _created; + + // used by the static interfaces for creator token ids + static uint32_t _nextCreatorTokenID; + static std::map _tokenIDsToIDs; }; +/// Scriptable interface to a single Particle object. Used exclusively in the JavaScript API for interacting with single +/// Particles. class ParticleScriptObject : public QObject { Q_OBJECT public: diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index d3a8dd56be..80dcff7e85 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -17,20 +17,19 @@ uint32_t ParticleEditHandle::_nextCreatorTokenID = 0; ParticleEditHandle::ParticleEditHandle(ParticleEditPacketSender* packetSender, ParticleTree* localTree, uint32_t id) { if (id == NEW_PARTICLE) { - _creatorTokenID = _nextCreatorTokenID; - _nextCreatorTokenID++; + _creatorTokenID = Particle::getNextCreatorTokenID(); _id = NEW_PARTICLE; _isKnownID = false; _allHandles[_creatorTokenID] = this; } else { - _creatorTokenID = UNKNOWN_TOKEN; + _creatorTokenID = UNKNOWN_TOKEN; _id = id; _isKnownID = true; // don't add to _allHandles because we already know it... } _packetSender = packetSender; _localTree = localTree; - + } ParticleEditHandle::~ParticleEditHandle() { @@ -40,21 +39,21 @@ ParticleEditHandle::~ParticleEditHandle() { } } -void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, +void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); ParticleDetail addParticleDetail = { NEW_PARTICLE, now, - position, radius, {color.red, color.green, color.blue }, + position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, updateScript, _creatorTokenID }; - + // queue the packet _packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &addParticleDetail); - + // release them _packetSender->releaseQueuedMessages(); - + // if we have a local tree, also update it... if (_localTree) { // we can't really do this here, because if we create a particle locally, we'll get a ghost particle @@ -62,22 +61,22 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor } } -bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, +bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { if (!isKnownID()) { return false; // not allowed until we know the id } - + // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); ParticleDetail newParticleDetail = { _id, now, - position, radius, {color.red, color.green, color.blue }, + position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, updateScript, _creatorTokenID }; // queue the packet _packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &newParticleDetail); - + // release them _packetSender->releaseQueuedMessages(); @@ -87,7 +86,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor Particle tempParticle(position, radius, rcolor, velocity, gravity, damping, lifetime, inHand, updateScript, _id); _localTree->storeParticle(tempParticle); } - + return true; } @@ -95,7 +94,7 @@ void ParticleEditHandle::handleAddResponse(unsigned char* packetData , int packe unsigned char* dataAt = packetData; int numBytesPacketHeader = numBytesForPacketHeader(packetData); dataAt += numBytesPacketHeader; - + uint32_t creatorTokenID; memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID)); dataAt += sizeof(creatorTokenID); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 7466370df8..7828a9d4a7 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -18,8 +18,7 @@ ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float ra xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { // The application will keep track of creatorTokenID - uint32_t creatorTokenID = _nextCreatorTokenID; - _nextCreatorTokenID++; + uint32_t creatorTokenID = Particle::getNextCreatorTokenID(); // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); @@ -30,7 +29,7 @@ ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float ra // queue the packet queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); - ParticleID id(NEW_PARTICLE, creatorTokenID, false ); + ParticleID id(NEW_PARTICLE, creatorTokenID, false); return id; } @@ -38,9 +37,21 @@ ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float ra void ParticlesScriptingInterface::editParticle(ParticleID particleID, glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { + uint32_t actualID = particleID.id; // may not be valid... will check below.. + + // if we don't know the actual id, look it up + if (!particleID.isKnownID) { + actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); + + // if we couldn't fine it, then bail without changing anything... + if (actualID == UNKNOWN_PARTICLE_ID) { + return; // no changes... + } + } + // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); - ParticleDetail editParticleDetail = { particleID.id , now, + ParticleDetail editParticleDetail = { actualID , now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, script, UNKNOWN_TOKEN }; @@ -49,9 +60,9 @@ void ParticlesScriptingInterface::editParticle(ParticleID particleID, glm::vec3 } ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& properties) { + // The application will keep track of creatorTokenID - uint32_t creatorTokenID = _nextCreatorTokenID; - _nextCreatorTokenID++; + uint32_t creatorTokenID = Particle::getNextCreatorTokenID(); // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); @@ -71,18 +82,26 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr } void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) { - // expected behavior... - // - // if !particleID.isKnownID - // try to lookup the particle - // do nothing + uint32_t actualID = particleID.id; // may not be valid... will check below.. + + // if we don't know the actual id, look it up + if (!particleID.isKnownID) { + actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); + + qDebug() << "ParticlesScriptingInterface::editParticle()... actualID: " << actualID; + + // if we couldn't fine it, then bail without changing anything... + if (actualID == UNKNOWN_PARTICLE_ID) { + return; // no changes... + } + } // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); xColor color = properties.getColor(); - ParticleDetail editParticleDetail = { particleID.id, now, + ParticleDetail editParticleDetail = { actualID, now, properties.getPosition(), properties.getRadius(), {color.red, color.green, color.blue }, properties.getVelocity(), properties.getGravity(), properties.getDamping(), properties.getLifetime(), From d831f9df5e48a097d6f70e5f4853935437ad4c05 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 20 Jan 2014 16:34:45 -0800 Subject: [PATCH 08/24] first cut at using partial property info in particle edits --- .../octree/src/OctreeEditPacketSender.cpp | 78 ++-- libraries/particles/src/Particle.cpp | 391 +++++++++++++----- libraries/particles/src/Particle.h | 35 +- .../particles/src/ParticleEditHandle.cpp | 8 +- libraries/particles/src/ParticleEditHandle.h | 1 - .../src/ParticleEditPacketSender.cpp | 35 +- .../particles/src/ParticleEditPacketSender.h | 12 +- libraries/particles/src/ParticleTree.cpp | 58 ++- libraries/particles/src/ParticleTree.h | 16 +- .../src/ParticlesScriptingInterface.cpp | 89 +--- .../src/ParticlesScriptingInterface.h | 9 +- 11 files changed, 439 insertions(+), 293 deletions(-) diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index ff6a1ded61..7ce7701a7d 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -21,14 +21,14 @@ EditPacketBuffer::EditPacketBuffer(PACKET_TYPE type, unsigned char* buffer, ssiz _nodeUUID = nodeUUID; _currentType = type; _currentSize = length; - memcpy(_currentBuffer, buffer, length); + memcpy(_currentBuffer, buffer, length); }; -const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::DEFAULT_PACKETS_PER_SECOND; +const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::DEFAULT_PACKETS_PER_SECOND; -OctreeEditPacketSender::OctreeEditPacketSender(PacketSenderNotify* notify) : - PacketSender(notify), +OctreeEditPacketSender::OctreeEditPacketSender(PacketSenderNotify* notify) : + PacketSender(notify), _shouldSend(true), _maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES), _releaseQueuedMessagesPending(false), @@ -57,7 +57,7 @@ bool OctreeEditPacketSender::serversExist() const { bool hasServers = false; bool atLeastOnJurisdictionMissing = false; // assume the best NodeList* nodeList = NodeList::getInstance(); - + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getType() == getMyNodeType()) { @@ -78,15 +78,15 @@ bool OctreeEditPacketSender::serversExist() const { break; // no point in looking further... } } - + return (hasServers && !atLeastOnJurisdictionMissing); } // This method is called when the edit packet layer has determined that it has a fully formed packet destined for -// a known nodeID. +// a known nodeID. void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) { NodeList* nodeList = NodeList::getInstance(); - + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getType() == getMyNodeType() && @@ -94,7 +94,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c if (nodeList->getNodeActiveSocketOrPing(node.data())) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); queuePacketForSending(*nodeAddress, buffer, length); - + // debugging output... bool wantDebugging = false; if (wantDebugging) { @@ -103,10 +103,10 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c uint64_t createdAt = (*((uint64_t*)(buffer + numBytesPacketHeader + sizeof(sequence)))); uint64_t queuedAt = usecTimestampNow(); uint64_t transitTime = queuedAt - createdAt; - - qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << - " - command to node bytes=" << length << - " sequence=" << sequence << + + qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << + " - command to node bytes=" << length << + " sequence=" << sequence << " transitTimeSoFar=" << transitTime << " usecs"; } } @@ -116,7 +116,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c void OctreeEditPacketSender::processPreServerExistsPackets() { assert(serversExist()); // we should only be here if we have jurisdictions - + // First send out all the single message packets... while (!_preServerSingleMessagePackets.empty()) { EditPacketBuffer* packet = _preServerSingleMessagePackets.front(); @@ -133,7 +133,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { _preServerPackets.erase(_preServerPackets.begin()); } - // if while waiting for the jurisdictions the caller called releaseQueuedMessages() + // if while waiting for the jurisdictions the caller called releaseQueuedMessages() // then we want to honor that request now. if (_releaseQueuedMessagesPending) { releaseQueuedMessages(); @@ -160,17 +160,17 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l if (!_shouldSend) { return; // bail early } - + assert(serversExist()); // we must have jurisdictions to be here!! int headerBytes = numBytesForPacketHeader(buffer) + sizeof(short) + sizeof(uint64_t); unsigned char* octCode = buffer + headerBytes; // skip the packet header to get to the octcode - + // We want to filter out edit messages for servers based on the server's Jurisdiction - // But we can't really do that with a packed message, since each edit message could be destined + // But we can't really do that with a packed message, since each edit message could be destined // for a different server... So we need to actually manage multiple queued packets... one // for each server - + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) { @@ -181,7 +181,12 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); if (isMyJurisdiction) { + +qDebug() << "calling queuePacketToNode(nodeUUID, buffer, length); nodeUUID=" << nodeUUID << " length=" << length; + queuePacketToNode(nodeUUID, buffer, length); + } else { +qDebug() << "not my jurisdiction skipping queuePacketToNode(nodeUUID, buffer, length); nodeUUID=" << nodeUUID << " length=" << length; } } } @@ -190,10 +195,14 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l // NOTE: codeColorBuffer - is JUST the octcode/color and does not contain the packet header! void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length) { + +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; if (!_shouldSend) { return; // bail early } - + +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + // If we don't have jurisdictions, then we will simply queue up all of these packets and wait till we have // jurisdictions for processing if (!serversExist()) { @@ -211,52 +220,61 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c } return; // bail early } - + +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + // We want to filter out edit messages for servers based on the server's Jurisdiction - // But we can't really do that with a packed message, since each edit message could be destined + // But we can't really do that with a packed message, since each edit message could be destined // for a different server... So we need to actually manage multiple queued packets... one // for each server - + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) { QUuid nodeUUID = node->getUUID(); bool isMyJurisdiction = true; - + if (_serverJurisdictions) { // we need to get the jurisdiction for this // here we need to get the "pending packet" for this server if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); +qDebug() << "queueOctreeEditMessage() line:" << __LINE__ << " isMyJurisdiction=" << isMyJurisdiction; } else { isMyJurisdiction = false; +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; } } if (isMyJurisdiction) { EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID]; packetBuffer._nodeUUID = nodeUUID; - + +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + // If we're switching type, then we send the last one and start over if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || (packetBuffer._currentSize + length >= _maxPacketSize)) { releaseQueuedPacket(packetBuffer); initializePacket(packetBuffer, type); } - + // If the buffer is empty and not correctly initialized for our type... if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) { initializePacket(packetBuffer, type); } - + // This is really the first time we know which server/node this particular edit message // is going to, so we couldn't adjust for clock skew till now. But here's our chance. // We call this virtual function that allows our specific type of EditPacketSender to // fixup the buffer for any clock skew if (node->getClockSkewUsec() != 0) { adjustEditPacketForClockSkew(codeColorBuffer, length, node->getClockSkewUsec()); +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; } - + +qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length); packetBuffer._currentSize += length; } @@ -265,7 +283,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c } void OctreeEditPacketSender::releaseQueuedMessages() { - // if we don't yet have jurisdictions then we can't actually release messages yet because we don't + // if we don't yet have jurisdictions then we can't actually release messages yet because we don't // know where to send them to. Instead, just remember this request and when we eventually get jurisdictions // call release again at that time. if (!serversExist()) { @@ -273,12 +291,14 @@ void OctreeEditPacketSender::releaseQueuedMessages() { } else { for (std::map::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) { releaseQueuedPacket(i->second); +qDebug() << "releaseQueuedMessages() line:" << __LINE__; } } } void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) { if (packetBuffer._currentSize > 0 && packetBuffer._currentType != PACKET_TYPE_UNKNOWN) { +qDebug() << "OctreeEditPacketSender::releaseQueuedPacket() line:" << __LINE__; queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize); } packetBuffer._currentSize = 0; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index dbf6fde300..85f2380a8e 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -22,6 +22,7 @@ #include "ParticlesScriptingInterface.h" #include "Particle.h" +#include "ParticleTree.h" uint32_t Particle::_nextID = 0; VoxelEditPacketSender* Particle::_voxelEditSender = NULL; @@ -57,6 +58,8 @@ void Particle::handleAddParticleResponse(unsigned char* packetData , int packetL memcpy(&particleID, dataAt, sizeof(particleID)); dataAt += sizeof(particleID); +qDebug() << "handleAddParticleResponse()... particleID=" << particleID << " creatorTokenID=" << creatorTokenID; + // add our token to id mapping _tokenIDsToIDs[creatorTokenID] = particleID; } @@ -278,7 +281,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef } -Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) { +Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree) { Particle newParticle; // id and _lastUpdated will get set here... unsigned char* dataAt = data; processedBytes = 0; @@ -309,10 +312,30 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe newParticle._newlyCreated = true; newParticle.setAge(0); // this guy is new! +qDebug() << "fromEditPacket() NEW_PARTICLE"; } else { + qDebug() << "fromEditPacket() existingParticle id=" << editID; + + // look up the existing particle + + qDebug() << "fromEditPacket() existingParticle id=" << editID << "calling tree->findParticleByID(editID)"; + const Particle* existingParticle = tree->findParticleByID(editID, true); + qDebug() << "fromEditPacket() existingParticle id=" << editID << "DONE tree->findParticleByID(editID)"; + + // copy existing properties before over-writing with new properties + if (existingParticle) { + newParticle = *existingParticle; + qDebug() << "found it..."; + existingParticle->debugDump(); + } else { + qDebug() << "WHOA! Didn't find it..."; + } + newParticle._id = editID; newParticle._newlyCreated = false; + + } // lastEdited @@ -320,55 +343,92 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe dataAt += sizeof(newParticle._lastEdited); processedBytes += sizeof(newParticle._lastEdited); + // All of the remaining items are optional, and may or may not be included based on their included values in the + // properties included bits + uint16_t packetContainsBits = 0; + memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits)); + dataAt += sizeof(packetContainsBits); + processedBytes += sizeof(packetContainsBits); + +qDebug() << "fromEditPacket() packetContainsBits=" << packetContainsBits; + // radius - memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); - dataAt += sizeof(newParticle._radius); - processedBytes += sizeof(newParticle._radius); + if ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_RADIUS"; + + memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); + dataAt += sizeof(newParticle._radius); + processedBytes += sizeof(newParticle._radius); + } // position - memcpy(&newParticle._position, dataAt, sizeof(newParticle._position)); - dataAt += sizeof(newParticle._position); - processedBytes += sizeof(newParticle._position); + if ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_POSITION"; + memcpy(&newParticle._position, dataAt, sizeof(newParticle._position)); + dataAt += sizeof(newParticle._position); + processedBytes += sizeof(newParticle._position); + } // color - memcpy(newParticle._color, dataAt, sizeof(newParticle._color)); - dataAt += sizeof(newParticle._color); - processedBytes += sizeof(newParticle._color); + if ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_COLOR"; + memcpy(newParticle._color, dataAt, sizeof(newParticle._color)); + dataAt += sizeof(newParticle._color); + processedBytes += sizeof(newParticle._color); + } // velocity - memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity)); - dataAt += sizeof(newParticle._velocity); - processedBytes += sizeof(newParticle._velocity); + if ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_VELOCITY"; + memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity)); + dataAt += sizeof(newParticle._velocity); + processedBytes += sizeof(newParticle._velocity); + } // gravity - memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity)); - dataAt += sizeof(newParticle._gravity); - processedBytes += sizeof(newParticle._gravity); + if ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_GRAVITY"; + memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity)); + dataAt += sizeof(newParticle._gravity); + processedBytes += sizeof(newParticle._gravity); + } // damping - memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping)); - dataAt += sizeof(newParticle._damping); - processedBytes += sizeof(newParticle._damping); + if ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_DAMPING"; + memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping)); + dataAt += sizeof(newParticle._damping); + processedBytes += sizeof(newParticle._damping); + } // lifetime - memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime)); - dataAt += sizeof(newParticle._lifetime); - processedBytes += sizeof(newParticle._lifetime); + if ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_LIFETIME"; + memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime)); + dataAt += sizeof(newParticle._lifetime); + processedBytes += sizeof(newParticle._lifetime); + } // inHand - memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand)); - dataAt += sizeof(newParticle._inHand); - processedBytes += sizeof(newParticle._inHand); + if ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_INHAND"; + memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand)); + dataAt += sizeof(newParticle._inHand); + processedBytes += sizeof(newParticle._inHand); + } // script - uint16_t scriptLength; - memcpy(&scriptLength, dataAt, sizeof(scriptLength)); - dataAt += sizeof(scriptLength); - processedBytes += sizeof(scriptLength); - QString tempString((const char*)dataAt); - newParticle._script = tempString; - dataAt += scriptLength; - processedBytes += scriptLength; + if ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT) { +qDebug() << "fromEditPacket() PACKET_CONTAINS_SCRIPT"; + uint16_t scriptLength; + memcpy(&scriptLength, dataAt, sizeof(scriptLength)); + dataAt += sizeof(scriptLength); + processedBytes += sizeof(scriptLength); + QString tempString((const char*)dataAt); + newParticle._script = tempString; + dataAt += scriptLength; + processedBytes += scriptLength; + } const bool wantDebugging = true; if (wantDebugging) { @@ -386,116 +446,168 @@ void Particle::debugDump() const { printf(" age:%f\n", getAge()); printf(" edited ago:%f\n", getEditedAgo()); printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z); + printf(" radius:%f\n", getRadius()); printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z); printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z); printf(" color:%d,%d,%d\n", _color[0], _color[1], _color[2]); } -bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, +bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID id, const ParticleProperties& properties, unsigned char* bufferOut, int sizeIn, int& sizeOut) { bool success = true; // assume the best unsigned char* copyAt = bufferOut; sizeOut = 0; - for (int i = 0; i < count && success; i++) { - // get the octal code for the particle - unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y, - details[i].position.z, details[i].radius); + // get the octal code for the particle - int octets = numberOfThreeBitSectionsInCode(octcode); - int lengthOfOctcode = bytesRequiredForCodeLength(octets); - int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes(); + // this could be a problem if the caller doesn't include position.... + glm::vec3 rootPosition(0); + float rootScale = 0.5f; + unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale); - // make sure we have room to copy this particle - if (sizeOut + lenfthOfEditData > sizeIn) { - success = false; - } else { - // add it to our message - memcpy(copyAt, octcode, lengthOfOctcode); - copyAt += lengthOfOctcode; - sizeOut += lengthOfOctcode; + // old code... this matters for particle servers with different jurisdictions, but for now, we'll send + // everything to the root, since the tree does the right thing... + // + //unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y, + // details[i].position.z, details[i].radius); - // Now add our edit content details... + int octets = numberOfThreeBitSectionsInCode(octcode); + int lengthOfOctcode = bytesRequiredForCodeLength(octets); + int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes(); - // id - memcpy(copyAt, &details[i].id, sizeof(details[i].id)); - copyAt += sizeof(details[i].id); - sizeOut += sizeof(details[i].id); - // special case for handling "new" particles - if (details[i].id == NEW_PARTICLE) { - // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that - // we want to send back to the creator as an map to the actual id - memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID)); - copyAt += sizeof(details[i].creatorTokenID); - sizeOut += sizeof(details[i].creatorTokenID); - } + // make sure we have room to copy this particle + if (sizeOut + lenfthOfEditData > sizeIn) { + success = false; + } else { + // add it to our message + memcpy(copyAt, octcode, lengthOfOctcode); + copyAt += lengthOfOctcode; + sizeOut += lengthOfOctcode; - // lastEdited - memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited)); - copyAt += sizeof(details[i].lastEdited); - sizeOut += sizeof(details[i].lastEdited); + // Now add our edit content details... - // radius - memcpy(copyAt, &details[i].radius, sizeof(details[i].radius)); - copyAt += sizeof(details[i].radius); - sizeOut += sizeof(details[i].radius); + // id + memcpy(copyAt, &id.id, sizeof(id.id)); + copyAt += sizeof(id.id); + sizeOut += sizeof(id.id); + // special case for handling "new" particles + if (id.id == NEW_PARTICLE) { + // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that + // we want to send back to the creator as an map to the actual id + memcpy(copyAt, &id.creatorTokenID, sizeof(id.creatorTokenID)); + copyAt += sizeof(id.creatorTokenID); + sizeOut += sizeof(id.creatorTokenID); + } - // position - memcpy(copyAt, &details[i].position, sizeof(details[i].position)); - copyAt += sizeof(details[i].position); - sizeOut += sizeof(details[i].position); + // lastEdited + uint64_t lastEdited = properties.getLastEdited(); + memcpy(copyAt, &lastEdited, sizeof(lastEdited)); + copyAt += sizeof(lastEdited); + sizeOut += sizeof(lastEdited); - // color - memcpy(copyAt, details[i].color, sizeof(details[i].color)); - copyAt += sizeof(details[i].color); - sizeOut += sizeof(details[i].color); + // All of the remaining items are optional, and may or may not be included based on their included values in the + // properties included bits + uint16_t packetContainsBits = properties.getChangedBits(); + memcpy(copyAt, &packetContainsBits, sizeof(packetContainsBits)); + copyAt += sizeof(packetContainsBits); + sizeOut += sizeof(packetContainsBits); - // velocity - memcpy(copyAt, &details[i].velocity, sizeof(details[i].velocity)); - copyAt += sizeof(details[i].velocity); - sizeOut += sizeof(details[i].velocity); +qDebug() << " packetContainsBits = " << packetContainsBits; - // gravity - memcpy(copyAt, &details[i].gravity, sizeof(details[i].gravity)); - copyAt += sizeof(details[i].gravity); - sizeOut += sizeof(details[i].gravity); + // radius + if ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_RADIUS\n"); + float radius = properties.getRadius(); + memcpy(copyAt, &radius, sizeof(radius)); + copyAt += sizeof(radius); + sizeOut += sizeof(radius); + } - // damping - memcpy(copyAt, &details[i].damping, sizeof(details[i].damping)); - copyAt += sizeof(details[i].damping); - sizeOut += sizeof(details[i].damping); + // position + if ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_POSITION\n"); + memcpy(copyAt, &properties.getPosition(), sizeof(properties.getPosition())); + copyAt += sizeof(properties.getPosition()); + sizeOut += sizeof(properties.getPosition()); + } - // damping - memcpy(copyAt, &details[i].lifetime, sizeof(details[i].lifetime)); - copyAt += sizeof(details[i].lifetime); - sizeOut += sizeof(details[i].lifetime); + // color + if ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_COLOR\n"); + rgbColor color = { properties.getColor().red, properties.getColor().green, properties.getColor().blue }; + memcpy(copyAt, color, sizeof(color)); + copyAt += sizeof(color); + sizeOut += sizeof(color); + } - // inHand - memcpy(copyAt, &details[i].inHand, sizeof(details[i].inHand)); - copyAt += sizeof(details[i].inHand); - sizeOut += sizeof(details[i].inHand); + // velocity + if ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_VELOCITY\n"); + memcpy(copyAt, &properties.getVelocity(), sizeof(properties.getVelocity())); + copyAt += sizeof(properties.getVelocity()); + sizeOut += sizeof(properties.getVelocity()); + } - // script - uint16_t scriptLength = details[i].updateScript.size() + 1; + // gravity + if ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_GRAVITY\n"); + memcpy(copyAt, &properties.getGravity(), sizeof(properties.getGravity())); + copyAt += sizeof(properties.getGravity()); + sizeOut += sizeof(properties.getGravity()); + } + + // damping + if ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_DAMPING\n"); + float damping = properties.getDamping(); + memcpy(copyAt, &damping, sizeof(damping)); + copyAt += sizeof(damping); + sizeOut += sizeof(damping); + } + + // lifetime + if ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_LIFETIME\n"); + float lifetime = properties.getLifetime(); + memcpy(copyAt, &lifetime, sizeof(lifetime)); + copyAt += sizeof(lifetime); + sizeOut += sizeof(lifetime); + } + + // inHand + if ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) { + printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_INHAND\n"); + bool inHand = properties.getInHand(); + memcpy(copyAt, &inHand, sizeof(inHand)); + copyAt += sizeof(inHand); + sizeOut += sizeof(inHand); + } + + // script + if ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT) { + printf("encodeParticleEditMessageDetails() including SCRIPT\n"); + + uint16_t scriptLength = properties.getScript().size() + 1; memcpy(copyAt, &scriptLength, sizeof(scriptLength)); copyAt += sizeof(scriptLength); sizeOut += sizeof(scriptLength); - memcpy(copyAt, qPrintable(details[i].updateScript), scriptLength); + memcpy(copyAt, qPrintable(properties.getScript()), scriptLength); copyAt += scriptLength; sizeOut += scriptLength; - - bool wantDebugging = false; - if (wantDebugging) { - printf("encodeParticleEditMessageDetails()....\n"); - printf("Particle id :%u\n", details[i].id); - printf(" nextID:%u\n", _nextID); - } } - // cleanup - delete[] octcode; + + bool wantDebugging = false; + if (wantDebugging) { + printf("encodeParticleEditMessageDetails()....\n"); + printf("Particle id :%u\n", id.id); + printf(" nextID:%u\n", _nextID); + } } + // cleanup + delete[] octcode; + return success; } @@ -696,7 +808,7 @@ void Particle::setProperties(const ParticleProperties& properties) { ParticleProperties::ParticleProperties() : _position(0), _color(), - _radius(DEFAULT_RADIUS), + _radius(0), _velocity(0), _gravity(DEFAULT_GRAVITY), _damping(DEFAULT_DAMPING), @@ -705,6 +817,7 @@ ParticleProperties::ParticleProperties() : _inHand(false), _shouldDie(false), + _lastEdited(usecTimestampNow()), _positionChanged(false), _colorChanged(false), _radiusChanged(false), @@ -718,6 +831,55 @@ ParticleProperties::ParticleProperties() : { } + +uint16_t ParticleProperties::getChangedBits() const { + uint16_t changedBits = 0; + if (_radiusChanged) { + changedBits += PACKET_CONTAINS_RADIUS; + } + + if (_positionChanged) { + changedBits += PACKET_CONTAINS_POSITION; + } + + if (_colorChanged) { + changedBits += PACKET_CONTAINS_COLOR; + } + + if (_velocityChanged) { + changedBits += PACKET_CONTAINS_VELOCITY; + } + + if (_gravityChanged) { + changedBits += PACKET_CONTAINS_GRAVITY; + } + + if (_dampingChanged) { + changedBits += PACKET_CONTAINS_DAMPING; + } + + if (_lifetimeChanged) { + changedBits += PACKET_CONTAINS_LIFETIME; + } + + if (_inHandChanged) { + changedBits += PACKET_CONTAINS_INHAND; + } + + if (_scriptChanged) { + changedBits += PACKET_CONTAINS_SCRIPT; + } + + // how do we want to handle this? + + //if (_shouldDieChanged) { + // changedBits += PACKET_CONTAINS_SHOULDDIE; + //} + + return changedBits; +} + + QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const { QScriptValue properties = engine->newObject(); @@ -783,13 +945,18 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { } QScriptValue radius = object.property("radius"); +qDebug() << "copyFromScriptValue() line:" << __LINE__; if (radius.isValid()) { +qDebug() << "copyFromScriptValue() line:" << __LINE__; float newRadius; newRadius = radius.toVariant().toFloat(); +qDebug() << "copyFromScriptValue() line:" << __LINE__ << " newRadius=" << newRadius; +qDebug() << "copyFromScriptValue() line:" << __LINE__ << " _radius=" << _radius; if (newRadius != _radius) { _radius = newRadius; _radiusChanged = true; } +qDebug() << "copyFromScriptValue() line:" << __LINE__ << " _radiusChanged=" << _radiusChanged; } QScriptValue velocity = object.property("velocity"); @@ -875,6 +1042,8 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { _shouldDieChanged = true; } } + + _lastEdited = usecTimestampNow(); } void ParticleProperties::copyToParticle(Particle& particle) const { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index e52cfd90a5..e4072e1e46 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -25,26 +25,21 @@ class VoxelEditPacketSender; class ParticleEditPacketSender; class ParticleProperties; class Particle; +class ParticleTree; const uint32_t NEW_PARTICLE = 0xFFFFFFFF; const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; const uint32_t UNKNOWN_PARTICLE_ID = 0xFFFFFFFF; -class ParticleDetail { -public: - uint32_t id; - uint64_t lastEdited; - glm::vec3 position; - float radius; - rgbColor color; - glm::vec3 velocity; - glm::vec3 gravity; - float damping; - float lifetime; - bool inHand; - QString updateScript; - uint32_t creatorTokenID; -}; +const uint16_t PACKET_CONTAINS_RADIUS = 1; +const uint16_t PACKET_CONTAINS_POSITION = 2; +const uint16_t PACKET_CONTAINS_COLOR = 4; +const uint16_t PACKET_CONTAINS_VELOCITY = 8; +const uint16_t PACKET_CONTAINS_GRAVITY = 16; +const uint16_t PACKET_CONTAINS_DAMPING = 32; +const uint16_t PACKET_CONTAINS_LIFETIME = 64; +const uint16_t PACKET_CONTAINS_INHAND = 128; +const uint16_t PACKET_CONTAINS_SCRIPT = 256; const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default const float DEFAULT_DAMPING = 0.99f; @@ -74,10 +69,13 @@ public: const glm::vec3& getGravity() const { return _gravity; } float getDamping() const { return _damping; } float getLifetime() const { return _lifetime; } - QString getScript() const { return _script; } + const QString& getScript() const { return _script; } bool getInHand() const { return _inHand; } bool getShouldDie() const { return _shouldDie; } + uint64_t getLastEdited() const { return _lastEdited; } + uint16_t getChangedBits() const; + private: glm::vec3 _position; xColor _color; @@ -90,6 +88,7 @@ private: bool _inHand; bool _shouldDie; + uint64_t _lastEdited; bool _positionChanged; bool _colorChanged; bool _radiusChanged; @@ -138,7 +137,7 @@ public: bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); /// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer - static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes); + static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree); virtual ~Particle(); virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, @@ -196,7 +195,7 @@ public: static int expectedBytes(); static int expectedEditMessageBytes(); - static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, + static bool encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID id, const ParticleProperties& details, unsigned char* bufferOut, int sizeIn, int& sizeOut); static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index 80dcff7e85..30ff71951d 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -13,7 +13,6 @@ #include "ParticleTree.h" std::map ParticleEditHandle::_allHandles; -uint32_t ParticleEditHandle::_nextCreatorTokenID = 0; ParticleEditHandle::ParticleEditHandle(ParticleEditPacketSender* packetSender, ParticleTree* localTree, uint32_t id) { if (id == NEW_PARTICLE) { @@ -43,13 +42,14 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { // setup a ParticleDetail struct with the data +/**** uint64_t now = usecTimestampNow(); ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, updateScript, _creatorTokenID }; // queue the packet - _packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &addParticleDetail); + _packetSender->queueParticleEditMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &addParticleDetail); // release them _packetSender->releaseQueuedMessages(); @@ -59,6 +59,8 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor // we can't really do this here, because if we create a particle locally, we'll get a ghost particle // because we can't really handle updating/deleting it locally } +****/ + } bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, @@ -69,6 +71,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor } // setup a ParticleDetail struct with the data +/**** uint64_t now = usecTimestampNow(); ParticleDetail newParticleDetail = { _id, now, position, radius, {color.red, color.green, color.blue }, @@ -86,6 +89,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor Particle tempParticle(position, radius, rcolor, velocity, gravity, damping, lifetime, inHand, updateScript, _id); _localTree->storeParticle(tempParticle); } +***/ return true; } diff --git a/libraries/particles/src/ParticleEditHandle.h b/libraries/particles/src/ParticleEditHandle.h index f0a9191f35..5343b29343 100644 --- a/libraries/particles/src/ParticleEditHandle.h +++ b/libraries/particles/src/ParticleEditHandle.h @@ -45,7 +45,6 @@ private: uint32_t _creatorTokenID; uint32_t _id; bool _isKnownID; - static uint32_t _nextCreatorTokenID; static std::map _allHandles; ParticleEditPacketSender* _packetSender; ParticleTree* _localTree; diff --git a/libraries/particles/src/ParticleEditPacketSender.cpp b/libraries/particles/src/ParticleEditPacketSender.cpp index bd56728176..65734f97a5 100644 --- a/libraries/particles/src/ParticleEditPacketSender.cpp +++ b/libraries/particles/src/ParticleEditPacketSender.cpp @@ -16,7 +16,7 @@ #include "Particle.h" -void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, const ParticleDetail& detail) { +void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties) { // allows app to disable sending if for example voxels have been disabled if (!_shouldSend) { return; // bail early @@ -26,35 +26,42 @@ void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, const P int sizeOut = 0; // This encodes the voxel edit message into a buffer... - if (Particle::encodeParticleEditMessageDetails(type, 1, &detail, &bufferOut[0], _maxPacketSize, sizeOut)){ + if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)){ // If we don't have voxel jurisdictions, then we will simply queue up these packets and wait till we have // jurisdictions for processing if (!serversExist()) { queuePendingPacketToNodes(type, bufferOut, sizeOut); } else { + +qDebug("calling queuePacketToNodes(bufferOut, sizeOut=%d)... ", sizeOut); + queuePacketToNodes(bufferOut, sizeOut); } } } -void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { +void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew); -} +} -void ParticleEditPacketSender::queueParticleEditMessages(PACKET_TYPE type, int numberOfDetails, ParticleDetail* details) { +void ParticleEditPacketSender::queueParticleEditMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties) { + +qDebug() << "ParticleEditPacketSender::queueParticleEditMessage() id.id=" << particleID.id << " id.creatorTokenID=" << particleID.creatorTokenID; + if (!_shouldSend) { return; // bail early } - for (int i = 0; i < numberOfDetails; i++) { - // use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize - static unsigned char bufferOut[MAX_PACKET_SIZE]; - int sizeOut = 0; - - if (Particle::encodeParticleEditMessageDetails(type, 1, &details[i], &bufferOut[0], _maxPacketSize, sizeOut)) { - queueOctreeEditMessage(type, bufferOut, sizeOut); - } - } + // use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize + static unsigned char bufferOut[MAX_PACKET_SIZE]; + int sizeOut = 0; + + if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) { + +qDebug("calling queueOctreeEditMessage(bufferOut, sizeOut=%d)... ", sizeOut); + + queueOctreeEditMessage(type, bufferOut, sizeOut); + } } diff --git a/libraries/particles/src/ParticleEditPacketSender.h b/libraries/particles/src/ParticleEditPacketSender.h index 2295ee22b2..c45a3ef8c4 100644 --- a/libraries/particles/src/ParticleEditPacketSender.h +++ b/libraries/particles/src/ParticleEditPacketSender.h @@ -19,14 +19,14 @@ class ParticleEditPacketSender : public OctreeEditPacketSender { public: ParticleEditPacketSender(PacketSenderNotify* notify = NULL) : OctreeEditPacketSender(notify) { } ~ParticleEditPacketSender() { } - - /// Send particle add message immediately - void sendEditParticleMessage(PACKET_TYPE type, const ParticleDetail& detail); - /// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines - /// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in + /// Send particle add message immediately + void sendEditParticleMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties); + + /// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines + /// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in /// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known. - void queueParticleEditMessages(PACKET_TYPE type, int numberOfDetails, ParticleDetail* details); + void queueParticleEditMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties); // My server type is the particle server virtual unsigned char getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; } diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index b02df9d500..fb290186b2 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -15,7 +15,7 @@ ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) { } ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const { - ParticleTreeElement* newElement = new ParticleTreeElement(octalCode); + ParticleTreeElement* newElement = new ParticleTreeElement(octalCode); return newElement; } @@ -35,7 +35,7 @@ public: const Particle& searchParticle; bool found; }; - + bool ParticleTree::findAndUpdateOperation(OctreeElement* element, void* extraData) { FindAndUpdateParticleArgs* args = static_cast(extraData); ParticleTreeElement* particleTreeElement = static_cast(element); @@ -51,7 +51,7 @@ void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) { // First, look for the existing particle in the tree.. FindAndUpdateParticleArgs args = { particle, false }; recurseTreeWithOperation(findAndUpdateOperation, &args); - + // if we didn't find it in the tree, then store it... if (!args.found) { glm::vec3 position = particle.getPosition(); @@ -59,7 +59,7 @@ void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) { ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size); element->storeParticle(particle, senderNode); - } + } // what else do we need to do here to get reaveraging to work _isDirty = true; } @@ -72,25 +72,25 @@ public: const Particle* closestParticle; float closestParticleDistance; }; - + bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraData) { FindNearPointArgs* args = static_cast(extraData); ParticleTreeElement* particleTreeElement = static_cast(element); glm::vec3 penetration; - bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position, + bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position, args->targetRadius, penetration); // If this particleTreeElement contains the point, then search it... if (sphereIntersection) { const Particle* thisClosestParticle = particleTreeElement->getClosestParticle(args->position); - + // we may have gotten NULL back, meaning no particle was available if (thisClosestParticle) { glm::vec3 particlePosition = thisClosestParticle->getPosition(); float distanceFromPointToParticle = glm::distance(particlePosition, args->position); - + // If we're within our target radius if (distanceFromPointToParticle <= args->targetRadius) { // we are closer than anything else we've found @@ -101,11 +101,11 @@ bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraDat } } } - + // we should be able to optimize this... return true; // keep searching in case children have closer particles } - + // if this element doesn't contain the point, then none of it's children can contain the point, so stop searching return false; } @@ -124,9 +124,11 @@ public: bool found; const Particle* foundParticle; }; - + bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) { +qDebug() << "ParticleTree::findByIDOperation()...."; + FindByIDArgs* args = static_cast(extraData); ParticleTreeElement* particleTreeElement = static_cast(element); @@ -134,7 +136,7 @@ bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) { if (args->found) { return false; } - + // as the tree element if it has this particle const Particle* foundParticle = particleTreeElement->getParticleWithID(args->id); if (foundParticle) { @@ -142,17 +144,23 @@ bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) { args->found = true; return false; } - + // keep looking return true; } -const Particle* ParticleTree::findParticleByID(uint32_t id) { +const Particle* ParticleTree::findParticleByID(uint32_t id, bool alreadyLocked) { FindByIDArgs args = { id, false, NULL }; - lockForRead(); + if (!alreadyLocked) { + qDebug() << "ParticleTree::findParticleByID().... about to call lockForRead()...."; + lockForRead(); + qDebug() << "ParticleTree::findParticleByID().... after call lockForRead()...."; + } recurseTreeWithOperation(findByIDOperation, &args); - unlock(); + if (!alreadyLocked) { + unlock(); + } return args.foundParticle; } @@ -164,13 +172,21 @@ int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* p // we handle these types of "edit" packets switch (packetType) { case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: { - Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes); + +qDebug() << " got PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; + + Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this); +qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling storeParticle() "; storeParticle(newParticle, senderNode); +qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER storeParticle() "; if (newParticle.isNewlyCreated()) { +qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling notifyNewlyCreatedParticle() "; notifyNewlyCreatedParticle(newParticle, senderNode); +qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER notifyNewlyCreatedParticle() "; } +qDebug() << " DONE... PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; } break; - + case PACKET_TYPE_PARTICLE_ERASE: { processedBytes = 0; } break; @@ -227,7 +243,7 @@ void ParticleTree::update() { ParticleTreeUpdateArgs args = { }; recurseTreeWithOperation(updateOperation, &args); - + // now add back any of the particles that moved elements.... int movingParticles = args._movingParticles.size(); for (int i = 0; i < movingParticles; i++) { @@ -235,12 +251,12 @@ void ParticleTree::update() { // if the particle is still inside our total bounds, then re-add it AABox treeBounds = getRoot()->getAABox(); - + if (!shouldDie && treeBounds.contains(args._movingParticles[i].getPosition())) { storeParticle(args._movingParticles[i]); } } - + // prune the tree... recurseTreeWithOperation(pruneOperation, NULL); } diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 7c8d724a17..14502ea235 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -21,14 +21,14 @@ class ParticleTree : public Octree { Q_OBJECT public: ParticleTree(bool shouldReaverage = false); - + /// Implements our type specific root element factory virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL) const; - + /// Type safe version of getRoot() ParticleTreeElement* getRoot() { return (ParticleTreeElement*)_rootNode; } - - + + // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return true; } @@ -37,11 +37,11 @@ public: virtual int processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength, unsigned char* editData, int maxLength, Node* senderNode); - virtual void update(); + virtual void update(); void storeParticle(const Particle& particle, Node* senderNode = NULL); const Particle* findClosestParticle(glm::vec3 position, float targetRadius); - const Particle* findParticleByID(uint32_t id); + const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false); void addNewlyCreatedHook(NewlyCreatedParticleHook* hook); void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook); @@ -53,9 +53,9 @@ private: static bool findNearPointOperation(OctreeElement* element, void* extraData); static bool pruneOperation(OctreeElement* element, void* extraData); static bool findByIDOperation(OctreeElement* element, void* extraData); - + void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode); - + QReadWriteLock _newlyCreatedHooksLock; std::vector _newlyCreatedHooks; }; diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 7828a9d4a7..099e4ad463 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -10,53 +10,12 @@ -void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails) { - getParticlePacketSender()->queueParticleEditMessages(packetType, 1, &particleDetails); -} +void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, + ParticleID particleID, const ParticleProperties& properties) { -ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { +qDebug() << "ParticlesScriptingInterface::queueParticleMessage()..."; - // The application will keep track of creatorTokenID - uint32_t creatorTokenID = Particle::getNextCreatorTokenID(); - - // setup a ParticleDetail struct with the data - uint64_t now = usecTimestampNow(); - ParticleDetail addParticleDetail = { NEW_PARTICLE, now, - position, radius, {color.red, color.green, color.blue }, velocity, - gravity, damping, lifetime, inHand, script, creatorTokenID }; - - // queue the packet - queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); - - ParticleID id(NEW_PARTICLE, creatorTokenID, false); - return id; -} - - -void ParticlesScriptingInterface::editParticle(ParticleID particleID, glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { - - uint32_t actualID = particleID.id; // may not be valid... will check below.. - - // if we don't know the actual id, look it up - if (!particleID.isKnownID) { - actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); - - // if we couldn't fine it, then bail without changing anything... - if (actualID == UNKNOWN_PARTICLE_ID) { - return; // no changes... - } - } - - // setup a ParticleDetail struct with the data - uint64_t now = usecTimestampNow(); - ParticleDetail editParticleDetail = { actualID , now, - position, radius, {color.red, color.green, color.blue }, velocity, - gravity, damping, lifetime, inHand, script, UNKNOWN_TOKEN }; - - // queue the packet - queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail); + getParticlePacketSender()->queueParticleEditMessage(packetType, particleID, properties); } ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& properties) { @@ -64,53 +23,33 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr // The application will keep track of creatorTokenID uint32_t creatorTokenID = Particle::getNextCreatorTokenID(); - // setup a ParticleDetail struct with the data - uint64_t now = usecTimestampNow(); - xColor color = properties.getColor(); - ParticleDetail addParticleDetail = { NEW_PARTICLE, now, - properties.getPosition(), properties.getRadius(), - {color.red, color.green, color.blue }, properties.getVelocity(), - properties.getGravity(), properties.getDamping(), properties.getLifetime(), - properties.getInHand(), properties.getScript(), - creatorTokenID }; + ParticleID id(NEW_PARTICLE, creatorTokenID, false ); // queue the packet - queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); + queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, id, properties); - ParticleID id(NEW_PARTICLE, creatorTokenID, false ); return id; } void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) { - uint32_t actualID = particleID.id; // may not be valid... will check below.. +qDebug() << "ParticlesScriptingInterface::editParticle() id.id=" << particleID.id << " id.creatorTokenID=" << particleID.creatorTokenID; - // if we don't know the actual id, look it up + uint32_t actualID = particleID.id; if (!particleID.isKnownID) { actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); - qDebug() << "ParticlesScriptingInterface::editParticle()... actualID: " << actualID; - - // if we couldn't fine it, then bail without changing anything... + // hmmm... we kind of want to bail if someone attempts to edit an unknown if (actualID == UNKNOWN_PARTICLE_ID) { - return; // no changes... + return; // bailing early } +qDebug() << "ParticlesScriptingInterface::editParticle() actualID=" << actualID; } - // setup a ParticleDetail struct with the data - uint64_t now = usecTimestampNow(); + particleID.id = actualID; + particleID.isKnownID = true; - xColor color = properties.getColor(); - ParticleDetail editParticleDetail = { actualID, now, - properties.getPosition(), properties.getRadius(), - {color.red, color.green, color.blue }, properties.getVelocity(), - properties.getGravity(), properties.getDamping(), properties.getLifetime(), - properties.getInHand(), properties.getScript(), - UNKNOWN_TOKEN }; - - - // queue the packet - queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail); + queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties); } diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index c8e0d45234..121f55fdc5 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -24,19 +24,12 @@ public: virtual OctreeEditPacketSender* createPacketSender() { return new ParticleEditPacketSender(); } public slots: - ParticleID addParticle(glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script); - - void editParticle(ParticleID particleID, glm::vec3 position, float radius, - xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script); - ParticleID addParticle(const ParticleProperties& properties); - void editParticle(ParticleID particleID, const ParticleProperties& properties); void deleteParticle(ParticleID particleID); private: - void queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails); + void queueParticleMessage(PACKET_TYPE packetType, ParticleID particleID, const ParticleProperties& properties); uint32_t _nextCreatorTokenID; }; From cd0e8e742c28ee95390a911fd5c050e325071bdb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 02:12:31 -0800 Subject: [PATCH 09/24] particle edit checkpoint --- .../src/OctreeInboundPacketProcessor.cpp | 30 +-- libraries/particles/src/Particle.cpp | 204 +++++++++++------- libraries/particles/src/Particle.h | 17 +- libraries/particles/src/ParticleTree.cpp | 10 +- .../particles/src/ParticleTreeElement.cpp | 66 +++--- .../src/ParticlesScriptingInterface.cpp | 29 ++- libraries/shared/src/PacketHeaders.cpp | 2 +- 7 files changed, 229 insertions(+), 129 deletions(-) diff --git a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp index e6a89c76ed..2e5872c180 100644 --- a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp +++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp @@ -34,7 +34,7 @@ void OctreeInboundPacketProcessor::resetStats() { _totalLockWaitTime = 0; _totalElementsInPacket = 0; _totalPackets = 0; - + _singleSenderStats.clear(); } @@ -43,14 +43,14 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA unsigned char* packetData, ssize_t packetLength) { bool debugProcessPacket = _myServer->wantsVerboseDebug(); - + if (debugProcessPacket) { printf("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%ld\n", packetData, packetLength); } int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - + + // Ask our tree subclass if it can handle the incoming packet... PACKET_TYPE packetType = packetData[0]; if (_myServer->getOctree()->handlesEditPacketType(packetType)) { @@ -58,7 +58,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA _receivedPacketCount++; SharedNodePointer senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); - + unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); uint64_t arrivedAt = usecTimestampNow(); @@ -66,10 +66,10 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA int editsInPacket = 0; uint64_t processTime = 0; uint64_t lockWaitTime = 0; - - if (_myServer->wantsDebugReceiving()) { - qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount - << " command from client receivedBytes=" << packetLength + + if (true || _myServer->wantsDebugReceiving()) { + qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount + << " command from client receivedBytes=" << packetLength << " sequence=" << sequence << " transitTime=" << transitTime << " usecs"; } int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt); @@ -77,7 +77,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA while (atByte < packetLength) { int maxSize = packetLength - atByte; - if (debugProcessPacket) { + if (true || debugProcessPacket) { printf("OctreeInboundPacketProcessor::processPacket() %c " "packetData=%p packetLength=%ld voxelData=%p atByte=%d maxSize=%d\n", packetType, packetData, packetLength, editData, atByte, maxSize); @@ -86,7 +86,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA uint64_t startLock = usecTimestampNow(); _myServer->getOctree()->lockForWrite(); uint64_t startProcess = usecTimestampNow(); - int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType, + int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType, packetData, packetLength, editData, maxSize, senderNode.data()); @@ -129,15 +129,15 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA } } -void OctreeInboundPacketProcessor::trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, +void OctreeInboundPacketProcessor::trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, int editsInPacket, uint64_t processTime, uint64_t lockWaitTime) { - + _totalTransitTime += transitTime; _totalProcessTime += processTime; _totalLockWaitTime += lockWaitTime; _totalElementsInPacket += editsInPacket; _totalPackets++; - + // find the individual senders stats and track them there too... // see if this is the first we've heard of this node... if (_singleSenderStats.find(nodeUUID) == _singleSenderStats.end()) { @@ -162,7 +162,7 @@ void OctreeInboundPacketProcessor::trackInboundPackets(const QUuid& nodeUUID, in SingleSenderStats::SingleSenderStats() { - _totalTransitTime = 0; + _totalTransitTime = 0; _totalProcessTime = 0; _totalLockWaitTime = 0; _totalElementsInPacket = 0; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 85f2380a8e..22f99182dd 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -86,8 +86,10 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 if (id == NEW_PARTICLE) { _id = _nextID; _nextID++; +qDebug() << "Particle::init()... assigning new id... _id=" << _id; } else { _id = id; +qDebug() << "Particle::init()... assigning id from init... _id=" << _id; } uint64_t now = usecTimestampNow(); _lastEdited = now; @@ -152,6 +154,13 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { if (success) { success = packetData->appendValue(getInHand()); } +/** + if (success) { +qDebug() << "appendParticleData().... getShouldDie()=" << getShouldDie(); + success = packetData->appendValue(getShouldDie()); + } +**/ + if (success) { uint16_t scriptLength = _script.size() + 1; // include NULL success = packetData->appendValue(scriptLength); @@ -265,6 +274,15 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef dataAt += sizeof(_inHand); bytesRead += sizeof(_inHand); +/** + // shouldDie + memcpy(&_shouldDie, dataAt, sizeof(_shouldDie)); + dataAt += sizeof(_shouldDie); + bytesRead += sizeof(_shouldDie); + +qDebug() << "readParticleDataFromBuffer().... _shouldDie()=" << _shouldDie; +**/ + // script uint16_t scriptLength; memcpy(&scriptLength, dataAt, sizeof(scriptLength)); @@ -282,6 +300,9 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree) { + +qDebug() << "Particle::fromEditPacket() length=" << length; + Particle newParticle; // id and _lastUpdated will get set here... unsigned char* dataAt = data; processedBytes = 0; @@ -290,6 +311,9 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe int octets = numberOfThreeBitSectionsInCode(data); int lengthOfOctcode = bytesRequiredForCodeLength(octets); +qDebug() << "Particle::fromEditPacket() lengthOfOctcode=" << lengthOfOctcode; +printOctalCode(data); + // we don't actually do anything with this octcode... dataAt += lengthOfOctcode; processedBytes += lengthOfOctcode; @@ -300,36 +324,38 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe dataAt += sizeof(editID); processedBytes += sizeof(editID); +qDebug() << "editID:" << editID; + + bool isNewParticle = (editID == NEW_PARTICLE); + // special case for handling "new" particles - if (editID == NEW_PARTICLE) { + if (isNewParticle) { +qDebug() << "editID == NEW_PARTICLE"; // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that // we want to send back to the creator as an map to the actual id uint32_t creatorTokenID; memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID)); dataAt += sizeof(creatorTokenID); processedBytes += sizeof(creatorTokenID); + +qDebug() << "creatorTokenID:" << creatorTokenID; + newParticle.setCreatorTokenID(creatorTokenID); newParticle._newlyCreated = true; newParticle.setAge(0); // this guy is new! -qDebug() << "fromEditPacket() NEW_PARTICLE"; } else { - qDebug() << "fromEditPacket() existingParticle id=" << editID; - // look up the existing particle - - qDebug() << "fromEditPacket() existingParticle id=" << editID << "calling tree->findParticleByID(editID)"; const Particle* existingParticle = tree->findParticleByID(editID, true); - qDebug() << "fromEditPacket() existingParticle id=" << editID << "DONE tree->findParticleByID(editID)"; // copy existing properties before over-writing with new properties if (existingParticle) { newParticle = *existingParticle; - qDebug() << "found it..."; + +qDebug() << "newParticle = *existingParticle... calling debugDump()..."; + existingParticle->debugDump(); - } else { - qDebug() << "WHOA! Didn't find it..."; } newParticle._id = editID; @@ -342,84 +368,97 @@ qDebug() << "fromEditPacket() NEW_PARTICLE"; memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited)); dataAt += sizeof(newParticle._lastEdited); processedBytes += sizeof(newParticle._lastEdited); +qDebug() << "newParticle._lastEdited:" << newParticle._lastEdited; + // All of the remaining items are optional, and may or may not be included based on their included values in the // properties included bits uint16_t packetContainsBits = 0; - memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits)); - dataAt += sizeof(packetContainsBits); - processedBytes += sizeof(packetContainsBits); + if (!isNewParticle) { + memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits)); + dataAt += sizeof(packetContainsBits); + processedBytes += sizeof(packetContainsBits); + qDebug() << "packetContainsBits:" << packetContainsBits; + } -qDebug() << "fromEditPacket() packetContainsBits=" << packetContainsBits; // radius - if ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_RADIUS"; - + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS)) { memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); dataAt += sizeof(newParticle._radius); processedBytes += sizeof(newParticle._radius); +qDebug() << "newParticle._radius:" << newParticle._radius; } // position - if ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_POSITION"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION)) { memcpy(&newParticle._position, dataAt, sizeof(newParticle._position)); dataAt += sizeof(newParticle._position); processedBytes += sizeof(newParticle._position); +qDebug() << "newParticle._position:"; } // color - if ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_COLOR"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR)) { memcpy(newParticle._color, dataAt, sizeof(newParticle._color)); dataAt += sizeof(newParticle._color); processedBytes += sizeof(newParticle._color); +qDebug() << "newParticle._color:"; } // velocity - if ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_VELOCITY"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY)) { memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity)); dataAt += sizeof(newParticle._velocity); processedBytes += sizeof(newParticle._velocity); +qDebug() << "newParticle._velocity:"; } // gravity - if ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_GRAVITY"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY)) { memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity)); dataAt += sizeof(newParticle._gravity); processedBytes += sizeof(newParticle._gravity); +qDebug() << "newParticle._gravity:"; } // damping - if ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_DAMPING"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING)) { memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping)); dataAt += sizeof(newParticle._damping); processedBytes += sizeof(newParticle._damping); +qDebug() << "newParticle._damping:" << newParticle._damping; } // lifetime - if ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_LIFETIME"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME)) { memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime)); dataAt += sizeof(newParticle._lifetime); processedBytes += sizeof(newParticle._lifetime); +qDebug() << "newParticle._lifetime:" << newParticle._lifetime; } + // TODO: make inHand and shouldDie into single bits // inHand - if ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_INHAND"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND)) { memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand)); dataAt += sizeof(newParticle._inHand); processedBytes += sizeof(newParticle._inHand); +qDebug() << "newParticle._inHand:" << newParticle._inHand; } +/** + // shouldDie + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SHOULDDIE) == PACKET_CONTAINS_SHOULDDIE)) { + memcpy(&newParticle._shouldDie, dataAt, sizeof(newParticle._shouldDie)); + dataAt += sizeof(newParticle._shouldDie); + processedBytes += sizeof(newParticle._shouldDie); +qDebug() << "fromEditPacket().... newParticle._shouldDie=" << newParticle._shouldDie; + } +**/ + // script - if ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT) { -qDebug() << "fromEditPacket() PACKET_CONTAINS_SCRIPT"; + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT)) { uint16_t scriptLength; memcpy(&scriptLength, dataAt, sizeof(scriptLength)); dataAt += sizeof(scriptLength); @@ -428,12 +467,13 @@ qDebug() << "fromEditPacket() PACKET_CONTAINS_SCRIPT"; newParticle._script = tempString; dataAt += scriptLength; processedBytes += scriptLength; +qDebug() << "newParticle._script:" << newParticle._script; } const bool wantDebugging = true; if (wantDebugging) { qDebug("Particle::fromEditPacket()..."); - qDebug(" Particle id in packet:%u", editID); + qDebug() << " Particle id in packet:" << editID; //qDebug() << " position: " << newParticle._position; newParticle.debugDump(); } @@ -445,6 +485,7 @@ void Particle::debugDump() const { printf("Particle id :%u\n", _id); printf(" age:%f\n", getAge()); printf(" edited ago:%f\n", getEditedAgo()); + printf(" should die:%s\n", debug::valueOf(getShouldDie())); printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z); printf(" radius:%f\n", getRadius()); printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z); @@ -486,18 +527,23 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID sizeOut += lengthOfOctcode; // Now add our edit content details... + bool isNewParticle = (id.id == NEW_PARTICLE); // id memcpy(copyAt, &id.id, sizeof(id.id)); copyAt += sizeof(id.id); sizeOut += sizeof(id.id); +qDebug() << "encoding, id.id:" << id.id; + // special case for handling "new" particles - if (id.id == NEW_PARTICLE) { + if (isNewParticle) { +qDebug() << "encodeParticleEditMessageDetails()... isNewParticle..."; // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that // we want to send back to the creator as an map to the actual id memcpy(copyAt, &id.creatorTokenID, sizeof(id.creatorTokenID)); copyAt += sizeof(id.creatorTokenID); sizeOut += sizeof(id.creatorTokenID); +qDebug() << "encoding, id.creatorTokenID:" << id.creatorTokenID; } // lastEdited @@ -505,89 +551,101 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID memcpy(copyAt, &lastEdited, sizeof(lastEdited)); copyAt += sizeof(lastEdited); sizeOut += sizeof(lastEdited); +qDebug() << "encoding, lastEdited:" << lastEdited; - // All of the remaining items are optional, and may or may not be included based on their included values in the - // properties included bits + + // For new particles, all remaining items are mandatory, for an edited particle, All of the remaining items are + // optional, and may or may not be included based on their included values in the properties included bits uint16_t packetContainsBits = properties.getChangedBits(); - memcpy(copyAt, &packetContainsBits, sizeof(packetContainsBits)); - copyAt += sizeof(packetContainsBits); - sizeOut += sizeof(packetContainsBits); - -qDebug() << " packetContainsBits = " << packetContainsBits; + if (!isNewParticle) { + memcpy(copyAt, &packetContainsBits, sizeof(packetContainsBits)); + copyAt += sizeof(packetContainsBits); + sizeOut += sizeof(packetContainsBits); +qDebug() << "encoding, packetContainsBits:" << packetContainsBits; + } // radius - if ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_RADIUS\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS)) { float radius = properties.getRadius(); memcpy(copyAt, &radius, sizeof(radius)); copyAt += sizeof(radius); sizeOut += sizeof(radius); +qDebug() << "encoding, radius:" << radius; } // position - if ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_POSITION\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION)) { memcpy(copyAt, &properties.getPosition(), sizeof(properties.getPosition())); copyAt += sizeof(properties.getPosition()); sizeOut += sizeof(properties.getPosition()); +qDebug() << "encoding, properties.getPosition():"; } // color - if ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_COLOR\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR)) { rgbColor color = { properties.getColor().red, properties.getColor().green, properties.getColor().blue }; memcpy(copyAt, color, sizeof(color)); copyAt += sizeof(color); sizeOut += sizeof(color); +qDebug() << "encoding, color:"; } // velocity - if ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_VELOCITY\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY)) { memcpy(copyAt, &properties.getVelocity(), sizeof(properties.getVelocity())); copyAt += sizeof(properties.getVelocity()); sizeOut += sizeof(properties.getVelocity()); +qDebug() << "encoding, getVelocity:"; } // gravity - if ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_GRAVITY\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY)) { memcpy(copyAt, &properties.getGravity(), sizeof(properties.getGravity())); copyAt += sizeof(properties.getGravity()); sizeOut += sizeof(properties.getGravity()); +qDebug() << "encoding, getGravity():"; } // damping - if ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_DAMPING\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING)) { float damping = properties.getDamping(); memcpy(copyAt, &damping, sizeof(damping)); copyAt += sizeof(damping); sizeOut += sizeof(damping); +qDebug() << "encoding, damping:" << damping; } // lifetime - if ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_LIFETIME\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME)) { float lifetime = properties.getLifetime(); memcpy(copyAt, &lifetime, sizeof(lifetime)); copyAt += sizeof(lifetime); sizeOut += sizeof(lifetime); +qDebug() << "encoding, lifetime:" << lifetime; } // inHand - if ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) { - printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_INHAND\n"); + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND)) { bool inHand = properties.getInHand(); memcpy(copyAt, &inHand, sizeof(inHand)); copyAt += sizeof(inHand); sizeOut += sizeof(inHand); +qDebug() << "encoding, inHand:" << inHand; } - // script - if ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT) { - printf("encodeParticleEditMessageDetails() including SCRIPT\n"); +/** + // shoulDie + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SHOULDDIE) == PACKET_CONTAINS_SHOULDDIE)) { + bool shouldDie = properties.getShouldDie(); + memcpy(copyAt, &shouldDie, sizeof(shouldDie)); + copyAt += sizeof(shouldDie); + sizeOut += sizeof(shouldDie); +qDebug() << "encoding, shouldDie:" << shouldDie; + } +**/ + // script + if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT)) { uint16_t scriptLength = properties.getScript().size() + 1; memcpy(copyAt, &scriptLength, sizeof(scriptLength)); copyAt += sizeof(scriptLength); @@ -595,6 +653,7 @@ qDebug() << " packetContainsBits = " << packetContainsBits; memcpy(copyAt, qPrintable(properties.getScript()), scriptLength); copyAt += scriptLength; sizeOut += scriptLength; +qDebug() << "encoding, getScript:" << properties.getScript(); } bool wantDebugging = false; @@ -608,6 +667,8 @@ qDebug() << " packetContainsBits = " << packetContainsBits; // cleanup delete[] octcode; +qDebug() << "encoding... sizeOut:" << sizeOut; + return success; } @@ -660,8 +721,12 @@ void Particle::update() { // Lifetime - even if you're moving, or in hand, if you're age is greater than your requested lifetime, you are going to die bool shouldDie = getShouldDie() || (getAge() > getLifetime()) || (!isInHand && !isStillMoving && isReallyOld); +//qDebug() << "update()... getShouldDie()=" << getShouldDie(); + setShouldDie(shouldDie); +//qDebug() << "update()... getShouldDie()=" << getShouldDie(); + runUpdateScript(); // allow the javascript to alter our state // If the ball is in hand, it doesn't move or have gravity effect it @@ -808,7 +873,7 @@ void Particle::setProperties(const ParticleProperties& properties) { ParticleProperties::ParticleProperties() : _position(0), _color(), - _radius(0), + _radius(DEFAULT_RADIUS), _velocity(0), _gravity(DEFAULT_GRAVITY), _damping(DEFAULT_DAMPING), @@ -870,12 +935,12 @@ uint16_t ParticleProperties::getChangedBits() const { changedBits += PACKET_CONTAINS_SCRIPT; } +/** // how do we want to handle this? - - //if (_shouldDieChanged) { - // changedBits += PACKET_CONTAINS_SHOULDDIE; - //} - + if (_shouldDieChanged) { + changedBits += PACKET_CONTAINS_SHOULDDIE; + } +**/ return changedBits; } @@ -945,18 +1010,13 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { } QScriptValue radius = object.property("radius"); -qDebug() << "copyFromScriptValue() line:" << __LINE__; if (radius.isValid()) { -qDebug() << "copyFromScriptValue() line:" << __LINE__; float newRadius; newRadius = radius.toVariant().toFloat(); -qDebug() << "copyFromScriptValue() line:" << __LINE__ << " newRadius=" << newRadius; -qDebug() << "copyFromScriptValue() line:" << __LINE__ << " _radius=" << _radius; if (newRadius != _radius) { _radius = newRadius; _radiusChanged = true; } -qDebug() << "copyFromScriptValue() line:" << __LINE__ << " _radiusChanged=" << _radiusChanged; } QScriptValue velocity = object.property("velocity"); diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index e4072e1e46..1205a75301 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -40,10 +40,12 @@ const uint16_t PACKET_CONTAINS_DAMPING = 32; const uint16_t PACKET_CONTAINS_LIFETIME = 64; const uint16_t PACKET_CONTAINS_INHAND = 128; const uint16_t PACKET_CONTAINS_SCRIPT = 256; +const uint16_t PACKET_CONTAINS_SHOULDDIE = 512; -const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default +const float DEFAULT_LIFETIME = 10.f; //60.0f * 60.0f * 24.0f; // particles live for 1 day by default const float DEFAULT_DAMPING = 0.99f; -const float DEFAULT_RADIUS = 0.1f / TREE_SCALE; // really shouldn't be a default? +const float DEFAULT_RADIUS = 0.1f / TREE_SCALE; +const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container const glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0); const QString DEFAULT_SCRIPT(""); const bool IN_HAND = true; // it's in a hand @@ -76,6 +78,17 @@ public: uint64_t getLastEdited() const { return _lastEdited; } uint16_t getChangedBits() const; + void setPosition(const glm::vec3& value) { _position = value; _positionChanged = true; } + void setVelocity(const glm::vec3& value) { _velocity = value; _velocityChanged = true; } + void setColor(const xColor& value) { _color = value; _colorChanged = true; } + void setRadius(float value) { _radius = value; _radiusChanged = true; } + void setGravity(const glm::vec3& value) { _gravity = value; _gravityChanged = true; } + void setInHand(bool inHand) { _inHand = inHand; _inHandChanged = true; } + void setDamping(float value) { _damping = value; _dampingChanged = true; } + void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; _shouldDieChanged = true; } + void setLifetime(float value) { _lifetime = value; _lifetimeChanged = true; } + void setScript(QString updateScript) { _script = updateScript; _scriptChanged = true; } + private: glm::vec3 _position; xColor _color; diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index fb290186b2..d3677323e4 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -55,7 +55,7 @@ void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) { // if we didn't find it in the tree, then store it... if (!args.found) { glm::vec3 position = particle.getPosition(); - float size = particle.getRadius(); + float size = std::max(MINIMUM_PARTICLE_ELEMENT_SIZE, particle.getRadius()); ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size); element->storeParticle(particle, senderNode); @@ -127,7 +127,7 @@ public: bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) { -qDebug() << "ParticleTree::findByIDOperation()...."; +//qDebug() << "ParticleTree::findByIDOperation()...."; FindByIDArgs* args = static_cast(extraData); ParticleTreeElement* particleTreeElement = static_cast(element); @@ -153,9 +153,9 @@ qDebug() << "ParticleTree::findByIDOperation()...."; const Particle* ParticleTree::findParticleByID(uint32_t id, bool alreadyLocked) { FindByIDArgs args = { id, false, NULL }; if (!alreadyLocked) { - qDebug() << "ParticleTree::findParticleByID().... about to call lockForRead()...."; + //qDebug() << "ParticleTree::findParticleByID().... about to call lockForRead()...."; lockForRead(); - qDebug() << "ParticleTree::findParticleByID().... after call lockForRead()...."; + //qDebug() << "ParticleTree::findParticleByID().... after call lockForRead()...."; } recurseTreeWithOperation(findByIDOperation, &args); if (!alreadyLocked) { @@ -178,7 +178,7 @@ qDebug() << " got PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this); qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling storeParticle() "; storeParticle(newParticle, senderNode); -qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER storeParticle() "; +qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER storeParticle() newParticle.getShouldDie()=" << newParticle.getShouldDie(); if (newParticle.isNewlyCreated()) { qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling notifyNewlyCreatedParticle() "; notifyNewlyCreatedParticle(newParticle, senderNode); diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index 44cb8db008..ab9d9d861a 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -11,7 +11,7 @@ #include "ParticleTree.h" #include "ParticleTreeElement.h" -ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement() { +ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement() { init(octalCode); }; @@ -20,7 +20,7 @@ ParticleTreeElement::~ParticleTreeElement() { } // This will be called primarily on addChildAt(), which means we're adding a child of our -// own type to our own tree. This means we should initialize that child with any tree and type +// own type to our own tree. This means we should initialize that child with any tree and type // specific settings that our children must have. One example is out VoxelSystem, which // we know must match ours. OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) const { @@ -34,8 +34,8 @@ void ParticleTreeElement::init(unsigned char* octalCode) { _voxelMemoryUsage += sizeof(ParticleTreeElement); } -ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) { - ParticleTreeElement* newElement = (ParticleTreeElement*)OctreeElement::addChildAtIndex(index); +ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) { + ParticleTreeElement* newElement = (ParticleTreeElement*)OctreeElement::addChildAtIndex(index); newElement->setTree(_myTree); return newElement; } @@ -66,17 +66,29 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) { // update our contained particles uint16_t numberOfParticles = _particles.size(); + if (numberOfParticles > 0) { +// qDebug() << "ParticleTreeElement::update()... numberOfParticles="<< numberOfParticles; + } + for (uint16_t i = 0; i < numberOfParticles; i++) { _particles[i].update(); // If the particle wants to die, or if it's left our bounding box, then move it // into the arguments moving particles. These will be added back or deleted completely + +// qDebug() << "ParticleTreeElement::update()... _particles[i="<< i << "].getShouldDie()=" +// << _particles[i].getShouldDie() << " getID()=" << _particles[i].getID(); + if (_particles[i].getShouldDie() || !_box.contains(_particles[i].getPosition())) { - args._movingParticles.push_back(_particles[i]); - + + // if it moved out of bounds, add it to the movingParticles + //if (!_particles[i].getShouldDie()) { + args._movingParticles.push_back(_particles[i]); + //} + // erase this particle _particles.erase(_particles.begin()+i); - + // reduce our index since we just removed this item i--; numberOfParticles--; @@ -84,14 +96,14 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) { } } -bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius, +bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { - + uint16_t numberOfParticles = _particles.size(); for (uint16_t i = 0; i < numberOfParticles; i++) { glm::vec3 particleCenter = _particles[i].getPosition(); float particleRadius = _particles[i].getRadius(); - + // don't penetrate yourself if (particleCenter == center && particleRadius == radius) { return false; @@ -106,7 +118,7 @@ bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float r return false; } } - + if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) { *penetratedObject = (void*)&_particles[i]; return true; @@ -122,7 +134,7 @@ bool ParticleTreeElement::containsParticle(const Particle& particle) const { return true; } } - return false; + return false; } bool ParticleTreeElement::updateParticle(const Particle& particle) { @@ -133,27 +145,27 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) { int difference = _particles[i].getLastUpdated() - particle.getLastUpdated(); bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited(); bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated(); - if (changedOnServer || localOlder) { + if (changedOnServer || localOlder) { if (wantDebug) { - printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", + printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", particle.getID(), (changedOnServer ? "CHANGED" : "same"), - (localOlder ? "OLDER" : "NEWER"), + (localOlder ? "OLDER" : "NEWER"), difference, debug::valueOf(particle.isNewlyCreated()) ); } _particles[i].copyChangedProperties(particle); } else { if (wantDebug) { printf(">>> IGNORING SERVER!!! Would've caused jutter! <<< " - "local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", + "local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", particle.getID(), (changedOnServer ? "CHANGED" : "same"), - (localOlder ? "OLDER" : "NEWER"), + (localOlder ? "OLDER" : "NEWER"), difference, debug::valueOf(particle.isNewlyCreated()) ); } } return true; } } - return false; + return false; } const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) const { @@ -166,7 +178,7 @@ const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) cons closestParticle = &_particles[i]; } } - return closestParticle; + return closestParticle; } const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const { @@ -178,26 +190,26 @@ const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const { break; } } - return foundParticle; + return foundParticle; } -int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args) { - +int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args) { + const unsigned char* dataAt = data; int bytesRead = 0; uint16_t numberOfParticles = 0; int expectedBytesPerParticle = Particle::expectedBytes(); if (bytesLeftToRead >= sizeof(numberOfParticles)) { - + // read our particles in.... numberOfParticles = *(uint16_t*)dataAt; dataAt += sizeof(numberOfParticles); bytesLeftToRead -= sizeof(numberOfParticles); bytesRead += sizeof(numberOfParticles); - + if (bytesLeftToRead >= (numberOfParticles * expectedBytesPerParticle)) { for (uint16_t i = 0; i < numberOfParticles; i++) { Particle tempParticle; @@ -209,7 +221,7 @@ int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, in } } } - + return bytesRead; } @@ -220,7 +232,7 @@ void ParticleTreeElement::calculateAverageFromChildren() { // will detect if children are leaves AND collapsable into the parent node // and in that case will collapse children and make this node -// a leaf, returns TRUE if all the leaves are collapsed into a +// a leaf, returns TRUE if all the leaves are collapsed into a // single node bool ParticleTreeElement::collapseChildren() { // nothing to do here yet... diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 099e4ad463..ed8883d9b0 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -12,9 +12,6 @@ void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, ParticleID particleID, const ParticleProperties& properties) { - -qDebug() << "ParticlesScriptingInterface::queueParticleMessage()..."; - getParticlePacketSender()->queueParticleEditMessage(packetType, particleID, properties); } @@ -32,9 +29,6 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr } void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) { - -qDebug() << "ParticlesScriptingInterface::editParticle() id.id=" << particleID.id << " id.creatorTokenID=" << particleID.creatorTokenID; - uint32_t actualID = particleID.id; if (!particleID.isKnownID) { actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); @@ -43,7 +37,6 @@ qDebug() << "ParticlesScriptingInterface::editParticle() id.id=" << particleID.i if (actualID == UNKNOWN_PARTICLE_ID) { return; // bailing early } -qDebug() << "ParticlesScriptingInterface::editParticle() actualID=" << actualID; } particleID.id = actualID; @@ -54,4 +47,26 @@ qDebug() << "ParticlesScriptingInterface::editParticle() actualID=" << actualID; void ParticlesScriptingInterface::deleteParticle(ParticleID particleID) { + + // setup properties to kill the particle + ParticleProperties properties; + properties.setScript("print('here'); Particle.setShouldDie(true);"); + //properties.setShouldDie(true); + + uint32_t actualID = particleID.id; + if (!particleID.isKnownID) { + actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); + + // hmmm... we kind of want to bail if someone attempts to edit an unknown + if (actualID == UNKNOWN_PARTICLE_ID) { +qDebug() << "ParticlesScriptingInterface::deleteParticle(), bailing - unknown particle..."; + return; // bailing early + } + } + + particleID.id = actualID; + particleID.isKnownID = true; + +qDebug() << "ParticlesScriptingInterface::deleteParticle(), queueParticleMessage......"; + queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties); } diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index b0e55e4b29..2d9ffbcf39 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -51,7 +51,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { return 3; case PACKET_TYPE_PARTICLE_DATA: - return 6; + return 7; case PACKET_TYPE_PING_REPLY: return 1; From 97b0ed2cc5556fdfec39871dd0546073cde01475 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 13:24:35 -0800 Subject: [PATCH 10/24] implemented support for PACKET_TYPE_PARTICLE_ERASE --- interface/src/Application.cpp | 1 + interface/src/ParticleTreeRenderer.cpp | 17 +- interface/src/ParticleTreeRenderer.h | 2 + interface/src/VoxelPacketProcessor.cpp | 23 +- .../octree-server/src/OctreeSendThread.cpp | 3 +- libraries/octree-server/src/OctreeServer.cpp | 104 ++++----- libraries/octree-server/src/OctreeServer.h | 16 +- libraries/octree/src/Octree.cpp | 2 +- .../particle-server/src/ParticleNodeData.h | 11 +- .../particle-server/src/ParticleServer.cpp | 81 ++++++- .../particle-server/src/ParticleServer.h | 12 +- libraries/particles/src/ParticleTree.cpp | 200 +++++++++++++++++- libraries/particles/src/ParticleTree.h | 12 ++ .../particles/src/ParticleTreeElement.cpp | 14 ++ libraries/particles/src/ParticleTreeElement.h | 28 +-- libraries/voxel-server/src/VoxelServer.cpp | 6 +- libraries/voxel-server/src/VoxelServer.h | 8 +- 17 files changed, 427 insertions(+), 113 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cdf917e73b..1f1311d714 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4187,6 +4187,7 @@ void Application::processDatagrams() { break; case PACKET_TYPE_PARTICLE_DATA: + case PACKET_TYPE_PARTICLE_ERASE: case PACKET_TYPE_VOXEL_DATA: case PACKET_TYPE_VOXEL_ERASE: case PACKET_TYPE_OCTREE_STATS: diff --git a/interface/src/ParticleTreeRenderer.cpp b/interface/src/ParticleTreeRenderer.cpp index 81ef7f1221..aa4978891f 100644 --- a/interface/src/ParticleTreeRenderer.cpp +++ b/interface/src/ParticleTreeRenderer.cpp @@ -11,7 +11,7 @@ #include "ParticleTreeRenderer.h" -ParticleTreeRenderer::ParticleTreeRenderer() : +ParticleTreeRenderer::ParticleTreeRenderer() : OctreeRenderer() { } @@ -31,13 +31,13 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg // actually render it here... // we need to iterate the actual particles of the element ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element; - + const QList& particles = particleTreeElement->getParticles(); - + uint16_t numberOfParticles = particles.size(); - + bool drawAsSphere = true; - + for (uint16_t i = 0; i < numberOfParticles; i++) { const Particle& particle = particles[i]; // render particle aspoints @@ -46,7 +46,7 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg float sphereRadius = particle.getRadius() * (float)TREE_SCALE; args->_renderedItems++; - + if (drawAsSphere) { glPushMatrix(); glTranslatef(position.x, position.y, position.z); @@ -60,3 +60,8 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg } } } + +void ParticleTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, + Node* sourceNode) { + static_cast(_tree)->processEraseMessage(dataByteArray, senderSockAddr, sourceNode); +} diff --git a/interface/src/ParticleTreeRenderer.h b/interface/src/ParticleTreeRenderer.h index ba11799776..1c76cf623d 100644 --- a/interface/src/ParticleTreeRenderer.h +++ b/interface/src/ParticleTreeRenderer.h @@ -37,6 +37,8 @@ public: ParticleTree* getTree() { return (ParticleTree*)_tree; } + void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode); + protected: }; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 9c2ec2a539..fe50271ca4 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -17,7 +17,7 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, unsigned char* packetData, ssize_t packetLength) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "VoxelPacketProcessor::processPacket()"); - + const int WAY_BEHIND = 300; if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) { @@ -27,19 +27,19 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns Application* app = Application::getInstance(); bool wasStatsPacket = false; - - + + // check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that if (app->_wantToKillLocalVoxels) { app->_voxels.killLocalVoxels(); app->_wantToKillLocalVoxels = false; } - + // note: PACKET_TYPE_OCTREE_STATS can have PACKET_TYPE_VOXEL_DATA // immediately following them inside the same packet. So, we process the PACKET_TYPE_OCTREE_STATS first // then process any remaining bytes as if it was another packet if (packetData[0] == PACKET_TYPE_OCTREE_STATS) { - + int statsMessageLength = app->parseOctreeStats(packetData, messageLength, senderSockAddr); wasStatsPacket = true; if (messageLength > statsMessageLength) { @@ -56,20 +56,25 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { app->trackIncomingVoxelPacket(packetData, messageLength, senderSockAddr, wasStatsPacket); - + SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (serverNode && serverNode->getActiveSocket() && *serverNode->getActiveSocket() == senderSockAddr) { - + switch(packetData[0]) { + case PACKET_TYPE_PARTICLE_ERASE: { + app->_particles.processEraseMessage(QByteArray((char*) packetData, messageLength), + senderSockAddr, serverNode.data()); + } break; + case PACKET_TYPE_PARTICLE_DATA: { app->_particles.processDatagram(QByteArray((char*) packetData, messageLength), senderSockAddr, serverNode.data()); } break; - + case PACKET_TYPE_ENVIRONMENT_DATA: { app->_environment.parseData(senderSockAddr, packetData, messageLength); } break; - + default : { app->_voxels.setDataSourceUUID(serverNode->getUUID()); app->_voxels.parseData(packetData, messageLength); diff --git a/libraries/octree-server/src/OctreeSendThread.cpp b/libraries/octree-server/src/OctreeSendThread.cpp index 6aba5fafaf..a12a633e58 100644 --- a/libraries/octree-server/src/OctreeSendThread.cpp +++ b/libraries/octree-server/src/OctreeSendThread.cpp @@ -525,7 +525,8 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b // Here's where we can/should allow the server to send other data... // send the environment packet - if (_myServer->hasSpecialPacketToSend()) { + // TODO: should we turn this into a while loop to better handle sending multiple special packets + if (_myServer->hasSpecialPacketToSend(node)) { trueBytesSent += _myServer->sendSpecialPacket(node); truePacketsSent++; packetsSentThisInterval++; diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 55bc77f1bf..4a0ad0d827 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -100,27 +100,27 @@ void OctreeServer::initHTTPManager(int port) { } bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& path) { - + #ifdef FORCE_CRASH if (connection->requestOperation() == QNetworkAccessManager::GetOperation && path == "/force_crash") { - + qDebug() << "About to force a crash!"; - + int foo; int* forceCrash = &foo; - + QString responseString("forcing a crash..."); connection->respond(HTTPConnection::StatusCode200, qPrintable(responseString)); - + delete[] forceCrash; - + return true; } #endif - + bool showStats = false; - + if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (path == "/") { showStats = true; @@ -129,28 +129,28 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& showStats = true; } } - + if (showStats) { uint64_t checkSum; // return a 200 QString statsString("\r\n
\r\n");
         statsString += QString("Your %1 Server is running... [RELOAD]\r\n").arg(getMyServerName());
-        
+
         tm* localtm = localtime(&_started);
         const int MAX_TIME_LENGTH = 128;
         char buffer[MAX_TIME_LENGTH];
         strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm);
         statsString += QString("Running since: %1").arg(buffer);
-        
+
         // Convert now to tm struct for UTC
         tm* gmtm = gmtime(&_started);
         if (gmtm) {
             strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", gmtm);
             statsString += (QString(" [%1 UTM] ").arg(buffer));
         }
-        
+
         statsString += "\r\n";
-        
+
         uint64_t now  = usecTimestampNow();
         const int USECS_PER_MSEC = 1000;
         uint64_t msecsElapsed = (now - _startedUSecs) / USECS_PER_MSEC;
@@ -158,13 +158,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         const int SECS_PER_MIN = 60;
         const int MIN_PER_HOUR = 60;
         const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN;
-        
+
         float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
         int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
         int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
-        
+
         statsString += "Uptime: ";
-        
+
         if (hours > 0) {
             statsString += QString("%1 hour%2").arg(hours).arg((hours > 1) ? "s" : "");
         }
@@ -175,7 +175,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
             statsString += QString().sprintf("%.3f seconds", seconds);
         }
         statsString += "\r\n\r\n";
-        
+
         // display voxel file load time
         if (isInitialLoadComplete()) {
             if (isPersistEnabled()) {
@@ -183,14 +183,14 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
             } else {
                 statsString += QString("%1 File Persist Disabled...\r\n").arg(getMyServerName());
             }
-            
+
             statsString += "\r\n";
-            
+
             uint64_t msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;;
             float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
             int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
             int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
-            
+
             statsString += QString("%1 File Load Took").arg(getMyServerName());
             if (hours > 0) {
                 statsString += QString("%1 hour%2").arg(hours).arg((hours > 1) ? "s" : "");
@@ -202,25 +202,25 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
                 statsString += QString().sprintf("%.3f seconds", seconds);
             }
             statsString += "\r\n";
-            
+
         } else {
             statsString += "Voxels not yet loaded...\r\n";
         }
-        
+
         statsString += "\r\n\r\n";
         statsString += "Configuration:\r\n";
-        
+
         for (int i = 1; i < _argc; i++) {
             statsString += _argv[i];
         }
         statsString += "\r\n"; //one to end the config line
         statsString += "\r\n\r\n"; // two more for spacing
-        
+
         // display scene stats
         unsigned long nodeCount = OctreeElement::getNodeCount();
         unsigned long internalNodeCount = OctreeElement::getInternalNodeCount();
         unsigned long leafNodeCount = OctreeElement::getLeafNodeCount();
-        
+
         QLocale locale(QLocale::English);
         const float AS_PERCENT = 100.0;
         statsString += "Current Nodes in scene:\r\n";
@@ -234,7 +234,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
                                          ((float)leafNodeCount / (float)nodeCount) * AS_PERCENT);
         statsString += "\r\n";
         statsString += "\r\n";
-        
+
         // display outbound packet stats
         statsString += QString("%1 Outbound Packet Statistics...\r\n").arg(getMyServerName());
         uint64_t totalOutboundPackets = OctreeSendThread::_totalPackets;
@@ -243,7 +243,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         uint64_t totalBytesOfOctalCodes = OctreePacketData::getTotalBytesOfOctalCodes();
         uint64_t totalBytesOfBitMasks = OctreePacketData::getTotalBytesOfBitMasks();
         uint64_t totalBytesOfColor = OctreePacketData::getTotalBytesOfColor();
-        
+
         const int COLUMN_WIDTH = 10;
         statsString += QString("           Total Outbound Packets: %1 packets\r\n")
             .arg(locale.toString((uint)totalOutboundPackets).rightJustified(COLUMN_WIDTH, ' '));
@@ -260,10 +260,10 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         statsString += QString().sprintf("                Total Color Bytes: %s bytes (%5.2f%%)\r\n",
             locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
             ((float)totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT);
-        
+
         statsString += "\r\n";
         statsString += "\r\n";
-        
+
         // display inbound packet stats
         statsString += QString().sprintf("%s Edit Statistics... [RESET]\r\n",
                                          getMyServerName());
@@ -274,9 +274,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         uint64_t averageLockWaitTimePerElement = _octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
         uint64_t totalElementsProcessed = _octreeInboundPacketProcessor->getTotalElementsProcessed();
         uint64_t totalPacketsProcessed = _octreeInboundPacketProcessor->getTotalPacketsProcessed();
-        
+
         float averageElementsPerPacket = totalPacketsProcessed == 0 ? 0 : totalElementsProcessed / totalPacketsProcessed;
-        
+
         statsString += QString("           Total Inbound Packets: %1 packets\r\n")
             .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' '));
         statsString += QString("          Total Inbound Elements: %1 elements\r\n")
@@ -292,18 +292,18 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
             .arg(locale.toString((uint)averageProcessTimePerElement).rightJustified(COLUMN_WIDTH, ' '));
         statsString += QString("  Average Wait Lock Time/Element: %1 usecs\r\n")
             .arg(locale.toString((uint)averageLockWaitTimePerElement).rightJustified(COLUMN_WIDTH, ' '));
-        
-        
+
+
         int senderNumber = 0;
         NodeToSenderStatsMap& allSenderStats = _octreeInboundPacketProcessor->getSingleSenderStats();
         for (NodeToSenderStatsMapIterator i = allSenderStats.begin(); i != allSenderStats.end(); i++) {
             senderNumber++;
             QUuid senderID = i->first;
             SingleSenderStats& senderStats = i->second;
-            
+
             statsString += QString("\r\n             Stats for sender %1 uuid: %2\r\n")
                 .arg(senderNumber).arg(senderID.toString());
-            
+
             averageTransitTimePerPacket = senderStats.getAverageTransitTimePerPacket();
             averageProcessTimePerPacket = senderStats.getAverageProcessTimePerPacket();
             averageLockWaitTimePerPacket = senderStats.getAverageLockWaitTimePerPacket();
@@ -311,9 +311,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
             averageLockWaitTimePerElement = senderStats.getAverageLockWaitTimePerElement();
             totalElementsProcessed = senderStats.getTotalElementsProcessed();
             totalPacketsProcessed = senderStats.getTotalPacketsProcessed();
-            
+
             averageElementsPerPacket = totalPacketsProcessed == 0 ? 0 : totalElementsProcessed / totalPacketsProcessed;
-            
+
             statsString += QString("               Total Inbound Packets: %1 packets\r\n")
                 .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' '));
             statsString += QString("              Total Inbound Elements: %1 elements\r\n")
@@ -330,16 +330,16 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
                 .arg(locale.toString((uint)averageProcessTimePerElement).rightJustified(COLUMN_WIDTH, ' '));
             statsString += QString("      Average Wait Lock Time/Element: %1 usecs\r\n")
                 .arg(locale.toString((uint)averageLockWaitTimePerElement).rightJustified(COLUMN_WIDTH, ' '));
-            
+
         }
-        
+
         statsString += "\r\n\r\n";
-        
+
         // display memory usage stats
         statsString += "Current Memory Usage Statistics\r\n";
         statsString += QString().sprintf("\r\nOctreeElement size... %ld bytes\r\n", sizeof(OctreeElement));
         statsString += "\r\n";
-        
+
         const char* memoryScaleLabel;
         const float MEGABYTES = 1000000.f;
         const float GIGABYTES = 1000000000.f;
@@ -351,7 +351,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
             memoryScaleLabel = "GB";
             memoryScale = GIGABYTES;
         }
-        
+
         statsString += QString().sprintf("Element Node Memory Usage:       %8.2f %s\r\n",
                                          OctreeElement::getVoxelMemoryUsage() / memoryScale, memoryScaleLabel);
         statsString += QString().sprintf("Octcode Memory Usage:            %8.2f %s\r\n",
@@ -362,7 +362,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         statsString += QString().sprintf("                         Total:  %8.2f %s\r\n",
                                          OctreeElement::getTotalMemoryUsage() / memoryScale, memoryScaleLabel);
         statsString += "\r\n";
-        
+
         statsString += "OctreeElement Children Population Statistics...\r\n";
         checkSum = 0;
         for (int i=0; i <= NUMBER_OF_CHILDREN; i++) {
@@ -374,11 +374,11 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         statsString += "                                ----------------------\r\n";
         statsString += QString("                    Total:      %1 nodes\r\n")
             .arg(locale.toString((uint)checkSum).rightJustified(16, ' '));
-        
+
 #ifdef BLENDED_UNION_CHILDREN
         statsString += "\r\n";
         statsString += "OctreeElement Children Encoding Statistics...\r\n";
-        
+
         statsString += QString().sprintf("    Single or No Children:      %10.llu nodes (%5.2f%%)\r\n",
                                          OctreeElement::getSingleChildrenCount(),
                                          ((float)OctreeElement::getSingleChildrenCount() / (float)nodeCount) * AS_PERCENT));
@@ -397,31 +397,31 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
         statsString += QString().sprintf("    Children as External Array: %10.llu nodes (%5.2f%%)\r\n",
                                          OctreeElement::getExternalChildrenCount(),
                                          ((float)OctreeElement::getExternalChildrenCount() / (float)nodeCount) * AS_PERCENT);
-        
+
         checkSum = OctreeElement::getSingleChildrenCount() +
         OctreeElement::getTwoChildrenOffsetCount() + OctreeElement::getTwoChildrenExternalCount() +
         OctreeElement::getThreeChildrenOffsetCount() + OctreeElement::getThreeChildrenExternalCount() +
         OctreeElement::getExternalChildrenCount();
-        
+
         statsString += "                                ----------------\r\n";
         statsString += QString().sprintf("                         Total: %10.llu nodes\r\n", checkSum);
         statsString += QString().sprintf("                      Expected: %10.lu nodes\r\n", nodeCount);
-        
+
         statsString += "\r\n";
         statsString += "In other news....\r\n";
-        
+
         statsString += QString().sprintf("could store 4 children internally:     %10.llu nodes\r\n",
                                          OctreeElement::getCouldStoreFourChildrenInternally());
         statsString += QString().sprintf("could NOT store 4 children internally: %10.llu nodes\r\n",
                                          OctreeElement::getCouldNotStoreFourChildrenInternally());
 #endif
-        
+
         statsString += "\r\n\r\n";
         statsString += "
\r\n"; statsString += "
"; - + connection->respond(HTTPConnection::StatusCode200, qPrintable(statsString), "text/html"); - + return true; } else { // have HTTPManager attempt to process this request from the document_root diff --git a/libraries/octree-server/src/OctreeServer.h b/libraries/octree-server/src/OctreeServer.h index 7e9538f38c..c68f09b6e0 100644 --- a/libraries/octree-server/src/OctreeServer.h +++ b/libraries/octree-server/src/OctreeServer.h @@ -27,7 +27,7 @@ /// Handles assignments of type OctreeServer - sending octrees to various clients. class OctreeServer : public ThreadedAssignment, public HTTPRequestHandler { Q_OBJECT -public: +public: OctreeServer(const unsigned char* dataBuffer, int numBytes); ~OctreeServer(); @@ -58,27 +58,27 @@ public: // subclass may implement these method virtual void beforeRun() { }; - virtual bool hasSpecialPacketToSend() { return false; } + virtual bool hasSpecialPacketToSend(Node* node) { return false; } virtual int sendSpecialPacket(Node* node) { return 0; } static void attachQueryNodeToNode(Node* newNode); - + bool handleHTTPRequest(HTTPConnection* connection, const QString& path); public slots: /// runs the voxel server assignment void run(); void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); - + void nodeKilled(SharedNodePointer node); protected: void parsePayload(); void initHTTPManager(int port); - + int _argc; const char** _argv; char** _parsedArgV; - + HTTPManager* _httpManager; char _persistFilename[MAX_FILENAME_LENGTH]; @@ -94,9 +94,9 @@ protected: OctreePersistThread* _persistThread; static OctreeServer* _instance; - + time_t _started; - uint64_t _startedUSecs; + uint64_t _startedUSecs; }; #endif // __octree_server__OctreeServer__ diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index c090ea1512..dad97b18cd 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1367,7 +1367,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) { PACKET_TYPE expectedType = expectedDataPacketType(); PACKET_VERSION expectedVersion = versionForPacketType(expectedType); file.write(&expectedType, sizeof(expectedType)); - file.write(&expectedVersion, sizeof(expectedType)); + file.write(&expectedVersion, sizeof(expectedVersion)); } OctreeElementBag nodeBag; diff --git a/libraries/particle-server/src/ParticleNodeData.h b/libraries/particle-server/src/ParticleNodeData.h index 991c4c063c..5d6655f505 100644 --- a/libraries/particle-server/src/ParticleNodeData.h +++ b/libraries/particle-server/src/ParticleNodeData.h @@ -15,8 +15,17 @@ class ParticleNodeData : public OctreeQueryNode { public: - ParticleNodeData(Node* owningNode) : OctreeQueryNode(owningNode) { }; + ParticleNodeData(Node* owningNode) : + OctreeQueryNode(owningNode), + _lastDeletedParticlesSentAt(0) { }; + virtual PACKET_TYPE getMyPacketType() const { return PACKET_TYPE_PARTICLE_DATA; } + + uint64_t getLastDeletedParticlesSentAt() const { return _lastDeletedParticlesSentAt; } + void setLastDeletedParticlesSentAt(uint64_t sentAt) { _lastDeletedParticlesSentAt = sentAt; } + +private: + uint64_t _lastDeletedParticlesSentAt; }; #endif /* defined(__hifi__ParticleNodeData__) */ diff --git a/libraries/particle-server/src/ParticleServer.cpp b/libraries/particle-server/src/ParticleServer.cpp index b1b46b3133..f30ddfa931 100644 --- a/libraries/particle-server/src/ParticleServer.cpp +++ b/libraries/particle-server/src/ParticleServer.cpp @@ -6,6 +6,7 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include #include #include "ParticleServer.h" @@ -36,7 +37,10 @@ Octree* ParticleServer::createTree() { } void ParticleServer::beforeRun() { - // nothing special to do... + QTimer* pruneDeletedParticlesTimer = new QTimer(this); + connect(pruneDeletedParticlesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedParticles())); + const int PRUNE_DELETED_PARTICLES_INTERVAL_MSECS = 1 * 1000; // once every second + pruneDeletedParticlesTimer->start(PRUNE_DELETED_PARTICLES_INTERVAL_MSECS); } void ParticleServer::particleCreated(const Particle& newParticle, Node* node) { @@ -46,20 +50,89 @@ void ParticleServer::particleCreated(const Particle& newParticle, Node* node) { int numBytesPacketHeader = populateTypeAndVersion(outputBuffer, PACKET_TYPE_PARTICLE_ADD_RESPONSE); int packetLength = numBytesPacketHeader; copyAt += numBytesPacketHeader; - + // encode the creatorTokenID uint32_t creatorTokenID = newParticle.getCreatorTokenID(); memcpy(copyAt, &creatorTokenID, sizeof(creatorTokenID)); copyAt += sizeof(creatorTokenID); packetLength += sizeof(creatorTokenID); - + // encode the particle ID uint32_t particleID = newParticle.getID(); memcpy(copyAt, &particleID, sizeof(particleID)); copyAt += sizeof(particleID); packetLength += sizeof(particleID); - + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) outputBuffer, packetLength, node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); } + + +// ParticleServer will use the "special packets" to send list of recently deleted particles +bool ParticleServer::hasSpecialPacketToSend(Node* node) { + bool shouldSendDeletedParticles = false; + + // check to see if any new particles have been added since we last sent to this node... + ParticleNodeData* nodeData = static_cast(node->getLinkedData()); + if (nodeData) { + uint64_t deletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt(); + + ParticleTree* tree = static_cast(_tree); + shouldSendDeletedParticles = tree->hasParitclesDeletedSince(deletedParticlesSentAt); + } + + return shouldSendDeletedParticles; +} + +int ParticleServer::sendSpecialPacket(Node* node) { + unsigned char outputBuffer[MAX_PACKET_SIZE]; + size_t packetLength = 0; + + ParticleNodeData* nodeData = static_cast(node->getLinkedData()); + if (nodeData) { + uint64_t deletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt(); + uint64_t deletePacketSentAt = usecTimestampNow(); + + ParticleTree* tree = static_cast(_tree); + bool hasMoreToSend = true; + + // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 particles? + while (hasMoreToSend) { + hasMoreToSend = tree->encodeParitclesDeletedSince(deletedParticlesSentAt, + outputBuffer, MAX_PACKET_SIZE, packetLength); + + //qDebug() << "sending PACKET_TYPE_PARTICLE_ERASE packetLength:" << packetLength; + + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) outputBuffer, packetLength, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); + } + + nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt); + } + + // TODO: caller is expecting a packetLength, what if we send more than one packet?? + return packetLength; +} + +void ParticleServer::pruneDeletedParticles() { + ParticleTree* tree = static_cast(_tree); + if (tree->hasAnyDeletedParitcles()) { + + //qDebug() << "there are some deleted particles to consider..."; + uint64_t earliestLastDeletedParticlesSent = usecTimestampNow() + 1; // in the future + foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) { + if (otherNode->getLinkedData()) { + ParticleNodeData* nodeData = static_cast(otherNode->getLinkedData()); + uint64_t nodeLastDeletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt(); + if (nodeLastDeletedParticlesSentAt < earliestLastDeletedParticlesSent) { + earliestLastDeletedParticlesSent = nodeLastDeletedParticlesSentAt; + } + } + } + //qDebug() << "earliestLastDeletedParticlesSent=" << earliestLastDeletedParticlesSent; + tree->forgetParitclesDeletedBefore(earliestLastDeletedParticlesSent); + } +} + diff --git a/libraries/particle-server/src/ParticleServer.h b/libraries/particle-server/src/ParticleServer.h index 5ace2ef7fc..e925d4e9ce 100644 --- a/libraries/particle-server/src/ParticleServer.h +++ b/libraries/particle-server/src/ParticleServer.h @@ -18,11 +18,12 @@ /// Handles assignments of type ParticleServer - sending particles to various clients. class ParticleServer : public OctreeServer, public NewlyCreatedParticleHook { -public: + Q_OBJECT +public: ParticleServer(const unsigned char* dataBuffer, int numBytes); ~ParticleServer(); - // Subclasses must implement these methods + // Subclasses must implement these methods virtual OctreeQueryNode* createOctreeQueryNode(Node* newNode); virtual Octree* createTree(); virtual unsigned char getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; } @@ -30,12 +31,17 @@ public: virtual const char* getMyServerName() const { return PARTICLE_SERVER_NAME; } virtual const char* getMyLoggingServerTargetName() const { return PARTICLE_SERVER_LOGGING_TARGET_NAME; } virtual const char* getMyDefaultPersistFilename() const { return LOCAL_PARTICLES_PERSIST_FILE; } - + // subclass may implement these method virtual void beforeRun(); + virtual bool hasSpecialPacketToSend(Node* node); + virtual int sendSpecialPacket(Node* node); virtual void particleCreated(const Particle& newParticle, Node* senderNode); +public slots: + void pruneDeletedParticles(); + private: }; diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index d3677323e4..4911be7104 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -29,6 +29,48 @@ bool ParticleTree::handlesEditPacketType(PACKET_TYPE packetType) const { return false; } +class FindAndDeleteParticlesArgs { +public: + QList _idsToDelete; +}; + +bool ParticleTree::findAndDeleteOperation(OctreeElement* element, void* extraData) { + //qDebug() << "findAndDeleteOperation()"; + + FindAndDeleteParticlesArgs* args = static_cast< FindAndDeleteParticlesArgs*>(extraData); + + // if we've found and deleted all our target particles, then we can stop looking + if (args->_idsToDelete.size() <= 0) { + return false; + } + + ParticleTreeElement* particleTreeElement = static_cast(element); + + //qDebug() << "findAndDeleteOperation() args->_idsToDelete.size():" << args->_idsToDelete.size(); + + for (QList::iterator it = args->_idsToDelete.begin(); it != args->_idsToDelete.end(); it++) { + uint32_t particleID = *it; + //qDebug() << "findAndDeleteOperation() particleID:" << particleID; + + if (particleTreeElement->removeParticleWithID(particleID)) { + // if the particle was in this element, then remove it from our search list. + //qDebug() << "findAndDeleteOperation() it = args->_idsToDelete.erase(it)"; + it = args->_idsToDelete.erase(it); + } + + if (it == args->_idsToDelete.end()) { + //qDebug() << "findAndDeleteOperation() breaking"; + break; + } + } + + // if we've found and deleted all our target particles, then we can stop looking + if (args->_idsToDelete.size() <= 0) { + return false; + } + return true; +} + class FindAndUpdateParticleArgs { public: @@ -172,21 +214,17 @@ int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* p // we handle these types of "edit" packets switch (packetType) { case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: { - -qDebug() << " got PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; - + //qDebug() << " got PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this); -qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling storeParticle() "; storeParticle(newParticle, senderNode); -qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER storeParticle() newParticle.getShouldDie()=" << newParticle.getShouldDie(); if (newParticle.isNewlyCreated()) { -qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling notifyNewlyCreatedParticle() "; notifyNewlyCreatedParticle(newParticle, senderNode); -qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER notifyNewlyCreatedParticle() "; } -qDebug() << " DONE... PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; + //qDebug() << " DONE... PACKET_TYPE_PARTICLE_ADD_OR_EDIT... "; } break; + // TODO: wire in support here for server to get PACKET_TYPE_PARTICLE_ERASE messages + // instead of using PACKET_TYPE_PARTICLE_ADD_OR_EDIT messages to delete particles case PACKET_TYPE_PARTICLE_ERASE: { processedBytes = 0; } break; @@ -254,6 +292,12 @@ void ParticleTree::update() { if (!shouldDie && treeBounds.contains(args._movingParticles[i].getPosition())) { storeParticle(args._movingParticles[i]); + } else { + uint32_t particleID = args._movingParticles[i].getID(); + uint64_t deletedAt = usecTimestampNow(); + _recentlyDeletedParticlesLock.lockForWrite(); + _recentlyDeletedParticleIDs.insert(deletedAt, particleID); + _recentlyDeletedParticlesLock.unlock(); } } @@ -262,3 +306,143 @@ void ParticleTree::update() { } +bool ParticleTree::hasParitclesDeletedSince(uint64_t sinceTime) { + // we can probably leverage the ordered nature of QMultiMap to do this quickly... + bool hasSomethingNewer = false; + + _recentlyDeletedParticlesLock.lockForRead(); + QMultiMap::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin(); + while (iterator != _recentlyDeletedParticleIDs.constEnd()) { + //qDebug() << "considering... time/key:" << iterator.key(); + if (iterator.key() > sinceTime) { + //qDebug() << "YES newer... time/key:" << iterator.key(); + hasSomethingNewer = true; + } + ++iterator; + } + _recentlyDeletedParticlesLock.unlock(); + return hasSomethingNewer; +} + +// sinceTime is an in/out parameter - it will be side effected with the last time sent out +bool ParticleTree::encodeParitclesDeletedSince(uint64_t& sinceTime, unsigned char* outputBuffer, size_t maxLength, + size_t& outputLength) { + + bool hasMoreToSend = true; + + unsigned char* copyAt = outputBuffer; + size_t numBytesPacketHeader = populateTypeAndVersion(outputBuffer, PACKET_TYPE_PARTICLE_ERASE); + copyAt += numBytesPacketHeader; + outputLength = numBytesPacketHeader; + + uint16_t numberOfIds = 0; // placeholder for now + unsigned char* numberOfIDsAt = copyAt; + memcpy(copyAt, &numberOfIds, sizeof(numberOfIds)); + copyAt += sizeof(numberOfIds); + outputLength += sizeof(numberOfIds); + + // we keep a multi map of particle IDs to timestamps, we only want to include the particle IDs that have been + // deleted since we last sent to this node + _recentlyDeletedParticlesLock.lockForRead(); + QMultiMap::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin(); + while (iterator != _recentlyDeletedParticleIDs.constEnd()) { + QList values = _recentlyDeletedParticleIDs.values(iterator.key()); + for (int valueItem = 0; valueItem < values.size(); ++valueItem) { + //qDebug() << "considering... " << iterator.key() << ": " << values.at(valueItem); + + // if the timestamp is more recent then out last sent time, include it + if (iterator.key() > sinceTime) { + //qDebug() << "including... " << iterator.key() << ": " << values.at(valueItem); + uint32_t particleID = values.at(valueItem); + memcpy(copyAt, &particleID, sizeof(particleID)); + copyAt += sizeof(particleID); + outputLength += sizeof(particleID); + numberOfIds++; + + // check to make sure we have room for one more id... + if (outputLength + sizeof(uint32_t) > maxLength) { + break; + } + } + } + + // check to make sure we have room for one more id... + if (outputLength + sizeof(uint32_t) > maxLength) { + + // let our caller know how far we got + sinceTime = iterator.key(); + break; + } + ++iterator; + } + + // if we got to the end, then we're done sending + if (iterator == _recentlyDeletedParticleIDs.constEnd()) { + hasMoreToSend = false; + } + _recentlyDeletedParticlesLock.unlock(); + + // replace the correct count for ids included + memcpy(numberOfIDsAt, &numberOfIds, sizeof(numberOfIds)); + + return hasMoreToSend; +} + +// called by the server when it knows all nodes have been sent deleted packets +void ParticleTree::forgetParitclesDeletedBefore(uint64_t sinceTime) { + _recentlyDeletedParticlesLock.lockForWrite(); + QMultiMap::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin(); + while (iterator != _recentlyDeletedParticleIDs.constEnd()) { + //qDebug() << "considering... time/key:" << iterator.key(); + if (iterator.key() <= sinceTime) { + //qDebug() << "YES older... time/key:" << iterator.key(); + _recentlyDeletedParticleIDs.remove(iterator.key()); + } + ++iterator; + } + _recentlyDeletedParticlesLock.unlock(); +} + + +void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, + Node* sourceNode) { + //qDebug() << "ParticleTree::processEraseMessage()..."; + + const unsigned char* packetData = (const unsigned char*)dataByteArray.constData(); + const unsigned char* dataAt = packetData; + size_t packetLength = dataByteArray.size(); + + size_t numBytesPacketHeader = numBytesForPacketHeader(packetData); + size_t processedBytes = numBytesPacketHeader; + dataAt += numBytesPacketHeader; + + uint16_t numberOfIds = 0; // placeholder for now + memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); + dataAt += sizeof(numberOfIds); + processedBytes += sizeof(numberOfIds); + + //qDebug() << "got erase message for numberOfIds:" << numberOfIds; + + if (numberOfIds > 0) { + FindAndDeleteParticlesArgs args; + + for (size_t i = 0; i < numberOfIds; i++) { + if (processedBytes + sizeof(uint32_t) > packetLength) { + //qDebug() << "bailing?? processedBytes:" << processedBytes << " packetLength:" << packetLength; + break; // bail to prevent buffer overflow + } + + uint32_t particleID = 0; // placeholder for now + memcpy(&particleID, dataAt, sizeof(particleID)); + dataAt += sizeof(particleID); + processedBytes += sizeof(particleID); + + //qDebug() << "got erase message for particleID:" << particleID; + args._idsToDelete.push_back(particleID); + } + + // calling recurse to actually delete the particles + //qDebug() << "calling recurse to actually delete the particles"; + recurseTreeWithOperation(findAndDeleteOperation, &args); + } +} diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 14502ea235..38462a1ecc 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -46,6 +46,13 @@ public: void addNewlyCreatedHook(NewlyCreatedParticleHook* hook); void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook); + bool hasAnyDeletedParitcles() const { return _recentlyDeletedParticleIDs.size() > 0; } + bool hasParitclesDeletedSince(uint64_t sinceTime); + bool encodeParitclesDeletedSince(uint64_t& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); + void forgetParitclesDeletedBefore(uint64_t sinceTime); + + void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode); + private: static bool updateOperation(OctreeElement* element, void* extraData); @@ -53,11 +60,16 @@ private: static bool findNearPointOperation(OctreeElement* element, void* extraData); static bool pruneOperation(OctreeElement* element, void* extraData); static bool findByIDOperation(OctreeElement* element, void* extraData); + static bool findAndDeleteOperation(OctreeElement* element, void* extraData); void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode); QReadWriteLock _newlyCreatedHooksLock; std::vector _newlyCreatedHooks; + + + QReadWriteLock _recentlyDeletedParticlesLock; + QMultiMap _recentlyDeletedParticleIDs; }; #endif /* defined(__hifi__ParticleTree__) */ diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index 8ccadf858f..5dcae129b7 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -200,6 +200,20 @@ const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const { return foundParticle; } +bool ParticleTreeElement::removeParticleWithID(uint32_t id) { + bool foundParticle = false; + uint16_t numberOfParticles = _particles->size(); + for (uint16_t i = 0; i < numberOfParticles; i++) { + if ((*_particles)[i].getID() == id) { + foundParticle = true; + _particles->removeAt(i); + break; + } + } + return foundParticle; +} + + int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { diff --git a/libraries/particles/src/ParticleTreeElement.h b/libraries/particles/src/ParticleTreeElement.h index ab697aed1b..8493d59bb8 100644 --- a/libraries/particles/src/ParticleTreeElement.h +++ b/libraries/particles/src/ParticleTreeElement.h @@ -28,11 +28,11 @@ public: class ParticleTreeElement : public OctreeElement { friend class ParticleTree; // to allow createElement to new us... - + ParticleTreeElement(unsigned char* octalCode = NULL); virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL) const; - + public: virtual ~ParticleTreeElement(); @@ -40,31 +40,31 @@ public: ParticleTreeElement* getChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::getChildAtIndex(index); } // methods you can and should override to implement your tree functionality - + /// Adds a child to the current element. Override this if there is additional child initialization your class needs. virtual ParticleTreeElement* addChildAtIndex(int index); - /// Override this to implement LOD averaging on changes to the tree. + /// Override this to implement LOD averaging on changes to the tree. virtual void calculateAverageFromChildren(); - /// Override this to implement LOD collapsing and identical child pruning on changes to the tree. + /// Override this to implement LOD collapsing and identical child pruning on changes to the tree. virtual bool collapseChildren(); /// Should this element be considered to have content in it. This will be used in collision and ray casting methods. /// By default we assume that only leaves are actual content, but some octrees may have different semantics. virtual bool hasContent() const { return isLeaf(); } - + /// Override this to break up large octree elements when an edit operation is performed on a smaller octree element. - /// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the + /// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the /// meaningful split would be to break the larger cube into smaller cubes of the same color/texture. virtual void splitChildren() { } - + /// Override to indicate that this element requires a split before editing lower elements in the octree virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. virtual bool appendElementData(OctreePacketData* packetData) const; - + /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); @@ -76,21 +76,23 @@ public: virtual bool isRendered() const { return getShouldRender(); } virtual bool deleteApproved() const { return !hasParticles(); } - virtual bool findSpherePenetration(const glm::vec3& center, float radius, + virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; const QList& getParticles() const { return *_particles; } QList& getParticles() { return *_particles; } bool hasParticles() const { return _particles->size() > 0; } - + void update(ParticleTreeUpdateArgs& args); void setTree(ParticleTree* tree) { _myTree = tree; } - + bool containsParticle(const Particle& particle) const; bool updateParticle(const Particle& particle); const Particle* getClosestParticle(glm::vec3 position) const; const Particle* getParticleWithID(uint32_t id) const; - + + bool removeParticleWithID(uint32_t id); + protected: virtual void init(unsigned char * octalCode); diff --git a/libraries/voxel-server/src/VoxelServer.cpp b/libraries/voxel-server/src/VoxelServer.cpp index 1147718486..a1f5eaf55e 100644 --- a/libraries/voxel-server/src/VoxelServer.cpp +++ b/libraries/voxel-server/src/VoxelServer.cpp @@ -32,7 +32,7 @@ Octree* VoxelServer::createTree() { return new VoxelTree(true); } -bool VoxelServer::hasSpecialPacketToSend() { +bool VoxelServer::hasSpecialPacketToSend(Node* node) { bool shouldSendEnvironments = _sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, OCTREE_SEND_INTERVAL_USECS); return shouldSendEnvironments; } @@ -41,11 +41,11 @@ int VoxelServer::sendSpecialPacket(Node* node) { int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA); int envPacketLength = numBytesPacketHeader; int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount(); - + for (int i = 0; i < environmentsToSend; i++) { envPacketLength += getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength); } - + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) _tempOutputBuffer, envPacketLength, node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); diff --git a/libraries/voxel-server/src/VoxelServer.h b/libraries/voxel-server/src/VoxelServer.h index e785d2f65e..316280e37c 100644 --- a/libraries/voxel-server/src/VoxelServer.h +++ b/libraries/voxel-server/src/VoxelServer.h @@ -24,7 +24,7 @@ /// Handles assignments of type VoxelServer - sending voxels to various clients. class VoxelServer : public OctreeServer { -public: +public: VoxelServer(const unsigned char* dataBuffer, int numBytes); ~VoxelServer(); @@ -33,7 +33,7 @@ public: EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; } int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); } - // Subclasses must implement these methods + // Subclasses must implement these methods virtual OctreeQueryNode* createOctreeQueryNode(Node* newNode); virtual Octree* createTree(); virtual unsigned char getMyNodeType() const { return NODE_TYPE_VOXEL_SERVER; } @@ -41,10 +41,10 @@ public: virtual const char* getMyServerName() const { return VOXEL_SERVER_NAME; } virtual const char* getMyLoggingServerTargetName() const { return VOXEL_SERVER_LOGGING_TARGET_NAME; } virtual const char* getMyDefaultPersistFilename() const { return LOCAL_VOXELS_PERSIST_FILE; } - + // subclass may implement these method virtual void beforeRun(); - virtual bool hasSpecialPacketToSend(); + virtual bool hasSpecialPacketToSend(Node* node); virtual int sendSpecialPacket(Node* node); From 278ca02595071e9a81a76e5b8faf4448d1dc63bb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 14:06:55 -0800 Subject: [PATCH 11/24] remove debug code --- .../src/OctreeInboundPacketProcessor.cpp | 4 +- .../octree/src/OctreeEditPacketSender.cpp | 24 ++---- libraries/particles/src/Particle.cpp | 82 +++++-------------- .../src/ParticleEditPacketSender.cpp | 9 -- .../src/ParticlesScriptingInterface.cpp | 11 ++- 5 files changed, 37 insertions(+), 93 deletions(-) diff --git a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp index 2e5872c180..e537838649 100644 --- a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp +++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp @@ -67,7 +67,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA uint64_t processTime = 0; uint64_t lockWaitTime = 0; - if (true || _myServer->wantsDebugReceiving()) { + if (_myServer->wantsDebugReceiving()) { qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client receivedBytes=" << packetLength << " sequence=" << sequence << " transitTime=" << transitTime << " usecs"; @@ -77,7 +77,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA while (atByte < packetLength) { int maxSize = packetLength - atByte; - if (true || debugProcessPacket) { + if (debugProcessPacket) { printf("OctreeInboundPacketProcessor::processPacket() %c " "packetData=%p packetLength=%ld voxelData=%p atByte=%d maxSize=%d\n", packetType, packetData, packetLength, editData, atByte, maxSize); diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 7ce7701a7d..a3d4e7862b 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -181,12 +181,7 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); if (isMyJurisdiction) { - -qDebug() << "calling queuePacketToNode(nodeUUID, buffer, length); nodeUUID=" << nodeUUID << " length=" << length; - queuePacketToNode(nodeUUID, buffer, length); - } else { -qDebug() << "not my jurisdiction skipping queuePacketToNode(nodeUUID, buffer, length); nodeUUID=" << nodeUUID << " length=" << length; } } } @@ -196,13 +191,10 @@ qDebug() << "not my jurisdiction skipping queuePacketToNode(nodeUUID, buffer, le // NOTE: codeColorBuffer - is JUST the octcode/color and does not contain the packet header! void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length) { -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; if (!_shouldSend) { return; // bail early } -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; - // If we don't have jurisdictions, then we will simply queue up all of these packets and wait till we have // jurisdictions for processing if (!serversExist()) { @@ -221,7 +213,7 @@ qDebug() << "queueOctreeEditMessage() line:" << __LINE__; return; // bail early } -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + //qDebug() << "queueOctreeEditMessage() line:" << __LINE__; // We want to filter out edit messages for servers based on the server's Jurisdiction // But we can't really do that with a packed message, since each edit message could be destined @@ -240,17 +232,17 @@ qDebug() << "queueOctreeEditMessage() line:" << __LINE__; if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); -qDebug() << "queueOctreeEditMessage() line:" << __LINE__ << " isMyJurisdiction=" << isMyJurisdiction; + //qDebug() << "queueOctreeEditMessage() line:" << __LINE__ << " isMyJurisdiction=" << isMyJurisdiction; } else { isMyJurisdiction = false; -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + //qDebug() << "queueOctreeEditMessage() line:" << __LINE__; } } if (isMyJurisdiction) { EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID]; packetBuffer._nodeUUID = nodeUUID; -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + //qDebug() << "queueOctreeEditMessage() line:" << __LINE__; // If we're switching type, then we send the last one and start over if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || @@ -270,10 +262,10 @@ qDebug() << "queueOctreeEditMessage() line:" << __LINE__; // fixup the buffer for any clock skew if (node->getClockSkewUsec() != 0) { adjustEditPacketForClockSkew(codeColorBuffer, length, node->getClockSkewUsec()); -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + //qDebug() << "queueOctreeEditMessage() line:" << __LINE__; } -qDebug() << "queueOctreeEditMessage() line:" << __LINE__; + //qDebug() << "queueOctreeEditMessage() line:" << __LINE__; memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length); packetBuffer._currentSize += length; @@ -291,14 +283,14 @@ void OctreeEditPacketSender::releaseQueuedMessages() { } else { for (std::map::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) { releaseQueuedPacket(i->second); -qDebug() << "releaseQueuedMessages() line:" << __LINE__; + //qDebug() << "releaseQueuedMessages() line:" << __LINE__; } } } void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) { if (packetBuffer._currentSize > 0 && packetBuffer._currentType != PACKET_TYPE_UNKNOWN) { -qDebug() << "OctreeEditPacketSender::releaseQueuedPacket() line:" << __LINE__; + //qDebug() << "OctreeEditPacketSender::releaseQueuedPacket() line:" << __LINE__; queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize); } packetBuffer._currentSize = 0; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 5551e51fcd..b26494d680 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -58,7 +58,7 @@ void Particle::handleAddParticleResponse(unsigned char* packetData , int packetL memcpy(&particleID, dataAt, sizeof(particleID)); dataAt += sizeof(particleID); -qDebug() << "handleAddParticleResponse()... particleID=" << particleID << " creatorTokenID=" << creatorTokenID; + //qDebug() << "handleAddParticleResponse()... particleID=" << particleID << " creatorTokenID=" << creatorTokenID; // add our token to id mapping _tokenIDsToIDs[creatorTokenID] = particleID; @@ -86,10 +86,10 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 if (id == NEW_PARTICLE) { _id = _nextID; _nextID++; -qDebug() << "Particle::init()... assigning new id... _id=" << _id; + //qDebug() << "Particle::init()... assigning new id... _id=" << _id; } else { _id = id; -qDebug() << "Particle::init()... assigning id from init... _id=" << _id; + //qDebug() << "Particle::init()... assigning id from init... _id=" << _id; } uint64_t now = usecTimestampNow(); _lastEdited = now; @@ -154,12 +154,9 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { if (success) { success = packetData->appendValue(getInHand()); } -/** if (success) { -qDebug() << "appendParticleData().... getShouldDie()=" << getShouldDie(); success = packetData->appendValue(getShouldDie()); } -**/ if (success) { uint16_t scriptLength = _script.size() + 1; // include NULL @@ -274,15 +271,11 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef dataAt += sizeof(_inHand); bytesRead += sizeof(_inHand); -/** // shouldDie memcpy(&_shouldDie, dataAt, sizeof(_shouldDie)); dataAt += sizeof(_shouldDie); bytesRead += sizeof(_shouldDie); -qDebug() << "readParticleDataFromBuffer().... _shouldDie()=" << _shouldDie; -**/ - // script uint16_t scriptLength; memcpy(&scriptLength, dataAt, sizeof(scriptLength)); @@ -301,7 +294,7 @@ qDebug() << "readParticleDataFromBuffer().... _shouldDie()=" << _shouldDie; Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree) { -qDebug() << "Particle::fromEditPacket() length=" << length; + //qDebug() << "Particle::fromEditPacket() length=" << length; Particle newParticle; // id and _lastUpdated will get set here... unsigned char* dataAt = data; @@ -311,8 +304,8 @@ qDebug() << "Particle::fromEditPacket() length=" << length; int octets = numberOfThreeBitSectionsInCode(data); int lengthOfOctcode = bytesRequiredForCodeLength(octets); -qDebug() << "Particle::fromEditPacket() lengthOfOctcode=" << lengthOfOctcode; -printOctalCode(data); + //qDebug() << "Particle::fromEditPacket() lengthOfOctcode=" << lengthOfOctcode; + //printOctalCode(data); // we don't actually do anything with this octcode... dataAt += lengthOfOctcode; @@ -324,13 +317,14 @@ printOctalCode(data); dataAt += sizeof(editID); processedBytes += sizeof(editID); -qDebug() << "editID:" << editID; + //qDebug() << "editID:" << editID; bool isNewParticle = (editID == NEW_PARTICLE); // special case for handling "new" particles if (isNewParticle) { -qDebug() << "editID == NEW_PARTICLE"; + //qDebug() << "editID == NEW_PARTICLE"; + // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that // we want to send back to the creator as an map to the actual id uint32_t creatorTokenID; @@ -338,7 +332,7 @@ qDebug() << "editID == NEW_PARTICLE"; dataAt += sizeof(creatorTokenID); processedBytes += sizeof(creatorTokenID); -qDebug() << "creatorTokenID:" << creatorTokenID; + //qDebug() << "creatorTokenID:" << creatorTokenID; newParticle.setCreatorTokenID(creatorTokenID); newParticle._newlyCreated = true; @@ -352,10 +346,8 @@ qDebug() << "creatorTokenID:" << creatorTokenID; // copy existing properties before over-writing with new properties if (existingParticle) { newParticle = *existingParticle; - -qDebug() << "newParticle = *existingParticle... calling debugDump()..."; - - existingParticle->debugDump(); + //qDebug() << "newParticle = *existingParticle... calling debugDump()..."; + //existingParticle->debugDump(); } newParticle._id = editID; @@ -368,8 +360,6 @@ qDebug() << "newParticle = *existingParticle... calling debugDump()..."; memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited)); dataAt += sizeof(newParticle._lastEdited); processedBytes += sizeof(newParticle._lastEdited); -qDebug() << "newParticle._lastEdited:" << newParticle._lastEdited; - // All of the remaining items are optional, and may or may not be included based on their included values in the // properties included bits @@ -378,7 +368,7 @@ qDebug() << "newParticle._lastEdited:" << newParticle._lastEdited; memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits)); dataAt += sizeof(packetContainsBits); processedBytes += sizeof(packetContainsBits); - qDebug() << "packetContainsBits:" << packetContainsBits; + //qDebug() << "packetContainsBits:" << packetContainsBits; } @@ -387,7 +377,6 @@ qDebug() << "newParticle._lastEdited:" << newParticle._lastEdited; memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); dataAt += sizeof(newParticle._radius); processedBytes += sizeof(newParticle._radius); -qDebug() << "newParticle._radius:" << newParticle._radius; } // position @@ -395,7 +384,6 @@ qDebug() << "newParticle._radius:" << newParticle._radius; memcpy(&newParticle._position, dataAt, sizeof(newParticle._position)); dataAt += sizeof(newParticle._position); processedBytes += sizeof(newParticle._position); -qDebug() << "newParticle._position:"; } // color @@ -403,7 +391,6 @@ qDebug() << "newParticle._position:"; memcpy(newParticle._color, dataAt, sizeof(newParticle._color)); dataAt += sizeof(newParticle._color); processedBytes += sizeof(newParticle._color); -qDebug() << "newParticle._color:"; } // velocity @@ -411,7 +398,6 @@ qDebug() << "newParticle._color:"; memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity)); dataAt += sizeof(newParticle._velocity); processedBytes += sizeof(newParticle._velocity); -qDebug() << "newParticle._velocity:"; } // gravity @@ -419,7 +405,6 @@ qDebug() << "newParticle._velocity:"; memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity)); dataAt += sizeof(newParticle._gravity); processedBytes += sizeof(newParticle._gravity); -qDebug() << "newParticle._gravity:"; } // damping @@ -427,7 +412,6 @@ qDebug() << "newParticle._gravity:"; memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping)); dataAt += sizeof(newParticle._damping); processedBytes += sizeof(newParticle._damping); -qDebug() << "newParticle._damping:" << newParticle._damping; } // lifetime @@ -435,7 +419,6 @@ qDebug() << "newParticle._damping:" << newParticle._damping; memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime)); dataAt += sizeof(newParticle._lifetime); processedBytes += sizeof(newParticle._lifetime); -qDebug() << "newParticle._lifetime:" << newParticle._lifetime; } // TODO: make inHand and shouldDie into single bits @@ -444,18 +427,14 @@ qDebug() << "newParticle._lifetime:" << newParticle._lifetime; memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand)); dataAt += sizeof(newParticle._inHand); processedBytes += sizeof(newParticle._inHand); -qDebug() << "newParticle._inHand:" << newParticle._inHand; } -/** // shouldDie if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SHOULDDIE) == PACKET_CONTAINS_SHOULDDIE)) { memcpy(&newParticle._shouldDie, dataAt, sizeof(newParticle._shouldDie)); dataAt += sizeof(newParticle._shouldDie); processedBytes += sizeof(newParticle._shouldDie); -qDebug() << "fromEditPacket().... newParticle._shouldDie=" << newParticle._shouldDie; } -**/ // script if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT)) { @@ -467,10 +446,9 @@ qDebug() << "fromEditPacket().... newParticle._shouldDie=" << newParticle._shoul newParticle._script = tempString; dataAt += scriptLength; processedBytes += scriptLength; -qDebug() << "newParticle._script:" << newParticle._script; } - const bool wantDebugging = true; + const bool wantDebugging = false; if (wantDebugging) { qDebug("Particle::fromEditPacket()..."); qDebug() << " Particle id in packet:" << editID; @@ -507,8 +485,9 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID float rootScale = 0.5f; unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale); - // old code... this matters for particle servers with different jurisdictions, but for now, we'll send - // everything to the root, since the tree does the right thing... + // TODO: Consider this old code... including the correct octree for where the particle will go matters for + // particle servers with different jurisdictions, but for now, we'll send everything to the root, since the + // tree does the right thing... // //unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y, // details[i].position.z, details[i].radius); @@ -533,17 +512,14 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID memcpy(copyAt, &id.id, sizeof(id.id)); copyAt += sizeof(id.id); sizeOut += sizeof(id.id); -qDebug() << "encoding, id.id:" << id.id; // special case for handling "new" particles if (isNewParticle) { -qDebug() << "encodeParticleEditMessageDetails()... isNewParticle..."; // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that // we want to send back to the creator as an map to the actual id memcpy(copyAt, &id.creatorTokenID, sizeof(id.creatorTokenID)); copyAt += sizeof(id.creatorTokenID); sizeOut += sizeof(id.creatorTokenID); -qDebug() << "encoding, id.creatorTokenID:" << id.creatorTokenID; } // lastEdited @@ -551,8 +527,6 @@ qDebug() << "encoding, id.creatorTokenID:" << id.creatorTokenID; memcpy(copyAt, &lastEdited, sizeof(lastEdited)); copyAt += sizeof(lastEdited); sizeOut += sizeof(lastEdited); -qDebug() << "encoding, lastEdited:" << lastEdited; - // For new particles, all remaining items are mandatory, for an edited particle, All of the remaining items are // optional, and may or may not be included based on their included values in the properties included bits @@ -561,7 +535,6 @@ qDebug() << "encoding, lastEdited:" << lastEdited; memcpy(copyAt, &packetContainsBits, sizeof(packetContainsBits)); copyAt += sizeof(packetContainsBits); sizeOut += sizeof(packetContainsBits); -qDebug() << "encoding, packetContainsBits:" << packetContainsBits; } // radius @@ -570,7 +543,6 @@ qDebug() << "encoding, packetContainsBits:" << packetContainsBits; memcpy(copyAt, &radius, sizeof(radius)); copyAt += sizeof(radius); sizeOut += sizeof(radius); -qDebug() << "encoding, radius:" << radius; } // position @@ -578,7 +550,6 @@ qDebug() << "encoding, radius:" << radius; memcpy(copyAt, &properties.getPosition(), sizeof(properties.getPosition())); copyAt += sizeof(properties.getPosition()); sizeOut += sizeof(properties.getPosition()); -qDebug() << "encoding, properties.getPosition():"; } // color @@ -587,7 +558,6 @@ qDebug() << "encoding, properties.getPosition():"; memcpy(copyAt, color, sizeof(color)); copyAt += sizeof(color); sizeOut += sizeof(color); -qDebug() << "encoding, color:"; } // velocity @@ -595,7 +565,6 @@ qDebug() << "encoding, color:"; memcpy(copyAt, &properties.getVelocity(), sizeof(properties.getVelocity())); copyAt += sizeof(properties.getVelocity()); sizeOut += sizeof(properties.getVelocity()); -qDebug() << "encoding, getVelocity:"; } // gravity @@ -603,7 +572,6 @@ qDebug() << "encoding, getVelocity:"; memcpy(copyAt, &properties.getGravity(), sizeof(properties.getGravity())); copyAt += sizeof(properties.getGravity()); sizeOut += sizeof(properties.getGravity()); -qDebug() << "encoding, getGravity():"; } // damping @@ -612,7 +580,6 @@ qDebug() << "encoding, getGravity():"; memcpy(copyAt, &damping, sizeof(damping)); copyAt += sizeof(damping); sizeOut += sizeof(damping); -qDebug() << "encoding, damping:" << damping; } // lifetime @@ -621,7 +588,6 @@ qDebug() << "encoding, damping:" << damping; memcpy(copyAt, &lifetime, sizeof(lifetime)); copyAt += sizeof(lifetime); sizeOut += sizeof(lifetime); -qDebug() << "encoding, lifetime:" << lifetime; } // inHand @@ -630,19 +596,15 @@ qDebug() << "encoding, lifetime:" << lifetime; memcpy(copyAt, &inHand, sizeof(inHand)); copyAt += sizeof(inHand); sizeOut += sizeof(inHand); -qDebug() << "encoding, inHand:" << inHand; } -/** // shoulDie if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SHOULDDIE) == PACKET_CONTAINS_SHOULDDIE)) { bool shouldDie = properties.getShouldDie(); memcpy(copyAt, &shouldDie, sizeof(shouldDie)); copyAt += sizeof(shouldDie); sizeOut += sizeof(shouldDie); -qDebug() << "encoding, shouldDie:" << shouldDie; } -**/ // script if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT)) { @@ -653,7 +615,6 @@ qDebug() << "encoding, shouldDie:" << shouldDie; memcpy(copyAt, qPrintable(properties.getScript()), scriptLength); copyAt += scriptLength; sizeOut += scriptLength; -qDebug() << "encoding, getScript:" << properties.getScript(); } bool wantDebugging = false; @@ -666,8 +627,8 @@ qDebug() << "encoding, getScript:" << properties.getScript(); // cleanup delete[] octcode; - -qDebug() << "encoding... sizeOut:" << sizeOut; + + //qDebug() << "encoding... sizeOut:" << sizeOut; return success; } @@ -721,8 +682,6 @@ void Particle::update(const uint64_t& now) { bool shouldDie = getShouldDie() || (!isInHand && isStopped && isReallyOld); setShouldDie(shouldDie); -//qDebug() << "update()... getShouldDie()=" << getShouldDie(); - runUpdateScript(); // allow the javascript to alter our state // If the ball is in hand, it doesn't move or have gravity effect it @@ -931,12 +890,11 @@ uint16_t ParticleProperties::getChangedBits() const { changedBits += PACKET_CONTAINS_SCRIPT; } -/** // how do we want to handle this? if (_shouldDieChanged) { changedBits += PACKET_CONTAINS_SHOULDDIE; } -**/ + return changedBits; } diff --git a/libraries/particles/src/ParticleEditPacketSender.cpp b/libraries/particles/src/ParticleEditPacketSender.cpp index 65734f97a5..f745adc05b 100644 --- a/libraries/particles/src/ParticleEditPacketSender.cpp +++ b/libraries/particles/src/ParticleEditPacketSender.cpp @@ -32,9 +32,6 @@ void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, Particl if (!serversExist()) { queuePendingPacketToNodes(type, bufferOut, sizeOut); } else { - -qDebug("calling queuePacketToNodes(bufferOut, sizeOut=%d)... ", sizeOut); - queuePacketToNodes(bufferOut, sizeOut); } } @@ -46,9 +43,6 @@ void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeC void ParticleEditPacketSender::queueParticleEditMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties) { - -qDebug() << "ParticleEditPacketSender::queueParticleEditMessage() id.id=" << particleID.id << " id.creatorTokenID=" << particleID.creatorTokenID; - if (!_shouldSend) { return; // bail early } @@ -58,9 +52,6 @@ qDebug() << "ParticleEditPacketSender::queueParticleEditMessage() id.id=" << par int sizeOut = 0; if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) { - -qDebug("calling queueOctreeEditMessage(bufferOut, sizeOut=%d)... ", sizeOut); - queueOctreeEditMessage(type, bufferOut, sizeOut); } } diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index ed8883d9b0..7bec62e7b1 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -46,12 +46,15 @@ void ParticlesScriptingInterface::editParticle(ParticleID particleID, const Part } +// TODO: This deleteParticle() method uses the PACKET_TYPE_PARTICLE_ADD_OR_EDIT message to send +// a changed particle with a shouldDie() property set to true. This works and is currently the only +// way to tell the particle server to delete a particle. But we should change this to use the PACKET_TYPE_PARTICLE_ERASE +// message which takes a list of particle id's to delete. void ParticlesScriptingInterface::deleteParticle(ParticleID particleID) { // setup properties to kill the particle ParticleProperties properties; - properties.setScript("print('here'); Particle.setShouldDie(true);"); - //properties.setShouldDie(true); + properties.setShouldDie(true); uint32_t actualID = particleID.id; if (!particleID.isKnownID) { @@ -59,7 +62,7 @@ void ParticlesScriptingInterface::deleteParticle(ParticleID particleID) { // hmmm... we kind of want to bail if someone attempts to edit an unknown if (actualID == UNKNOWN_PARTICLE_ID) { -qDebug() << "ParticlesScriptingInterface::deleteParticle(), bailing - unknown particle..."; + //qDebug() << "ParticlesScriptingInterface::deleteParticle(), bailing - unknown particle..."; return; // bailing early } } @@ -67,6 +70,6 @@ qDebug() << "ParticlesScriptingInterface::deleteParticle(), bailing - unknown pa particleID.id = actualID; particleID.isKnownID = true; -qDebug() << "ParticlesScriptingInterface::deleteParticle(), queueParticleMessage......"; + //qDebug() << "ParticlesScriptingInterface::deleteParticle(), queueParticleMessage......"; queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties); } From 03a9253748e4fdf1914e9348a5be9896b546b7ad Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 14:07:46 -0800 Subject: [PATCH 12/24] remove usage of ParticleEditHandle from application --- interface/src/Application.cpp | 63 ----------- interface/src/Application.h | 6 - interface/src/avatar/Hand.cpp | 200 +--------------------------------- interface/src/avatar/Hand.h | 13 --- 4 files changed, 1 insertion(+), 281 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1f1311d714..02902ab37b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -652,8 +652,6 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); switch (event->key()) { - case Qt::Key_N: - shootParticle(); break; case Qt::Key_Shift: if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) { @@ -1503,63 +1501,6 @@ void Application::removeVoxel(glm::vec3 position, _voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); } -void Application::shootParticle() { - - glm::vec3 position = _viewFrustum.getPosition(); - glm::vec3 direction = _viewFrustum.getDirection(); - const float LINEAR_VELOCITY = 5.f; - glm::vec3 lookingAt = position + (direction * LINEAR_VELOCITY); - - const float radius = 0.125 / TREE_SCALE; - xColor color = { 0, 255, 255}; - glm::vec3 velocity = lookingAt - position; - glm::vec3 gravity = DEFAULT_GRAVITY * 0.01f; - float damping = DEFAULT_DAMPING * 0.01f; - float lifetime = 5.0f; // bullets have 5 second lifetime - QString script( - " function collisionWithVoxel(voxel) { " - " print('collisionWithVoxel(voxel)... '); " - " print('myID=' + Particle.getID()); " - " var voxelColor = voxel.getColor();" - " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue ); " - " var myColor = Particle.getColor();" - " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue ); " - " var newProps = { color: voxelColor }; " - " print('about to call Particle.setProperties()'); " - " Particle.setProperties(newProps); " - " var voxelAt = voxel.getPosition();" - " var voxelScale = voxel.getScale();" - " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " - " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')...'); " - " } " - " Particle.collisionWithVoxel.connect(collisionWithVoxel); " ); - - - ParticleEditHandle* particleEditHandle = makeParticle(position / (float)TREE_SCALE, radius, color, - velocity / (float)TREE_SCALE, gravity, damping, lifetime, NOT_IN_HAND, script); - - // If we wanted to be able to edit this particle after shooting, then we could store this value - // and use it for editing later. But we don't care about that for "shooting" and therefore we just - // clean up our memory now. deleting a ParticleEditHandle does not effect the underlying particle, - // it just removes your ability to edit that particle later. - delete particleEditHandle; -} - -// Caller is responsible for managing this EditableParticle -ParticleEditHandle* Application::newParticleEditHandle(uint32_t id) { - ParticleEditHandle* particleEditHandle = new ParticleEditHandle(&_particleEditSender, _particles.getTree(), id); - return particleEditHandle; -} - -// Caller is responsible for managing this EditableParticle -ParticleEditHandle* Application::makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { - - ParticleEditHandle* particleEditHandle = newParticleEditHandle(); - particleEditHandle->createParticle(position, radius, color, velocity, gravity, damping, lifetime, inHand, updateScript); - return particleEditHandle; -} - void Application::makeVoxel(glm::vec3 position, float scale, @@ -4178,10 +4119,6 @@ void Application::processDatagrams() { break; case PACKET_TYPE_PARTICLE_ADD_RESPONSE: - - // This will make sure our local ParticleEditHandle are handles correctly - ParticleEditHandle::handleAddResponse(_incomingPacket, bytesReceived); - // this will keep creatorTokenIDs to IDs mapped correctly Particle::handleAddParticleResponse(_incomingPacket, bytesReceived); break; diff --git a/interface/src/Application.h b/interface/src/Application.h index 1b465d9a59..3c03fb0d66 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -66,7 +66,6 @@ #include "ui/LogDialog.h" #include "FileLogger.h" #include "ParticleTreeRenderer.h" -#include "ParticleEditHandle.h" #include "ControllerScriptingInterface.h" @@ -123,11 +122,6 @@ public: void wheelEvent(QWheelEvent* event); - void shootParticle(); // shoots a particle in the direction you're looking - ParticleEditHandle* newParticleEditHandle(uint32_t id = NEW_PARTICLE); - ParticleEditHandle* makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, - glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript); - void makeVoxel(glm::vec3 position, float scale, unsigned char red, diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 4cc109b08e..51f1bc10de 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -21,26 +21,7 @@ using namespace std; const float FINGERTIP_COLLISION_RADIUS = 0.01f; const float FINGERTIP_VOXEL_SIZE = 0.05f; -const int TOY_BALL_HAND = 1; -const float TOY_BALL_RADIUS = 0.05f; -const float TOY_BALL_DAMPING = 0.1f; -const float TOY_BALL_LIFETIME = 30.0f; // toy balls live for 30 seconds -const glm::vec3 NO_VELOCITY = glm::vec3(0,0,0); -const glm::vec3 NO_GRAVITY = glm::vec3(0,0,0); -const float NO_DAMPING = 0.f; -const glm::vec3 TOY_BALL_GRAVITY = glm::vec3(0,-2.0f,0); -const QString TOY_BALL_UPDATE_SCRIPT(""); const float PALM_COLLISION_RADIUS = 0.03f; -const float CATCH_RADIUS = 0.3f; -const xColor TOY_BALL_ON_SERVER_COLOR[] = - { - { 255, 0, 0 }, - { 0, 255, 0 }, - { 0, 0, 255 }, - { 255, 255, 0 }, - { 0, 255, 255 }, - { 255, 0, 255 }, - }; Hand::Hand(Avatar* owningAvatar) : @@ -56,16 +37,8 @@ Hand::Hand(Avatar* owningAvatar) : _grabDelta(0, 0, 0), _grabDeltaVelocity(0, 0, 0), _grabStartRotation(0, 0, 0, 1), - _grabCurrentRotation(0, 0, 0, 1), - _throwSound(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw")), - _catchSound(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw")) + _grabCurrentRotation(0, 0, 0, 1) { - for (int i = 0; i < MAX_HANDS; i++) { - _toyBallInHand[i] = false; - _ballParticleEditHandles[i] = NULL; - _whichBallColor[i] = 0; - } - _lastControllerButtons = 0; } void Hand::init() { @@ -81,161 +54,7 @@ void Hand::init() { void Hand::reset() { } -void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) { - Application* app = Application::getInstance(); - ParticleTree* particles = app->getParticles()->getTree(); - int handID = palm.getSixenseID(); - - const int NEW_BALL_BUTTON = BUTTON_3; - - bool grabButtonPressed = ((palm.getControllerButtons() & BUTTON_FWD) || - (palm.getControllerButtons() & BUTTON_3)); - - bool ballAlreadyInHand = _toyBallInHand[handID]; - glm::vec3 targetPosition; - palm.getBallHoldPosition(targetPosition); - float targetRadius = CATCH_RADIUS / (float)TREE_SCALE; - - // If I don't currently have a ball in my hand, then try to catch closest one - if (!ballAlreadyInHand && grabButtonPressed) { - - const Particle* closestParticle = particles->findClosestParticle(targetPosition, targetRadius); - - if (closestParticle) { - ParticleEditHandle* caughtParticle = app->newParticleEditHandle(closestParticle->getID()); - glm::vec3 newPosition = targetPosition; - glm::vec3 newVelocity = NO_VELOCITY; - - // update the particle with it's new state... - caughtParticle->updateParticle(newPosition, - closestParticle->getRadius(), - closestParticle->getXColor(), - newVelocity, - NO_GRAVITY, - NO_DAMPING, - DEFAULT_LIFETIME, - IN_HAND, // we just grabbed it! - closestParticle->getScript()); - - - // now tell our hand about us having caught it... - _toyBallInHand[handID] = true; - - //printf(">>>>>>> caught... handID:%d particle ID:%d _toyBallInHand[handID] = true\n", handID, closestParticle->getID()); - _ballParticleEditHandles[handID] = caughtParticle; - caughtParticle = NULL; - - // use the threadSound static method to inject the catch sound - // pass an AudioInjectorOptions struct to set position and disable loopback - AudioInjectorOptions injectorOptions; - injectorOptions.setPosition(newPosition); - injectorOptions.setLoopbackAudioInterface(app->getAudio()); - - AudioScriptingInterface::playSound(&_catchSound, &injectorOptions); - } - } - - // If there's a ball in hand, and the user presses the skinny button, then change the color of the ball - int currentControllerButtons = palm.getControllerButtons(); - - if (currentControllerButtons != _lastControllerButtons && (currentControllerButtons & BUTTON_0)) { - _whichBallColor[handID]++; - if (_whichBallColor[handID] >= sizeof(TOY_BALL_ON_SERVER_COLOR)/sizeof(TOY_BALL_ON_SERVER_COLOR[0])) { - _whichBallColor[handID] = 0; - } - } - - // If '3' is pressed, and not holding a ball, make a new one - if ((palm.getControllerButtons() & NEW_BALL_BUTTON) && (_toyBallInHand[handID] == false)) { - _toyBallInHand[handID] = true; - // Create a particle on the particle server - glm::vec3 ballPosition; - palm.getBallHoldPosition(ballPosition); - _ballParticleEditHandles[handID] = app->makeParticle( - ballPosition / (float)TREE_SCALE, - TOY_BALL_RADIUS / (float) TREE_SCALE, - TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]], - NO_VELOCITY / (float)TREE_SCALE, - TOY_BALL_GRAVITY / (float) TREE_SCALE, - TOY_BALL_DAMPING, - TOY_BALL_LIFETIME, - IN_HAND, - TOY_BALL_UPDATE_SCRIPT); - // Play a new ball sound - app->getAudio()->startDrumSound(1.0f, 2000, 0.5f, 0.02f); - } - - if (grabButtonPressed) { - // If we don't currently have a ball in hand, then create it... - if (_toyBallInHand[handID]) { - // Update ball that is in hand - uint32_t particleInHandID = _ballParticleEditHandles[handID]->getID(); - const Particle* particleInHand = particles->findParticleByID(particleInHandID); - xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor() - : TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]]; - - glm::vec3 ballPosition; - palm.getBallHoldPosition(ballPosition); - _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, - TOY_BALL_RADIUS / (float) TREE_SCALE, - colorForParticleInHand, - NO_VELOCITY / (float)TREE_SCALE, - TOY_BALL_GRAVITY / (float) TREE_SCALE, - TOY_BALL_DAMPING, - TOY_BALL_LIFETIME, - IN_HAND, - TOY_BALL_UPDATE_SCRIPT); - } - } else { - // If toy ball just released, add velocity to it! - if (_toyBallInHand[handID]) { - - const float THROWN_VELOCITY_SCALING = 1.5f; - _toyBallInHand[handID] = false; - palm.updateCollisionlessPaddleExpiry(); - glm::vec3 ballPosition; - palm.getBallHoldPosition(ballPosition); - glm::vec3 ballVelocity = palm.getTipVelocity(); - glm::quat avatarRotation = _owningAvatar->getOrientation(); - ballVelocity = avatarRotation * ballVelocity; - ballVelocity *= THROWN_VELOCITY_SCALING; - - uint32_t particleInHandID = _ballParticleEditHandles[handID]->getID(); - const Particle* particleInHand = particles->findParticleByID(particleInHandID); - xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor() - : TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]]; - - _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, - TOY_BALL_RADIUS / (float) TREE_SCALE, - colorForParticleInHand, - ballVelocity / (float)TREE_SCALE, - TOY_BALL_GRAVITY / (float) TREE_SCALE, - TOY_BALL_DAMPING, - TOY_BALL_LIFETIME, - NOT_IN_HAND, - TOY_BALL_UPDATE_SCRIPT); - - // after releasing the ball, we free our ParticleEditHandle so we can't edit it further - // note: deleting the edit handle doesn't effect the actual particle - delete _ballParticleEditHandles[handID]; - _ballParticleEditHandles[handID] = NULL; - - // use the threadSound static method to inject the throw sound - // pass an AudioInjectorOptions struct to set position and disable loopback - AudioInjectorOptions injectorOptions; - injectorOptions.setPosition(ballPosition); - injectorOptions.setLoopbackAudioInterface(app->getAudio()); - - AudioScriptingInterface::playSound(&_throwSound, &injectorOptions); - } - } - - // remember the last pressed button state - if (currentControllerButtons != 0) { - _lastControllerButtons = currentControllerButtons; - } -} glm::vec3 Hand::getAndResetGrabDelta() { const float HAND_GRAB_SCALE_DISTANCE = 2.f; @@ -282,8 +101,6 @@ void Hand::simulate(float deltaTime, bool isMine) { FingerData& finger = palm.getFingers()[0]; // Sixense has only one finger glm::vec3 fingerTipPosition = finger.getTipPosition(); - simulateToyBall(palm, fingerTipPosition, deltaTime); - _buckyBalls.grab(palm, fingerTipPosition, _owningAvatar->getOrientation(), deltaTime); if (palm.getControllerButtons() & BUTTON_4) { @@ -517,7 +334,6 @@ void Hand::render(bool isMine) { glPopMatrix(); } } - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { renderLeapHands(isMine); @@ -546,7 +362,6 @@ void Hand::render(bool isMine) { void Hand::renderLeapHands(bool isMine) { const float alpha = 1.0f; - const float TARGET_ALPHA = 0.5f; //const glm::vec3 handColor = _ballColor; const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color @@ -564,19 +379,6 @@ void Hand::renderLeapHands(bool isMine) { palm.getBallHoldPosition(targetPosition); glPushMatrix(); - ParticleTree* particles = Application::getInstance()->getParticles()->getTree(); - const Particle* closestParticle = particles->findClosestParticle(targetPosition / (float)TREE_SCALE, - CATCH_RADIUS / (float)TREE_SCALE); - - // If we are hitting a particle then draw the target green, otherwise yellow - if (closestParticle) { - glColor4f(0,1,0, TARGET_ALPHA); - } else { - glColor4f(1,1,0, TARGET_ALPHA); - } - glTranslatef(targetPosition.x, targetPosition.y, targetPosition.z); - glutWireSphere(CATCH_RADIUS, 10.f, 10.f); - const float collisionRadius = 0.05f; glColor4f(0.5f,0.5f,0.5f, alpha); glutWireSphere(collisionRadius, 10.f, 10.f); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 0552c021f1..3c8ec2d562 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -19,7 +19,6 @@ #include #include #include -#include #include "BuckyBalls.h" #include "InterfaceConfig.h" @@ -102,24 +101,12 @@ private: void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); - void simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime); - - #define MAX_HANDS 2 - bool _toyBallInHand[MAX_HANDS]; - int _whichBallColor[MAX_HANDS]; - ParticleEditHandle* _ballParticleEditHandles[MAX_HANDS]; - int _lastControllerButtons; - float _pitchUpdate; glm::vec3 _grabDelta; glm::vec3 _grabDeltaVelocity; glm::quat _grabStartRotation; glm::quat _grabCurrentRotation; - - Sound _throwSound; - Sound _catchSound; - }; #endif From 1c5e32fcb1df0243ddd91634016c715ad1ec996d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 14:08:19 -0800 Subject: [PATCH 13/24] add example of new particle edit JS api --- examples/editParticleExample.js | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 examples/editParticleExample.js diff --git a/examples/editParticleExample.js b/examples/editParticleExample.js new file mode 100644 index 0000000000..932d9ccbe2 --- /dev/null +++ b/examples/editParticleExample.js @@ -0,0 +1,85 @@ +// +// editParticleExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 12/31/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates creating and editing a particle +// + +var count = 0; + +var originalProperties = { + position: { x: 1/TREE_SCALE, + y: 0/TREE_SCALE, + z: 1/TREE_SCALE }, + + velocity: { x: 0, + y: 0, + z: 0 }, + + gravity: { x: 0, + y: 0, + z: 0 }, + + + radius : 0.1/TREE_SCALE, + + color: { red: 0, + green: 255, + blue: 0 } + +}; + +var positionDelta = { x: 0.5/TREE_SCALE, y: 0, z: 0 }; + + +var particleID = Particles.addParticle(originalProperties); + +function moveParticle() { + if (count >= 10) { + //Agent.stop(); + + // delete it... + if (count == 10) { + print("calling Particles.deleteParticle()"); + Particles.deleteParticle(particleID); + } + + // stop it... + if (count >= 100) { + print("calling Agent.stop()"); + Agent.stop(); + } + + count++; + return; // break early + } + + print("count =" + count); + count++; + + print("particleID.creatorTokenID = " + particleID.creatorTokenID); + + var newProperties = { + position: { + x: originalProperties.position.x + (count * positionDelta.x), + y: originalProperties.position.y + (count * positionDelta.y), + z: originalProperties.position.z + (count * positionDelta.z) + }, + radius : 0.25/TREE_SCALE, + + }; + + + //print("particleID = " + particleID); + print("newProperties.position.x = " + newProperties.position.x); + + Particles.editParticle(particleID, newProperties); +} + + +// register the call back so it fires before each data send +Agent.willSendVisualDataCallback.connect(moveParticle); + From 90c841ff01eef5c9adc91ce5253fedca52ffa57a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 14:29:20 -0800 Subject: [PATCH 14/24] add findClosestParticle() to JS interface --- examples/editParticleExample.js | 8 +++++++ interface/src/Application.cpp | 1 + .../src/ParticlesScriptingInterface.cpp | 21 +++++++++++++++++++ .../src/ParticlesScriptingInterface.h | 7 +++++++ 4 files changed, 37 insertions(+) diff --git a/examples/editParticleExample.js b/examples/editParticleExample.js index 932d9ccbe2..117483da79 100644 --- a/examples/editParticleExample.js +++ b/examples/editParticleExample.js @@ -77,6 +77,14 @@ function moveParticle() { print("newProperties.position.x = " + newProperties.position.x); Particles.editParticle(particleID, newProperties); + + // also check to see if we can "find" particles... + var searchAt = { x: 0, y: 0, z: 0}; + var searchRadius = 2; + var foundParticle = Particles.findClosestParticle(searchAt, searchRadius); + if (foundParticle.isKnownID) { + print("found particle:" + foundParticle.id); + } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 02902ab37b..d0e74a9f4c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4224,6 +4224,7 @@ void Application::loadScript() { // we can use the same ones from the application. scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); + scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); QThread* workerThread = new QThread(this); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 7bec62e7b1..b1a5aa28c2 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -7,7 +7,13 @@ // #include "ParticlesScriptingInterface.h" +#include "ParticleTree.h" +ParticlesScriptingInterface::ParticlesScriptingInterface() : + _nextCreatorTokenID(0), + _particleTree(NULL) +{ +} void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, @@ -73,3 +79,18 @@ void ParticlesScriptingInterface::deleteParticle(ParticleID particleID) { //qDebug() << "ParticlesScriptingInterface::deleteParticle(), queueParticleMessage......"; queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties); } + +ParticleID ParticlesScriptingInterface::findClosestParticle(const glm::vec3& center, float radius) const { + ParticleID result(UNKNOWN_PARTICLE_ID, UNKNOWN_TOKEN, false); + if (_particleTree) { + const Particle* closestParticle = _particleTree->findClosestParticle(center/(float)TREE_SCALE, + radius/(float)TREE_SCALE); + + if (closestParticle) { + result.id = closestParticle->getID(); + result.isKnownID = true; + } + } + return result; +} + diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index 121f55fdc5..edd2ac43dc 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -19,19 +19,26 @@ class ParticlesScriptingInterface : public OctreeScriptingInterface { Q_OBJECT public: + ParticlesScriptingInterface(); + ParticleEditPacketSender* getParticlePacketSender() const { return (ParticleEditPacketSender*)getPacketSender(); } virtual NODE_TYPE getServerNodeType() const { return NODE_TYPE_PARTICLE_SERVER; } virtual OctreeEditPacketSender* createPacketSender() { return new ParticleEditPacketSender(); } + void setParticleTree(ParticleTree* particleTree) { _particleTree = particleTree; } + ParticleTree* getParticleTree(ParticleTree*) { return _particleTree; } + public slots: ParticleID addParticle(const ParticleProperties& properties); void editParticle(ParticleID particleID, const ParticleProperties& properties); void deleteParticle(ParticleID particleID); + ParticleID findClosestParticle(const glm::vec3& center, float radius) const; private: void queueParticleMessage(PACKET_TYPE packetType, ParticleID particleID, const ParticleProperties& properties); uint32_t _nextCreatorTokenID; + ParticleTree* _particleTree; }; #endif /* defined(__hifi__ParticlesScriptingInterface__) */ From eb1e72b838e105a5662760d96513c706d08fd423 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 16:40:03 -0800 Subject: [PATCH 15/24] fix a bug where x was only attribute being copied for vec3s WHT --- examples/editParticleExample.js | 8 ++++---- libraries/particles/src/Particle.cpp | 12 ++++++------ .../particles/src/ParticlesScriptingInterface.cpp | 8 ++++++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/examples/editParticleExample.js b/examples/editParticleExample.js index 117483da79..24725ddf42 100644 --- a/examples/editParticleExample.js +++ b/examples/editParticleExample.js @@ -11,9 +11,9 @@ var count = 0; var originalProperties = { - position: { x: 1/TREE_SCALE, + position: { x: 10/TREE_SCALE, y: 0/TREE_SCALE, - z: 1/TREE_SCALE }, + z: 0/TREE_SCALE }, velocity: { x: 0, y: 0, @@ -32,7 +32,7 @@ var originalProperties = { }; -var positionDelta = { x: 0.5/TREE_SCALE, y: 0, z: 0 }; +var positionDelta = { x: 0.1/TREE_SCALE, y: 0, z: 0 }; var particleID = Particles.addParticle(originalProperties); @@ -74,7 +74,7 @@ function moveParticle() { //print("particleID = " + particleID); - print("newProperties.position.x = " + newProperties.position.x); + print("newProperties.position = " + newProperties.position.x + "," + newProperties.position.y+ "," + newProperties.position.z); Particles.editParticle(particleID, newProperties); diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index b26494d680..0e732d72ef 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -935,8 +935,8 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (x.isValid() && y.isValid() && z.isValid()) { glm::vec3 newPosition; newPosition.x = x.toVariant().toFloat(); - newPosition.y = x.toVariant().toFloat(); - newPosition.z = x.toVariant().toFloat(); + newPosition.y = y.toVariant().toFloat(); + newPosition.z = z.toVariant().toFloat(); if (newPosition != _position) { _position = newPosition; _positionChanged = true; @@ -981,8 +981,8 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (x.isValid() && y.isValid() && z.isValid()) { glm::vec3 newVelocity; newVelocity.x = x.toVariant().toFloat(); - newVelocity.y = x.toVariant().toFloat(); - newVelocity.z = x.toVariant().toFloat(); + newVelocity.y = y.toVariant().toFloat(); + newVelocity.z = z.toVariant().toFloat(); if (newVelocity != _velocity) { _velocity = newVelocity; _velocityChanged = true; @@ -998,8 +998,8 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (x.isValid() && y.isValid() && z.isValid()) { glm::vec3 newGravity; newGravity.x = x.toVariant().toFloat(); - newGravity.y = x.toVariant().toFloat(); - newGravity.z = x.toVariant().toFloat(); + newGravity.y = y.toVariant().toFloat(); + newGravity.z = z.toVariant().toFloat(); if (newGravity != _gravity) { _gravity = newGravity; _gravityChanged = true; diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index b1a5aa28c2..8f69a07bc8 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -41,12 +41,20 @@ void ParticlesScriptingInterface::editParticle(ParticleID particleID, const Part // hmmm... we kind of want to bail if someone attempts to edit an unknown if (actualID == UNKNOWN_PARTICLE_ID) { + +qDebug() << "ParticlesScriptingInterface::editParticle()... BAILING!!! particleID.creatorTokenID=" << particleID.creatorTokenID; + return; // bailing early } } particleID.id = actualID; particleID.isKnownID = true; +qDebug() << "ParticlesScriptingInterface::editParticle()... FOUND IT!!! actualID=" << actualID; +qDebug() << "ParticlesScriptingInterface::editParticle()... properties.getPositon()=" + << properties.getPosition().x << ", " + << properties.getPosition().y << ", " + << properties.getPosition().z << "..."; queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties); } From 164e703decce788b14f31745e65ad58c4553548d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 20:05:00 -0800 Subject: [PATCH 16/24] tweaks to JS particle editing api --- libraries/particles/src/Particle.cpp | 26 ++++++++------- libraries/particles/src/Particle.h | 1 + .../src/ParticlesScriptingInterface.cpp | 32 +++++++++++++------ 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 0e732d72ef..057ad07c36 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -847,7 +847,8 @@ ParticleProperties::ParticleProperties() : _lifetimeChanged(false), _scriptChanged(false), _inHandChanged(false), - _shouldDieChanged(false) + _shouldDieChanged(false), + _defaultSettings(true) { } @@ -937,7 +938,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { newPosition.x = x.toVariant().toFloat(); newPosition.y = y.toVariant().toFloat(); newPosition.z = z.toVariant().toFloat(); - if (newPosition != _position) { + if (_defaultSettings || newPosition != _position) { _position = newPosition; _positionChanged = true; } @@ -954,9 +955,9 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { newColor.red = red.toVariant().toInt(); newColor.green = green.toVariant().toInt(); newColor.blue = blue.toVariant().toInt(); - if (newColor.red != _color.red || + if (_defaultSettings || (newColor.red != _color.red || newColor.green != _color.green || - newColor.blue != _color.blue) { + newColor.blue != _color.blue)) { _color = newColor; _colorChanged = true; } @@ -967,7 +968,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (radius.isValid()) { float newRadius; newRadius = radius.toVariant().toFloat(); - if (newRadius != _radius) { + if (_defaultSettings || newRadius != _radius) { _radius = newRadius; _radiusChanged = true; } @@ -983,7 +984,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { newVelocity.x = x.toVariant().toFloat(); newVelocity.y = y.toVariant().toFloat(); newVelocity.z = z.toVariant().toFloat(); - if (newVelocity != _velocity) { + if (_defaultSettings || newVelocity != _velocity) { _velocity = newVelocity; _velocityChanged = true; } @@ -1000,7 +1001,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { newGravity.x = x.toVariant().toFloat(); newGravity.y = y.toVariant().toFloat(); newGravity.z = z.toVariant().toFloat(); - if (newGravity != _gravity) { + if (_defaultSettings || newGravity != _gravity) { _gravity = newGravity; _gravityChanged = true; } @@ -1011,7 +1012,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (damping.isValid()) { float newDamping; newDamping = damping.toVariant().toFloat(); - if (newDamping != _damping) { + if (_defaultSettings || newDamping != _damping) { _damping = newDamping; _dampingChanged = true; } @@ -1021,7 +1022,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (lifetime.isValid()) { float newLifetime; newLifetime = lifetime.toVariant().toFloat(); - if (newLifetime != _lifetime) { + if (_defaultSettings || newLifetime != _lifetime) { _lifetime = newLifetime; _lifetimeChanged = true; } @@ -1031,7 +1032,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (script.isValid()) { QString newScript; newScript = script.toVariant().toString(); - if (newScript != _script) { + if (_defaultSettings || newScript != _script) { _script = newScript; _scriptChanged = true; } @@ -1041,7 +1042,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (inHand.isValid()) { bool newInHand; newInHand = inHand.toVariant().toBool(); - if (newInHand != _inHand) { + if (_defaultSettings || newInHand != _inHand) { _inHand = newInHand; _inHandChanged = true; } @@ -1051,7 +1052,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { if (shouldDie.isValid()) { bool newShouldDie; newShouldDie = shouldDie.toVariant().toBool(); - if (newShouldDie != _shouldDie) { + if (_defaultSettings || newShouldDie != _shouldDie) { _shouldDie = newShouldDie; _shouldDieChanged = true; } @@ -1124,6 +1125,7 @@ void ParticleProperties::copyFromParticle(const Particle& particle) { _scriptChanged = false; _inHandChanged = false; _shouldDieChanged = false; + _defaultSettings = false; } QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties) { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index a0d9ca45f0..da8cf35ac2 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -112,6 +112,7 @@ private: bool _scriptChanged; bool _inHandChanged; bool _shouldDieChanged; + bool _defaultSettings; }; Q_DECLARE_METATYPE(ParticleProperties); QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 8f69a07bc8..14388b6ac4 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -38,24 +38,38 @@ void ParticlesScriptingInterface::editParticle(ParticleID particleID, const Part uint32_t actualID = particleID.id; if (!particleID.isKnownID) { actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID); - // hmmm... we kind of want to bail if someone attempts to edit an unknown if (actualID == UNKNOWN_PARTICLE_ID) { - -qDebug() << "ParticlesScriptingInterface::editParticle()... BAILING!!! particleID.creatorTokenID=" << particleID.creatorTokenID; - + //qDebug() << "ParticlesScriptingInterface::editParticle()... BAILING!!! particleID.creatorTokenID=" + // << particleID.creatorTokenID; return; // bailing early } } particleID.id = actualID; particleID.isKnownID = true; -qDebug() << "ParticlesScriptingInterface::editParticle()... FOUND IT!!! actualID=" << actualID; -qDebug() << "ParticlesScriptingInterface::editParticle()... properties.getPositon()=" - << properties.getPosition().x << ", " - << properties.getPosition().y << ", " - << properties.getPosition().z << "..."; + //qDebug() << "ParticlesScriptingInterface::editParticle()... FOUND IT!!! actualID=" << actualID; + bool wantDebugging = false; + if (wantDebugging) { + uint16_t containsBits = properties.getChangedBits(); + qDebug() << "ParticlesScriptingInterface::editParticle()... containsBits=" << containsBits; + if ((containsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) { + qDebug() << "ParticlesScriptingInterface::editParticle()... properties.getPositon()=" + << properties.getPosition().x << ", " + << properties.getPosition().y << ", " + << properties.getPosition().z << "..."; + } + if ((containsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) { + qDebug() << "ParticlesScriptingInterface::editParticle()... properties.getVelocity()=" + << properties.getVelocity().x << ", " + << properties.getVelocity().y << ", " + << properties.getVelocity().z << "..."; + } + if ((containsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) { + qDebug() << "ParticlesScriptingInterface::editParticle()... properties.getInHand()=" << properties.getInHand(); + } + } queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties); } From cefac50100b5e7b84a608e3e9294695500197e59 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 21 Jan 2014 20:05:41 -0800 Subject: [PATCH 17/24] adding toyball script --- examples/toyball.js | 263 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 examples/toyball.js diff --git a/examples/toyball.js b/examples/toyball.js new file mode 100644 index 0000000000..1d690be2a6 --- /dev/null +++ b/examples/toyball.js @@ -0,0 +1,263 @@ +// +// toyball.js +// hifi +// +// Created by Brad Hefta-Gaub on 12/31/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that turns the hydra controllers into a toy ball catch and throw game. +// It reads the controller, watches for button presses and trigger pulls, and launches particles. +// +// The particles it creates have a script that when they collide with Voxels, the +// particle will change it's color to match the voxel it hits. +// +// + +var leftBallAlreadyInHand = false; +var rightBallAlreadyInHand = false; +var leftHandParticle; +var rightHandParticle; + +function checkController() { + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + + // this is expected for hydras + if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) { + print("no hydra connected?"); + return; // bail if no hydra + } + + // maybe we should make these constants... + var LEFT_PALM = 0; + var LEFT_TIP = 1; + var LEFT_BUTTON_FWD = 5; + var LEFT_BUTTON_3 = 3; + + var RIGHT_PALM = 2; + var RIGHT_TIP = 3; + var RIGHT_BUTTON_FWD = 11; + var RIGHT_BUTTON_3 = 9; + + var leftGrabButtonPressed = (Controller.isButtonPressed(LEFT_BUTTON_FWD) || Controller.isButtonPressed(LEFT_BUTTON_3)); + var rightGrabButtonPressed = (Controller.isButtonPressed(RIGHT_BUTTON_FWD) || Controller.isButtonPressed(RIGHT_BUTTON_3)); + + var leftPalmPosition = Controller.getSpatialControlPosition(LEFT_PALM); + //print("leftPalmPosition: " + leftPalmPosition.x + ", "+ leftPalmPosition.y + ", "+ leftPalmPosition.z); + + var rightPalmPosition = Controller.getSpatialControlPosition(RIGHT_PALM); + //print("rightPalmPosition: " + rightPalmPosition.x + ", "+ rightPalmPosition.y + ", "+ rightPalmPosition.z); + + var targetRadius = 3.0; + + // If I don't currently have a ball in my left hand, then try to catch closest one + if (!leftBallAlreadyInHand && leftGrabButtonPressed) { + var closestParticle = Particles.findClosestParticle(leftPalmPosition, targetRadius); + + if (closestParticle.isKnownID) { + +print("LEFT HAND- CAUGHT SOMETHING!!"); + + leftBallAlreadyInHand = true; + leftHandParticle = closestParticle; + var properties = { position: { x: leftPalmPosition.x / TREE_SCALE, + y: leftPalmPosition.y / TREE_SCALE, + z: leftPalmPosition.z / TREE_SCALE }, + velocity : { x: 0, y: 0, z: 0}, inHand: true }; + Particles.editParticle(leftHandParticle, properties); + + /** + AudioInjectorOptions injectorOptions; + injectorOptions.setPosition(newPosition); + injectorOptions.setLoopbackAudioInterface(app->getAudio()); + + AudioScriptingInterface::playSound(&_catchSound, &injectorOptions); + **/ + + return; // exit early + } + } + + // If I don't currently have a ball in my right hand, then try to catch closest one + if (!rightBallAlreadyInHand && rightGrabButtonPressed) { + var closestParticle = Particles.findClosestParticle(rightPalmPosition, targetRadius); + + if (closestParticle.isKnownID) { + +print("RIGHT HAND- CAUGHT SOMETHING!!"); + + rightBallAlreadyInHand = true; + rightHandParticle = closestParticle; + var properties = { position: { x: rightPalmPosition.x / TREE_SCALE, + y: rightPalmPosition.y / TREE_SCALE, + z: rightPalmPosition.z / TREE_SCALE }, + velocity : { x: 0, y: 0, z: 0}, inHand: true }; + Particles.editParticle(rightHandParticle, properties); + + /** + AudioInjectorOptions injectorOptions; + injectorOptions.setPosition(newPosition); + injectorOptions.setLoopbackAudioInterface(app->getAudio()); + + AudioScriptingInterface::playSound(&_catchSound, &injectorOptions); + **/ + + return; // exit early + } + } + + // change ball color logic... + /*** + if (currentControllerButtons != _lastControllerButtons && (currentControllerButtons & BUTTON_0)) { + _whichBallColor[handID]++; + if (_whichBallColor[handID] >= sizeof(TOY_BALL_ON_SERVER_COLOR)/sizeof(TOY_BALL_ON_SERVER_COLOR[0])) { + _whichBallColor[handID] = 0; + } + } + ***/ + + // LEFT HAND -- If '3' is pressed, and not holding a ball, make a new one + if (Controller.isButtonPressed(LEFT_BUTTON_3) && !leftBallAlreadyInHand) { + leftBallAlreadyInHand = true; + var properties = { + position: { x: leftPalmPosition.x / TREE_SCALE, + y: leftPalmPosition.y / TREE_SCALE, + z: leftPalmPosition.z / TREE_SCALE } , + velocity: { x: 0, y: 0, z: 0}, + gravity: { x: 0, y: 0, z: 0}, + inHand: true, + radius: 0.05 / TREE_SCALE, + color: { red: 255, green: 0, blue: 0 }, + lifetime: 30 + }; + +print("calling addParticle()"); + leftHandParticle = Particles.addParticle(properties); +print("leftHandParticle=" + leftHandParticle.creatorTokenID); + + // Play a new ball sound + //app->getAudio()->startDrumSound(1.0f, 2000, 0.5f, 0.02f); + + return; // exit early + } + + // RIGHT HAND -- If '3' is pressed, and not holding a ball, make a new one + if (Controller.isButtonPressed(RIGHT_BUTTON_3) && !rightBallAlreadyInHand) { + rightBallAlreadyInHand = true; + var properties = { + position: { x: rightPalmPosition.x / TREE_SCALE, + y: rightPalmPosition.y / TREE_SCALE, + z: rightPalmPosition.z / TREE_SCALE } , + velocity: { x: 0, y: 0, z: 0}, + gravity: { x: 0, y: 0, z: 0}, + inHand: true, + radius: 0.05 / TREE_SCALE, + color: { red: 255, green: 255, blue: 0 }, + lifetime: 30 + }; + +print("calling addParticle()"); + rightHandParticle = Particles.addParticle(properties); +print("rightHandParticle=" + rightHandParticle.creatorTokenID); + + // Play a new ball sound + //app->getAudio()->startDrumSound(1.0f, 2000, 0.5f, 0.02f); + + return; // exit early + } + + + if (leftBallAlreadyInHand) { + // If holding the ball keep it in the palm + if (leftGrabButtonPressed) { + var properties = { + position: { x: leftPalmPosition.x / TREE_SCALE, + y: leftPalmPosition.y / TREE_SCALE, + z: leftPalmPosition.z / TREE_SCALE } , + }; + +print("Particles.editParticle()... staying in hand leftHandParticle=" + leftHandParticle.creatorTokenID); + Particles.editParticle(leftHandParticle, properties); +print("leftPalmPosition: " + leftPalmPosition.x + ", "+ leftPalmPosition.y + ", "+ leftPalmPosition.z); +print("leftPalmPosition: " + leftPalmPosition.x / TREE_SCALE + ", "+ leftPalmPosition.y / TREE_SCALE + ", "+ leftPalmPosition.z / TREE_SCALE); + } else { +print(">>>>> LEFT-BALL IN HAND, but NOT GRABBING!!!"); + + // If toy ball just released, add velocity to it! + var leftTipVelocity = Controller.getSpatialControlVelocity(LEFT_TIP); + + var properties = { + velocity: { x: leftTipVelocity.x / TREE_SCALE, + y: leftTipVelocity.y / TREE_SCALE, + z: leftTipVelocity.z / TREE_SCALE } , + inHand: false, + gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, + }; + +print("leftTipVelocity: " + leftTipVelocity.x + ", "+ leftTipVelocity.y + ", "+ leftTipVelocity.z); +print("leftTipVelocity: " + leftTipVelocity.x / TREE_SCALE + ", "+ leftTipVelocity.y / TREE_SCALE + ", "+ leftTipVelocity.z / TREE_SCALE); + +print("Particles.editParticle()... releasing leftHandParticle=" + leftHandParticle.creatorTokenID); + Particles.editParticle(leftHandParticle, properties); + leftBallAlreadyInHand = false; + leftHandParticle = false; + + /** + AudioInjectorOptions injectorOptions; + injectorOptions.setPosition(ballPosition); + injectorOptions.setLoopbackAudioInterface(app->getAudio()); + + AudioScriptingInterface::playSound(&_throwSound, &injectorOptions); + **/ + } + } + + if (rightBallAlreadyInHand) { + // If holding the ball keep it in the palm + if (rightGrabButtonPressed) { + var properties = { + position: { x: rightPalmPosition.x / TREE_SCALE, + y: rightPalmPosition.y / TREE_SCALE, + z: rightPalmPosition.z / TREE_SCALE } , + }; + +print("Particles.editParticle()... staying in hand rightHandParticle=" + rightHandParticle.creatorTokenID); + Particles.editParticle(rightHandParticle, properties); +print("rightPalmPosition: " + rightPalmPosition.x + ", "+ rightPalmPosition.y + ", "+ rightPalmPosition.z); +print("rightPalmPosition: " + rightPalmPosition.x / TREE_SCALE + ", "+ rightPalmPosition.y / TREE_SCALE + ", "+ rightPalmPosition.z / TREE_SCALE); + + } else { +print(">>>>> RIGHT-BALL IN HAND, but NOT GRABBING!!!"); + + // If toy ball just released, add velocity to it! + var rightTipVelocity = Controller.getSpatialControlVelocity(LEFT_TIP); + + var properties = { + velocity: { x: rightTipVelocity.x / TREE_SCALE, + y: rightTipVelocity.y / TREE_SCALE, + z: rightTipVelocity.z / TREE_SCALE } , + inHand: false, + gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, + }; + +print("Particles.editParticle()... releasing rightHandParticle=" + rightHandParticle.creatorTokenID); + Particles.editParticle(rightHandParticle, properties); + rightBallAlreadyInHand = false; + rightHandParticle = false; + + /** + AudioInjectorOptions injectorOptions; + injectorOptions.setPosition(ballPosition); + injectorOptions.setLoopbackAudioInterface(app->getAudio()); + + AudioScriptingInterface::playSound(&_throwSound, &injectorOptions); + **/ + } + } +} + + +// register the call back so it fires before each data send +Agent.willSendVisualDataCallback.connect(checkController); From 74fe9893ba0ef833203b8bd382d984b09ff57271 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 09:17:42 -0800 Subject: [PATCH 18/24] make tipVelocity() world relative --- interface/src/BuckyBalls.cpp | 2 +- libraries/avatars/src/HandData.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/BuckyBalls.cpp b/interface/src/BuckyBalls.cpp index 318126cc03..fec77d97f3 100644 --- a/interface/src/BuckyBalls.cpp +++ b/interface/src/BuckyBalls.cpp @@ -73,7 +73,7 @@ void BuckyBalls::grab(PalmData& palm, const glm::vec3& fingerTipPosition, glm::q diff = _bballPosition[_bballIsGrabbed[palm.getSixenseID()]] - fingerTipPosition; penetration = glm::length(diff) - (_bballRadius[_bballIsGrabbed[palm.getSixenseID()]] + COLLISION_RADIUS); _bballPosition[_bballIsGrabbed[palm.getSixenseID()]] -= glm::normalize(diff) * penetration; - glm::vec3 fingerTipVelocity = avatarOrientation * palm.getTipVelocity(); + glm::vec3 fingerTipVelocity = palm.getTipVelocity(); if (_bballElement[_bballIsGrabbed[palm.getSixenseID()]] != 1) { _bballVelocity[_bballIsGrabbed[palm.getSixenseID()]] = fingerTipVelocity; } diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 4faf408fca..0f1e393db9 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -169,10 +169,11 @@ public: void setTipPosition(const glm::vec3& position) { _tipPosition = position; } const glm::vec3 getTipPosition() const { return _owningHandData->leapPositionToWorldPosition(_tipPosition); } - const glm::vec3 getTipRawPosition() const { return _tipPosition; } + const glm::vec3& getTipRawPosition() const { return _tipPosition; } - const glm::vec3& getTipVelocity() const { return _tipVelocity; } void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; } + const glm::vec3 getTipVelocity() const { return _owningHandData->leapDirectionToWorldDirection(_tipVelocity); } + const glm::vec3& getTipRawVelocity() const { return _tipVelocity; } void incrementFramesWithoutData() { _numFramesWithoutData++; } void resetFramesWithoutData() { _numFramesWithoutData = 0; } From 64940a04ff199efd3b70afdf1b0dab324be2cbc1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 09:18:01 -0800 Subject: [PATCH 19/24] latest toyball script --- examples/toyball.js | 248 ++++++++++++++++++++++++-------------------- 1 file changed, 134 insertions(+), 114 deletions(-) diff --git a/examples/toyball.js b/examples/toyball.js index 1d690be2a6..e68f76f320 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -13,11 +13,56 @@ // // +// maybe we should make these constants... +var LEFT_PALM = 0; +var LEFT_TIP = 1; +var LEFT_BUTTON_FWD = 5; +var LEFT_BUTTON_3 = 3; + +var RIGHT_PALM = 2; +var RIGHT_TIP = 3; +var RIGHT_BUTTON_FWD = 11; +var RIGHT_BUTTON_3 = 9; + var leftBallAlreadyInHand = false; var rightBallAlreadyInHand = false; var leftHandParticle; var rightHandParticle; +var throwSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); +var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); + +function getBallHoldPosition(leftHand) { + var normal; + var tipPosition; + if (leftHand) { + normal = Controller.getSpatialControlNormal(LEFT_PALM); + tipPosition = Controller.getSpatialControlPosition(LEFT_TIP); + } else { + normal = Controller.getSpatialControlNormal(RIGHT_PALM); + tipPosition = Controller.getSpatialControlPosition(RIGHT_TIP); + } + + var BALL_FORWARD_OFFSET = 0.08; // put the ball a bit forward of fingers + position = { x: BALL_FORWARD_OFFSET * normal.x, + y: BALL_FORWARD_OFFSET * normal.y, + z: BALL_FORWARD_OFFSET * normal.z }; + + position.x += tipPosition.x; + position.y += tipPosition.y; + position.z += tipPosition.z; + + return position; +} + +var wantDebugging = false; +function debugPrint(message) { + if (wantDebugging) { + print(message); + } +} + + function checkController() { var numberOfButtons = Controller.getNumberOfButtons(); var numberOfTriggers = Controller.getNumberOfTriggers(); @@ -26,31 +71,18 @@ function checkController() { // this is expected for hydras if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) { - print("no hydra connected?"); + debugPrint("no hydra connected?"); return; // bail if no hydra } - // maybe we should make these constants... - var LEFT_PALM = 0; - var LEFT_TIP = 1; - var LEFT_BUTTON_FWD = 5; - var LEFT_BUTTON_3 = 3; - - var RIGHT_PALM = 2; - var RIGHT_TIP = 3; - var RIGHT_BUTTON_FWD = 11; - var RIGHT_BUTTON_3 = 9; - var leftGrabButtonPressed = (Controller.isButtonPressed(LEFT_BUTTON_FWD) || Controller.isButtonPressed(LEFT_BUTTON_3)); var rightGrabButtonPressed = (Controller.isButtonPressed(RIGHT_BUTTON_FWD) || Controller.isButtonPressed(RIGHT_BUTTON_3)); var leftPalmPosition = Controller.getSpatialControlPosition(LEFT_PALM); - //print("leftPalmPosition: " + leftPalmPosition.x + ", "+ leftPalmPosition.y + ", "+ leftPalmPosition.z); - var rightPalmPosition = Controller.getSpatialControlPosition(RIGHT_PALM); - //print("rightPalmPosition: " + rightPalmPosition.x + ", "+ rightPalmPosition.y + ", "+ rightPalmPosition.z); var targetRadius = 3.0; + var exitEarly = false; // If I don't currently have a ball in my left hand, then try to catch closest one if (!leftBallAlreadyInHand && leftGrabButtonPressed) { @@ -58,25 +90,23 @@ function checkController() { if (closestParticle.isKnownID) { -print("LEFT HAND- CAUGHT SOMETHING!!"); + debugPrint("LEFT HAND- CAUGHT SOMETHING!!"); leftBallAlreadyInHand = true; leftHandParticle = closestParticle; - var properties = { position: { x: leftPalmPosition.x / TREE_SCALE, - y: leftPalmPosition.y / TREE_SCALE, - z: leftPalmPosition.z / TREE_SCALE }, + var ballPosition = getBallHoldPosition(true); + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, velocity : { x: 0, y: 0, z: 0}, inHand: true }; Particles.editParticle(leftHandParticle, properties); - /** - AudioInjectorOptions injectorOptions; - injectorOptions.setPosition(newPosition); - injectorOptions.setLoopbackAudioInterface(app->getAudio()); - - AudioScriptingInterface::playSound(&_catchSound, &injectorOptions); - **/ + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(catchSound, options); - return; // exit early + exitEarly = true; } } @@ -86,45 +116,47 @@ print("LEFT HAND- CAUGHT SOMETHING!!"); if (closestParticle.isKnownID) { -print("RIGHT HAND- CAUGHT SOMETHING!!"); + debugPrint("RIGHT HAND- CAUGHT SOMETHING!!"); rightBallAlreadyInHand = true; rightHandParticle = closestParticle; - var properties = { position: { x: rightPalmPosition.x / TREE_SCALE, - y: rightPalmPosition.y / TREE_SCALE, - z: rightPalmPosition.z / TREE_SCALE }, + + var ballPosition = getBallHoldPosition(false); // false == right hand + + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, velocity : { x: 0, y: 0, z: 0}, inHand: true }; Particles.editParticle(rightHandParticle, properties); - /** - AudioInjectorOptions injectorOptions; - injectorOptions.setPosition(newPosition); - injectorOptions.setLoopbackAudioInterface(app->getAudio()); - - AudioScriptingInterface::playSound(&_catchSound, &injectorOptions); - **/ + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(catchSound, options); - return; // exit early + exitEarly = true; } } - // change ball color logic... - /*** - if (currentControllerButtons != _lastControllerButtons && (currentControllerButtons & BUTTON_0)) { - _whichBallColor[handID]++; - if (_whichBallColor[handID] >= sizeof(TOY_BALL_ON_SERVER_COLOR)/sizeof(TOY_BALL_ON_SERVER_COLOR[0])) { - _whichBallColor[handID] = 0; - } + // If we did one of the actions above, then exit now + if (exitEarly) { + debugPrint("exiting early - caught something"); + return; } - ***/ + + // change ball color logic... + // + //if (wasButtonJustPressed()) { + // rotateColor(); + //} // LEFT HAND -- If '3' is pressed, and not holding a ball, make a new one if (Controller.isButtonPressed(LEFT_BUTTON_3) && !leftBallAlreadyInHand) { leftBallAlreadyInHand = true; - var properties = { - position: { x: leftPalmPosition.x / TREE_SCALE, - y: leftPalmPosition.y / TREE_SCALE, - z: leftPalmPosition.z / TREE_SCALE } , + var ballPosition = getBallHoldPosition(true); // true == left hand + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, velocity: { x: 0, y: 0, z: 0}, gravity: { x: 0, y: 0, z: 0}, inHand: true, @@ -133,23 +165,24 @@ print("RIGHT HAND- CAUGHT SOMETHING!!"); lifetime: 30 }; -print("calling addParticle()"); leftHandParticle = Particles.addParticle(properties); -print("leftHandParticle=" + leftHandParticle.creatorTokenID); // Play a new ball sound - //app->getAudio()->startDrumSound(1.0f, 2000, 0.5f, 0.02f); + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(catchSound, options); - return; // exit early + exitEarly = true; } // RIGHT HAND -- If '3' is pressed, and not holding a ball, make a new one if (Controller.isButtonPressed(RIGHT_BUTTON_3) && !rightBallAlreadyInHand) { rightBallAlreadyInHand = true; - var properties = { - position: { x: rightPalmPosition.x / TREE_SCALE, - y: rightPalmPosition.y / TREE_SCALE, - z: rightPalmPosition.z / TREE_SCALE } , + var ballPosition = getBallHoldPosition(false); // false == right hand + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, velocity: { x: 0, y: 0, z: 0}, gravity: { x: 0, y: 0, z: 0}, inHand: true, @@ -158,102 +191,89 @@ print("leftHandParticle=" + leftHandParticle.creatorTokenID); lifetime: 30 }; -print("calling addParticle()"); rightHandParticle = Particles.addParticle(properties); -print("rightHandParticle=" + rightHandParticle.creatorTokenID); // Play a new ball sound - //app->getAudio()->startDrumSound(1.0f, 2000, 0.5f, 0.02f); + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(catchSound, options); - return; // exit early + exitEarly = true; + } + + // If we did one of the actions above, then exit now + if (exitEarly) { + debugPrint("exiting early - ball created"); + return; } - if (leftBallAlreadyInHand) { // If holding the ball keep it in the palm if (leftGrabButtonPressed) { - var properties = { - position: { x: leftPalmPosition.x / TREE_SCALE, - y: leftPalmPosition.y / TREE_SCALE, - z: leftPalmPosition.z / TREE_SCALE } , + debugPrint(">>>>> LEFT-BALL IN HAND, grabbing, hold and move"); + var ballPosition = getBallHoldPosition(true); // true == left hand + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, }; - -print("Particles.editParticle()... staying in hand leftHandParticle=" + leftHandParticle.creatorTokenID); Particles.editParticle(leftHandParticle, properties); -print("leftPalmPosition: " + leftPalmPosition.x + ", "+ leftPalmPosition.y + ", "+ leftPalmPosition.z); -print("leftPalmPosition: " + leftPalmPosition.x / TREE_SCALE + ", "+ leftPalmPosition.y / TREE_SCALE + ", "+ leftPalmPosition.z / TREE_SCALE); } else { -print(">>>>> LEFT-BALL IN HAND, but NOT GRABBING!!!"); - + debugPrint(">>>>> LEFT-BALL IN HAND, not grabbing, THROW!!!"); // If toy ball just released, add velocity to it! - var leftTipVelocity = Controller.getSpatialControlVelocity(LEFT_TIP); - + var tipVelocity = Controller.getSpatialControlVelocity(LEFT_TIP); + var THROWN_VELOCITY_SCALING = 1.5; var properties = { - velocity: { x: leftTipVelocity.x / TREE_SCALE, - y: leftTipVelocity.y / TREE_SCALE, - z: leftTipVelocity.z / TREE_SCALE } , + velocity: { x: (tipVelocity.x * THROWN_VELOCITY_SCALING) / TREE_SCALE, + y: (tipVelocity.y * THROWN_VELOCITY_SCALING) / TREE_SCALE, + z: (tipVelocity.z * THROWN_VELOCITY_SCALING) / TREE_SCALE } , inHand: false, gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, }; -print("leftTipVelocity: " + leftTipVelocity.x + ", "+ leftTipVelocity.y + ", "+ leftTipVelocity.z); -print("leftTipVelocity: " + leftTipVelocity.x / TREE_SCALE + ", "+ leftTipVelocity.y / TREE_SCALE + ", "+ leftTipVelocity.z / TREE_SCALE); - -print("Particles.editParticle()... releasing leftHandParticle=" + leftHandParticle.creatorTokenID); Particles.editParticle(leftHandParticle, properties); leftBallAlreadyInHand = false; leftHandParticle = false; - /** - AudioInjectorOptions injectorOptions; - injectorOptions.setPosition(ballPosition); - injectorOptions.setLoopbackAudioInterface(app->getAudio()); - - AudioScriptingInterface::playSound(&_throwSound, &injectorOptions); - **/ + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(throwSound, options); } } if (rightBallAlreadyInHand) { // If holding the ball keep it in the palm if (rightGrabButtonPressed) { - var properties = { - position: { x: rightPalmPosition.x / TREE_SCALE, - y: rightPalmPosition.y / TREE_SCALE, - z: rightPalmPosition.z / TREE_SCALE } , - }; - -print("Particles.editParticle()... staying in hand rightHandParticle=" + rightHandParticle.creatorTokenID); + debugPrint(">>>>> RIGHT-BALL IN HAND, grabbing, hold and move"); + var ballPosition = getBallHoldPosition(false); // false == right hand + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, + }; Particles.editParticle(rightHandParticle, properties); -print("rightPalmPosition: " + rightPalmPosition.x + ", "+ rightPalmPosition.y + ", "+ rightPalmPosition.z); -print("rightPalmPosition: " + rightPalmPosition.x / TREE_SCALE + ", "+ rightPalmPosition.y / TREE_SCALE + ", "+ rightPalmPosition.z / TREE_SCALE); - } else { -print(">>>>> RIGHT-BALL IN HAND, but NOT GRABBING!!!"); + debugPrint(">>>>> RIGHT-BALL IN HAND, not grabbing, THROW!!!"); // If toy ball just released, add velocity to it! - var rightTipVelocity = Controller.getSpatialControlVelocity(LEFT_TIP); - + var tipVelocity = Controller.getSpatialControlVelocity(RIGHT_TIP); + var THROWN_VELOCITY_SCALING = 1.5; var properties = { - velocity: { x: rightTipVelocity.x / TREE_SCALE, - y: rightTipVelocity.y / TREE_SCALE, - z: rightTipVelocity.z / TREE_SCALE } , + velocity: { x: (tipVelocity.x * THROWN_VELOCITY_SCALING) / TREE_SCALE, + y: (tipVelocity.y * THROWN_VELOCITY_SCALING) / TREE_SCALE, + z: (tipVelocity.z * THROWN_VELOCITY_SCALING) / TREE_SCALE } , inHand: false, gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, }; -print("Particles.editParticle()... releasing rightHandParticle=" + rightHandParticle.creatorTokenID); Particles.editParticle(rightHandParticle, properties); rightBallAlreadyInHand = false; rightHandParticle = false; - /** - AudioInjectorOptions injectorOptions; - injectorOptions.setPosition(ballPosition); - injectorOptions.setLoopbackAudioInterface(app->getAudio()); - - AudioScriptingInterface::playSound(&_throwSound, &injectorOptions); - **/ + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(throwSound, options); } } } From 1b5938d0afa1968efcc3e44ba39dd301599a991a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 09:48:04 -0800 Subject: [PATCH 20/24] new toyball script that is DRY-er --- examples/toyball.js | 362 +++++++++++++++++++------------------------- 1 file changed, 153 insertions(+), 209 deletions(-) diff --git a/examples/toyball.js b/examples/toyball.js index e68f76f320..4588c0397b 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -2,8 +2,8 @@ // toyball.js // hifi // -// Created by Brad Hefta-Gaub on 12/31/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// Created by Brad Hefta-Gaub on 1/20/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // // This is an example script that turns the hydra controllers into a toy ball catch and throw game. // It reads the controller, watches for button presses and trigger pulls, and launches particles. @@ -31,11 +31,20 @@ var rightHandParticle; var throwSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); +var targetRadius = 0.25; -function getBallHoldPosition(leftHand) { + +var wantDebugging = false; +function debugPrint(message) { + if (wantDebugging) { + print(message); + } +} + +function getBallHoldPosition(whichSide) { var normal; var tipPosition; - if (leftHand) { + if (whichSide == LEFT_PALM) { normal = Controller.getSpatialControlNormal(LEFT_PALM); tipPosition = Controller.getSpatialControlPosition(LEFT_TIP); } else { @@ -55,10 +64,144 @@ function getBallHoldPosition(leftHand) { return position; } -var wantDebugging = false; -function debugPrint(message) { - if (wantDebugging) { - print(message); +function checkControllerSide(whichSide) { + var BUTTON_FWD; + var BUTTON_3; + var palmPosition; + var ballAlreadyInHand; + var handMessage; + + if (whichSide == LEFT_PALM) { + BUTTON_FWD = LEFT_BUTTON_FWD; + BUTTON_3 = LEFT_BUTTON_3; + palmPosition = Controller.getSpatialControlPosition(LEFT_PALM); + ballAlreadyInHand = leftBallAlreadyInHand; + handMessage = "LEFT"; + } else { + BUTTON_FWD = RIGHT_BUTTON_FWD; + BUTTON_3 = RIGHT_BUTTON_3; + palmPosition = Controller.getSpatialControlPosition(RIGHT_PALM); + ballAlreadyInHand = rightBallAlreadyInHand; + handMessage = "RIGHT"; + } + + var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3)); + + // If I don't currently have a ball in my hand, then try to catch closest one + if (!ballAlreadyInHand && grabButtonPressed) { + var closestParticle = Particles.findClosestParticle(palmPosition, targetRadius); + + if (closestParticle.isKnownID) { + + debugPrint(handMessage + " HAND- CAUGHT SOMETHING!!"); + + if (whichSide == LEFT_PALM) { + leftBallAlreadyInHand = true; + leftHandParticle = closestParticle; + } else { + rightBallAlreadyInHand = true; + rightHandParticle = closestParticle; + } + var ballPosition = getBallHoldPosition(whichSide); + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, + velocity : { x: 0, y: 0, z: 0}, inHand: true }; + Particles.editParticle(closestParticle, properties); + + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(catchSound, options); + + return; // exit early + } + } + + // change ball color logic... + // + //if (wasButtonJustPressed()) { + // rotateColor(); + //} + + // If '3' is pressed, and not holding a ball, make a new one + if (Controller.isButtonPressed(BUTTON_3) && !ballAlreadyInHand) { + var ballPosition = getBallHoldPosition(whichSide); + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, + velocity: { x: 0, y: 0, z: 0}, + gravity: { x: 0, y: 0, z: 0}, + inHand: true, + radius: 0.05 / TREE_SCALE, + color: { red: 255, green: 0, blue: 0 }, + lifetime: 10 // 10 seconds + }; + + newParticle = Particles.addParticle(properties); + if (whichSide == LEFT_PALM) { + leftBallAlreadyInHand = true; + leftHandParticle = newParticle; + } else { + rightBallAlreadyInHand = true; + rightHandParticle = newParticle; + } + + // Play a new ball sound + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(catchSound, options); + + return; // exit early + } + + if (ballAlreadyInHand) { + if (whichSide == LEFT_PALM) { + handParticle = leftHandParticle; + whichTip = LEFT_TIP; + } else { + handParticle = rightHandParticle; + whichTip = RIGHT_TIP; + } + + // If holding the ball keep it in the palm + if (grabButtonPressed) { + debugPrint(">>>>> " + handMessage + "-BALL IN HAND, grabbing, hold and move"); + var ballPosition = getBallHoldPosition(whichSide); + var properties = { position: { x: ballPosition.x / TREE_SCALE, + y: ballPosition.y / TREE_SCALE, + z: ballPosition.z / TREE_SCALE }, + }; + Particles.editParticle(handParticle, properties); + } else { + debugPrint(">>>>> " + handMessage + "-BALL IN HAND, not grabbing, THROW!!!"); + // If toy ball just released, add velocity to it! + var tipVelocity = Controller.getSpatialControlVelocity(whichTip); + var THROWN_VELOCITY_SCALING = 1.5; + var properties = { + velocity: { x: (tipVelocity.x * THROWN_VELOCITY_SCALING) / TREE_SCALE, + y: (tipVelocity.y * THROWN_VELOCITY_SCALING) / TREE_SCALE, + z: (tipVelocity.z * THROWN_VELOCITY_SCALING) / TREE_SCALE } , + inHand: false, + gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, + }; + + Particles.editParticle(handParticle, properties); + + if (whichSide == LEFT_PALM) { + leftBallAlreadyInHand = false; + leftHandParticle = false; + } else { + rightBallAlreadyInHand = false; + rightHandParticle = false; + } + + var options = new AudioInjectionOptions();
 + options.position = ballPosition; + options.volume = 1.0; + Audio.playSound(throwSound, options); + } } } @@ -75,207 +218,8 @@ function checkController() { return; // bail if no hydra } - var leftGrabButtonPressed = (Controller.isButtonPressed(LEFT_BUTTON_FWD) || Controller.isButtonPressed(LEFT_BUTTON_3)); - var rightGrabButtonPressed = (Controller.isButtonPressed(RIGHT_BUTTON_FWD) || Controller.isButtonPressed(RIGHT_BUTTON_3)); - - var leftPalmPosition = Controller.getSpatialControlPosition(LEFT_PALM); - var rightPalmPosition = Controller.getSpatialControlPosition(RIGHT_PALM); - - var targetRadius = 3.0; - var exitEarly = false; - - // If I don't currently have a ball in my left hand, then try to catch closest one - if (!leftBallAlreadyInHand && leftGrabButtonPressed) { - var closestParticle = Particles.findClosestParticle(leftPalmPosition, targetRadius); - - if (closestParticle.isKnownID) { - - debugPrint("LEFT HAND- CAUGHT SOMETHING!!"); - - leftBallAlreadyInHand = true; - leftHandParticle = closestParticle; - var ballPosition = getBallHoldPosition(true); - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, - velocity : { x: 0, y: 0, z: 0}, inHand: true }; - Particles.editParticle(leftHandParticle, properties); - - var options = new AudioInjectionOptions();
 - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(catchSound, options); - - exitEarly = true; - } - } - - // If I don't currently have a ball in my right hand, then try to catch closest one - if (!rightBallAlreadyInHand && rightGrabButtonPressed) { - var closestParticle = Particles.findClosestParticle(rightPalmPosition, targetRadius); - - if (closestParticle.isKnownID) { - - debugPrint("RIGHT HAND- CAUGHT SOMETHING!!"); - - rightBallAlreadyInHand = true; - rightHandParticle = closestParticle; - - var ballPosition = getBallHoldPosition(false); // false == right hand - - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, - velocity : { x: 0, y: 0, z: 0}, inHand: true }; - Particles.editParticle(rightHandParticle, properties); - - var options = new AudioInjectionOptions();
 - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(catchSound, options); - - exitEarly = true; - } - } - - // If we did one of the actions above, then exit now - if (exitEarly) { - debugPrint("exiting early - caught something"); - return; - } - - // change ball color logic... - // - //if (wasButtonJustPressed()) { - // rotateColor(); - //} - - // LEFT HAND -- If '3' is pressed, and not holding a ball, make a new one - if (Controller.isButtonPressed(LEFT_BUTTON_3) && !leftBallAlreadyInHand) { - leftBallAlreadyInHand = true; - var ballPosition = getBallHoldPosition(true); // true == left hand - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, - velocity: { x: 0, y: 0, z: 0}, - gravity: { x: 0, y: 0, z: 0}, - inHand: true, - radius: 0.05 / TREE_SCALE, - color: { red: 255, green: 0, blue: 0 }, - lifetime: 30 - }; - - leftHandParticle = Particles.addParticle(properties); - - // Play a new ball sound - var options = new AudioInjectionOptions();
 - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(catchSound, options); - - exitEarly = true; - } - - // RIGHT HAND -- If '3' is pressed, and not holding a ball, make a new one - if (Controller.isButtonPressed(RIGHT_BUTTON_3) && !rightBallAlreadyInHand) { - rightBallAlreadyInHand = true; - var ballPosition = getBallHoldPosition(false); // false == right hand - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, - velocity: { x: 0, y: 0, z: 0}, - gravity: { x: 0, y: 0, z: 0}, - inHand: true, - radius: 0.05 / TREE_SCALE, - color: { red: 255, green: 255, blue: 0 }, - lifetime: 30 - }; - - rightHandParticle = Particles.addParticle(properties); - - // Play a new ball sound - var options = new AudioInjectionOptions();
 - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(catchSound, options); - - exitEarly = true; - } - - // If we did one of the actions above, then exit now - if (exitEarly) { - debugPrint("exiting early - ball created"); - return; - } - - if (leftBallAlreadyInHand) { - // If holding the ball keep it in the palm - if (leftGrabButtonPressed) { - debugPrint(">>>>> LEFT-BALL IN HAND, grabbing, hold and move"); - var ballPosition = getBallHoldPosition(true); // true == left hand - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, - }; - Particles.editParticle(leftHandParticle, properties); - } else { - debugPrint(">>>>> LEFT-BALL IN HAND, not grabbing, THROW!!!"); - // If toy ball just released, add velocity to it! - var tipVelocity = Controller.getSpatialControlVelocity(LEFT_TIP); - var THROWN_VELOCITY_SCALING = 1.5; - var properties = { - velocity: { x: (tipVelocity.x * THROWN_VELOCITY_SCALING) / TREE_SCALE, - y: (tipVelocity.y * THROWN_VELOCITY_SCALING) / TREE_SCALE, - z: (tipVelocity.z * THROWN_VELOCITY_SCALING) / TREE_SCALE } , - inHand: false, - gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, - }; - - Particles.editParticle(leftHandParticle, properties); - leftBallAlreadyInHand = false; - leftHandParticle = false; - - var options = new AudioInjectionOptions();
 - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(throwSound, options); - } - } - - if (rightBallAlreadyInHand) { - // If holding the ball keep it in the palm - if (rightGrabButtonPressed) { - debugPrint(">>>>> RIGHT-BALL IN HAND, grabbing, hold and move"); - var ballPosition = getBallHoldPosition(false); // false == right hand - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, - }; - Particles.editParticle(rightHandParticle, properties); - } else { - debugPrint(">>>>> RIGHT-BALL IN HAND, not grabbing, THROW!!!"); - - // If toy ball just released, add velocity to it! - var tipVelocity = Controller.getSpatialControlVelocity(RIGHT_TIP); - var THROWN_VELOCITY_SCALING = 1.5; - var properties = { - velocity: { x: (tipVelocity.x * THROWN_VELOCITY_SCALING) / TREE_SCALE, - y: (tipVelocity.y * THROWN_VELOCITY_SCALING) / TREE_SCALE, - z: (tipVelocity.z * THROWN_VELOCITY_SCALING) / TREE_SCALE } , - inHand: false, - gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, - }; - - Particles.editParticle(rightHandParticle, properties); - rightBallAlreadyInHand = false; - rightHandParticle = false; - - var options = new AudioInjectionOptions();
 - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(throwSound, options); - } - } + checkControllerSide(LEFT_PALM); + checkControllerSide(RIGHT_PALM); } From f81adb88107f5b1ac97150cb2e62f449271a1f7a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 09:48:19 -0800 Subject: [PATCH 21/24] update packet versions --- libraries/shared/src/PacketHeaders.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index b475c9febc..f595dfcafc 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -45,10 +45,10 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { return 1; case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: - return 3; + return 4; case PACKET_TYPE_PARTICLE_DATA: - return 7; + return 8; case PACKET_TYPE_PING_REPLY: return 1; From c3b681786adc756ae9500f832f61e48b576089c4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 11:12:52 -0800 Subject: [PATCH 22/24] make particles and voxels JS APIs all operate on meters not domain units --- examples/collidingParticles.js | 61 +++++++++++++------ examples/editParticleExample.js | 22 ++++--- examples/fountain.js | 33 +++++----- examples/gun.js | 58 ++++++++---------- examples/movingVoxel.js | 4 +- examples/paintGun.js | 52 ++++++---------- examples/toyball.js | 28 ++++----- examples/voxelBird.js | 14 ++--- libraries/particles/src/Particle.cpp | 39 ++++++------ libraries/particles/src/Particle.h | 56 ++++++++++++++--- .../voxels/src/VoxelsScriptingInterface.cpp | 14 +++-- .../voxels/src/VoxelsScriptingInterface.h | 44 +++++++------ 12 files changed, 239 insertions(+), 186 deletions(-) diff --git a/examples/collidingParticles.js b/examples/collidingParticles.js index f53933871f..cf1fce5660 100644 --- a/examples/collidingParticles.js +++ b/examples/collidingParticles.js @@ -18,14 +18,14 @@ var numberParticlesAdded = 0; var MAX_PARTICLES = 1; var velocity = { - x: 1/TREE_SCALE, - y: 0/TREE_SCALE, - z: 1/TREE_SCALE }; + x: 1, + y: 0, + z: 1 }; var gravity = { - x: 0/TREE_SCALE, - y: 0/TREE_SCALE, - z: 0/TREE_SCALE }; + x: 0, + y: 0, + z: 0 }; var damping = 0.1; @@ -65,16 +65,27 @@ function draw() { if (currentIteration == 0) { var colorGreen = { red: 0, green: 255, blue: 0 }; var startPosition = { - x: 2/TREE_SCALE, - y: 0/TREE_SCALE, - z: 2/TREE_SCALE }; - var largeRadius = 0.5/TREE_SCALE; + x: 2, + y: 0, + z: 2 }; + var largeRadius = 0.5; var verySlow = { - x: 0.01/TREE_SCALE, - y: 0/TREE_SCALE, - z: 0.01/TREE_SCALE }; + x: 0.01, + y: 0, + z: 0.01 }; + + var properties = { + position: startPosition, + radius: largeRadius, + color: colorGreen, + velocity: verySlow, + gravity: gravity, + damping: damping, + inHand: false, + script: scriptA + }; - Particles.queueParticleAdd(startPosition, largeRadius, colorGreen, verySlow, gravity, damping, false, scriptA); + Particles.addParticle(properties); print("hello... added particle... script=\n"); print(scriptA); numberParticlesAdded++; @@ -84,15 +95,15 @@ function draw() { print("draw()... sending another... currentIteration=" +currentIteration + "\n"); var center = { - x: 0/TREE_SCALE, - y: 0/TREE_SCALE, - z: 0/TREE_SCALE }; + x: 0, + y: 0, + z: 0 }; - var particleSize = 0.1 / TREE_SCALE; + var particleSize = 0.1; print("number of particles=" + numberParticlesAdded +"\n"); - var velocityStep = 0.1/TREE_SCALE; + var velocityStep = 0.1; if (velocity.x > 0) { velocity.x -= velocityStep; velocity.z += velocityStep; @@ -106,7 +117,17 @@ function draw() { } if (numberParticlesAdded <= MAX_PARTICLES) { - Particles.queueParticleAdd(center, particleSize, color, velocity, gravity, damping, false, scriptB); + var properties = { + position: center, + radius: particleSize, + color: color, + velocity: velocity, + gravity: gravity, + damping: damping, + inHand: false, + script: scriptB + }; + Particles.addParticle(properties); print("hello... added particle... script=\n"); print(scriptB); numberParticlesAdded++; diff --git a/examples/editParticleExample.js b/examples/editParticleExample.js index 24725ddf42..4eb5dfe907 100644 --- a/examples/editParticleExample.js +++ b/examples/editParticleExample.js @@ -11,9 +11,9 @@ var count = 0; var originalProperties = { - position: { x: 10/TREE_SCALE, - y: 0/TREE_SCALE, - z: 0/TREE_SCALE }, + position: { x: 10, + y: 0, + z: 0 }, velocity: { x: 0, y: 0, @@ -24,7 +24,7 @@ var originalProperties = { z: 0 }, - radius : 0.1/TREE_SCALE, + radius : 0.1, color: { red: 0, green: 255, @@ -32,23 +32,23 @@ var originalProperties = { }; -var positionDelta = { x: 0.1/TREE_SCALE, y: 0, z: 0 }; +var positionDelta = { x: 0.05, y: 0, z: 0 }; var particleID = Particles.addParticle(originalProperties); function moveParticle() { - if (count >= 10) { + if (count >= 100) { //Agent.stop(); // delete it... - if (count == 10) { + if (count == 100) { print("calling Particles.deleteParticle()"); Particles.deleteParticle(particleID); } // stop it... - if (count >= 100) { + if (count >= 200) { print("calling Agent.stop()"); Agent.stop(); } @@ -68,7 +68,7 @@ function moveParticle() { y: originalProperties.position.y + (count * positionDelta.y), z: originalProperties.position.z + (count * positionDelta.z) }, - radius : 0.25/TREE_SCALE, + radius : 0.25, }; @@ -79,11 +79,13 @@ function moveParticle() { Particles.editParticle(particleID, newProperties); // also check to see if we can "find" particles... - var searchAt = { x: 0, y: 0, z: 0}; + var searchAt = { x: 9, y: 0, z: 0}; var searchRadius = 2; var foundParticle = Particles.findClosestParticle(searchAt, searchRadius); if (foundParticle.isKnownID) { print("found particle:" + foundParticle.id); + } else { + print("could not find particle in or around x=9 to x=11:"); } } diff --git a/examples/fountain.js b/examples/fountain.js index b15557c8ee..86c125a834 100644 --- a/examples/fountain.js +++ b/examples/fountain.js @@ -37,25 +37,30 @@ function vInterpolate(a, b, fraction) { return rval; } -var position = { x: 5.0 / TREE_SCALE, y: 5.0 / TREE_SCALE, z: 5.0 / TREE_SCALE }; -Voxels.queueDestructiveVoxelAdd(position.x, position.y - (1.0 / TREE_SCALE), position.z, 0.5 / TREE_SCALE, 255, 255, 1); +var position = { x: 5.0, y: 0.6, z: 5.0 }; +Voxels.setVoxel(position.x, 0, position.z, 0.5, 0, 0, 255); +var totalParticles = 0; function makeFountain() { if (Math.random() < 0.06) { //print("Made particle!\n"); + var properties = { + position: position, + radius: (0.02 + (Math.random() * 0.05)), + color: { red: 0, green: 0, blue: 128 }, + velocity: { x: (Math.random() * 1.0 - 0.5), + y: (1.0 + (Math.random() * 2.0)), + z: (Math.random() * 1.0 - 0.5) }, + gravity: { x: 0, y: -0.5, z: 0 }, + damping: 0.25, + lifetime: 2 + } - var size = (0.02 + (Math.random() * 0.05)) / TREE_SCALE; - var velocity = { x: (Math.random() * 1.0 - 0.5) / TREE_SCALE, - y: (1.0 + (Math.random() * 2.0)) / TREE_SCALE, - z: (Math.random() * 1.0 - 0.5) / TREE_SCALE }; - - var gravity = { x: 0, y: -0.5 / TREE_SCALE, z: 0 }; // gravity has no effect on these bullets - var color = { red: 0, green: 0, blue: 128 }; - var damping = 0.25; // no damping - var inHand = false; - var script = ""; - - Particles.queueParticleAdd(position, size, color, velocity, gravity, damping, inHand, script); + Particles.addParticle(properties); + totalParticles++; + } + if (totalParticles > 100) { + Agent.stop(); } } // register the call back so it fires before each data send diff --git a/examples/gun.js b/examples/gun.js index b93131c0f7..30d2b41449 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -45,46 +45,30 @@ function checkController() { } if (shootABullet) { - var palmController = t * controllersPerTrigger; + var palmController = t * controllersPerTrigger; var palmPosition = Controller.getSpatialControlPosition(palmController); - var fingerTipController = palmController + 1; + var fingerTipController = palmController + 1; var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController); - var bulletSize = 0.05/TREE_SCALE; - - var palmInParticleSpace = - { x: palmPosition.x/TREE_SCALE, - y: palmPosition.y/TREE_SCALE, - z: palmPosition.z/TREE_SCALE }; - - var tipInParticleSpace = - { x: fingerTipPosition.x/TREE_SCALE, - y: fingerTipPosition.y/TREE_SCALE, - z: fingerTipPosition.z/TREE_SCALE }; - - var palmToFingerTipVector = - { x: (tipInParticleSpace.x - palmInParticleSpace.x), - y: (tipInParticleSpace.y - palmInParticleSpace.y), - z: (tipInParticleSpace.z - palmInParticleSpace.z) }; - + + var palmToFingerTipVector = + { x: (fingerTipPosition.x - palmPosition.x), + y: (fingerTipPosition.y - palmPosition.y), + z: (fingerTipPosition.z - palmPosition.z) }; + // just off the front of the finger tip - var position = { x: tipInParticleSpace.x + palmToFingerTipVector.x/2, - y: tipInParticleSpace.y + palmToFingerTipVector.y/2, - z: tipInParticleSpace.z + palmToFingerTipVector.z/2}; - - var linearVelocity = 5; + var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2, + y: fingerTipPosition.y + palmToFingerTipVector.y/2, + z: fingerTipPosition.z + palmToFingerTipVector.z/2}; + var linearVelocity = 25; + var velocity = { x: palmToFingerTipVector.x * linearVelocity, y: palmToFingerTipVector.y * linearVelocity, z: palmToFingerTipVector.z * linearVelocity }; - var gravity = { x: 0, y: -0.1/TREE_SCALE, z: 0 }; // gravity has no effect on these bullets - var color = { red: 128, green: 128, blue: 128 }; - var damping = 0; // no damping - var inHand = false; - // This is the script for the particles that this gun shoots. - var script = + var script = " function collisionWithVoxel(voxel) { " + " print('collisionWithVoxel(voxel)... '); " + " print('myID=' + Particle.getID() + '\\n'); " + @@ -92,16 +76,22 @@ function checkController() { " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " + " var myColor = Particle.getColor();" + " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " + - " var newProps = { color: voxelColor }; " + - " Particle.setProperties(newProps); " + + " Particle.setColor(voxelColor); " + " var voxelAt = voxel.getPosition();" + " var voxelScale = voxel.getScale();" + " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " } " + " Particle.collisionWithVoxel.connect(collisionWithVoxel); "; - - Particles.queueParticleAdd(position, bulletSize, color, velocity, gravity, damping, inHand, script); + + Particles.addParticle( + { position: position, + radius: 0.05, + color: { red: 128, green: 128, blue: 128 }, + velocity: velocity, + gravity: { x: 0, y: -0.1, z: 0 }, + damping: 0, + script: script }); } } } diff --git a/examples/movingVoxel.js b/examples/movingVoxel.js index 44ab418aaf..0aadf7b30c 100644 --- a/examples/movingVoxel.js +++ b/examples/movingVoxel.js @@ -28,9 +28,9 @@ function moveVoxel() { thisColor = colorEdge; } // Create a new voxel - Voxels.queueDestructiveVoxelAdd(position.x / TREE_SCALE, position.y / TREE_SCALE, position.z / TREE_SCALE, size / TREE_SCALE, thisColor.r, thisColor.g, thisColor.b); + Voxels.setVoxel(position.x, position.y, position.z, size, thisColor.r, thisColor.g, thisColor.b); // delete old voxel - Voxels.queueVoxelDelete(oldPosition.x / TREE_SCALE, oldPosition.y / TREE_SCALE, oldPosition.z / TREE_SCALE, size / TREE_SCALE); + Voxels.eraseVoxel(oldPosition.x, oldPosition.y, oldPosition.z, size); // Copy old location to new oldPosition.x = position.x; oldPosition.y = position.y; diff --git a/examples/paintGun.js b/examples/paintGun.js index f75df58314..0cbe3ff366 100644 --- a/examples/paintGun.js +++ b/examples/paintGun.js @@ -1,17 +1,10 @@ // -// gun.js +// paintGun.js // hifi // // Created by Brad Hefta-Gaub on 12/31/13. // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // -// This is an example script that turns the hydra controllers into a particle gun. -// It reads the controller, watches for trigger pulls, and launches particles. -// The particles it creates have a script that when they collide with Voxels, the -// particle will change it's color to match the voxel it hits, and then delete the -// voxel. -// -// // initialize our triggers var triggerPulled = new Array(); @@ -51,27 +44,15 @@ function checkController() { var fingerTipController = palmController + 1; var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController); - var bulletSize = 0.01/TREE_SCALE; - - var palmInParticleSpace = - { x: palmPosition.x/TREE_SCALE, - y: palmPosition.y/TREE_SCALE, - z: palmPosition.z/TREE_SCALE }; - - var tipInParticleSpace = - { x: fingerTipPosition.x/TREE_SCALE, - y: fingerTipPosition.y/TREE_SCALE, - z: fingerTipPosition.z/TREE_SCALE }; - var palmToFingerTipVector = - { x: (tipInParticleSpace.x - palmInParticleSpace.x), - y: (tipInParticleSpace.y - palmInParticleSpace.y), - z: (tipInParticleSpace.z - palmInParticleSpace.z) }; + { x: (fingerTipPosition.x - palmPosition.x), + y: (fingerTipPosition.y - palmPosition.y), + z: (fingerTipPosition.z - palmPosition.z) }; // just off the front of the finger tip - var position = { x: tipInParticleSpace.x + palmToFingerTipVector.x/2, - y: tipInParticleSpace.y + palmToFingerTipVector.y/2, - z: tipInParticleSpace.z + palmToFingerTipVector.z/2}; + var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2, + y: fingerTipPosition.y + palmToFingerTipVector.y/2, + z: fingerTipPosition.z + palmToFingerTipVector.z/2}; var linearVelocity = 25; @@ -79,11 +60,6 @@ function checkController() { y: palmToFingerTipVector.y * linearVelocity, z: palmToFingerTipVector.z * linearVelocity }; - var gravity = { x: 0, y: -0.1/TREE_SCALE, z: 0 }; // gravity has no effect on these bullets - var color = { red: 128, green: 128, blue: 128 }; - var damping = 0; // no damping - var inHand = false; - // This is the script for the particles that this gun shoots. var script = " function collisionWithVoxel(voxel) { " + @@ -96,12 +72,20 @@ function checkController() { " Particle.setColor(voxelColor); " + " var voxelAt = voxel.getPosition();" + " var voxelScale = voxel.getScale();" + - " Voxels.queueVoxelAdd(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale, 255, 255, 0); " + - " print('Voxels.queueVoxelDelete(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + + " Voxels.setVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale, 255, 255, 0); " + + " print('Voxels.setVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " } " + " Particle.collisionWithVoxel.connect(collisionWithVoxel); "; - Particles.queueParticleAdd(position, bulletSize, color, velocity, gravity, damping, inHand, script); + Particles.addParticle( + { position: position, + radius: 0.01, + color: { red: 128, green: 128, blue: 128 }, + velocity: velocity, + gravity: { x: 0, y: -0.1, z: 0 }, + damping: 0, + script: script } + ); } } } diff --git a/examples/toyball.js b/examples/toyball.js index 4588c0397b..1682cbe3d4 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -103,9 +103,9 @@ function checkControllerSide(whichSide) { rightHandParticle = closestParticle; } var ballPosition = getBallHoldPosition(whichSide); - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, + var properties = { position: { x: ballPosition.x, + y: ballPosition.y, + z: ballPosition.z }, velocity : { x: 0, y: 0, z: 0}, inHand: true }; Particles.editParticle(closestParticle, properties); @@ -127,13 +127,13 @@ function checkControllerSide(whichSide) { // If '3' is pressed, and not holding a ball, make a new one if (Controller.isButtonPressed(BUTTON_3) && !ballAlreadyInHand) { var ballPosition = getBallHoldPosition(whichSide); - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, + var properties = { position: { x: ballPosition.x, + y: ballPosition.y, + z: ballPosition.z }, velocity: { x: 0, y: 0, z: 0}, gravity: { x: 0, y: 0, z: 0}, inHand: true, - radius: 0.05 / TREE_SCALE, + radius: 0.05, color: { red: 255, green: 0, blue: 0 }, lifetime: 10 // 10 seconds }; @@ -169,9 +169,9 @@ function checkControllerSide(whichSide) { if (grabButtonPressed) { debugPrint(">>>>> " + handMessage + "-BALL IN HAND, grabbing, hold and move"); var ballPosition = getBallHoldPosition(whichSide); - var properties = { position: { x: ballPosition.x / TREE_SCALE, - y: ballPosition.y / TREE_SCALE, - z: ballPosition.z / TREE_SCALE }, + var properties = { position: { x: ballPosition.x, + y: ballPosition.y, + z: ballPosition.z }, }; Particles.editParticle(handParticle, properties); } else { @@ -180,11 +180,11 @@ function checkControllerSide(whichSide) { var tipVelocity = Controller.getSpatialControlVelocity(whichTip); var THROWN_VELOCITY_SCALING = 1.5; var properties = { - velocity: { x: (tipVelocity.x * THROWN_VELOCITY_SCALING) / TREE_SCALE, - y: (tipVelocity.y * THROWN_VELOCITY_SCALING) / TREE_SCALE, - z: (tipVelocity.z * THROWN_VELOCITY_SCALING) / TREE_SCALE } , + velocity: { x: tipVelocity.x * THROWN_VELOCITY_SCALING, + y: tipVelocity.y * THROWN_VELOCITY_SCALING, + z: tipVelocity.z * THROWN_VELOCITY_SCALING } , inHand: false, - gravity: { x: 0, y: -2 / TREE_SCALE, z: 0}, + gravity: { x: 0, y: -2, z: 0}, }; Particles.editParticle(handParticle, properties); diff --git a/examples/voxelBird.js b/examples/voxelBird.js index bc4cac0247..54c0129045 100644 --- a/examples/voxelBird.js +++ b/examples/voxelBird.js @@ -110,17 +110,17 @@ function moveBird() { if (tweeting > 0) { // Change color of voxel to blinky red a bit while playing the sound var blinkColor = { r: Math.random() * 255, g: 0, b: 0 }; - Voxels.queueDestructiveVoxelAdd(position.x / TREE_SCALE, - position.y / TREE_SCALE, - position.z / TREE_SCALE, - size / TREE_SCALE, - blinkColor.r, blinkColor.g, blinkColor.b); + Voxels.setVoxel(position.x, + position.y, + position.z, + size, + blinkColor.r, blinkColor.g, blinkColor.b); } if (moved) { - Voxels.queueDestructiveVoxelAdd(position.x / TREE_SCALE, position.y / TREE_SCALE, position.z / TREE_SCALE, size / TREE_SCALE, thisColor.r, thisColor.g, thisColor.b); + Voxels.setVoxel(position.x, position.y, position.z, size, thisColor.r, thisColor.g, thisColor.b); // delete old voxel - Voxels.queueVoxelDelete(oldPosition.x / TREE_SCALE, oldPosition.y / TREE_SCALE, oldPosition.z / TREE_SCALE, size / TREE_SCALE); + Voxels.eraseVoxel(oldPosition.x, oldPosition.y, oldPosition.z, size); // Copy old location to new vCopy(oldPosition, position); moved = false; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 057ad07c36..5570797ab4 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -539,7 +539,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID // radius if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS)) { - float radius = properties.getRadius(); + float radius = properties.getRadius() / (float) TREE_SCALE; memcpy(copyAt, &radius, sizeof(radius)); copyAt += sizeof(radius); sizeOut += sizeof(radius); @@ -547,9 +547,10 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID // position if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION)) { - memcpy(copyAt, &properties.getPosition(), sizeof(properties.getPosition())); - copyAt += sizeof(properties.getPosition()); - sizeOut += sizeof(properties.getPosition()); + glm::vec3 position = properties.getPosition() / (float)TREE_SCALE; + memcpy(copyAt, &position, sizeof(position)); + copyAt += sizeof(position); + sizeOut += sizeof(position); } // color @@ -562,16 +563,18 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID // velocity if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY)) { - memcpy(copyAt, &properties.getVelocity(), sizeof(properties.getVelocity())); - copyAt += sizeof(properties.getVelocity()); - sizeOut += sizeof(properties.getVelocity()); + glm::vec3 velocity = properties.getVelocity() / (float)TREE_SCALE; + memcpy(copyAt, &velocity, sizeof(velocity)); + copyAt += sizeof(velocity); + sizeOut += sizeof(velocity); } // gravity if (isNewParticle || ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY)) { - memcpy(copyAt, &properties.getGravity(), sizeof(properties.getGravity())); - copyAt += sizeof(properties.getGravity()); - sizeOut += sizeof(properties.getGravity()); + glm::vec3 gravity = properties.getGravity() / (float)TREE_SCALE; + memcpy(copyAt, &gravity, sizeof(gravity)); + copyAt += sizeof(gravity); + sizeOut += sizeof(gravity); } // damping @@ -1063,7 +1066,7 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) { void ParticleProperties::copyToParticle(Particle& particle) const { if (_positionChanged) { - particle.setPosition(_position); + particle.setPosition(_position / (float) TREE_SCALE); } if (_colorChanged) { @@ -1071,15 +1074,15 @@ void ParticleProperties::copyToParticle(Particle& particle) const { } if (_radiusChanged) { - particle.setRadius(_radius); + particle.setRadius(_radius / (float) TREE_SCALE); } if (_velocityChanged) { - particle.setVelocity(_velocity); + particle.setVelocity(_velocity / (float) TREE_SCALE); } if (_gravityChanged) { - particle.setGravity(_gravity); + particle.setGravity(_gravity / (float) TREE_SCALE); } if (_dampingChanged) { @@ -1104,11 +1107,11 @@ void ParticleProperties::copyToParticle(Particle& particle) const { } void ParticleProperties::copyFromParticle(const Particle& particle) { - _position = particle.getPosition(); + _position = particle.getPosition() * (float) TREE_SCALE; _color = particle.getXColor(); - _radius = particle.getRadius(); - _velocity = particle.getVelocity(); - _gravity = particle.getGravity(); + _radius = particle.getRadius() * (float) TREE_SCALE; + _velocity = particle.getVelocity() * (float) TREE_SCALE; + _gravity = particle.getGravity() * (float) TREE_SCALE; _damping = particle.getDamping(); _lifetime = particle.getLifetime(); _script = particle.getScript(); diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index da8cf35ac2..10a8d6868c 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -54,6 +54,7 @@ const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand /// A collection of properties of a particle used in the scripting API. Translates between the actual properties of a particle /// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of /// particle properties via JavaScript hashes/QScriptValues +/// all units for position, velocity, gravity, radius, etc are in meter units class ParticleProperties { public: ParticleProperties(); @@ -78,10 +79,15 @@ public: uint64_t getLastEdited() const { return _lastEdited; } uint16_t getChangedBits() const; + /// set position in meter units void setPosition(const glm::vec3& value) { _position = value; _positionChanged = true; } + + /// set velocity in meter units void setVelocity(const glm::vec3& value) { _velocity = value; _velocityChanged = true; } void setColor(const xColor& value) { _color = value; _colorChanged = true; } void setRadius(float value) { _radius = value; _radiusChanged = true; } + + /// set gravity in meter units void setGravity(const glm::vec3& value) { _gravity = value; _gravityChanged = true; } void setInHand(bool inHand) { _inHand = inHand; _inHandChanged = true; } void setDamping(float value) { _damping = value; _dampingChanged = true; } @@ -146,6 +152,8 @@ class Particle { public: Particle(); + + /// all position, velocity, gravity, radius units are in domain units (0.0 to 1.0) Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, float lifetime = DEFAULT_LIFETIME, bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); @@ -158,13 +166,22 @@ public: glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, float lifetime = DEFAULT_LIFETIME, bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); + /// get position in domain scale units (0.0 - 1.0) const glm::vec3& getPosition() const { return _position; } + const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } + + /// get radius in domain scale units (0.0 - 1.0) float getRadius() const { return _radius; } float getMass() const { return _mass; } + + /// get velocity in domain scale units (0.0 - 1.0) const glm::vec3& getVelocity() const { return _velocity; } + + /// get gravity in domain scale units (0.0 - 1.0) const glm::vec3& getGravity() const { return _gravity; } + bool getInHand() const { return _inHand; } float getDamping() const { return _damping; } float getLifetime() const { return _lifetime; } @@ -185,7 +202,10 @@ public: uint32_t getCreatorTokenID() const { return _creatorTokenID; } bool isNewlyCreated() const { return _newlyCreated; } + /// set position in domain scale units (0.0 - 1.0) void setPosition(const glm::vec3& value) { _position = value; } + + /// set velocity in domain scale units (0.0 - 1.0) void setVelocity(const glm::vec3& value) { _velocity = value; } void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } void setColor(const xColor& value) { @@ -193,8 +213,11 @@ public: _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; } + /// set radius in domain scale units (0.0 - 1.0) void setRadius(float value) { _radius = value; } void setMass(float value); + + /// set gravity in domain scale units (0.0 - 1.0) void setGravity(const glm::vec3& value) { _gravity = value; } void setInHand(bool inHand) { _inHand = inHand; } void setDamping(float value) { _damping = value; } @@ -291,23 +314,40 @@ public: public slots: unsigned int getID() const { return _particle->getID(); } - glm::vec3 getPosition() const { return _particle->getPosition(); } - glm::vec3 getVelocity() const { return _particle->getVelocity(); } + + /// get position in meter units + glm::vec3 getPosition() const { return _particle->getPosition() * (float)TREE_SCALE; } + + /// get velocity in meter units + glm::vec3 getVelocity() const { return _particle->getVelocity() * (float)TREE_SCALE; } xColor getColor() const { return _particle->getXColor(); } - glm::vec3 getGravity() const { return _particle->getGravity(); } + + /// get gravity in meter units + glm::vec3 getGravity() const { return _particle->getGravity() * (float)TREE_SCALE; } + float getDamping() const { return _particle->getDamping(); } - float getRadius() const { return _particle->getRadius(); } + + /// get radius in meter units + float getRadius() const { return _particle->getRadius() * (float)TREE_SCALE; } bool getShouldDie() { return _particle->getShouldDie(); } float getAge() const { return _particle->getAge(); } float getLifetime() const { return _particle->getLifetime(); } ParticleProperties getProperties() const { return _particle->getProperties(); } - void setPosition(glm::vec3 value) { _particle->setPosition(value); } - void setVelocity(glm::vec3 value) { _particle->setVelocity(value); } - void setGravity(glm::vec3 value) { _particle->setGravity(value); } + /// set position in meter units + void setPosition(glm::vec3 value) { _particle->setPosition(value / (float)TREE_SCALE); } + + /// set velocity in meter units + void setVelocity(glm::vec3 value) { _particle->setVelocity(value / (float)TREE_SCALE); } + + /// set gravity in meter units + void setGravity(glm::vec3 value) { _particle->setGravity(value / (float)TREE_SCALE); } + void setDamping(float value) { _particle->setDamping(value); } void setColor(xColor value) { _particle->setColor(value); } - void setRadius(float value) { _particle->setRadius(value); } + + /// set radius in meter units + void setRadius(float value) { _particle->setRadius(value / (float)TREE_SCALE); } void setShouldDie(bool value) { _particle->setShouldDie(value); } void setScript(const QString& script) { _particle->setScript(script); } void setLifetime(float value) const { return _particle->setLifetime(value); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index df5dad8231..3f4e19f60a 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -12,18 +12,21 @@ void VoxelsScriptingInterface::queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDet getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails); } -void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { +void VoxelsScriptingInterface::setVoxelNonDestructive(float x, float y, float z, float scale, + uchar red, uchar green, uchar blue) { // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; + VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + scale / (float)TREE_SCALE, red, green, blue}; // queue the packet queueVoxelAdd(PACKET_TYPE_VOXEL_SET, addVoxelDetail); } -void VoxelsScriptingInterface::destructiveSetVoxel(float x, float y, float z, float scale, +void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; + VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + scale / (float)TREE_SCALE, red, green, blue}; // queue the destructive add queueVoxelAdd(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, addVoxelDetail); @@ -32,7 +35,8 @@ void VoxelsScriptingInterface::destructiveSetVoxel(float x, float y, float z, fl void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale) { // setup a VoxelDetail struct with data - VoxelDetail deleteVoxelDetail = {x, y, z, scale, 0, 0, 0}; + VoxelDetail deleteVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + scale / (float)TREE_SCALE, 0, 0, 0}; getVoxelPacketSender()->queueVoxelEditMessages(PACKET_TYPE_VOXEL_ERASE, 1, &deleteVoxelDetail); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index ea9f6a4205..6bbe21d601 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -13,6 +13,8 @@ #include #include + +#include "VoxelConstants.h" #include "VoxelEditPacketSender.h" /// handles scripting of voxel commands from JS passed to assigned clients @@ -26,30 +28,30 @@ public: public slots: /// queues the creation of a voxel which will be sent by calling process on the PacketSender - /// \param x the x-coordinate of the voxel (in VS space) - /// \param y the y-coordinate of the voxel (in VS space) - /// \param z the z-coordinate of the voxel (in VS space) - /// \param scale the scale of the voxel (in VS space) + /// \param x the x-coordinate of the voxel (in meter units) + /// \param y the y-coordinate of the voxel (in meter units) + /// \param z the z-coordinate of the voxel (in meter units) + /// \param scale the scale of the voxel (in meter units) + /// \param red the R value for RGB color of voxel + /// \param green the G value for RGB color of voxel + /// \param blue the B value for RGB color of voxel + void setVoxelNonDestructive(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); + + /// queues the destructive creation of a voxel which will be sent by calling process on the PacketSender + /// \param x the x-coordinate of the voxel (in meter units) + /// \param y the y-coordinate of the voxel (in meter units) + /// \param z the z-coordinate of the voxel (in meter units) + /// \param scale the scale of the voxel (in meter units) /// \param red the R value for RGB color of voxel /// \param green the G value for RGB color of voxel /// \param blue the B value for RGB color of voxel void setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - /// queues the destructive creation of a voxel which will be sent by calling process on the PacketSender - /// \param x the x-coordinate of the voxel (in VS space) - /// \param y the y-coordinate of the voxel (in VS space) - /// \param z the z-coordinate of the voxel (in VS space) - /// \param scale the scale of the voxel (in VS space) - /// \param red the R value for RGB color of voxel - /// \param green the G value for RGB color of voxel - /// \param blue the B value for RGB color of voxel - void destructiveSetVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - /// queues the deletion of a voxel, sent by calling process on the PacketSender - /// \param x the x-coordinate of the voxel (in VS space) - /// \param y the y-coordinate of the voxel (in VS space) - /// \param z the z-coordinate of the voxel (in VS space) - /// \param scale the scale of the voxel (in VS space) + /// \param x the x-coordinate of the voxel (in meter units) + /// \param y the y-coordinate of the voxel (in meter units) + /// \param z the z-coordinate of the voxel (in meter units) + /// \param scale the scale of the voxel (in meter units) void eraseVoxel(float x, float y, float z, float scale); private: @@ -62,9 +64,11 @@ public: VoxelDetailScriptObject(VoxelDetail* voxelDetail) { _voxelDetail = voxelDetail; } public slots: - glm::vec3 getPosition() const { return glm::vec3(_voxelDetail->x, _voxelDetail->y, _voxelDetail->z); } + /// position in meter units + glm::vec3 getPosition() const { return glm::vec3(_voxelDetail->x, _voxelDetail->y, _voxelDetail->z) * (float)TREE_SCALE; } xColor getColor() const { xColor color = { _voxelDetail->red, _voxelDetail->green, _voxelDetail->blue }; return color; } - float getScale() const { return _voxelDetail->s; } + /// scale in meter units + float getScale() const { return _voxelDetail->s * (float)TREE_SCALE; } private: VoxelDetail* _voxelDetail; From 34dc1a698ef1ed811d539cde101f6bf23f275c82 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 14:09:39 -0800 Subject: [PATCH 23/24] fixed types --- libraries/particle-server/src/ParticleServer.cpp | 8 ++++---- libraries/particles/src/ParticleTree.cpp | 6 +++--- libraries/particles/src/ParticleTree.h | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/particle-server/src/ParticleServer.cpp b/libraries/particle-server/src/ParticleServer.cpp index f30ddfa931..9d7d70db83 100644 --- a/libraries/particle-server/src/ParticleServer.cpp +++ b/libraries/particle-server/src/ParticleServer.cpp @@ -79,7 +79,7 @@ bool ParticleServer::hasSpecialPacketToSend(Node* node) { uint64_t deletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt(); ParticleTree* tree = static_cast(_tree); - shouldSendDeletedParticles = tree->hasParitclesDeletedSince(deletedParticlesSentAt); + shouldSendDeletedParticles = tree->hasParticlesDeletedSince(deletedParticlesSentAt); } return shouldSendDeletedParticles; @@ -99,7 +99,7 @@ int ParticleServer::sendSpecialPacket(Node* node) { // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 particles? while (hasMoreToSend) { - hasMoreToSend = tree->encodeParitclesDeletedSince(deletedParticlesSentAt, + hasMoreToSend = tree->encodeParticlesDeletedSince(deletedParticlesSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); //qDebug() << "sending PACKET_TYPE_PARTICLE_ERASE packetLength:" << packetLength; @@ -118,7 +118,7 @@ int ParticleServer::sendSpecialPacket(Node* node) { void ParticleServer::pruneDeletedParticles() { ParticleTree* tree = static_cast(_tree); - if (tree->hasAnyDeletedParitcles()) { + if (tree->hasAnyDeletedParticles()) { //qDebug() << "there are some deleted particles to consider..."; uint64_t earliestLastDeletedParticlesSent = usecTimestampNow() + 1; // in the future @@ -132,7 +132,7 @@ void ParticleServer::pruneDeletedParticles() { } } //qDebug() << "earliestLastDeletedParticlesSent=" << earliestLastDeletedParticlesSent; - tree->forgetParitclesDeletedBefore(earliestLastDeletedParticlesSent); + tree->forgetParticlesDeletedBefore(earliestLastDeletedParticlesSent); } } diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index 4911be7104..a3c8072b3a 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -306,7 +306,7 @@ void ParticleTree::update() { } -bool ParticleTree::hasParitclesDeletedSince(uint64_t sinceTime) { +bool ParticleTree::hasParticlesDeletedSince(uint64_t sinceTime) { // we can probably leverage the ordered nature of QMultiMap to do this quickly... bool hasSomethingNewer = false; @@ -325,7 +325,7 @@ bool ParticleTree::hasParitclesDeletedSince(uint64_t sinceTime) { } // sinceTime is an in/out parameter - it will be side effected with the last time sent out -bool ParticleTree::encodeParitclesDeletedSince(uint64_t& sinceTime, unsigned char* outputBuffer, size_t maxLength, +bool ParticleTree::encodeParticlesDeletedSince(uint64_t& sinceTime, unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) { bool hasMoreToSend = true; @@ -389,7 +389,7 @@ bool ParticleTree::encodeParitclesDeletedSince(uint64_t& sinceTime, unsigned cha } // called by the server when it knows all nodes have been sent deleted packets -void ParticleTree::forgetParitclesDeletedBefore(uint64_t sinceTime) { +void ParticleTree::forgetParticlesDeletedBefore(uint64_t sinceTime) { _recentlyDeletedParticlesLock.lockForWrite(); QMultiMap::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin(); while (iterator != _recentlyDeletedParticleIDs.constEnd()) { diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 38462a1ecc..33e5d5fe75 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -46,10 +46,10 @@ public: void addNewlyCreatedHook(NewlyCreatedParticleHook* hook); void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook); - bool hasAnyDeletedParitcles() const { return _recentlyDeletedParticleIDs.size() > 0; } - bool hasParitclesDeletedSince(uint64_t sinceTime); - bool encodeParitclesDeletedSince(uint64_t& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); - void forgetParitclesDeletedBefore(uint64_t sinceTime); + bool hasAnyDeletedParticles() const { return _recentlyDeletedParticleIDs.size() > 0; } + bool hasParticlesDeletedSince(uint64_t sinceTime); + bool encodeParticlesDeletedSince(uint64_t& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); + void forgetParticlesDeletedBefore(uint64_t sinceTime); void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode); From 8be6fcbcccadb25fb43c0ab23bd72415811293d0 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 22 Jan 2014 14:11:11 -0800 Subject: [PATCH 24/24] CR feedback --- libraries/particles/src/Particle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 10a8d6868c..160eee9db2 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -42,7 +42,7 @@ const uint16_t PACKET_CONTAINS_INHAND = 128; const uint16_t PACKET_CONTAINS_SCRIPT = 256; const uint16_t PACKET_CONTAINS_SHOULDDIE = 512; -const float DEFAULT_LIFETIME = 10.f; //60.0f * 60.0f * 24.0f; // particles live for 1 day by default +const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default const float DEFAULT_DAMPING = 0.99f; const float DEFAULT_RADIUS = 0.1f / TREE_SCALE; const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container