From cb8c0792b2c9977281b103a30f0124f4eded97cc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 Aug 2014 10:43:56 -0700 Subject: [PATCH 01/13] make main ragdoll and entity special also addded some logic (unused) to add ragdolls of other avatars --- interface/src/avatar/MyAvatar.cpp | 68 ++++++----- libraries/shared/src/PhysicsSimulation.cpp | 127 ++++++++++++--------- libraries/shared/src/PhysicsSimulation.h | 10 +- 3 files changed, 121 insertions(+), 84 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4d2d679956..41eba45ac4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -85,12 +85,12 @@ MyAvatar::MyAvatar() : _skeletonModel.setEnableShapes(true); // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. _physicsSimulation.addEntity(&_skeletonModel); - _physicsSimulation.addRagdoll(&_skeletonModel); + _physicsSimulation.setRagdoll(&_skeletonModel); } MyAvatar::~MyAvatar() { + _physicsSimulation.setRagdoll(NULL); _physicsSimulation.removeEntity(&_skeletonModel); - _physicsSimulation.removeRagdoll(&_skeletonModel); _lookAtTargetAvatar.clear(); } @@ -1532,41 +1532,53 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { } float myBoundingRadius = getBoundingRadius(); - const float BODY_COLLISION_RESOLUTION_FACTOR = glm::max(1.0f, deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE); - + // find nearest avatar + float nearestDistance2 = std::numeric_limits::max(); + Avatar* nearestAvatar = NULL; foreach (const AvatarSharedPointer& avatarPointer, avatars) { Avatar* avatar = static_cast(avatarPointer.data()); if (static_cast(this) == avatar) { // don't collide with ourselves continue; } - float distance = glm::length(_position - avatar->getPosition()); - if (_distanceToNearestAvatar > distance) { - _distanceToNearestAvatar = distance; + float distance2 = glm::distance2(_position, avatar->getPosition()); + if (nearestDistance2 > distance2) { + nearestDistance2 = distance2; + nearestAvatar = avatar; } - float theirBoundingRadius = avatar->getBoundingRadius(); - if (distance < myBoundingRadius + theirBoundingRadius) { - // collide our body against theirs - QVector myShapes; - _skeletonModel.getBodyShapes(myShapes); - QVector theirShapes; - avatar->getSkeletonModel().getBodyShapes(theirShapes); + } + _distanceToNearestAvatar = glm::sqrt(nearestDistance2); - CollisionInfo collision; - if (ShapeCollider::collideShapesCoarse(myShapes, theirShapes, collision)) { - float penetrationDepth = glm::length(collision._penetration); - if (penetrationDepth > myBoundingRadius) { - qDebug() << "WARNING: ignoring avatar-avatar penetration depth " << penetrationDepth; - } - else if (penetrationDepth > EPSILON) { - setPosition(getPosition() - BODY_COLLISION_RESOLUTION_FACTOR * collision._penetration); - _lastBodyPenetration += collision._penetration; - emit collisionWithAvatar(getSessionUUID(), avatar->getSessionUUID(), collision); - } + if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { + if (nearestAvatar != NULL) { + if (_distanceToNearestAvatar > myBoundingRadius + nearestAvatar->getBoundingRadius()) { + // they aren't close enough to put into the _physicsSimulation + // so we clear the pointer + nearestAvatar = NULL; + } + } + + foreach (const AvatarSharedPointer& avatarPointer, avatars) { + Avatar* avatar = static_cast(avatarPointer.data()); + if (static_cast(this) == avatar) { + // don't collide with ourselves + continue; + } + SkeletonModel* skeleton = &(avatar->getSkeletonModel()); + PhysicsSimulation* simulation = skeleton->getSimulation(); + if (avatar == nearestAvatar) { + if (simulation != &(_physicsSimulation)) { + std::cout << "adebug adding other avatar " << avatar << " to simulation" << std::endl; // adebug + skeleton->setEnableShapes(true); + _physicsSimulation.addEntity(skeleton); + _physicsSimulation.addRagdoll(skeleton); + } + } else if (simulation == &(_physicsSimulation)) { + std::cout << "adebug removing other avatar " << avatar << " from simulation" << std::endl; // adebug + _physicsSimulation.removeRagdoll(skeleton); + _physicsSimulation.removeEntity(skeleton); + skeleton->setEnableShapes(false); } - - // collide their hands against us - avatar->getHand()->collideAgainstAvatar(this, false); } } } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index c2a852c32b..5fd40543e7 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -24,19 +24,37 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _frame(0), _collisions(MAX_COLLISIONS_PER_SIMULATION) { +PhysicsSimulation::PhysicsSimulation() : _frame(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { // entities have a backpointer to this simulator that must be cleaned up - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { - _entities[i]->_simulation = NULL; + _otherEntities[i]->_simulation = NULL; + } + _otherEntities.clear(); + if (_entity) { + _entity->_simulation = NULL; } - _entities.clear(); // but Ragdolls do not - _dolls.clear(); + _ragdoll = NULL; + _otherRagdolls.clear(); +} + +void PhysicsSimulation::setEntity(PhysicsEntity* entity) { + if (_entity != entity) { + if (_entity) { + assert(_entity->_simulation == this); + _entity->_simulation = NULL; + } + _entity = entity; + if (_entity) { + assert(!(_entity->_simulation)); + _entity->_simulation = this; + } + } } bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { @@ -44,25 +62,24 @@ bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { return false; } if (entity->_simulation == this) { - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { - if (entity == _entities.at(i)) { + if (entity == _otherEntities.at(i)) { // already in list - assert(entity->_simulation == this); return true; } } // belongs to some other simulation return false; } - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); if (numEntities > MAX_ENTITIES_PER_SIMULATION) { // list is full return false; } // add to list entity->_simulation = this; - _entities.push_back(entity); + _otherEntities.push_back(entity); return true; } @@ -71,17 +88,17 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { return; } removeShapes(entity); - int numEntities = _entities.size(); + int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { - if (entity == _entities.at(i)) { + if (entity == _otherEntities.at(i)) { if (i == numEntities - 1) { // remove it - _entities.pop_back(); + _otherEntities.pop_back(); } else { // swap the last for this one - PhysicsEntity* lastEntity = _entities[numEntities - 1]; - _entities.pop_back(); - _entities[i] = lastEntity; + PhysicsEntity* lastEntity = _otherEntities[numEntities - 1]; + _otherEntities.pop_back(); + _otherEntities[i] = lastEntity; } entity->_simulation = NULL; break; @@ -105,34 +122,34 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { if (!doll) { return false; } - int numDolls = _dolls.size(); + int numDolls = _otherRagdolls.size(); if (numDolls > MAX_DOLLS_PER_SIMULATION) { // list is full return false; } for (int i = 0; i < numDolls; ++i) { - if (doll == _dolls[i]) { + if (doll == _otherRagdolls[i]) { // already in list return true; } } // add to list - _dolls.push_back(doll); + _otherRagdolls.push_back(doll); return true; } void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { - int numDolls = _dolls.size(); + int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - if (doll == _dolls[i]) { + if (doll == _otherRagdolls[i]) { if (i == numDolls - 1) { // remove it - _dolls.pop_back(); + _otherRagdolls.pop_back(); } else { // swap the last for this one - Ragdoll* lastDoll = _dolls[numDolls - 1]; - _dolls.pop_back(); - _dolls[i] = lastDoll; + Ragdoll* lastDoll = _otherRagdolls[numDolls - 1]; + _otherRagdolls.pop_back(); + _otherRagdolls[i] = lastDoll; } break; } @@ -141,17 +158,21 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { ++_frame; + if (!_ragdoll) { + return; + } quint64 now = usecTimestampNow(); quint64 startTime = now; quint64 expiry = startTime + maxUsec; moveRagdolls(deltaTime); buildContactConstraints(); - int numDolls = _dolls.size(); + int numDolls = _otherRagdolls.size(); { PerformanceTimer perfTimer("enforce"); + _ragdoll->enforceRagdollConstraints(); for (int i = 0; i < numDolls; ++i) { - _dolls[i]->enforceRagdollConstraints(); + _otherRagdolls[i]->enforceRagdollConstraints(); } } @@ -164,9 +185,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter { // enforce constraints PerformanceTimer perfTimer("enforce"); - error = 0.0f; + error = _ragdoll->enforceRagdollConstraints(); for (int i = 0; i < numDolls; ++i) { - error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); + error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints()); } } enforceContactConstraints(); @@ -180,40 +201,38 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter void PhysicsSimulation::moveRagdolls(float deltaTime) { PerformanceTimer perfTimer("integrate"); - int numDolls = _dolls.size(); + _ragdoll->stepRagdollForward(deltaTime); + int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - _dolls.at(i)->stepRagdollForward(deltaTime); + _otherRagdolls.at(i)->stepRagdollForward(deltaTime); } } void PhysicsSimulation::computeCollisions() { PerformanceTimer perfTimer("collide"); _collisions.clear(); - // TODO: keep track of QSet collidedEntities; - int numEntities = _entities.size(); - for (int i = 0; i < numEntities; ++i) { - PhysicsEntity* entity = _entities.at(i); - const QVector shapes = entity->getShapes(); - int numShapes = shapes.size(); - // collide with self - for (int j = 0; j < numShapes; ++j) { - const Shape* shape = shapes.at(j); - if (!shape) { - continue; - } - for (int k = j+1; k < numShapes; ++k) { - const Shape* otherShape = shapes.at(k); - if (otherShape && entity->collisionsAreEnabled(j, k)) { - ShapeCollider::collideShapes(shape, otherShape, _collisions); - } - } - } - // collide with others - for (int j = i+1; j < numEntities; ++j) { - const QVector otherShapes = _entities.at(j)->getShapes(); - ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); + const QVector shapes = _entity->getShapes(); + int numShapes = shapes.size(); + // collide with self + for (int i = 0; i < numShapes; ++i) { + const Shape* shape = shapes.at(i); + if (!shape) { + continue; } + for (int j = i+1; j < numShapes; ++j) { + const Shape* otherShape = shapes.at(j); + if (otherShape && _entity->collisionsAreEnabled(i, j)) { + ShapeCollider::collideShapes(shape, otherShape, _collisions); + } + } + } + + // collide with others + int numEntities = _otherEntities.size(); + for (int i = 0; i < numEntities; ++i) { + const QVector otherShapes = _otherEntities.at(i)->getShapes(); + ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); } } diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 506b37533a..c8f41bb656 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -28,6 +28,9 @@ public: PhysicsSimulation(); ~PhysicsSimulation(); + void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; } + void setEntity(PhysicsEntity* entity); + /// \return true if entity was added to or is already in the list bool addEntity(PhysicsEntity* entity); @@ -58,8 +61,11 @@ protected: private: quint32 _frame; - QVector _dolls; - QVector _entities; + PhysicsEntity* _entity; + Ragdoll* _ragdoll; + + QVector _otherRagdolls; + QVector _otherEntities; CollisionList _collisions; QMap _contacts; }; From 27b876e84cc40342e7b982ee33b3fead0c03ca19 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 09:02:31 -0700 Subject: [PATCH 02/13] namechange _frame --> _frameCount --- libraries/shared/src/PhysicsSimulation.cpp | 10 +++++----- libraries/shared/src/PhysicsSimulation.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 5fd40543e7..8fed575889 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -24,7 +24,7 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _frame(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { +PhysicsSimulation::PhysicsSimulation() : _frameCount(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { @@ -157,7 +157,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { } void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { - ++_frame; + ++_frameCount; if (!_ragdoll) { return; } @@ -288,9 +288,9 @@ void PhysicsSimulation::updateContacts() { } QMap::iterator itr = _contacts.find(key); if (itr == _contacts.end()) { - _contacts.insert(key, ContactPoint(*collision, _frame)); + _contacts.insert(key, ContactPoint(*collision, _frameCount)); } else { - itr.value().updateContact(*collision, _frame); + itr.value().updateContact(*collision, _frameCount); } } } @@ -300,7 +300,7 @@ const quint32 MAX_CONTACT_FRAME_LIFETIME = 2; void PhysicsSimulation::pruneContacts() { QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { - if (_frame - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { + if (_frameCount - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { itr = _contacts.erase(itr); } else { ++itr; diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index c8f41bb656..613440e71c 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -59,7 +59,7 @@ protected: void pruneContacts(); private: - quint32 _frame; + quint32 _frameCount; PhysicsEntity* _entity; Ragdoll* _ragdoll; From db1d6c8b49885113e9fe0ff394fae2e5fc0d2ed4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 09:23:05 -0700 Subject: [PATCH 03/13] MyAvatar's ragdoll is the main simulation ragdoll --- interface/src/avatar/MyAvatar.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 41eba45ac4..de85f1fe63 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -84,13 +84,13 @@ MyAvatar::MyAvatar() : } _skeletonModel.setEnableShapes(true); // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. - _physicsSimulation.addEntity(&_skeletonModel); + _physicsSimulation.setEntity(&_skeletonModel); _physicsSimulation.setRagdoll(&_skeletonModel); } MyAvatar::~MyAvatar() { _physicsSimulation.setRagdoll(NULL); - _physicsSimulation.removeEntity(&_skeletonModel); + _physicsSimulation.setEntity(NULL); _lookAtTargetAvatar.clear(); } @@ -1520,8 +1520,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float return false; } -const float BODY_COLLISION_RESOLUTION_TIMESCALE = 0.5f; // seconds - void MyAvatar::updateCollisionWithAvatars(float deltaTime) { // Reset detector for nearest avatar _distanceToNearestAvatar = std::numeric_limits::max(); From 87350ad2d0e03213e6d8da964ee5cdd7e85707a1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 11:45:06 -0700 Subject: [PATCH 04/13] ragdoll simulation now in model-relative frame (same rotation as world-frame, but translated to MyAvatar origin) --- interface/src/avatar/SkeletonModel.cpp | 85 +++++++++++++++++++--- interface/src/avatar/SkeletonModel.h | 1 + interface/src/renderer/Model.cpp | 50 +------------ interface/src/renderer/Model.h | 2 +- libraries/shared/src/FixedConstraint.cpp | 21 +++--- libraries/shared/src/FixedConstraint.h | 10 ++- libraries/shared/src/PhysicsSimulation.cpp | 5 +- libraries/shared/src/PhysicsSimulation.h | 5 ++ libraries/shared/src/Ragdoll.cpp | 67 +++++++++++++++-- libraries/shared/src/Ragdoll.h | 29 +++++++- libraries/shared/src/VerletPoint.cpp | 7 ++ libraries/shared/src/VerletPoint.h | 3 + 12 files changed, 199 insertions(+), 86 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c8e7451fc1..463ed28faf 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -490,11 +490,13 @@ void SkeletonModel::renderRagdoll() { float alpha = 0.3f; float radius1 = 0.008f; float radius2 = 0.01f; + glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); for (int i = 0; i < numPoints; ++i) { glPushMatrix(); - // draw each point as a yellow hexagon with black border - glm::vec3 position = _rotation * _ragdollPoints[i]._position; + // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative + glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation; glTranslatef(position.x, position.y, position.z); + // draw each point as a yellow hexagon with black border glColor4f(0.0f, 0.0f, 0.0f, alpha); glutSolidSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); glColor4f(1.0f, 1.0f, 0.0f, alpha); @@ -511,13 +513,14 @@ void SkeletonModel::initRagdollPoints() { clearRagdollConstraintsAndPoints(); _muscleConstraints.clear(); + initRagdollTransform(); // one point for each joint int numJoints = _jointStates.size(); _ragdollPoints.fill(VerletPoint(), numJoints); for (int i = 0; i < numJoints; ++i) { const JointState& state = _jointStates.at(i); - glm::vec3 position = state.getPosition(); - _ragdollPoints[i].initPosition(position); + // _ragdollPoints start in model-frame + _ragdollPoints[i].initPosition(state.getPosition()); } } @@ -534,12 +537,12 @@ void SkeletonModel::buildRagdollConstraints() { const JointState& state = _jointStates.at(i); int parentIndex = state.getParentIndex(); if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&(_ragdollPoints[i]), glm::vec3(0.0f)); - _ragdollConstraints.push_back(anchor); + FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); + _fixedConstraints.push_back(anchor); } else { DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); bone->setDistance(state.getDistanceToParent()); - _ragdollConstraints.push_back(bone); + _boneConstraints.push_back(bone); families.insert(parentIndex, i); } float boneLength = glm::length(state.getPositionInParentFrame()); @@ -558,11 +561,11 @@ void SkeletonModel::buildRagdollConstraints() { if (numChildren > 1) { for (int i = 1; i < numChildren; ++i) { DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); - _ragdollConstraints.push_back(bone); + _boneConstraints.push_back(bone); } if (numChildren > 2) { DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); - _ragdollConstraints.push_back(bone); + _boneConstraints.push_back(bone); } } ++itr; @@ -604,6 +607,7 @@ void SkeletonModel::updateVisibleJointStates() { } QVector points; points.reserve(_jointStates.size()); + glm::quat invRotation = glm::inverse(_rotation); for (int i = 0; i < _jointStates.size(); i++) { JointState& state = _jointStates[i]; points.push_back(_ragdollPoints[i]._position); @@ -628,8 +632,9 @@ void SkeletonModel::updateVisibleJointStates() { // we're looking for the rotation that moves visible bone parallel to ragdoll bone // rotationBetween(jointTip - jointPivot, shapeTip - shapePivot) + // NOTE: points are in simulation-frame so rotate line segment into model-frame glm::quat delta = rotationBetween(state.getVisiblePosition() - extractTranslation(parentTransform), - points[i] - points[parentIndex]); + invRotation * (points[i] - points[parentIndex])); // apply parentState.mixVisibleRotationDelta(delta, 0.01f); @@ -641,6 +646,7 @@ void SkeletonModel::updateVisibleJointStates() { // virtual void SkeletonModel::stepRagdollForward(float deltaTime) { + setRagdollTransform(_translation, _rotation); Ragdoll::stepRagdollForward(deltaTime); updateMuscles(); int numConstraints = _muscleConstraints.size(); @@ -714,6 +720,7 @@ void SkeletonModel::buildShapes() { if (_ragdollPoints.size() == numStates) { int numJoints = _jointStates.size(); for (int i = 0; i < numJoints; ++i) { + // ragdollPoints start in model-frame _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); } } @@ -735,9 +742,11 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); float oneMinusFraction = 1.0f - fraction; + glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); for (int i = 0; i < numStates; ++i) { + // ragdollPoints are in simulation-frame but jointStates are in model-frame _ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position + - fraction * _jointStates.at(i).getPosition()); + fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); } } @@ -748,7 +757,8 @@ void SkeletonModel::updateMuscles() { int j = constraint->getParentIndex(); int k = constraint->getChildIndex(); assert(j != -1 && k != -1); - constraint->setChildOffset(_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition()); + // ragdollPoints are in simulation-frame but jointStates are in model-frame + constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition())); } } @@ -891,3 +901,54 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) { glPopMatrix(); } +const int BALL_SUBDIVISIONS = 10; + +// virtual +void SkeletonModel::renderJointCollisionShapes(float alpha) { + glPushMatrix(); + Application::getInstance()->loadTranslatedViewMatrix(_translation); + glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + for (int i = 0; i < _shapes.size(); i++) { + Shape* shape = _shapes[i]; + if (!shape) { + continue; + } + + glPushMatrix(); + // shapes are stored in simulation-frame but we want position to be model-relative + if (shape->getType() == Shape::SPHERE_SHAPE) { + glm::vec3 position = shape->getTranslation() - simulationTranslation; + glTranslatef(position.x, position.y, position.z); + // draw a grey sphere at shape position + glColor4f(0.75f, 0.75f, 0.75f, alpha); + glutSolidSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + } else if (shape->getType() == Shape::CAPSULE_SHAPE) { + CapsuleShape* capsule = static_cast(shape); + + // draw a blue sphere at the capsule endpoint + glm::vec3 endPoint; + capsule->getEndPoint(endPoint); + endPoint = endPoint - simulationTranslation; + glTranslatef(endPoint.x, endPoint.y, endPoint.z); + glColor4f(0.6f, 0.6f, 0.8f, alpha); + glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + // draw a yellow sphere at the capsule startpoint + glm::vec3 startPoint; + capsule->getStartPoint(startPoint); + startPoint = startPoint - simulationTranslation; + glm::vec3 axis = endPoint - startPoint; + glTranslatef(-axis.x, -axis.y, -axis.z); + glColor4f(0.8f, 0.8f, 0.6f, alpha); + glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + // draw a green cylinder between the two points + glm::vec3 origin(0.0f); + glColor4f(0.6f, 0.8f, 0.6f, alpha); + Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius()); + } + glPopMatrix(); + } + glPopMatrix(); +} + diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 5cb89f5e44..55fedbcb6b 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -105,6 +105,7 @@ public: void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(float alpha); + void renderJointCollisionShapes(float alpha); float getBoundingShapeRadius() const { return _boundingShape.getRadius(); } const CapsuleShape& getBoundingShape() const { return _boundingShape; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 63a94772a7..025971db4b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1243,55 +1243,7 @@ float Model::getLimbLength(int jointIndex) const { const int BALL_SUBDIVISIONS = 10; void Model::renderJointCollisionShapes(float alpha) { - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); - for (int i = 0; i < _shapes.size(); i++) { - Shape* shape = _shapes[i]; - if (!shape) { - continue; - } - - glPushMatrix(); - // NOTE: the shapes are in the avatar local-frame - if (shape->getType() == Shape::SPHERE_SHAPE) { - // shapes are stored in world-frame, so we have to transform into model frame - glm::vec3 position = _rotation * shape->getTranslation(); - glTranslatef(position.x, position.y, position.z); - const glm::quat& rotation = shape->getRotation(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - // draw a grey sphere at shape position - glColor4f(0.75f, 0.75f, 0.75f, alpha); - glutSolidSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - } else if (shape->getType() == Shape::CAPSULE_SHAPE) { - CapsuleShape* capsule = static_cast(shape); - - // draw a blue sphere at the capsule endpoint - glm::vec3 endPoint; - capsule->getEndPoint(endPoint); - endPoint = _rotation * endPoint; - glTranslatef(endPoint.x, endPoint.y, endPoint.z); - glColor4f(0.6f, 0.6f, 0.8f, alpha); - glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - - // draw a yellow sphere at the capsule startpoint - glm::vec3 startPoint; - capsule->getStartPoint(startPoint); - startPoint = _rotation * startPoint; - glm::vec3 axis = endPoint - startPoint; - glTranslatef(-axis.x, -axis.y, -axis.z); - glColor4f(0.8f, 0.8f, 0.6f, alpha); - glutSolidSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - - // draw a green cylinder between the two points - glm::vec3 origin(0.0f); - glColor4f(0.6f, 0.8f, 0.6f, alpha); - Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius()); - } - glPopMatrix(); - } - glPopMatrix(); + // implement this when we have shapes for regular models } void Model::setBlendedVertices(const QVector& vertices, const QVector& normals) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index cbed941791..7a29b61420 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -149,7 +149,7 @@ public: virtual void buildShapes(); virtual void updateShapePositions(); - void renderJointCollisionShapes(float alpha); + virtual void renderJointCollisionShapes(float alpha); /// Sets blended vertices computed in a separate thread. void setBlendedVertices(const QVector& vertices, const QVector& normals); diff --git a/libraries/shared/src/FixedConstraint.cpp b/libraries/shared/src/FixedConstraint.cpp index 099c6d7bac..539978db5d 100644 --- a/libraries/shared/src/FixedConstraint.cpp +++ b/libraries/shared/src/FixedConstraint.cpp @@ -13,15 +13,22 @@ #include "Shape.h" // for MAX_SHAPE_MASS #include "VerletPoint.h" -FixedConstraint::FixedConstraint(VerletPoint* point, const glm::vec3& anchor) : _point(point), _anchor(anchor) { +FixedConstraint::FixedConstraint(glm::vec3* anchor, VerletPoint* point) : _anchor(anchor), _point(point) { + assert(anchor); + assert(point); + _point->_mass = MAX_SHAPE_MASS; } float FixedConstraint::enforce() { assert(_point != NULL); - // TODO: use fast approximate sqrt here - float distance = glm::distance(_anchor, _point->_position); - _point->_position = _anchor; - return distance; + _point->_position = *_anchor; + _point->_lastPosition = *_anchor; + return 0.0f; +} + +void FixedConstraint::setAnchor(glm::vec3* anchor) { + assert(anchor); + _anchor = anchor; } void FixedConstraint::setPoint(VerletPoint* point) { @@ -29,7 +36,3 @@ void FixedConstraint::setPoint(VerletPoint* point) { _point = point; _point->_mass = MAX_SHAPE_MASS; } - -void FixedConstraint::setAnchor(const glm::vec3& anchor) { - _anchor = anchor; -} diff --git a/libraries/shared/src/FixedConstraint.h b/libraries/shared/src/FixedConstraint.h index 050232a027..66a27369ce 100644 --- a/libraries/shared/src/FixedConstraint.h +++ b/libraries/shared/src/FixedConstraint.h @@ -18,15 +18,19 @@ class VerletPoint; +// FixedConstraint takes pointers to a glm::vec3 and a VerletPoint. +// The enforcement will copy the value of the vec3 into the VerletPoint. + class FixedConstraint : public Constraint { public: - FixedConstraint(VerletPoint* point, const glm::vec3& anchor); + FixedConstraint(glm::vec3* anchor, VerletPoint* point); + ~FixedConstraint() {} float enforce(); + void setAnchor(glm::vec3* anchor); void setPoint(VerletPoint* point); - void setAnchor(const glm::vec3& anchor); private: + glm::vec3* _anchor; VerletPoint* _point; - glm::vec3 _anchor; }; #endif // hifi_FixedConstraint_h diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 8fed575889..8ae30ce699 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -24,7 +24,8 @@ int MAX_ENTITIES_PER_SIMULATION = 64; int MAX_COLLISIONS_PER_SIMULATION = 256; -PhysicsSimulation::PhysicsSimulation() : _frameCount(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) { +PhysicsSimulation::PhysicsSimulation() : _translation(0.0f), _frameCount(0), _entity(NULL), _ragdoll(NULL), + _collisions(MAX_COLLISIONS_PER_SIMULATION) { } PhysicsSimulation::~PhysicsSimulation() { @@ -204,7 +205,7 @@ void PhysicsSimulation::moveRagdolls(float deltaTime) { _ragdoll->stepRagdollForward(deltaTime); int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - _otherRagdolls.at(i)->stepRagdollForward(deltaTime); + _otherRagdolls[i]->stepRagdollForward(deltaTime); } } diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 613440e71c..be1f2fb366 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -28,6 +28,9 @@ public: PhysicsSimulation(); ~PhysicsSimulation(); + void setTranslation(const glm::vec3& translation) { _translation = translation; } + const glm::vec3& getTranslation() const { return _translation; } + void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; } void setEntity(PhysicsEntity* entity); @@ -59,6 +62,8 @@ protected: void pruneContacts(); private: + glm::vec3 _translation; // origin of simulation in world-frame + quint32 _frameCount; PhysicsEntity* _entity; diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 6282db4dfb..5b21687bbd 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -9,13 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Ragdoll.h" #include "Constraint.h" #include "DistanceConstraint.h" #include "FixedConstraint.h" +#include "PhysicsSimulation.h" +#include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() { +Ragdoll::Ragdoll() : _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { } Ragdoll::~Ragdoll() { @@ -23,6 +27,9 @@ Ragdoll::~Ragdoll() { } void Ragdoll::stepRagdollForward(float deltaTime) { + if (_ragdollSimulation) { + updateSimulationTransforms(_ragdollTranslation - _ragdollSimulation->getTranslation(), _ragdollRotation); + } int numPoints = _ragdollPoints.size(); for (int i = 0; i < numPoints; ++i) { _ragdollPoints[i].integrateForward(); @@ -30,21 +37,65 @@ void Ragdoll::stepRagdollForward(float deltaTime) { } void Ragdoll::clearRagdollConstraintsAndPoints() { - int numConstraints = _ragdollConstraints.size(); + int numConstraints = _boneConstraints.size(); for (int i = 0; i < numConstraints; ++i) { - delete _ragdollConstraints[i]; + delete _boneConstraints[i]; } - _ragdollConstraints.clear(); + _boneConstraints.clear(); + numConstraints = _fixedConstraints.size(); + for (int i = 0; i < numConstraints; ++i) { + delete _fixedConstraints[i]; + } + _fixedConstraints.clear(); _ragdollPoints.clear(); } float Ragdoll::enforceRagdollConstraints() { float maxDistance = 0.0f; - const int numConstraints = _ragdollConstraints.size(); + // enforce the bone constraints first + int numConstraints = _boneConstraints.size(); for (int i = 0; i < numConstraints; ++i) { - DistanceConstraint* c = static_cast(_ragdollConstraints[i]); - //maxDistance = glm::max(maxDistance, _ragdollConstraints[i]->enforce()); - maxDistance = glm::max(maxDistance, c->enforce()); + maxDistance = glm::max(maxDistance, _boneConstraints[i]->enforce()); + } + // enforce FixedConstraints second + numConstraints = _fixedConstraints.size(); + for (int i = 0; i < _fixedConstraints.size(); ++i) { + maxDistance = glm::max(maxDistance, _fixedConstraints[i]->enforce()); } return maxDistance; } + +void Ragdoll::initRagdollTransform() { + _ragdollTranslation = glm::vec3(0.0f); + _ragdollRotation = glm::quat(); + _translationInSimulationFrame = glm::vec3(0.0f); + _rotationInSimulationFrame = glm::quat(); +} + +void Ragdoll::setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation) { + _ragdollTranslation = translation; + _ragdollRotation = rotation; +} + +void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { + const float EPSILON2 = EPSILON * EPSILON; + if (glm::distance2(translation, _translationInSimulationFrame) < EPSILON2 && + glm::abs(1.0f - glm::abs(glm::dot(rotation, _rotationInSimulationFrame))) < EPSILON2) { + // nothing to do + return; + } + + // compute linear and angular deltas + glm::vec3 deltaPosition = translation - _translationInSimulationFrame; + glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); + + // apply the deltas to all ragdollPoints + int numPoints = _ragdollPoints.size(); + for (int i = 0; i < numPoints; ++i) { + _ragdollPoints[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); + } + + // remember the current transform + _translationInSimulationFrame = translation; + _rotationInSimulationFrame = rotation; +} diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index 91a7e7330e..421e8e3ff8 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -18,7 +18,14 @@ #include -class Constraint; +//#include "PhysicsSimulation.h" + +class DistanceConstraint; +class FixedConstraint; +class PhysicsSimulation; + +// TODO: don't derive SkeletonModel from Ragdoll so we can clean up the Ragdoll API +// (==> won't need to worry about namespace conflicts between Entity and Ragdoll). class Ragdoll { public: @@ -35,13 +42,31 @@ public: const QVector& getRagdollPoints() const { return _ragdollPoints; } QVector& getRagdollPoints() { return _ragdollPoints; } + void initRagdollTransform(); + + /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. + void setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation); + + const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } + protected: void clearRagdollConstraintsAndPoints(); virtual void initRagdollPoints() = 0; virtual void buildRagdollConstraints() = 0; + glm::vec3 _ragdollTranslation; // world-frame + glm::quat _ragdollRotation; // world-frame + glm::vec3 _translationInSimulationFrame; + glm::quat _rotationInSimulationFrame; + QVector _ragdollPoints; - QVector _ragdollConstraints; + QVector _boneConstraints; + QVector _fixedConstraints; +private: + void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); + + friend class PhysicsSimulation; + PhysicsSimulation* _ragdollSimulation; }; #endif // hifi_Ragdoll_h diff --git a/libraries/shared/src/VerletPoint.cpp b/libraries/shared/src/VerletPoint.cpp index 654a74d7ac..dae861a7ab 100644 --- a/libraries/shared/src/VerletPoint.cpp +++ b/libraries/shared/src/VerletPoint.cpp @@ -31,3 +31,10 @@ void VerletPoint::applyAccumulatedDelta() { _numDeltas = 0; } } + +void VerletPoint::move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot) { + glm::vec3 arm = _position - oldPivot; + _position += deltaPosition + (deltaRotation * arm - arm); + arm = _lastPosition - oldPivot; + _lastPosition += deltaPosition + (deltaRotation * arm - arm); +} diff --git a/libraries/shared/src/VerletPoint.h b/libraries/shared/src/VerletPoint.h index f59afb16c5..a1dca3e955 100644 --- a/libraries/shared/src/VerletPoint.h +++ b/libraries/shared/src/VerletPoint.h @@ -13,6 +13,8 @@ #define hifi_VerletPoint_h #include +#include + class VerletPoint { public: @@ -22,6 +24,7 @@ public: void integrateForward(); void accumulateDelta(const glm::vec3& delta); void applyAccumulatedDelta(); + void move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot); glm::vec3 _position; glm::vec3 _lastPosition; From 0f784a9cc514ec38887e7d25a48c0a1b35be31be Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 13:09:05 -0700 Subject: [PATCH 05/13] add other ragdolls to simulation --- interface/src/avatar/MyAvatar.cpp | 5 +--- libraries/shared/src/PhysicsSimulation.cpp | 30 +++++++++++++++++++--- libraries/shared/src/PhysicsSimulation.h | 2 +- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index de85f1fe63..33c053464c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -204,6 +204,7 @@ void MyAvatar::simulate(float deltaTime) { const int minError = 0.01f; const float maxIterations = 10; const quint64 maxUsec = 2000; + _physicsSimulation.setTranslation(_position); _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); } else { _skeletonModel.moveShapesTowardJoints(1.0f); @@ -230,12 +231,10 @@ void MyAvatar::simulate(float deltaTime) { } else { _trapDuration = 0.0f; } - /* TODO: Andrew to make this work if (_collisionGroups & COLLISION_GROUP_AVATARS) { PerformanceTimer perfTimer("avatars"); updateCollisionWithAvatars(deltaTime); } - */ } // consider updating our billboard @@ -1566,13 +1565,11 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { PhysicsSimulation* simulation = skeleton->getSimulation(); if (avatar == nearestAvatar) { if (simulation != &(_physicsSimulation)) { - std::cout << "adebug adding other avatar " << avatar << " to simulation" << std::endl; // adebug skeleton->setEnableShapes(true); _physicsSimulation.addEntity(skeleton); _physicsSimulation.addRagdoll(skeleton); } } else if (simulation == &(_physicsSimulation)) { - std::cout << "adebug removing other avatar " << avatar << " from simulation" << std::endl; // adebug _physicsSimulation.removeRagdoll(skeleton); _physicsSimulation.removeEntity(skeleton); skeleton->setEnableShapes(false); diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 8ae30ce699..1007998b56 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -44,6 +44,19 @@ PhysicsSimulation::~PhysicsSimulation() { _otherRagdolls.clear(); } +void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { + if (_ragdoll != ragdoll) { + if (_ragdoll) { + _ragdoll->_ragdollSimulation = NULL; + } + _ragdoll = ragdoll; + if (_ragdoll) { + assert(!(_ragdoll->_ragdollSimulation)); + _ragdoll->_ragdollSimulation = this; + } + } +} + void PhysicsSimulation::setEntity(PhysicsEntity* entity) { if (_entity != entity) { if (_entity) { @@ -79,6 +92,7 @@ bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { return false; } // add to list + assert(!(entity->_simulation)); entity->_simulation = this; _otherEntities.push_back(entity); return true; @@ -128,19 +142,26 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { // list is full return false; } - for (int i = 0; i < numDolls; ++i) { - if (doll == _otherRagdolls[i]) { - // already in list - return true; + if (doll->_ragdollSimulation == this) { + for (int i = 0; i < numDolls; ++i) { + if (doll == _otherRagdolls[i]) { + // already in list + return true; + } } } // add to list + assert(!(doll->_ragdollSimulation)); + doll->_ragdollSimulation = this; _otherRagdolls.push_back(doll); return true; } void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { int numDolls = _otherRagdolls.size(); + if (doll->_ragdollSimulation != this) { + return; + } for (int i = 0; i < numDolls; ++i) { if (doll == _otherRagdolls[i]) { if (i == numDolls - 1) { @@ -152,6 +173,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { _otherRagdolls.pop_back(); _otherRagdolls[i] = lastDoll; } + doll->_ragdollSimulation = NULL; break; } } diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index be1f2fb366..61ab1bf177 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -31,7 +31,7 @@ public: void setTranslation(const glm::vec3& translation) { _translation = translation; } const glm::vec3& getTranslation() const { return _translation; } - void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; } + void setRagdoll(Ragdoll* ragdoll); void setEntity(PhysicsEntity* entity); /// \return true if entity was added to or is already in the list From 94da63006c420e79b759a7d9ee62b4b2d63a4d8b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 14:35:32 -0700 Subject: [PATCH 06/13] VerletPoint::_mass is now private We set the mass of other avatars artificially high so they are less movable. --- interface/src/avatar/SkeletonModel.cpp | 7 ++++--- libraries/shared/src/FixedConstraint.cpp | 3 --- libraries/shared/src/PhysicsSimulation.cpp | 10 ++++++++-- libraries/shared/src/Ragdoll.cpp | 16 +++++++++++++++- libraries/shared/src/Ragdoll.h | 4 ++++ libraries/shared/src/VerletCapsuleShape.cpp | 2 +- libraries/shared/src/VerletPoint.cpp | 9 +++++++++ libraries/shared/src/VerletPoint.h | 5 ++++- libraries/shared/src/VerletSphereShape.cpp | 2 +- 9 files changed, 46 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 463ed28faf..6b77e1c2f1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -671,6 +671,7 @@ void SkeletonModel::buildShapes() { } initRagdollPoints(); + float massScale = getMassScale(); float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); @@ -689,12 +690,12 @@ void SkeletonModel::buildShapes() { if (type == Shape::SPHERE_SHAPE) { shape = new VerletSphereShape(radius, &(_ragdollPoints[i])); shape->setEntity(this); - _ragdollPoints[i]._mass = glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); + _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } else if (type == Shape::CAPSULE_SHAPE) { assert(parentIndex != -1); shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i])); shape->setEntity(this); - _ragdollPoints[i]._mass = glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); + _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } if (parentIndex != -1) { // always disable collisions between joint and its parent @@ -702,7 +703,7 @@ void SkeletonModel::buildShapes() { } else { // give the base joint a very large mass since it doesn't actually move // in the local-frame simulation (it defines the origin) - _ragdollPoints[i]._mass = VERY_BIG_MASS; + _ragdollPoints[i].setMass(VERY_BIG_MASS); } _shapes.push_back(shape); } diff --git a/libraries/shared/src/FixedConstraint.cpp b/libraries/shared/src/FixedConstraint.cpp index 539978db5d..8f1edc1fb5 100644 --- a/libraries/shared/src/FixedConstraint.cpp +++ b/libraries/shared/src/FixedConstraint.cpp @@ -10,13 +10,11 @@ // #include "FixedConstraint.h" -#include "Shape.h" // for MAX_SHAPE_MASS #include "VerletPoint.h" FixedConstraint::FixedConstraint(glm::vec3* anchor, VerletPoint* point) : _anchor(anchor), _point(point) { assert(anchor); assert(point); - _point->_mass = MAX_SHAPE_MASS; } float FixedConstraint::enforce() { @@ -34,5 +32,4 @@ void FixedConstraint::setAnchor(glm::vec3* anchor) { void FixedConstraint::setPoint(VerletPoint* point) { assert(point); _point = point; - _point->_mass = MAX_SHAPE_MASS; } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 1007998b56..6dcafc6a54 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -133,6 +133,8 @@ void PhysicsSimulation::removeShapes(const PhysicsEntity* entity) { } } +const float OTHER_RAGDOLL_MASS_SCALE = 10.0f; + bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { if (!doll) { return false; @@ -154,6 +156,9 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { assert(!(doll->_ragdollSimulation)); doll->_ragdollSimulation = this; _otherRagdolls.push_back(doll); + + // set the massScale of otherRagdolls artificially high + doll->setMassScale(OTHER_RAGDOLL_MASS_SCALE); return true; } @@ -174,6 +179,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { _otherRagdolls[i] = lastDoll; } doll->_ragdollSimulation = NULL; + doll->setMassScale(1.0f); break; } } @@ -237,7 +243,7 @@ void PhysicsSimulation::computeCollisions() { const QVector shapes = _entity->getShapes(); int numShapes = shapes.size(); - // collide with self + // collide main ragdoll with self for (int i = 0; i < numShapes; ++i) { const Shape* shape = shapes.at(i); if (!shape) { @@ -251,7 +257,7 @@ void PhysicsSimulation::computeCollisions() { } } - // collide with others + // collide main ragdoll with others int numEntities = _otherEntities.size(); for (int i = 0; i < numEntities; ++i) { const QVector otherShapes = _otherEntities.at(i)->getShapes(); diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 5b21687bbd..e10e1620ae 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -19,7 +19,7 @@ #include "PhysicsSimulation.h" #include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() : _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { +Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { } Ragdoll::~Ragdoll() { @@ -99,3 +99,17 @@ void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm _translationInSimulationFrame = translation; _rotationInSimulationFrame = rotation; } + +void Ragdoll::setMassScale(float scale) { + const float MIN_SCALE = 1.0e-2f; + const float MAX_SCALE = 1.0e6f; + scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); + if (scale != _massScale) { + float rescale = scale / _massScale; + int numPoints = _ragdollPoints.size(); + for (int i = 0; i < numPoints; ++i) { + _ragdollPoints[i].setMass(rescale * _ragdollPoints[i].getMass()); + } + _massScale = scale; + } +} diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index 421e8e3ff8..ec5a561d1a 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -49,11 +49,15 @@ public: const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } + void setMassScale(float scale); + float getMassScale() const { return _massScale; } + protected: void clearRagdollConstraintsAndPoints(); virtual void initRagdollPoints() = 0; virtual void buildRagdollConstraints() = 0; + float _massScale; glm::vec3 _ragdollTranslation; // world-frame glm::quat _ragdollRotation; // world-frame glm::vec3 _translationInSimulationFrame; diff --git a/libraries/shared/src/VerletCapsuleShape.cpp b/libraries/shared/src/VerletCapsuleShape.cpp index 6f547d2048..ce324a781a 100644 --- a/libraries/shared/src/VerletCapsuleShape.cpp +++ b/libraries/shared/src/VerletCapsuleShape.cpp @@ -97,7 +97,7 @@ float VerletCapsuleShape::computeEffectiveMass(const glm::vec3& penetration, con _endLagrangeCoef = 1.0f; } // the effective mass is the weighted sum of the two endpoints - return _startLagrangeCoef * _startPoint->_mass + _endLagrangeCoef * _endPoint->_mass; + return _startLagrangeCoef * _startPoint->getMass() + _endLagrangeCoef * _endPoint->getMass(); } void VerletCapsuleShape::accumulateDelta(float relativeMassFactor, const glm::vec3& penetration) { diff --git a/libraries/shared/src/VerletPoint.cpp b/libraries/shared/src/VerletPoint.cpp index dae861a7ab..d2dd985587 100644 --- a/libraries/shared/src/VerletPoint.cpp +++ b/libraries/shared/src/VerletPoint.cpp @@ -38,3 +38,12 @@ void VerletPoint::move(const glm::vec3& deltaPosition, const glm::quat& deltaRot arm = _lastPosition - oldPivot; _lastPosition += deltaPosition + (deltaRotation * arm - arm); } + +void VerletPoint::setMass(float mass) { + const float MIN_MASS = 1.0e-6f; + const float MAX_MASS = 1.0e18f; + if (glm::isnan(mass)) { + mass = MIN_MASS; + } + _mass = glm::clamp(glm::abs(mass), MIN_MASS, MAX_MASS); +} diff --git a/libraries/shared/src/VerletPoint.h b/libraries/shared/src/VerletPoint.h index a1dca3e955..6f94656966 100644 --- a/libraries/shared/src/VerletPoint.h +++ b/libraries/shared/src/VerletPoint.h @@ -26,11 +26,14 @@ public: void applyAccumulatedDelta(); void move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot); + void setMass(float mass); + float getMass() const { return _mass; } + glm::vec3 _position; glm::vec3 _lastPosition; - float _mass; private: + float _mass; glm::vec3 _accumulatedDelta; int _numDeltas; }; diff --git a/libraries/shared/src/VerletSphereShape.cpp b/libraries/shared/src/VerletSphereShape.cpp index e24465fd89..da8242f26a 100644 --- a/libraries/shared/src/VerletSphereShape.cpp +++ b/libraries/shared/src/VerletSphereShape.cpp @@ -36,7 +36,7 @@ const glm::vec3& VerletSphereShape::getTranslation() const { // virtual float VerletSphereShape::computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint) { - return _point->_mass; + return _point->getMass(); } // virtual From 8c2dad1476bb4d2f9467be7f96f4030ebd53b783 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Aug 2014 14:40:06 -0700 Subject: [PATCH 07/13] remove animation server --- animation-server/CMakeLists.txt | 39 -- animation-server/src/AnimationServer.cpp | 852 ----------------------- animation-server/src/AnimationServer.h | 27 - animation-server/src/main.cpp | 17 - 4 files changed, 935 deletions(-) delete mode 100644 animation-server/CMakeLists.txt delete mode 100644 animation-server/src/AnimationServer.cpp delete mode 100644 animation-server/src/AnimationServer.h delete mode 100644 animation-server/src/main.cpp diff --git a/animation-server/CMakeLists.txt b/animation-server/CMakeLists.txt deleted file mode 100644 index 116ee0e942..0000000000 --- a/animation-server/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -if (WIN32) - cmake_policy (SET CMP0020 NEW) -endif (WIN32) - -set(TARGET_NAME animation-server) - -set(ROOT_DIR ..) -set(MACRO_DIR "${ROOT_DIR}/cmake/macros") - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -find_package(Qt5 COMPONENTS Script) -include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") - -# set up the external glm library -include("${MACRO_DIR}/IncludeGLM.cmake") -include_glm(${TARGET_NAME} "${ROOT_DIR}") - -include("${MACRO_DIR}/SetupHifiProject.cmake") -setup_hifi_project(${TARGET_NAME} TRUE) - -# link in the shared library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi octree library -link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") - -# link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") - -# link the hifi networking library -link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") - -# add a definition for ssize_t so that windows doesn't bail -if (WIN32) - add_definitions(-Dssize_t=long) -endif () diff --git a/animation-server/src/AnimationServer.cpp b/animation-server/src/AnimationServer.cpp deleted file mode 100644 index 32a95b48ea..0000000000 --- a/animation-server/src/AnimationServer.cpp +++ /dev/null @@ -1,852 +0,0 @@ -// -// AnimationServer.cpp -// animation-server/src -// -// Created by Stephen Birarda on 12/5/2013. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AnimationServer.h" - -bool shouldShowPacketsPerSecond = false; // do we want to debug packets per second -bool includeBillboard = true; -bool includeBorderTracer = true; -bool includeMovingBug = true; -bool includeBlinkingVoxel = false; -bool includeDanceFloor = true; -bool buildStreet = false; -bool nonThreadedPacketSender = false; -int packetsPerSecond = PacketSender::DEFAULT_PACKETS_PER_SECOND; -bool waitForVoxelServer = true; - - -const int ANIMATION_LISTEN_PORT = 40107; -int ANIMATE_FPS = 60; -double ANIMATE_FPS_IN_MILLISECONDS = 1000.0/ANIMATE_FPS; // determines FPS from our desired FPS -quint64 ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000); // converts from milliseconds to usecs - - -int PROCESSING_FPS = 60; -double PROCESSING_FPS_IN_MILLISECONDS = 1000.0/PROCESSING_FPS; // determines FPS from our desired FPS -int FUDGE_USECS = 650; // a little bit of fudge to actually do some processing -quint64 PROCESSING_INTERVAL_USECS = (PROCESSING_FPS_IN_MILLISECONDS * 1000) - FUDGE_USECS; // converts from milliseconds to usecs - -bool wantLocalDomain = false; - -unsigned long packetsSent = 0; -unsigned long bytesSent = 0; - -JurisdictionListener* jurisdictionListener = NULL; -VoxelEditPacketSender* voxelEditPacketSender = NULL; -pthread_t animateVoxelThread; - -glm::vec3 rotatePoint(glm::vec3 point, float angle) { - // First, create the quaternion based on this angle of rotation - glm::quat q(glm::vec3(0, -angle, 0)); - - // Next, create a rotation matrix from that quaternion - glm::mat4 rotation = glm::mat4_cast(q); - - // Transform the original vectors by the rotation matrix to get the new vectors - glm::vec4 quatPoint(point.x, point.y, point.z, 0); - glm::vec4 newPoint = quatPoint * rotation; - - return glm::vec3(newPoint.x, newPoint.y, newPoint.z); -} - - -const float BUG_VOXEL_SIZE = 0.0625f / TREE_SCALE; -glm::vec3 bugPosition = glm::vec3(BUG_VOXEL_SIZE * 20.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 20.0); -glm::vec3 bugDirection = glm::vec3(0, 0, 1); -const int VOXELS_PER_BUG = 18; -glm::vec3 bugPathCenter = glm::vec3(0.25f,0.15f,0.25f); // glm::vec3(BUG_VOXEL_SIZE * 150.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 150.0); -float bugPathRadius = 0.2f; //BUG_VOXEL_SIZE * 140.0; -float bugPathTheta = 0.0f * RADIANS_PER_DEGREE; -float bugRotation = 0.0f * RADIANS_PER_DEGREE; -float bugAngleDelta = 0.2f * RADIANS_PER_DEGREE; -bool moveBugInLine = false; - -class BugPart { -public: - glm::vec3 partLocation; - unsigned char partColor[3]; - - BugPart(const glm::vec3& location, unsigned char red, unsigned char green, unsigned char blue ) { - partLocation = location; - partColor[0] = red; - partColor[1] = green; - partColor[2] = blue; - } -}; - -const BugPart bugParts[VOXELS_PER_BUG] = { - - // tail - BugPart(glm::vec3( 0, 0, -3), 51, 51, 153) , - BugPart(glm::vec3( 0, 0, -2), 51, 51, 153) , - BugPart(glm::vec3( 0, 0, -1), 51, 51, 153) , - - // body - BugPart(glm::vec3( 0, 0, 0), 255, 200, 0) , - BugPart(glm::vec3( 0, 0, 1), 255, 200, 0) , - - // head - BugPart(glm::vec3( 0, 0, 2), 200, 0, 0) , - - // eyes - BugPart(glm::vec3( 1, 0, 3), 64, 64, 64) , - BugPart(glm::vec3(-1, 0, 3), 64, 64, 64) , - - // wings - BugPart(glm::vec3( 3, 1, 1), 0, 153, 0) , - BugPart(glm::vec3( 2, 1, 1), 0, 153, 0) , - BugPart(glm::vec3( 1, 0, 1), 0, 153, 0) , - BugPart(glm::vec3(-1, 0, 1), 0, 153, 0) , - BugPart(glm::vec3(-2, 1, 1), 0, 153, 0) , - BugPart(glm::vec3(-3, 1, 1), 0, 153, 0) , - - - BugPart(glm::vec3( 2, -1, 0), 153, 200, 0) , - BugPart(glm::vec3( 1, -1, 0), 153, 200, 0) , - BugPart(glm::vec3(-1, -1, 0), 153, 200, 0) , - BugPart(glm::vec3(-2, -1, 0), 153, 200, 0) , -}; - -static void renderMovingBug() { - VoxelDetail details[VOXELS_PER_BUG]; - - // Generate voxels for where bug used to be - for (int i = 0; i < VOXELS_PER_BUG; i++) { - details[i].s = BUG_VOXEL_SIZE; - - glm::vec3 partAt = bugParts[i].partLocation * BUG_VOXEL_SIZE * (bugDirection.x < 0 ? -1.0f : 1.0f); - glm::vec3 rotatedPartAt = rotatePoint(partAt, bugRotation); - glm::vec3 offsetPartAt = rotatedPartAt + bugPosition; - - details[i].x = offsetPartAt.x; - details[i].y = offsetPartAt.y; - details[i].z = offsetPartAt.z; - - details[i].red = bugParts[i].partColor[0]; - details[i].green = bugParts[i].partColor[1]; - details[i].blue = bugParts[i].partColor[2]; - } - - // send the "erase message" first... - PacketType message = PacketTypeVoxelErase; - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); - - // Move the bug... - if (moveBugInLine) { - bugPosition.x += (bugDirection.x * BUG_VOXEL_SIZE); - bugPosition.y += (bugDirection.y * BUG_VOXEL_SIZE); - bugPosition.z += (bugDirection.z * BUG_VOXEL_SIZE); - - // Check boundaries - if (bugPosition.z > 1.0f) { - bugDirection.z = -1.f; - } - if (bugPosition.z < BUG_VOXEL_SIZE) { - bugDirection.z = 1.f; - } - } else { - - //qDebug("bugPathCenter=(%f,%f,%f)", bugPathCenter.x, bugPathCenter.y, bugPathCenter.z); - - bugPathTheta += bugAngleDelta; // move slightly - bugRotation -= bugAngleDelta; // rotate slightly - - // If we loop past end of circle, just reset back into normal range - if (bugPathTheta > TWO_PI) { - bugPathTheta = 0.f; - bugRotation = 0.f; - } - - float x = bugPathCenter.x + bugPathRadius * cos(bugPathTheta); - float z = bugPathCenter.z + bugPathRadius * sin(bugPathTheta); - float y = bugPathCenter.y; - - bugPosition = glm::vec3(x, y, z); - //qDebug("bugPathTheta=%f", bugPathTheta); - //qDebug("bugRotation=%f", bugRotation); - } - - //qDebug("bugPosition=(%f,%f,%f)", bugPosition.x, bugPosition.y, bugPosition.z); - //qDebug("bugDirection=(%f,%f,%f)", bugDirection.x, bugDirection.y, bugDirection.z); - // would be nice to add some randomness here... - - // Generate voxels for where bug is going to - for (int i = 0; i < VOXELS_PER_BUG; i++) { - details[i].s = BUG_VOXEL_SIZE; - - glm::vec3 partAt = bugParts[i].partLocation * BUG_VOXEL_SIZE * (bugDirection.x < 0 ? -1.0f : 1.0f); - glm::vec3 rotatedPartAt = rotatePoint(partAt, bugRotation); - glm::vec3 offsetPartAt = rotatedPartAt + bugPosition; - - details[i].x = offsetPartAt.x; - details[i].y = offsetPartAt.y; - details[i].z = offsetPartAt.z; - - details[i].red = bugParts[i].partColor[0]; - details[i].green = bugParts[i].partColor[1]; - details[i].blue = bugParts[i].partColor[2]; - } - - // send the "create message" ... - message = PacketTypeVoxelSetDestructive; - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); -} - - -float intensity = 0.5f; -float intensityIncrement = 0.1f; -const float MAX_INTENSITY = 1.0f; -const float MIN_INTENSITY = 0.5f; -const float BEACON_SIZE = 0.25f / TREE_SCALE; // approximately 1/4th meter - -static void sendVoxelBlinkMessage() { - VoxelDetail detail; - detail.s = BEACON_SIZE; - - glm::vec3 position = glm::vec3(0.f, 0.f, detail.s); - - detail.x = detail.s * floor(position.x / detail.s); - detail.y = detail.s * floor(position.y / detail.s); - detail.z = detail.s * floor(position.z / detail.s); - - ::intensity += ::intensityIncrement; - if (::intensity >= MAX_INTENSITY) { - ::intensity = MAX_INTENSITY; - ::intensityIncrement = -::intensityIncrement; - } - if (::intensity <= MIN_INTENSITY) { - ::intensity = MIN_INTENSITY; - ::intensityIncrement = -::intensityIncrement; - } - - detail.red = 255 * ::intensity; - detail.green = 0 * ::intensity; - detail.blue = 0 * ::intensity; - - PacketType message = PacketTypeVoxelSetDestructive; - - ::voxelEditPacketSender->sendVoxelEditMessage(message, detail); -} - -bool stringOfLightsInitialized = false; -int currentLight = 0; -int lightMovementDirection = 1; -const int SEGMENT_COUNT = 4; -const int LIGHTS_PER_SEGMENT = 80; -const int LIGHT_COUNT = LIGHTS_PER_SEGMENT * SEGMENT_COUNT; -glm::vec3 stringOfLights[LIGHT_COUNT]; -unsigned char offColor[3] = { 240, 240, 240 }; -unsigned char onColor[3] = { 0, 255, 255 }; -const float STRING_OF_LIGHTS_SIZE = 0.125f / TREE_SCALE; // approximately 1/8th meter - -static void sendBlinkingStringOfLights() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = STRING_OF_LIGHTS_SIZE; - static VoxelDetail details[LIGHTS_PER_SEGMENT]; - - // first initialized the string of lights if needed... - if (!stringOfLightsInitialized) { - for (int segment = 0; segment < SEGMENT_COUNT; segment++) { - for (int indexInSegment = 0; indexInSegment < LIGHTS_PER_SEGMENT; indexInSegment++) { - - int i = (segment * LIGHTS_PER_SEGMENT) + indexInSegment; - - // four different segments on sides of initial platform - switch (segment) { - case 0: - // along x axis - stringOfLights[i] = glm::vec3(indexInSegment * lightScale, 0, 0); - break; - case 1: - // parallel to Z axis at outer X edge - stringOfLights[i] = glm::vec3(LIGHTS_PER_SEGMENT * lightScale, 0, indexInSegment * lightScale); - break; - case 2: - // parallel to X axis at outer Z edge - stringOfLights[i] = glm::vec3((LIGHTS_PER_SEGMENT-indexInSegment) * lightScale, 0, - LIGHTS_PER_SEGMENT * lightScale); - break; - case 3: - // on Z axis - stringOfLights[i] = glm::vec3(0, 0, (LIGHTS_PER_SEGMENT-indexInSegment) * lightScale); - break; - } - - details[indexInSegment].s = STRING_OF_LIGHTS_SIZE; - details[indexInSegment].x = stringOfLights[i].x; - details[indexInSegment].y = stringOfLights[i].y; - details[indexInSegment].z = stringOfLights[i].z; - - details[indexInSegment].red = offColor[0]; - details[indexInSegment].green = offColor[1]; - details[indexInSegment].blue = offColor[2]; - } - - ::voxelEditPacketSender->queueVoxelEditMessages(message, LIGHTS_PER_SEGMENT, (VoxelDetail*)&details); - } - stringOfLightsInitialized = true; - } else { - // turn off current light - details[0].x = stringOfLights[currentLight].x; - details[0].y = stringOfLights[currentLight].y; - details[0].z = stringOfLights[currentLight].z; - details[0].red = offColor[0]; - details[0].green = offColor[1]; - details[0].blue = offColor[2]; - - // move current light... - // if we're at the end of our string, then change direction - if (currentLight == LIGHT_COUNT-1) { - lightMovementDirection = -1; - } - if (currentLight == 0) { - lightMovementDirection = 1; - } - currentLight += lightMovementDirection; - - // turn on new current light - details[1].x = stringOfLights[currentLight].x; - details[1].y = stringOfLights[currentLight].y; - details[1].z = stringOfLights[currentLight].z; - details[1].red = onColor[0]; - details[1].green = onColor[1]; - details[1].blue = onColor[2]; - - // send both changes in same message - ::voxelEditPacketSender->queueVoxelEditMessages(message, 2, (VoxelDetail*)&details); - } -} - -bool danceFloorInitialized = false; -const float DANCE_FLOOR_LIGHT_SIZE = 1.0f / TREE_SCALE; // approximately 1 meter -const int DANCE_FLOOR_LENGTH = 10; -const int DANCE_FLOOR_WIDTH = 10; -glm::vec3 danceFloorPosition(100.0f / TREE_SCALE, 30.0f / TREE_SCALE, 10.0f / TREE_SCALE); -glm::vec3 danceFloorLights[DANCE_FLOOR_LENGTH][DANCE_FLOOR_WIDTH]; -unsigned char danceFloorOffColor[3] = { 240, 240, 240 }; -const int DANCE_FLOOR_COLORS = 6; - -unsigned char danceFloorOnColorA[DANCE_FLOOR_COLORS][3] = { - { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, - { 0, 191, 255 }, { 0, 250, 154 }, { 255, 69, 0 }, -}; -unsigned char danceFloorOnColorB[DANCE_FLOOR_COLORS][3] = { - { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } , - { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } -}; -float danceFloorGradient = 0.5f; -const float BEATS_PER_MINUTE = 118.0f; -const float SECONDS_PER_MINUTE = 60.0f; -const float FRAMES_PER_BEAT = (SECONDS_PER_MINUTE * ANIMATE_FPS) / BEATS_PER_MINUTE; -float danceFloorGradientIncrement = 1.0f / FRAMES_PER_BEAT; -const float DANCE_FLOOR_MAX_GRADIENT = 1.0f; -const float DANCE_FLOOR_MIN_GRADIENT = 0.0f; -const int DANCE_FLOOR_VOXELS_PER_PACKET = 100; -int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH]; - -void sendDanceFloor() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = DANCE_FLOOR_LIGHT_SIZE; - static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; - - // first initialized the billboard of lights if needed... - if (!::danceFloorInitialized) { - for (int i = 0; i < DANCE_FLOOR_WIDTH; i++) { - for (int j = 0; j < DANCE_FLOOR_LENGTH; j++) { - - int randomColorIndex = randIntInRange(-DANCE_FLOOR_COLORS, DANCE_FLOOR_COLORS); - ::danceFloorColors[i][j] = randomColorIndex; - ::danceFloorLights[i][j] = ::danceFloorPosition + - glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); - } - } - ::danceFloorInitialized = true; - } - - ::danceFloorGradient += ::danceFloorGradientIncrement; - - if (::danceFloorGradient >= DANCE_FLOOR_MAX_GRADIENT) { - ::danceFloorGradient = DANCE_FLOOR_MAX_GRADIENT; - ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; - } - if (::danceFloorGradient <= DANCE_FLOOR_MIN_GRADIENT) { - ::danceFloorGradient = DANCE_FLOOR_MIN_GRADIENT; - ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; - } - - for (int i = 0; i < DANCE_FLOOR_LENGTH; i++) { - for (int j = 0; j < DANCE_FLOOR_WIDTH; j++) { - - int nthVoxel = ((i * DANCE_FLOOR_WIDTH) + j); - int item = nthVoxel % DANCE_FLOOR_VOXELS_PER_PACKET; - - ::danceFloorLights[i][j] = ::danceFloorPosition + - glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); - - details[item].s = lightScale; - details[item].x = ::danceFloorLights[i][j].x; - details[item].y = ::danceFloorLights[i][j].y; - details[item].z = ::danceFloorLights[i][j].z; - - if (danceFloorColors[i][j] > 0) { - int color = danceFloorColors[i][j] - 1; - details[item].red = (::danceFloorOnColorA[color][0] + - ((::danceFloorOnColorB[color][0] - ::danceFloorOnColorA[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorA[color][1] + - ((::danceFloorOnColorB[color][1] - ::danceFloorOnColorA[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorA[color][2] + - ((::danceFloorOnColorB[color][2] - ::danceFloorOnColorA[color][2]) - * ::danceFloorGradient)); - } else if (::danceFloorColors[i][j] < 0) { - int color = -(::danceFloorColors[i][j] + 1); - details[item].red = (::danceFloorOnColorB[color][0] + - ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorB[color][1] + - ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorB[color][2] + - ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) - * ::danceFloorGradient)); - } else { - int color = 0; - details[item].red = (::danceFloorOnColorB[color][0] + - ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) - * ::danceFloorGradient)); - details[item].green = (::danceFloorOnColorB[color][1] + - ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) - * ::danceFloorGradient)); - details[item].blue = (::danceFloorOnColorB[color][2] + - ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) - * ::danceFloorGradient)); - } - - if (item == DANCE_FLOOR_VOXELS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, DANCE_FLOOR_VOXELS_PER_PACKET, (VoxelDetail*)&details); - } - } - } -} - -bool billboardInitialized = false; -const int BILLBOARD_HEIGHT = 9; -const int BILLBOARD_WIDTH = 45; -glm::vec3 billboardPosition((0.125f / TREE_SCALE),(0.125f / TREE_SCALE),0); -glm::vec3 billboardLights[BILLBOARD_HEIGHT][BILLBOARD_WIDTH]; -unsigned char billboardOffColor[3] = { 240, 240, 240 }; -unsigned char billboardOnColorA[3] = { 0, 0, 255 }; -unsigned char billboardOnColorB[3] = { 0, 255, 0 }; -float billboardGradient = 0.5f; -float billboardGradientIncrement = 0.01f; -const float BILLBOARD_MAX_GRADIENT = 1.0f; -const float BILLBOARD_MIN_GRADIENT = 0.0f; -const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light -const int VOXELS_PER_PACKET = 81; - -// top to bottom... -bool billboardMessage[BILLBOARD_HEIGHT][BILLBOARD_WIDTH] = { - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, - { 0,0,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,0,0 }, - { 0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,1,0,0,0,0,0 }, - { 0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,0,0,1,0,1,0 }, - { 0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0 }, - { 0,0,1,0,0,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,0,0,1,1,1,0 }, - { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 }, - { 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0 }, - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } -}; - -static void sendBillboard() { - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - float lightScale = BILLBOARD_LIGHT_SIZE; - static VoxelDetail details[VOXELS_PER_PACKET]; - - // first initialized the billboard of lights if needed... - if (!billboardInitialized) { - for (int i = 0; i < BILLBOARD_HEIGHT; i++) { - for (int j = 0; j < BILLBOARD_WIDTH; j++) { - - billboardLights[i][j] = billboardPosition + glm::vec3(j * lightScale, (float)((BILLBOARD_HEIGHT - i) * lightScale), 0); - } - } - billboardInitialized = true; - } - - ::billboardGradient += ::billboardGradientIncrement; - - if (::billboardGradient >= BILLBOARD_MAX_GRADIENT) { - ::billboardGradient = BILLBOARD_MAX_GRADIENT; - ::billboardGradientIncrement = -::billboardGradientIncrement; - } - if (::billboardGradient <= BILLBOARD_MIN_GRADIENT) { - ::billboardGradient = BILLBOARD_MIN_GRADIENT; - ::billboardGradientIncrement = -::billboardGradientIncrement; - } - - for (int i = 0; i < BILLBOARD_HEIGHT; i++) { - for (int j = 0; j < BILLBOARD_WIDTH; j++) { - - int nthVoxel = ((i * BILLBOARD_WIDTH) + j); - int item = nthVoxel % VOXELS_PER_PACKET; - - billboardLights[i][j] = billboardPosition + glm::vec3(j * lightScale, (float)((BILLBOARD_HEIGHT - i) * lightScale), 0); - - details[item].s = lightScale; - details[item].x = billboardLights[i][j].x; - details[item].y = billboardLights[i][j].y; - details[item].z = billboardLights[i][j].z; - - if (billboardMessage[i][j]) { - details[item].red = (billboardOnColorA[0] + ((billboardOnColorB[0] - billboardOnColorA[0]) * ::billboardGradient)); - details[item].green = (billboardOnColorA[1] + ((billboardOnColorB[1] - billboardOnColorA[1]) * ::billboardGradient)); - details[item].blue = (billboardOnColorA[2] + ((billboardOnColorB[2] - billboardOnColorA[2]) * ::billboardGradient)); - } else { - details[item].red = billboardOffColor[0]; - details[item].green = billboardOffColor[1]; - details[item].blue = billboardOffColor[2]; - } - - if (item == VOXELS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_PACKET, (VoxelDetail*)&details); - } - } - } -} - -bool roadInitialized = false; -const int BRICKS_ACROSS_ROAD = 32; -const float ROAD_BRICK_SIZE = 0.125f/TREE_SCALE; //(ROAD_WIDTH_METERS / TREE_SCALE) / BRICKS_ACROSS_ROAD; // in voxel units -const int ROAD_LENGTH = 1.0f / ROAD_BRICK_SIZE; // in bricks -const int ROAD_WIDTH = BRICKS_ACROSS_ROAD; // in bricks -glm::vec3 roadPosition(0.5f - (ROAD_BRICK_SIZE * BRICKS_ACROSS_ROAD), 0.0f, 0.0f); -const int BRICKS_PER_PACKET = 32; // guessing - -void doBuildStreet() { - if (roadInitialized) { - return; - } - - PacketType message = PacketTypeVoxelSetDestructive; // we're a bully! - static VoxelDetail details[BRICKS_PER_PACKET]; - - for (int z = 0; z < ROAD_LENGTH; z++) { - for (int x = 0; x < ROAD_WIDTH; x++) { - - int nthVoxel = ((z * ROAD_WIDTH) + x); - int item = nthVoxel % BRICKS_PER_PACKET; - - glm::vec3 brick = roadPosition + glm::vec3(x * ROAD_BRICK_SIZE, 0, z * ROAD_BRICK_SIZE); - - details[item].s = ROAD_BRICK_SIZE; - details[item].x = brick.x; - details[item].y = brick.y; - details[item].z = brick.z; - - unsigned char randomTone = randIntInRange(118,138); - details[item].red = randomTone; - details[item].green = randomTone; - details[item].blue = randomTone; - - if (item == BRICKS_PER_PACKET - 1) { - ::voxelEditPacketSender->queueVoxelEditMessages(message, BRICKS_PER_PACKET, (VoxelDetail*)&details); - } - } - } - roadInitialized = true; -} - - -double start = 0; - - -void* animateVoxels(void* args) { - - quint64 lastAnimateTime = 0; - quint64 lastProcessTime = 0; - int processesPerAnimate = 0; - - bool firstTime = true; - - qDebug() << "Setting PPS to " << ::packetsPerSecond; - ::voxelEditPacketSender->setPacketsPerSecond(::packetsPerSecond); - - qDebug() << "PPS set to " << ::voxelEditPacketSender->getPacketsPerSecond(); - - while (true) { - - // If we're asked to wait for voxel servers, and there isn't one available yet, then - // let the voxelEditPacketSender process and move on. - if (::waitForVoxelServer && !::voxelEditPacketSender->voxelServersExist()) { - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } - } else { - if (firstTime) { - lastAnimateTime = usecTimestampNow(); - firstTime = false; - } - lastProcessTime = usecTimestampNow(); - - // The while loop will be running at PROCESSING_FPS, but we only want to call these animation functions at - // ANIMATE_FPS. So we check out last animate time and only call these if we've elapsed that time. - quint64 now = usecTimestampNow(); - quint64 animationElapsed = now - lastAnimateTime; - int withinAnimationTarget = ANIMATE_VOXELS_INTERVAL_USECS - animationElapsed; - const int CLOSE_ENOUGH_TO_ANIMATE = 2000; // approximately 2 ms - - int animateLoopsPerAnimate = 0; - while (withinAnimationTarget < CLOSE_ENOUGH_TO_ANIMATE) { - processesPerAnimate = 0; - animateLoopsPerAnimate++; - - lastAnimateTime = now; - // some animations - //sendVoxelBlinkMessage(); - - if (::includeBillboard) { - sendBillboard(); - } - if (::includeBorderTracer) { - sendBlinkingStringOfLights(); - } - if (::includeMovingBug) { - renderMovingBug(); - } - if (::includeBlinkingVoxel) { - sendVoxelBlinkMessage(); - } - if (::includeDanceFloor) { - sendDanceFloor(); - } - - if (::buildStreet) { - doBuildStreet(); - } - - if (animationElapsed > ANIMATE_VOXELS_INTERVAL_USECS) { - animationElapsed -= ANIMATE_VOXELS_INTERVAL_USECS; // credit ourselves one animation frame - } else { - animationElapsed = 0; - } - withinAnimationTarget = ANIMATE_VOXELS_INTERVAL_USECS - animationElapsed; - - ::voxelEditPacketSender->releaseQueuedMessages(); - } - - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } - processesPerAnimate++; - } - // dynamically sleep until we need to fire off the next set of voxels - quint64 usecToSleep = ::PROCESSING_INTERVAL_USECS - (usecTimestampNow() - lastProcessTime); - if (usecToSleep > ::PROCESSING_INTERVAL_USECS) { - usecToSleep = ::PROCESSING_INTERVAL_USECS; - } - - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - pthread_exit(0); -} - -AnimationServer::AnimationServer(int &argc, char **argv) : - QCoreApplication(argc, argv) -{ - ::start = usecTimestampNow(); - - NodeList* nodeList = NodeList::createInstance(NodeType::AnimationServer, ANIMATION_LISTEN_PORT); - setvbuf(stdout, NULL, _IOLBF, 0); - - // Handle Local Domain testing with the --local command line - const char* NON_THREADED_PACKETSENDER = "--NonThreadedPacketSender"; - ::nonThreadedPacketSender = cmdOptionExists(argc, (const char**) argv, NON_THREADED_PACKETSENDER); - qDebug("nonThreadedPacketSender=%s", debug::valueOf(::nonThreadedPacketSender)); - - // Handle Local Domain testing with the --local command line - const char* NO_BILLBOARD = "--NoBillboard"; - ::includeBillboard = !cmdOptionExists(argc, (const char**) argv, NO_BILLBOARD); - qDebug("includeBillboard=%s", debug::valueOf(::includeBillboard)); - - const char* NO_BORDER_TRACER = "--NoBorderTracer"; - ::includeBorderTracer = !cmdOptionExists(argc, (const char**) argv, NO_BORDER_TRACER); - qDebug("includeBorderTracer=%s", debug::valueOf(::includeBorderTracer)); - - const char* NO_MOVING_BUG = "--NoMovingBug"; - ::includeMovingBug = !cmdOptionExists(argc, (const char**) argv, NO_MOVING_BUG); - qDebug("includeMovingBug=%s", debug::valueOf(::includeMovingBug)); - - const char* INCLUDE_BLINKING_VOXEL = "--includeBlinkingVoxel"; - ::includeBlinkingVoxel = cmdOptionExists(argc, (const char**) argv, INCLUDE_BLINKING_VOXEL); - qDebug("includeBlinkingVoxel=%s", debug::valueOf(::includeBlinkingVoxel)); - - const char* NO_DANCE_FLOOR = "--NoDanceFloor"; - ::includeDanceFloor = !cmdOptionExists(argc, (const char**) argv, NO_DANCE_FLOOR); - qDebug("includeDanceFloor=%s", debug::valueOf(::includeDanceFloor)); - - const char* BUILD_STREET = "--BuildStreet"; - ::buildStreet = cmdOptionExists(argc, (const char**) argv, BUILD_STREET); - qDebug("buildStreet=%s", debug::valueOf(::buildStreet)); - - // Handle Local Domain testing with the --local command line - const char* showPPS = "--showPPS"; - ::shouldShowPacketsPerSecond = cmdOptionExists(argc, (const char**) argv, showPPS); - - // Handle Local Domain testing with the --local command line - const char* local = "--local"; - ::wantLocalDomain = cmdOptionExists(argc, (const char**) argv,local); - if (::wantLocalDomain) { - qDebug("Local Domain MODE!"); - nodeList->getDomainHandler().setIPToLocalhost(); - } - - const char* domainHostname = getCmdOption(argc, (const char**) argv, "--domain"); - if (domainHostname) { - NodeList::getInstance()->getDomainHandler().setHostname(domainHostname); - } - - const char* packetsPerSecondCommand = getCmdOption(argc, (const char**) argv, "--pps"); - if (packetsPerSecondCommand) { - ::packetsPerSecond = atoi(packetsPerSecondCommand); - } - qDebug("packetsPerSecond=%d",packetsPerSecond); - - const char* animateFPSCommand = getCmdOption(argc, (const char**) argv, "--AnimateFPS"); - const char* animateIntervalCommand = getCmdOption(argc, (const char**) argv, "--AnimateInterval"); - if (animateFPSCommand || animateIntervalCommand) { - if (animateIntervalCommand) { - ::ANIMATE_FPS_IN_MILLISECONDS = atoi(animateIntervalCommand); - ::ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000.0); // converts from milliseconds to usecs - ::ANIMATE_FPS = PacketSender::USECS_PER_SECOND / ::ANIMATE_VOXELS_INTERVAL_USECS; - } else { - ::ANIMATE_FPS = atoi(animateFPSCommand); - ::ANIMATE_FPS_IN_MILLISECONDS = 1000.0/ANIMATE_FPS; // determines FPS from our desired FPS - ::ANIMATE_VOXELS_INTERVAL_USECS = (ANIMATE_FPS_IN_MILLISECONDS * 1000.0); // converts from milliseconds to usecs - } - } - qDebug("ANIMATE_FPS=%d",ANIMATE_FPS); - qDebug("ANIMATE_VOXELS_INTERVAL_USECS=%llu",ANIMATE_VOXELS_INTERVAL_USECS); - - const char* processingFPSCommand = getCmdOption(argc, (const char**) argv, "--ProcessingFPS"); - const char* processingIntervalCommand = getCmdOption(argc, (const char**) argv, "--ProcessingInterval"); - if (processingFPSCommand || processingIntervalCommand) { - if (processingIntervalCommand) { - ::PROCESSING_FPS_IN_MILLISECONDS = atoi(processingIntervalCommand); - ::PROCESSING_INTERVAL_USECS = ::PROCESSING_FPS_IN_MILLISECONDS * 1000.0; - ::PROCESSING_FPS = PacketSender::USECS_PER_SECOND / ::PROCESSING_INTERVAL_USECS; - } else { - ::PROCESSING_FPS = atoi(processingFPSCommand); - ::PROCESSING_FPS_IN_MILLISECONDS = 1000.0/PROCESSING_FPS; // determines FPS from our desired FPS - ::PROCESSING_INTERVAL_USECS = (PROCESSING_FPS_IN_MILLISECONDS * 1000.0) - FUDGE_USECS; // converts from milliseconds to usecs - } - } - qDebug("PROCESSING_FPS=%d",PROCESSING_FPS); - qDebug("PROCESSING_INTERVAL_USECS=%llu",PROCESSING_INTERVAL_USECS); - - nodeList->linkedDataCreateCallback = NULL; // do we need a callback? - - // Create our JurisdictionListener so we'll know where to send edit packets - ::jurisdictionListener = new JurisdictionListener(); - if (::jurisdictionListener) { - ::jurisdictionListener->initialize(true); - } - - // Create out VoxelEditPacketSender - ::voxelEditPacketSender = new VoxelEditPacketSender; - ::voxelEditPacketSender->initialize(!::nonThreadedPacketSender); - - if (::jurisdictionListener) { - ::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions()); - } - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->setProcessCallIntervalHint(PROCESSING_INTERVAL_USECS); - } - - srand((unsigned)time(0)); - - - pthread_create(&::animateVoxelThread, NULL, animateVoxels, NULL); - - NodeList::getInstance()->addNodeTypeToInterestSet(NodeType::VoxelServer); - - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), nodeList, SLOT(sendDomainServerCheckIn())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); - - QTimer* silentNodeTimer = new QTimer(this); - connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); - silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); - - connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readPendingDatagrams())); -} - -void AnimationServer::readPendingDatagrams() { - NodeList* nodeList = NodeList::getInstance(); - - static QByteArray receivedPacket; - static HifiSockAddr nodeSockAddr; - - // Nodes sending messages to us... - while (nodeList->getNodeSocket().hasPendingDatagrams()) { - receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); - nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(), - nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer()); - if (nodeList->packetVersionAndHashMatch(receivedPacket)) { - if (packetTypeForPacket(receivedPacket) == PacketTypeJurisdiction) { - int headerBytes = numBytesForPacketHeader(receivedPacket); - // PacketType_JURISDICTION, first byte is the node type... - if (receivedPacket.data()[headerBytes] == NodeType::VoxelServer && ::jurisdictionListener) { - - SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(receivedPacket); - if (matchedNode) { - ::jurisdictionListener->queueReceivedPacket(matchedNode, receivedPacket); - } - } - } - NodeList::getInstance()->processNodeData(nodeSockAddr, receivedPacket); - } - } -} - -AnimationServer::~AnimationServer() { - pthread_join(animateVoxelThread, NULL); - - if (::jurisdictionListener) { - ::jurisdictionListener->terminate(); - delete ::jurisdictionListener; - } - - if (::voxelEditPacketSender) { - ::voxelEditPacketSender->terminate(); - delete ::voxelEditPacketSender; - } -} diff --git a/animation-server/src/AnimationServer.h b/animation-server/src/AnimationServer.h deleted file mode 100644 index 58f05c32c5..0000000000 --- a/animation-server/src/AnimationServer.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// AnimationServer.h -// animation-server/src -// -// Created by Stephen Birarda on 12/5/2013. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_AnimationServer_h -#define hifi_AnimationServer_h - -#include - -class AnimationServer : public QCoreApplication { - Q_OBJECT -public: - AnimationServer(int &argc, char **argv); - ~AnimationServer(); -private slots: - void readPendingDatagrams(); -}; - - -#endif // hifi_AnimationServer_h diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp deleted file mode 100644 index 8acf3b8db2..0000000000 --- a/animation-server/src/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// main.cpp -// animation-server/src -// -// Created by Brad Hefta-Gaub on 05/16/2013. -// Copyright 2012 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "AnimationServer.h" - -int main(int argc, char * argv[]) { - AnimationServer animationServer(argc, argv); - return animationServer.exec(); -} From 64699a213a7088274f78b452718f6a42947e7859 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Aug 2014 14:48:51 -0700 Subject: [PATCH 08/13] remove animation server --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dbc89b75f..578c36841d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,11 +44,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -# targets not supported on windows -if (NOT WIN32) - add_subdirectory(animation-server) -endif () - # targets on all platforms add_subdirectory(assignment-client) add_subdirectory(domain-server) From 84f3ede32f04acdba5ed09feeb9544c256844e56 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Aug 2014 15:09:24 -0700 Subject: [PATCH 09/13] small change to force rebuild --- libraries/shared/src/SharedUtil.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 18494d48e4..4a9de2cc18 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -191,4 +191,5 @@ QByteArray createByteArray(const glm::vec3& vector); QString formatUsecTime(float usecs, int prec = 3); + #endif // hifi_SharedUtil_h From 9a55252587f1c02fe5fa88ce8e88c55e8aabf46f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Aug 2014 17:02:28 -0700 Subject: [PATCH 10/13] remove extraneous roots from Model::_jointStates --- interface/src/avatar/SkeletonModel.cpp | 24 +++++++--------- interface/src/renderer/Model.cpp | 40 ++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6b77e1c2f1..f759dc99a3 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -515,9 +515,9 @@ void SkeletonModel::initRagdollPoints() { initRagdollTransform(); // one point for each joint - int numJoints = _jointStates.size(); - _ragdollPoints.fill(VerletPoint(), numJoints); - for (int i = 0; i < numJoints; ++i) { + int numStates = _jointStates.size(); + _ragdollPoints.fill(VerletPoint(), numStates); + for (int i = 0; i < numStates; ++i) { const JointState& state = _jointStates.at(i); // _ragdollPoints start in model-frame _ragdollPoints[i].initPosition(state.getPosition()); @@ -719,8 +719,8 @@ void SkeletonModel::buildShapes() { // ... then move shapes back to current joint positions if (_ragdollPoints.size() == numStates) { - int numJoints = _jointStates.size(); - for (int i = 0; i < numJoints; ++i) { + int numStates = _jointStates.size(); + for (int i = 0; i < numStates; ++i) { // ragdollPoints start in model-frame _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); } @@ -765,17 +765,15 @@ void SkeletonModel::updateMuscles() { void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute default joint transforms - int numJoints = geometry.joints.size(); - if (numJoints != _ragdollPoints.size()) { - return; - } + int numStates = _jointStates.size(); QVector transforms; - transforms.fill(glm::mat4(), numJoints); + transforms.fill(glm::mat4(), numStates); // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) - for (int i = 0; i < numJoints; i++) { - const FBXJoint& joint = geometry.joints.at(i); + for (int i = 0; i < numStates; i++) { + JointState& state = _jointStates[i]; + const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); @@ -847,7 +845,7 @@ void SkeletonModel::resetShapePositionsToDefaultPose() { } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (geometry.joints.isEmpty() || _shapes.size() != geometry.joints.size()) { + if (geometry.joints.isEmpty()) { return; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 025971db4b..73b65b6d41 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -188,10 +188,38 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; - foreach (const FBXJoint& joint, geometry.joints) { - // NOTE: the state keeps a pointer to an FBXJoint + QVector roots; + roots.fill(-1, geometry.joints.size()); + for (int i = 0; i < geometry.joints.size(); ++i) { + const FBXJoint& joint = geometry.joints[i]; + int parentIndex = joint.parentIndex; + + // Some models may have multiple roots (?!), but these are causing problems in + // the Avatar Ragdoll simulation, so we prune them out of the JointState tree. + int rootIndex = 0; + if (parentIndex == -1) { + if (i != 0) { + // skip other root + continue; + } + } else { + rootIndex = roots[parentIndex]; + if (rootIndex == -1) { + roots[i] = parentIndex; + rootIndex = parentIndex; + } else { + roots[i] = rootIndex; + } + if (rootIndex != 0) { + // skip child of other root + continue; + } + } + + // store a pointer to the FBXJoint in the JointState JointState state; state.setFBXJoint(&joint); + jointStates.append(state); } return jointStates; @@ -199,8 +227,8 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { void Model::initJointTransforms() { // compute model transforms - int numJoints = _jointStates.size(); - for (int i = 0; i < numJoints; ++i) { + int numStates = _jointStates.size(); + for (int i = 0; i < numStates; ++i) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; @@ -538,9 +566,9 @@ void Model::setJointStates(QVector states) { _jointStates = states; initJointTransforms(); - int numJoints = _jointStates.size(); + int numStates = _jointStates.size(); float radius = 0.0f; - for (int i = 0; i < numJoints; ++i) { + for (int i = 0; i < numStates; ++i) { float distance = glm::length(_jointStates[i].getPosition()); if (distance > radius) { radius = distance; From 5de762361a70f12e560eb12ae6c1f12c22abc447 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 08:20:42 -0700 Subject: [PATCH 11/13] remove cleanup of Model::_jointStates tree the cleanup causes crashes and broken models --- interface/src/renderer/Model.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 73b65b6d41..a915406f8e 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -188,34 +188,8 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; - QVector roots; - roots.fill(-1, geometry.joints.size()); for (int i = 0; i < geometry.joints.size(); ++i) { const FBXJoint& joint = geometry.joints[i]; - int parentIndex = joint.parentIndex; - - // Some models may have multiple roots (?!), but these are causing problems in - // the Avatar Ragdoll simulation, so we prune them out of the JointState tree. - int rootIndex = 0; - if (parentIndex == -1) { - if (i != 0) { - // skip other root - continue; - } - } else { - rootIndex = roots[parentIndex]; - if (rootIndex == -1) { - roots[i] = parentIndex; - rootIndex = parentIndex; - } else { - roots[i] = rootIndex; - } - if (rootIndex != 0) { - // skip child of other root - continue; - } - } - // store a pointer to the FBXJoint in the JointState JointState state; state.setFBXJoint(&joint); From bcb0cb2c3c09ea77d0c3f85d7f0c6bc959c2afb6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 08:26:25 -0700 Subject: [PATCH 12/13] fix bug: variable should be float rather than int --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0b940dc3df..f59064732c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -206,7 +206,7 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("ragdoll"); if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - const int minError = 0.01f; + const float minError = 0.01f; const float maxIterations = 10; const quint64 maxUsec = 2000; _physicsSimulation.setTranslation(_position); From 05318acc7f4472d6e8e40449586c596b3b82ddf6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Aug 2014 08:37:28 -0700 Subject: [PATCH 13/13] don't make shapes for joints with zero radius --- interface/src/avatar/SkeletonModel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f759dc99a3..5e593526be 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -685,6 +685,9 @@ void SkeletonModel::buildShapes() { // this shape is forced to be a sphere type = Shape::SPHERE_SHAPE; } + if (radius < EPSILON) { + type = Shape::UNKNOWN_SHAPE; + } Shape* shape = NULL; int parentIndex = joint.parentIndex; if (type == Shape::SPHERE_SHAPE) { @@ -699,7 +702,9 @@ void SkeletonModel::buildShapes() { } if (parentIndex != -1) { // always disable collisions between joint and its parent - disableCollisions(i, parentIndex); + if (shape) { + disableCollisions(i, parentIndex); + } } else { // give the base joint a very large mass since it doesn't actually move // in the local-frame simulation (it defines the origin)