diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 2fa59ee43f..a25fa086de 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -77,6 +77,8 @@ void Hand::reset() { } void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) { + Application* app = Application::getInstance(); + ParticleTree* particles = app->getParticles()->getTree(); bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand); int handID = palm.getSixenseID(); @@ -85,14 +87,14 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f glm::vec3 targetPosition = (ballFromHand ? palm.getPosition() : fingerTipPosition) / (float)TREE_SCALE; float targetRadius = CATCH_RADIUS / (float)TREE_SCALE; - const Particle* closestParticle = Application::getInstance()->getParticles() - ->getTree()->findClosestParticle(targetPosition, targetRadius); + // If I don't currently have a ball in my hand, then I can catch this closest particle + if (!ballAlreadyInHand && grabButtonPressed) { - if (closestParticle) { - // If I don't currently have a ball in my hand, then I can catch this closest particle - if (!ballAlreadyInHand && grabButtonPressed) { - ParticleEditHandle* caughtParticle = Application::getInstance()->newParticleEditHandle(closestParticle->getID()); + const Particle* closestParticle = particles->findClosestParticle(targetPosition, targetRadius); + + if (closestParticle) { + ParticleEditHandle* caughtParticle = app->newParticleEditHandle(closestParticle->getID()); glm::vec3 newPosition = targetPosition; glm::vec3 newVelocity = NO_VELOCITY; @@ -117,10 +119,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f _ballParticleEditHandles[handID] = caughtParticle; caughtParticle = NULL; // Play a catch sound! - Application::getInstance()->getAudio()->startDrumSound(1.0, - 300, - 0.5, - 0.05); + app->getAudio()->startDrumSound(1.0, 300, 0.5, 0.05); } } @@ -155,20 +154,17 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f qDebug("Created New Ball\n"); #endif glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; - _ballParticleEditHandles[handID] = Application::getInstance()->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, - IN_HAND, - TOY_BALL_UPDATE_SCRIPT); + _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, + IN_HAND, + TOY_BALL_UPDATE_SCRIPT); // Play a new ball sound - Application::getInstance()->getAudio()->startDrumSound(1.0, - 2000, - 0.5, - 0.02); + app->getAudio()->startDrumSound(1.0, 2000, 0.5, 0.02); } } else { @@ -176,10 +172,16 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f #ifdef DEBUG_HAND //qDebug("Ball in hand\n"); #endif + + 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 = ballFromHand ? palm.getPosition() : fingerTipPosition; _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE, - TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]], + colorForParticleInHand, NO_VELOCITY / (float)TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_DAMPING, @@ -201,9 +203,14 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f #ifdef DEBUG_HAND qDebug("Threw ball, v = %.3f\n", glm::length(ballVelocity)); #endif + 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, - TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]], + colorForParticleInHand, ballVelocity / (float)TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_DAMPING, @@ -216,12 +223,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f _ballParticleEditHandles[handID] = NULL; // Play a throw sound - Application::getInstance()->getAudio()->startDrumSound(1.0, - 3000, - 0.5, - 0.02); - - + app->getAudio()->startDrumSound(1.0, 3000, 0.5, 0.02); } } @@ -474,30 +476,27 @@ void Hand::calculateGeometry() { } } -void Hand::render( bool isMine) { +void Hand::render(bool isMine) { _renderAlpha = 1.0; - - - - if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) { - for (int i = 0; i < getNumPalms(); i++) { - PalmData& palm = getPalms()[i]; - if (!palm.isActive()) { - continue; - } - glm::vec3 position = palm.getPosition(); - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glColor3f(0.0f, 1.0f, 0.0f); - glutSolidSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10); - glPopMatrix(); + if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) { + for (int i = 0; i < getNumPalms(); i++) { + PalmData& palm = getPalms()[i]; + if (!palm.isActive()) { + continue; } + glm::vec3 position = palm.getPosition(); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glColor3f(0.0f, 1.0f, 0.0f); + glutSolidSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10); + glPopMatrix(); } + } if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { - renderLeapHands(); + renderLeapHands(isMine); } if (isMine) { @@ -520,7 +519,7 @@ void Hand::render( bool isMine) { } -void Hand::renderLeapHands() { +void Hand::renderLeapHands(bool isMine) { const float alpha = 1.0f; const float TARGET_ALPHA = 0.5f; @@ -532,7 +531,7 @@ void Hand::renderLeapHands() { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) { + if (isMine && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) { for (size_t i = 0; i < getNumPalms(); ++i) { PalmData& palm = getPalms()[i]; if (!palm.isActive()) { @@ -541,8 +540,8 @@ void Hand::renderLeapHands() { glm::vec3 targetPosition = ballFromHand ? palm.getPosition() : palm.getTipPosition(); glPushMatrix(); - const Particle* closestParticle = Application::getInstance()->getParticles() - ->getTree()->findClosestParticle(targetPosition / (float)TREE_SCALE, + 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 diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 6afad1bbed..d7acba6a3e 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -89,7 +89,7 @@ private: void setLeapHands(const std::vector& handPositions, const std::vector& handNormals); - void renderLeapHands(); + void renderLeapHands(bool isMine); void renderLeapFingerTrails(); void updateCollisions(); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 5bd99ee308..dfc0eac1c8 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -583,7 +583,7 @@ public: float radius; glm::vec3& penetration; bool found; - OctreeElement* penetratedElement; + void* penetratedObject; /// the type is defined by the type of Octree, the caller is assumed to know the type }; bool findSpherePenetrationOp(OctreeElement* element, void* extraData) { @@ -599,23 +599,22 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) { } if (element->hasContent()) { glm::vec3 elementPenetration; - if (element->findSpherePenetration(args->center, args->radius, elementPenetration)) { + if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) { args->penetration = addPenetrations(args->penetration, elementPenetration * (float)TREE_SCALE); args->found = true; - args->penetratedElement = element; } } return false; } bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, - OctreeElement** penetratedElement) { + void** penetratedObject) { SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration, false, NULL }; penetration = glm::vec3(0.0f, 0.0f, 0.0f); recurseTreeWithOperation(findSpherePenetrationOp, &args); - if (penetratedElement) { - *penetratedElement = args.penetratedElement; + if (penetratedObject) { + *penetratedObject = args.penetratedObject; } return args.found; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index de74476a30..43ba3062b3 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -221,7 +221,7 @@ public: OctreeElement*& node, float& distance, BoxFace& face); bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, - OctreeElement** penetratedElement = NULL); + void** penetratedObject = NULL); bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 62561772bb..f59121877a 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1285,7 +1285,8 @@ void OctreeElement::notifyUpdateHooks() { } } -bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { +bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, + glm::vec3& penetration, void** penetratedObject) const { return _box.findSpherePenetration(center, radius, penetration); } diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 1b5b92cf2b..969b49f303 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -93,7 +93,8 @@ public: virtual bool deleteApproved() const { return true; } - virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; + virtual bool findSpherePenetration(const glm::vec3& center, float radius, + glm::vec3& penetration, void** penetratedObject) const; // Base class methods you don't need to implement const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; } diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index ec0783d0d9..83d313c95f 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -42,8 +42,8 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 _id = id; } uint64_t now = usecTimestampNow(); - _edited = now; - _lastSimulated = now; + _lastEdited = now; + _lastUpdated = now; _created = now; // will get updated as appropriate in setLifetime() _position = position; @@ -67,7 +67,10 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { success = packetData->appendValue(getLifetime()); } if (success) { - success = packetData->appendValue(getEditedAgo()); + success = packetData->appendValue(getLastUpdated()); + } + if (success) { + success = packetData->appendValue(getLastEdited()); } if (success) { success = packetData->appendValue(getRadius()); @@ -103,7 +106,8 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { int Particle::expectedBytes() { int expectedBytes = sizeof(uint32_t) // id + sizeof(float) // lifetime - + sizeof(float) // edited ago + + sizeof(uint64_t) // last updated + + sizeof(uint64_t) // lasted edited + sizeof(float) // radius + sizeof(glm::vec3) // position + sizeof(rgbColor) // color @@ -117,6 +121,7 @@ int Particle::expectedBytes() { int Particle::expectedEditMessageBytes() { int expectedBytes = sizeof(uint32_t) // id + + sizeof(uint64_t) // lasted edited + sizeof(float) // radius + sizeof(glm::vec3) // position + sizeof(rgbColor) // color @@ -145,12 +150,15 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += sizeof(lifetime); setLifetime(lifetime); - // edited ago - float editedAgo; - memcpy(&editedAgo, dataAt, sizeof(editedAgo)); - dataAt += sizeof(editedAgo); - bytesRead += sizeof(editedAgo); - setEditedAgo(editedAgo); + // _lastUpdated + memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated)); + dataAt += sizeof(_lastUpdated); + bytesRead += sizeof(_lastUpdated); + + // _lastEdited + memcpy(&_lastEdited, dataAt, sizeof(_lastEdited)); + dataAt += sizeof(_lastEdited); + bytesRead += sizeof(_lastEdited); // radius memcpy(&_radius, dataAt, sizeof(_radius)); @@ -204,7 +212,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) { - Particle newParticle; // id and _lastSimulated will get set here... + Particle newParticle; // id and _lastUpdated will get set here... unsigned char* dataAt = data; processedBytes = 0; @@ -240,8 +248,10 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe newParticle._newlyCreated = false; } - // clearly we just edited it - newParticle.setEditedAgo(0); + // lastEdited + memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited)); + dataAt += sizeof(newParticle._lastEdited); + processedBytes += sizeof(newParticle._lastEdited); // radius memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); @@ -347,6 +357,11 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, sizeOut += sizeof(details[i].creatorTokenID); } + // radius + memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited)); + copyAt += sizeof(details[i].lastEdited); + sizeOut += sizeof(details[i].lastEdited); + // radius memcpy(copyAt, &details[i].radius, sizeof(details[i].radius)); copyAt += sizeof(details[i].radius); @@ -409,7 +424,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, void Particle::update() { uint64_t now = usecTimestampNow(); - uint64_t elapsed = now - _lastSimulated; + int elapsed = now - _lastUpdated; // making this signed slightly improves clock skew behavior float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND); @@ -423,7 +438,7 @@ void Particle::update() { bool shouldDie = !isInHand && !isStillMoving && isReallyOld; setShouldDie(shouldDie); - bool wantDebug = false; + const bool wantDebug = false; if (wantDebug) { printf("Particle::update()... timeElapsed: %f lifeTime:%f editedAgo:%f " "isInHand:%s isStillMoveing:%s isReallyOld:%s shouldDie:%s\n", @@ -452,7 +467,7 @@ void Particle::update() { //printf("applying damping to Particle timeElapsed=%f\n",timeElapsed); } - _lastSimulated = now; + _lastUpdated = now; } void Particle::runScript() { @@ -488,11 +503,6 @@ void Particle::setLifetime(float lifetime) { _created = usecTimestampNow() - lifetimeInUsecs; } -void Particle::setEditedAgo(float editedAgo) { - uint64_t editedAgoInUsecs = editedAgo * USECS_PER_SECOND; - _edited = usecTimestampNow() - editedAgoInUsecs; -} - void Particle::copyChangedProperties(const Particle& other) { float lifetime = getLifetime(); *this = other; diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 5090828724..cbf4c94bd3 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -25,6 +25,7 @@ const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; class ParticleDetail { public: uint32_t id; + uint64_t lastEdited; glm::vec3 position; float radius; rgbColor color; @@ -66,11 +67,16 @@ public: const glm::vec3& getGravity() const { return _gravity; } bool getInHand() const { return _inHand; } float getDamping() const { return _damping; } + + /// The last updated/simulated time of this particle from the time perspective of the authoritative server/source + uint64_t getLastUpdated() const { return _lastUpdated; } + + /// The last edited time of this particle from the time perspective of the authoritative server/source + uint64_t getLastEdited() const { return _lastEdited; } /// lifetime of the particle in seconds float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } - /// seconds since last edited - float getEditedAgo() const { return (float)(usecTimestampNow() - _edited) / (float)USECS_PER_SECOND; } + float getEditedAgo() const { return (float)(usecTimestampNow() - _lastEdited) / (float)USECS_PER_SECOND; } uint32_t getID() const { return _id; } bool getShouldDie() const { return _shouldDie; } QString getUpdateScript() const { return _updateScript; } @@ -116,7 +122,6 @@ protected: static void xColorFromScriptValue(const QScriptValue &object, xColor& color); void setLifetime(float lifetime); - void setEditedAgo(float editedAgo); glm::vec3 _position; rgbColor _color; @@ -133,11 +138,11 @@ protected: uint32_t _creatorTokenID; bool _newlyCreated; - // these are never included in wire time - uint64_t _lastSimulated; + uint64_t _lastUpdated; + uint64_t _lastEdited; + + // this doesn't go on the wire, we send it as lifetime uint64_t _created; - uint64_t _edited; - }; class ParticleScriptObject : public QObject { diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 8281deb12d..e1286f91e2 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -73,8 +73,7 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { const float VOXEL_DAMPING = 0.0; const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; - OctreeElement* penetratedVoxel; - if (_voxels->findSpherePenetration(center, radius, penetration, &penetratedVoxel)) { + if (_voxels->findSpherePenetration(center, radius, penetration)) { penetration /= (float)TREE_SCALE; updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); @@ -88,11 +87,29 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) { const float VOXEL_DAMPING = 0.0; const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; - OctreeElement* penetratedElement; - if (_particles->findSpherePenetration(center, radius, penetration, &penetratedElement)) { + Particle* penetratedParticle; + if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) { penetration /= (float)TREE_SCALE; updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); - applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); + + // apply a hard collision to both particles of half the penetration each + + float particleShare, penetratedParticleShare; + if (particle->getInHand() && penetratedParticle->getInHand()) { + particleShare = 0.5f; + penetratedParticleShare = -0.5f; + } else if (particle->getInHand()) { + particleShare = 0.f; + penetratedParticleShare = -1.f; + } else if (penetratedParticle->getInHand()) { + particleShare = -1.f; + penetratedParticleShare = 0.f; + } else { + particleShare = 0.5f; + penetratedParticleShare = -0.5f; + } + applyHardCollision(particle, penetration * particleShare, VOXEL_ELASTICITY, VOXEL_DAMPING); + applyHardCollision(penetratedParticle, penetration * penetratedParticleShare, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -172,7 +189,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration, float elasticity, float damping, const glm::vec3& addedVelocity) { // - // Update the avatar in response to a hard collision. Position will be reset exactly + // Update the particle in response to a hard collision. Position will be reset exactly // to outside the colliding surface. Velocity will be modified according to elasticity. // // if elasticity = 1.0, collision is inelastic. @@ -197,6 +214,12 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm:: velocity *= 0.f; } } + const bool wantDebug = false; + if (wantDebug) { + printf("ParticleCollisionSystem::applyHardCollision() particle id:%d new velocity:%f,%f,%f inHand:%s\n", + particle->getID(), velocity.x, velocity.y, velocity.z, debug::valueOf(particle->getInHand())); + } + ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID()); particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity, particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getUpdateScript()); diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index d8466816c4..88d3143a0f 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -44,7 +44,8 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor glm::vec3 gravity, float damping, bool inHand, QString updateScript) { // setup a ParticleDetail struct with the data - ParticleDetail addParticleDetail = { NEW_PARTICLE, + uint64_t now = usecTimestampNow(); + ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; @@ -69,7 +70,8 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor } // setup a ParticleDetail struct with the data - ParticleDetail newParticleDetail = { _id, + uint64_t now = usecTimestampNow(); + ParticleDetail newParticleDetail = { _id, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; diff --git a/libraries/particles/src/ParticleScriptingInterface.cpp b/libraries/particles/src/ParticleScriptingInterface.cpp index 758b50035d..8edfae3b88 100644 --- a/libraries/particles/src/ParticleScriptingInterface.cpp +++ b/libraries/particles/src/ParticleScriptingInterface.cpp @@ -22,7 +22,8 @@ unsigned int ParticleScriptingInterface::queueParticleAdd(glm::vec3 position, fl _nextCreatorTokenID++; // setup a ParticleDetail struct with the data - ParticleDetail addParticleDetail = { NEW_PARTICLE, + uint64_t now = usecTimestampNow(); + ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, creatorTokenID }; diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index e0fc3e972e..e770347fd8 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -111,7 +111,6 @@ bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraDat } const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targetRadius) { - // First, look for the existing particle in the tree.. FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX }; lockForRead(); recurseTreeWithOperation(findNearPointOperation, &args); @@ -119,6 +118,44 @@ const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targ return args.closestParticle; } +class FindByIDArgs { +public: + uint32_t id; + bool found; + const Particle* foundParticle; +}; + + +bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) { + FindByIDArgs* args = static_cast(extraData); + ParticleTreeElement* particleTreeElement = static_cast(element); + + // if already found, stop looking + if (args->found) { + return false; + } + + // as the tree element if it has this particle + const Particle* foundParticle = particleTreeElement->getParticleWithID(args->id); + if (foundParticle) { + args->foundParticle = foundParticle; + args->found = true; + return false; + } + + // keep looking + return true; +} + + +const Particle* ParticleTree::findParticleByID(uint32_t id) { + FindByIDArgs args = { id, false, NULL }; + lockForRead(); + recurseTreeWithOperation(findByIDOperation, &args); + unlock(); + return args.foundParticle; +} + int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength, unsigned char* editData, int maxLength, Node* senderNode) { diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 0594b2f4b2..64d6982322 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -46,6 +46,7 @@ public: void storeParticle(const Particle& particle); const Particle* findClosestParticle(glm::vec3 position, float targetRadius); + const Particle* findParticleByID(uint32_t id); void addNewlyCreatedHook(NewlyCreatedParticleHook* hook); void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook); @@ -56,6 +57,7 @@ private: static bool findAndUpdateOperation(OctreeElement* element, void* extraData); 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); diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index b142c1f568..3d1a552d17 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -86,7 +86,9 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) { } } -bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { +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(); @@ -96,8 +98,19 @@ bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float r if (particleCenter == center && particleRadius == radius) { return false; } + + // We've considered making "inHand" particles not collide, if we want to do that, + // we should change this setting... but now, we do allow inHand particles to collide + const bool IN_HAND_PARTICLES_DONT_COLLIDE = false; + if (IN_HAND_PARTICLES_DONT_COLLIDE) { + // don't penetrate if the particle is "inHand" -- they don't collide + if (_particles[i].getInHand()) { + return false; + } + } if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) { + *penetratedObject = (void*)&_particles[i]; return true; } } @@ -115,23 +128,28 @@ bool ParticleTreeElement::containsParticle(const Particle& particle) const { } bool ParticleTreeElement::updateParticle(const Particle& particle) { - bool wantDebug = false; + const bool wantDebug = false; uint16_t numberOfParticles = _particles.size(); for (uint16_t i = 0; i < numberOfParticles; i++) { if (_particles[i].getID() == particle.getID()) { - bool changedOnServer = _particles[i].getEditedAgo() > particle.getEditedAgo(); - if (changedOnServer) { + 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 (wantDebug) { - printf("local particle [id:%d] %s, particle.isNewlyCreated()=%s\n", - particle.getID(), (changedOnServer ? "CHANGED" : "same"), - debug::valueOf(particle.isNewlyCreated()) ); + 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"), + difference, debug::valueOf(particle.isNewlyCreated()) ); } _particles[i].copyChangedProperties(particle); } else { if (wantDebug) { - printf(">>> NO CHANGE <<< -- local particle [id:%d] %s particle.isNewlyCreated()=%s\n", - particle.getID(), (changedOnServer ? "CHANGED" : "same"), - debug::valueOf(particle.isNewlyCreated()) ); + printf(">>> IGNORING SERVER!!! Would've caused jutter! <<< " + "local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", + particle.getID(), (changedOnServer ? "CHANGED" : "same"), + (localOlder ? "OLDER" : "NEWER"), + difference, debug::valueOf(particle.isNewlyCreated()) ); } } return true; @@ -153,6 +171,18 @@ const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) cons return closestParticle; } +const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const { + const Particle* foundParticle = NULL; + uint16_t numberOfParticles = _particles.size(); + for (uint16_t i = 0; i < numberOfParticles; i++) { + if (_particles[i].getID() == id) { + foundParticle = &_particles[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 cc58122515..0f9b3682c1 100644 --- a/libraries/particles/src/ParticleTreeElement.h +++ b/libraries/particles/src/ParticleTreeElement.h @@ -72,7 +72,8 @@ public: virtual bool isRendered() const { return getShouldRender(); } virtual bool deleteApproved() const { return !hasParticles(); } - virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; + virtual bool findSpherePenetration(const glm::vec3& center, float radius, + glm::vec3& penetration, void** penetratedObject) const; const std::vector& getParticles() const { return _particles; } std::vector& getParticles() { return _particles; } @@ -84,6 +85,8 @@ public: 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; + protected: void storeParticle(const Particle& particle); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 24865fff5c..05e4b4e21d 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -54,7 +54,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { return 2; case PACKET_TYPE_PARTICLE_DATA: - return 4; + return 5; default: return 0;