From 9e60b758df1c24dcd0cd6cde450ec30b91e117a9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 2 Jun 2014 11:34:59 -0700 Subject: [PATCH 01/71] Made JointState transforms private. Also changed some function names to be more descriptive. Using "Hybrid" to describe frame with world-rotation + model-local-origin. --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/FaceModel.cpp | 4 +- interface/src/avatar/SkeletonModel.cpp | 14 ++- interface/src/renderer/Model.cpp | 138 ++++++++++++++++++++----- interface/src/renderer/Model.h | 25 ++++- 5 files changed, 144 insertions(+), 39 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 306dc0194e..7850d089e1 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -378,7 +378,7 @@ void Avatar::simulateAttachments(float deltaTime) { model->setLODDistance(getLODDistance()); } if (_skeletonModel.getJointPosition(jointIndex, jointPosition) && - _skeletonModel.getJointRotation(jointIndex, jointRotation)) { + _skeletonModel.getJointRotationInWorldFrame(jointIndex, jointRotation)) { model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); model->setScale(_skeletonModel.getScale() * attachment.scale); diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index acd3d2c31f..080603ac7e 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -49,7 +49,7 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(_rotation); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState._transform * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getHybridTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation))); state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1])) @@ -59,7 +59,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // likewise with the eye joints - glm::mat4 inverse = glm::inverse(parentState._transform * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat4 inverse = glm::inverse(parentState.getHybridTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientation() * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() + diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 19f51d5db7..4c3cc72f37 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -221,9 +221,7 @@ void SkeletonModel::updateJointState(int index) { Model::updateJointState(index); if (index == _geometry->getFBXGeometry().rootJointIndex) { - state._transform[3][0] = 0.0f; - state._transform[3][1] = 0.0f; - state._transform[3][2] = 0.0f; + state.clearTransformTranslation(); } } @@ -233,7 +231,7 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const } // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(_rotation); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState._transform * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getHybridTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), @@ -259,11 +257,11 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { do { const FBXJoint& joint = geometry.joints.at(jointIndex); const JointState& jointState = _jointStates.at(jointIndex); - glm::vec3 position = extractTranslation(jointState._transform) + _translation; + glm::vec3 position = extractTranslation(jointState.getHybridTransform()) + _translation; glPushMatrix(); glTranslatef(position.x, position.y, position.z); - glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _jointStates.at(joint.parentIndex)._combinedRotation; + glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _rotation * _jointStates.at(joint.parentIndex).getRotationInModelFrame(); glm::vec3 rotationAxis = glm::axis(parentRotation); glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z); float fanScale = directionSize * 0.75f; @@ -296,7 +294,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { } glPopMatrix(); - renderOrientationDirections(position, jointState._combinedRotation, directionSize); + renderOrientationDirections(position, _rotation * jointState.getRotationInModelFrame(), directionSize); jointIndex = joint.parentIndex; } while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree); @@ -416,7 +414,7 @@ bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { if (geometry.neckJointIndex == -1) { return false; } - return getJointRotation(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); + return getJointRotationInWorldFrame(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); } bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 0335378a54..be9457a6bf 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -144,11 +144,26 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { jointStates.append(state); } + // compute model transforms + int numJoints = jointStates.size(); + for (int i = 0; i < numJoints; ++i) { + JointState& state = jointStates[i]; + const FBXJoint& joint = state.getFBXJoint(); + int parentIndex = joint.parentIndex; + if (parentIndex == -1) { + _rootIndex = i; + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + state.computeTransformInModelFrame(parentTransform); + } else { + const JointState& parentState = jointStates.at(parentIndex); + state.computeTransformInModelFrame(parentState.getTransformInModelFrame()); + } + } + // compute transforms // Unfortunately, the joints are not neccessarily in order from parents to children, // so we must iterate over the list multiple times until all are set correctly. QVector jointIsSet; - int numJoints = jointStates.size(); jointIsSet.fill(false, numJoints); int numJointsSet = 0; int lastNumJointsSet = -1; @@ -169,7 +184,8 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { jointIsSet[i] = true; } else if (jointIsSet[parentIndex]) { const JointState& parentState = jointStates.at(parentIndex); - state.computeTransforms(parentState._transform, parentState._combinedRotation); + glm::quat parentRotation = _rotation * parentState.getRotationInModelFrame(); + state.computeTransforms(parentState.getHybridTransform(), parentRotation); ++numJointsSet; jointIsSet[i] = true; } @@ -624,11 +640,12 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } - position = _translation + extractTranslation(_jointStates[jointIndex]._transform); + position = _translation + extractTranslation(_jointStates[jointIndex].getHybridTransform()); + //position = _translation + _rotation * _jointState[jointIndex].getPositionInModelFrame(); return true; } -bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) const { +bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation, bool fromBind) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } @@ -848,11 +865,12 @@ void Model::updateShapePositions() { for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; // shape position and rotation need to be in world-frame - glm::vec3 jointToShapeOffset = uniformScale * (_jointStates[i]._combinedRotation * joint.shapePosition); - glm::vec3 worldPosition = extractTranslation(_jointStates[i]._transform) + jointToShapeOffset + _translation; + glm::quat rotationInWorldFrame = _rotation * _jointStates[i].getRotationInModelFrame(); + glm::vec3 jointToShapeOffset = uniformScale * (rotationInWorldFrame * joint.shapePosition); + glm::vec3 worldPosition = extractTranslation(_jointStates[i].getHybridTransform()) + jointToShapeOffset + _translation; Shape* shape = _jointShapes[i]; shape->setPosition(worldPosition); - shape->setRotation(_jointStates[i]._combinedRotation * joint.shapeRotation); + shape->setRotation(rotationInWorldFrame * joint.shapeRotation); float distance = glm::distance(worldPosition, _translation) + shape->getBoundingRadius(); if (distance > _boundingRadius) { _boundingRadius = distance; @@ -874,12 +892,12 @@ bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct float radiusScale = extractUniformScale(_scale); for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; - glm::vec3 end = extractTranslation(_jointStates[i]._transform); + glm::vec3 end = extractTranslation(_jointStates[i].getHybridTransform()); float endRadius = joint.boneRadius * radiusScale; glm::vec3 start = end; float startRadius = joint.boneRadius * radiusScale; if (joint.parentIndex != -1) { - start = extractTranslation(_jointStates[joint.parentIndex]._transform); + start = extractTranslation(_jointStates[joint.parentIndex].getHybridTransform()); startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale; } // for now, use average of start and end radii @@ -1090,7 +1108,7 @@ void Model::simulateInternal(float deltaTime) { glm::vec3 jointTranslation = _translation; glm::quat jointRotation = _rotation; getJointPosition(attachment.jointIndex, jointTranslation); - getJointRotation(attachment.jointIndex, jointRotation); + getJointRotationInWorldFrame(attachment.jointIndex, jointRotation); model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); @@ -1106,7 +1124,7 @@ void Model::simulateInternal(float deltaTime) { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = _jointStates[cluster.jointIndex]._transform * cluster.inverseBindMatrix; + state.clusterMatrices[j] = _jointStates[cluster.jointIndex].getHybridTransform() * cluster.inverseBindMatrix; } } @@ -1120,13 +1138,26 @@ void Model::updateJointState(int index) { JointState& state = _jointStates[index]; const FBXJoint& joint = state.getFBXJoint(); - if (joint.parentIndex == -1) { + // compute model transforms + int parentIndex = joint.parentIndex; + if (parentIndex == -1) { + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + state.computeTransformInModelFrame(parentTransform); + } else { + const JointState& parentState = _jointStates.at(parentIndex); + state.computeTransformInModelFrame(parentState.getTransformInModelFrame()); + } + + // compute hybrid transforms + if (parentIndex == -1) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset; state.computeTransforms(baseTransform, _rotation); } else { - const JointState& parentState = _jointStates.at(joint.parentIndex); - state.computeTransforms(parentState._transform, parentState._combinedRotation); + const JointState& parentState = _jointStates.at(parentIndex); + glm::quat parentRotation = _rotation * parentState.getRotationInModelFrame(); + state.computeTransforms(parentState.getHybridTransform(), parentRotation); } } @@ -1162,7 +1193,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const } // then, we go from the joint upwards, rotating the end as close as possible to the target - glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex]._transform); + glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].getHybridTransform()); for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); JointState& state = _jointStates[index]; @@ -1170,9 +1201,9 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const if (!(joint.isFree || allIntermediatesFree)) { continue; } - glm::vec3 jointPosition = extractTranslation(state._transform); + glm::vec3 jointPosition = extractTranslation(state.getHybridTransform()); glm::vec3 jointVector = endPosition - jointPosition; - glm::quat oldCombinedRotation = state._combinedRotation; + glm::quat oldCombinedRotation = _rotation * state.getRotationInModelFrame(); glm::quat combinedDelta; float combinedWeight; if (useRotation) { @@ -1190,7 +1221,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const for (int k = j - 1; k > 0; k--) { int index = freeLineage.at(k); updateJointState(index); - positionSum += extractTranslation(_jointStates.at(index)._transform); + positionSum += extractTranslation(_jointStates.at(index).getHybridTransform()); } glm::vec3 projectedCenterOfMass = glm::cross(jointVector, glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); @@ -1202,7 +1233,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const } } state.applyRotationDelta(combinedDelta, true, priority); - glm::quat actualDelta = state._combinedRotation * glm::inverse(oldCombinedRotation); + glm::quat actualDelta = _rotation * state.getRotationInModelFrame() * glm::inverse(oldCombinedRotation); endPosition = actualDelta * jointVector + jointPosition; if (useRotation) { endRotation = actualDelta * endRotation; @@ -1827,6 +1858,11 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) { } } +glm::mat4 Model::getBaseTransform(const glm::mat4& geometryOffset) const { + //return glm::translate(_translation) * glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometryOffset; + return glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometryOffset; +} + // ---------------------------------------------------------------------------- // JointState TODO: move this class to its own files // ---------------------------------------------------------------------------- @@ -1844,23 +1880,44 @@ void JointState::setFBXJoint(const FBXJoint* joint) { void JointState::copyState(const JointState& state) { _rotation = state._rotation; - _transform = state._transform; + + _transformInModelFrame = state._transformInModelFrame; + _rotationInModelFrame = extractRotation(_transformInModelFrame); _combinedRotation = state._combinedRotation; + _transform = state._transform; + _animationPriority = state._animationPriority; // DO NOT copy _fbxJoint } -void JointState::computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation) { +void JointState::computeTransformInModelFrame(const glm::mat4& parentTransform) { + glm::quat modifiedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation; + glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; + _transformInModelFrame = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; + _rotationInModelFrame = extractRotation(_transformInModelFrame); +} + +glm::quat JointState::getRotationInWorldFrame(const glm::quat& baseRotation) const { + return baseRotation * _rotationInModelFrame; +} + +glm::vec3 JointState::getPositionInWorldFrame(const glm::quat& baseRotation, const glm::vec3& basePosition) const { + return basePosition + baseRotation * extractTranslation(_transformInModelFrame); +} + +void JointState::computeTransforms(const glm::mat4& parentTransform, const glm::quat& baseRotation) { assert(_fbxJoint != NULL); - glm::quat combinedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation; - _transform = baseTransform * glm::translate(_fbxJoint->translation) * _fbxJoint->preTransform - * glm::mat4_cast(combinedRotation) * _fbxJoint->postTransform; - _combinedRotation = baseRotation * combinedRotation; + + glm::quat modifiedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation; + glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; + _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; + _combinedRotation = baseRotation * modifiedRotation; } glm::quat JointState::getJointRotation(bool fromBind) const { assert(_fbxJoint != NULL); return _combinedRotation * (fromBind ? _fbxJoint->inverseBindRotation : _fbxJoint->inverseDefaultRotation); + //return _rotationInModelFrame * (fromBind ? _fbxJoint->inverseBindRotation : _fbxJoint->inverseDefaultRotation); } void JointState::restoreRotation(float fraction, float priority) { @@ -1879,6 +1936,15 @@ void JointState::setRotation(const glm::quat& rotation, float priority) { } } +void JointState::clearTransformTranslation() { + _transform[3][0] = 0.0f; + _transform[3][1] = 0.0f; + _transform[3][2] = 0.0f; + _transformInModelFrame[3][0] = 0.0f; + _transformInModelFrame[3][1] = 0.0f; + _transformInModelFrame[3][2] = 0.0f; +} + void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { assert(_fbxJoint != NULL); if (priority < _animationPriority) { @@ -1899,6 +1965,28 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa _rotation = newRotation; } +/* +void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { + assert(_fbxJoint != NULL); + if (priority < _animationPriority) { + return; + } + _animationPriority = priority; + if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && + _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { + // no constraints + _rotation = _rotation * glm::inverse(_rotationInModelFrame) * delta * _rotationInModelFrame; + _rotationInModelFrame = delta * _rotationInModelFrame; + return; + } + glm::quat targetRotation = delta * _rotationInModelFrame; + glm::vec3 eulers = safeEulerAngles(_rotation * glm::inverse(_rotationInModelFrame) * targetRotation); + glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax)); + _rotationInModelFrame = _rotationInModelFrame * glm::inverse(_rotation) * newRotation; + _rotation = newRotation; +} +*/ + const glm::vec3& JointState::getDefaultTranslationInParentFrame() const { assert(_fbxJoint != NULL); return _fbxJoint->translation; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 6e38c7eed4..26229a4a34 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -40,6 +40,15 @@ public: void copyState(const JointState& state); + void computeTransformInModelFrame(const glm::mat4& parentTransform); + const glm::mat4& getTransformInModelFrame() const { return _transformInModelFrame; } + + glm::quat getRotationInModelFrame() const { return _rotationInModelFrame; } + glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transformInModelFrame); } + + glm::quat getRotationInWorldFrame(const glm::quat& baseRotation) const; + glm::vec3 getPositionInWorldFrame(const glm::quat& baseRotation, const glm::vec3& basePosition) const; + /// computes new _transform and _combinedRotation void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); @@ -54,14 +63,22 @@ public: /// \param rotation is from bind- to world-frame /// computes parent relative _rotation and sets that + /// \warning no combined transforms are updated! void setRotation(const glm::quat& rotation, float priority); + const glm::mat4& getHybridTransform() const { return _transform; } + const glm::quat& getRotationInWorldFrame() const { return _combinedRotation; } + void clearTransformTranslation(); + glm::quat _rotation; // rotation relative to parent - glm::mat4 _transform; // rotation to world frame + translation in model frame - glm::quat _combinedRotation; // rotation from joint local to world frame float _animationPriority; // the priority of the animation affecting this joint private: + glm::mat4 _transformInModelFrame; + glm::quat _rotationInModelFrame; + glm::quat _combinedRotation; // rotation from joint local to world frame + glm::mat4 _transform; // rotation to world frame + translation in model frame + const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint }; @@ -156,7 +173,7 @@ public: int getLastFreeJointIndex(int jointIndex) const; bool getJointPosition(int jointIndex, glm::vec3& position) const; - bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; + bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation, bool fromBind = false) const; QStringList getJointNames() const; @@ -199,6 +216,8 @@ public: const CapsuleShape& getBoundingShape() const { return _boundingShape; } + glm::mat4 getBaseTransform(const glm::mat4& geometryOffset) const; + protected: QSharedPointer _geometry; From 9b3773fa3b7e3729cc25eb0cf321102d19ee0736 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 2 Jun 2014 14:20:13 -0700 Subject: [PATCH 02/71] remove 'fromBind' argument to getJointRotation() --- interface/src/avatar/SkeletonModel.cpp | 6 +++--- interface/src/renderer/Model.cpp | 16 ++++++++-------- interface/src/renderer/Model.h | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d347e39d2c..48efbdc4dc 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -147,7 +147,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) return; } JointState& state = _jointStates[jointIndex]; - glm::quat handRotation = state.getJointRotation(true); + glm::quat handRotation = state.getJointRotation(); // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; @@ -170,10 +170,10 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { JointState parentState = _jointStates[parentJointIndex]; - palmRotation = parentState.getJointRotation(true); + palmRotation = parentState.getJointRotation(); } else { JointState state = _jointStates[jointIndex]; - palmRotation = state.getJointRotation(true); + palmRotation = state.getJointRotation(); } palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d809909dfe..3a3adfc8cc 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -756,11 +756,11 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { return true; } -bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation, bool fromBind) const { +bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _jointStates[jointIndex].getJointRotation(fromBind); + rotation = _jointStates[jointIndex].getJointRotation(); return true; } @@ -768,7 +768,7 @@ bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _jointStates[jointIndex].getRotationInWorldFrame(); + rotation = _jointStates[jointIndex].getRotationInWorldFrame(_rotation); return true; } @@ -1306,9 +1306,9 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const JointState& state = _jointStates[jointIndex]; // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = state.getJointRotation(true); + endRotation = state.getJointRotation(); state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); - endRotation = state.getJointRotation(true); + endRotation = state.getJointRotation(); } // then, we go from the joint upwards, rotating the end as close as possible to the target @@ -2067,10 +2067,10 @@ void JointState::computeTransforms(const glm::mat4& parentTransform, const glm:: _combinedRotation = baseRotation * modifiedRotation; } -glm::quat JointState::getJointRotation(bool fromBind) const { +glm::quat JointState::getJointRotation() const { assert(_fbxJoint != NULL); - return _combinedRotation * (fromBind ? _fbxJoint->inverseBindRotation : _fbxJoint->inverseDefaultRotation); - //return _rotationInModelFrame * (fromBind ? _fbxJoint->inverseBindRotation : _fbxJoint->inverseDefaultRotation); + return _combinedRotation * _fbxJoint->inverseBindRotation; + //return _rotationInModelFrame * _fbxJoint->inverseBindRotation; } void JointState::restoreRotation(float fraction, float priority) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b7d089e713..b6ae6c9012 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -53,7 +53,7 @@ public: void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); /// \return rotation from the joint's default (or bind) frame to world frame - glm::quat getJointRotation(bool fromBind = false) const; + glm::quat getJointRotation() const; void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); @@ -67,7 +67,7 @@ public: void setRotation(const glm::quat& rotation, float priority); const glm::mat4& getHybridTransform() const { return _transform; } - const glm::quat& getRotationInWorldFrame() const { return _combinedRotation; } + //const glm::quat& getRotationInWorldFrame() const { return _combinedRotation; } void clearTransformTranslation(); glm::quat _rotation; // rotation relative to parent @@ -173,7 +173,7 @@ public: int getLastFreeJointIndex(int jointIndex) const; bool getJointPosition(int jointIndex, glm::vec3& position) const; - bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation, bool fromBind = false) const; + bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; QStringList getJointNames() const; From d7be5faa9d902f8826456bf5105d8c90a3bab0dd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 2 Jun 2014 14:43:25 -0700 Subject: [PATCH 03/71] unravel rotation code by giving proper names The goal is: eliminate dependency on JointState::_combinedRotation (which is joint-to-world) and store joint-to-model transforms instead --- interface/src/avatar/SkeletonModel.cpp | 10 +++++----- interface/src/renderer/Model.cpp | 16 +++++++--------- interface/src/renderer/Model.h | 6 +++--- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 48efbdc4dc..de9c413017 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -147,7 +147,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) return; } JointState& state = _jointStates[jointIndex]; - glm::quat handRotation = state.getJointRotation(); + glm::quat handRotation = state.getRotationFromBindToModelFrame(); // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; @@ -170,10 +170,10 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { JointState parentState = _jointStates[parentJointIndex]; - palmRotation = parentState.getJointRotation(); + palmRotation = parentState.getRotationFromBindToModelFrame(); } else { JointState state = _jointStates[jointIndex]; - palmRotation = state.getJointRotation(); + palmRotation = state.getRotationFromBindToModelFrame(); } palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; @@ -414,7 +414,7 @@ bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { if (geometry.neckJointIndex == -1) { return false; } - return getJointRotationInWorldFrame(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); + return getJointRotationFromBindToWorldFrame(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); } bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { @@ -433,7 +433,7 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco const float EYE_PROPORTION = 0.6f; glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION); glm::quat headRotation; - getJointRotationInWorldFrame(geometry.headJointIndex, headRotation); + getJointRotationFromBindToWorldFrame(geometry.headJointIndex, headRotation); const float EYES_FORWARD = 0.25f; const float EYE_SEPARATION = 0.1f; float headHeight = glm::distance(neckPosition, headPosition); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3a3adfc8cc..11cd4678e3 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -756,11 +756,11 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { return true; } -bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const { +bool Model::getJointRotationFromBindToWorldFrame(int jointIndex, glm::quat& rotation) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _jointStates[jointIndex].getJointRotation(); + rotation = _rotation * _jointStates[jointIndex].getRotationFromBindToModelFrame(); return true; } @@ -1227,7 +1227,7 @@ void Model::simulateInternal(float deltaTime) { glm::vec3 jointTranslation = _translation; glm::quat jointRotation = _rotation; getJointPosition(attachment.jointIndex, jointTranslation); - getJointRotationInWorldFrame(attachment.jointIndex, jointRotation); + getJointRotationFromBindToWorldFrame(attachment.jointIndex, jointRotation); model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); @@ -1306,9 +1306,9 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const JointState& state = _jointStates[jointIndex]; // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = state.getJointRotation(); + endRotation = _rotation * state.getRotationFromBindToModelFrame(); state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); - endRotation = state.getJointRotation(); + endRotation = _rotation * state.getRotationFromBindToModelFrame(); } // then, we go from the joint upwards, rotating the end as close as possible to the target @@ -2067,10 +2067,8 @@ void JointState::computeTransforms(const glm::mat4& parentTransform, const glm:: _combinedRotation = baseRotation * modifiedRotation; } -glm::quat JointState::getJointRotation() const { - assert(_fbxJoint != NULL); - return _combinedRotation * _fbxJoint->inverseBindRotation; - //return _rotationInModelFrame * _fbxJoint->inverseBindRotation; +glm::quat JointState::getRotationFromBindToModelFrame() const { + return _rotationInModelFrame * _fbxJoint->inverseBindRotation; } void JointState::restoreRotation(float fraction, float priority) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b6ae6c9012..2577953a3a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -52,8 +52,8 @@ public: /// computes new _transform and _combinedRotation void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); - /// \return rotation from the joint's default (or bind) frame to world frame - glm::quat getJointRotation() const; + /// \return rotation that moves a vector given in this joint's bind-frame to the model-frame + glm::quat getRotationFromBindToModelFrame() const; void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); @@ -173,7 +173,7 @@ public: int getLastFreeJointIndex(int jointIndex) const; bool getJointPosition(int jointIndex, glm::vec3& position) const; - bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; + bool getJointRotationFromBindToWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; QStringList getJointNames() const; From 6db385de7a738e746dc53faab7da4dd1128dfb75 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 2 Jun 2014 15:16:08 -0700 Subject: [PATCH 04/71] Ported over fixes that I made when working on delta-encoding for avatars. --- libraries/metavoxels/src/Bitstream.cpp | 58 ++++++++++-- libraries/metavoxels/src/Bitstream.h | 92 +++++++++++++++++++- libraries/metavoxels/src/DatagramSequencer.h | 2 +- libraries/metavoxels/src/SharedObject.cpp | 41 +++++---- libraries/metavoxels/src/SharedObject.h | 23 +++-- 5 files changed, 184 insertions(+), 32 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index ad929e533c..b3d5817fe9 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -193,7 +193,7 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { continue; } connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); - QPointer& reference = _sharedObjectReferences[it.key()->getID()]; + QPointer& reference = _sharedObjectReferences[it.key()->getOriginID()]; if (reference) { _sharedObjectStreamer.removePersistentID(reference); reference->disconnect(this); @@ -227,7 +227,7 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { if (!it.value()) { continue; } - QPointer& reference = _sharedObjectReferences[it.value()->getRemoteID()]; + QPointer& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()]; if (reference) { _sharedObjectStreamer.removePersistentValue(reference.data()); } @@ -411,6 +411,10 @@ Bitstream& Bitstream::operator>>(QUrl& url) { } Bitstream& Bitstream::operator<<(const QVariant& value) { + if (!value.isValid()) { + _typeStreamerStreamer << NULL; + return *this; + } const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); if (streamer) { _typeStreamerStreamer << streamer; @@ -424,7 +428,11 @@ Bitstream& Bitstream::operator<<(const QVariant& value) { Bitstream& Bitstream::operator>>(QVariant& value) { TypeReader reader; _typeStreamerStreamer >> reader; - value = reader.read(*this); + if (reader.getTypeName().isEmpty()) { + value = QVariant(); + } else { + value = reader.read(*this); + } return *this; } @@ -656,6 +664,10 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { } Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { + if (!streamer) { + *this << QByteArray(); + return *this; + } const char* typeName = QMetaType::typeName(streamer->getType()); *this << QByteArray::fromRawData(typeName, strlen(typeName)); if (_metadataType == NO_METADATA) { @@ -702,6 +714,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray typeName; *this >> typeName; + if (typeName.isEmpty()) { + reader = TypeReader(); + return *this; + } const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); if (!streamer) { streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); @@ -847,9 +863,10 @@ Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { return *this << (int)0; } *this << object->getID(); - QPointer reference = _sharedObjectReferences.value(object->getID()); + *this << object->getOriginID(); + QPointer reference = _sharedObjectReferences.value(object->getOriginID()); if (reference) { - writeRawDelta((QObject*)object.data(), (QObject*)reference.data()); + writeRawDelta((const QObject*)object.data(), (const QObject*)reference.data()); } else { *this << (QObject*)object.data(); } @@ -863,7 +880,9 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { object = SharedObjectPointer(); return *this; } - QPointer reference = _sharedObjectReferences.value(id); + int originID; + *this >> originID; + QPointer reference = _sharedObjectReferences.value(originID); QPointer& pointer = _weakSharedObjectHash[id]; if (pointer) { ObjectReader objectReader; @@ -876,15 +895,19 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { } else { QObject* rawObject; if (reference) { - readRawDelta(rawObject, (QObject*)reference.data()); + readRawDelta(rawObject, (const QObject*)reference.data()); } else { *this >> rawObject; } pointer = static_cast(rawObject); if (pointer) { + if (reference) { + pointer->setOriginID(reference->getOriginID()); + } pointer->setRemoteID(id); + pointer->setRemoteOriginID(originID); } else { - qDebug() << "Null object" << pointer << reference; + qDebug() << "Null object" << pointer << reference << id; } } object = static_cast(pointer.data()); @@ -893,7 +916,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { void Bitstream::clearSharedObject(QObject* object) { SharedObject* sharedObject = static_cast(object); - _sharedObjectReferences.remove(sharedObject->getID()); + _sharedObjectReferences.remove(sharedObject->getOriginID()); int id = _sharedObjectStreamer.takePersistentID(sharedObject); if (id != 0) { emit sharedObjectCleared(id); @@ -1099,6 +1122,10 @@ uint qHash(const TypeReader& typeReader, uint seed) { return qHash(typeReader.getTypeName(), seed); } +QDebug& operator<<(QDebug& debug, const TypeReader& typeReader) { + return debug << typeReader.getTypeName(); +} + FieldReader::FieldReader(const TypeReader& reader, int index) : _reader(reader), _index(index) { @@ -1152,6 +1179,10 @@ uint qHash(const ObjectReader& objectReader, uint seed) { return qHash(objectReader.getClassName(), seed); } +QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader) { + return debug << objectReader.getClassName(); +} + PropertyReader::PropertyReader(const TypeReader& reader, const QMetaProperty& property) : _reader(reader), _property(property) { @@ -1236,3 +1267,12 @@ QVariant TypeStreamer::getValue(const QVariant& object, int index) const { void TypeStreamer::setValue(QVariant& object, int index, const QVariant& value) const { // nothing by default } + +QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer) { + return debug << (typeStreamer ? QMetaType::typeName(typeStreamer->getType()) : "null"); +} + +QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { + return debug << (metaObject ? metaObject->className() : "null"); +} + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 34b66eb9f2..544d6dbd78 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -294,6 +294,9 @@ public: template void writeRawDelta(const QList& value, const QList& reference); template void readRawDelta(QList& value, const QList& reference); + template void writeRawDelta(const QVector& value, const QVector& reference); + template void readRawDelta(QVector& value, const QVector& reference); + template void writeRawDelta(const QSet& value, const QSet& reference); template void readRawDelta(QSet& value, const QSet& reference); @@ -339,6 +342,9 @@ public: template Bitstream& operator<<(const QList& list); template Bitstream& operator>>(QList& list); + template Bitstream& operator<<(const QVector& list); + template Bitstream& operator>>(QVector& list); + template Bitstream& operator<<(const QSet& set); template Bitstream& operator>>(QSet& set); @@ -472,6 +478,36 @@ template inline void Bitstream::readRawDelta(QList& value, const QLi } } +template inline void Bitstream::writeRawDelta(const QVector& value, const QVector& reference) { + *this << value.size(); + *this << reference.size(); + for (int i = 0; i < value.size(); i++) { + if (i < reference.size()) { + writeDelta(value.at(i), reference.at(i)); + } else { + *this << value.at(i); + } + } +} + +template inline void Bitstream::readRawDelta(QVector& value, const QVector& reference) { + value = reference; + int size, referenceSize; + *this >> size >> referenceSize; + if (size < value.size()) { + value.erase(value.begin() + size, value.end()); + } + for (int i = 0; i < size; i++) { + if (i < referenceSize) { + readDelta(value[i], reference.at(i)); + } else { + T element; + *this >> element; + value.append(element); + } + } +} + template inline void Bitstream::writeRawDelta(const QSet& value, const QSet& reference) { int addedOrRemoved = 0; foreach (const T& element, value) { @@ -600,6 +636,27 @@ template inline Bitstream& Bitstream::operator>>(QList& list) { return *this; } +template inline Bitstream& Bitstream::operator<<(const QVector& vector) { + *this << vector.size(); + foreach (const T& entry, vector) { + *this << entry; + } + return *this; +} + +template inline Bitstream& Bitstream::operator>>(QVector& vector) { + int size; + *this >> size; + vector.clear(); + vector.reserve(size); + for (int i = 0; i < size; i++) { + T entry; + *this >> entry; + vector.append(entry); + } + return *this; +} + template inline Bitstream& Bitstream::operator<<(const QSet& set) { *this << set.size(); foreach (const T& entry, set) { @@ -683,6 +740,8 @@ private: uint qHash(const TypeReader& typeReader, uint seed = 0); +QDebug& operator<<(QDebug& debug, const TypeReader& typeReader); + /// Contains the information required to read a metatype field from the stream and apply it. class FieldReader { public: @@ -726,6 +785,8 @@ private: uint qHash(const ObjectReader& objectReader, uint seed = 0); +QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader); + /// Contains the information required to read an object property from the stream and apply it. class PropertyReader { public: @@ -808,6 +869,10 @@ private: int _type; }; +QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer); + +QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject); + /// A streamer that works with Bitstream's operators. template class SimpleTypeStreamer : public TypeStreamer { public: @@ -818,11 +883,11 @@ public: virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { out.writeDelta(value.value(), reference.value()); } virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { - in.readDelta(*static_cast(value.data()), reference.value()); } + T rawValue; in.readDelta(rawValue, reference.value()); value = QVariant::fromValue(rawValue); } virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { out.writeRawDelta(value.value(), reference.value()); } virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { - in.readRawDelta(*static_cast(value.data()), reference.value()); } + T rawValue; in.readRawDelta(rawValue, reference.value()); value = QVariant::fromValue(rawValue); } }; /// A streamer for types compiled by mtc. @@ -858,6 +923,22 @@ public: static_cast*>(object.data())->replace(index, value.value()); } }; +/// A streamer for vector types. +template class CollectionTypeStreamer > : public SimpleTypeStreamer > { +public: + + virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; } + virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId()); } + virtual void insert(QVariant& object, const QVariant& value) const { + static_cast*>(object.data())->append(value.value()); } + virtual void prune(QVariant& object, int size) const { + QVector* list = static_cast*>(object.data()); list->erase(list->begin() + size, list->end()); } + virtual QVariant getValue(const QVariant& object, int index) const { + return QVariant::fromValue(static_cast*>(object.constData())->at(index)); } + virtual void setValue(QVariant& object, int index, const QVariant& value) const { + static_cast*>(object.data())->replace(index, value.value()); } +}; + /// A streamer for set types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: @@ -940,6 +1021,13 @@ template int registerStreamableMetaType() { return type; } +/// Registers a collection type and its streamer. +template int registerCollectionMetaType() { + int type = qRegisterMetaType(); + Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer()); + return type; +} + /// Flags a class as streamable (use as you would Q_OBJECT). #define STREAMABLE public: \ static const int Type; \ diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index ce9f36ba33..cf6ded74da 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -19,7 +19,7 @@ #include #include -#include "Bitstream.h" +#include "AttributeRegistry.h" class ReliableChannel; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index b578d70959..47d69f4abe 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -23,7 +23,9 @@ REGISTER_META_OBJECT(SharedObject) SharedObject::SharedObject() : _id(++_lastID), - _remoteID(0) { + _originID(_id), + _remoteID(0), + _remoteOriginID(0) { _weakHash.insert(_id, this); } @@ -39,26 +41,33 @@ void SharedObject::decrementReferenceCount() { } } -SharedObject* SharedObject::clone(bool withID) const { +SharedObject* SharedObject::clone(bool withID, SharedObject* target) const { // default behavior is to make a copy using the no-arg constructor and copy the stored properties const QMetaObject* metaObject = this->metaObject(); - SharedObject* newObject = static_cast(metaObject->newInstance()); + if (!target) { + target = static_cast(metaObject->newInstance()); + } for (int i = 0; i < metaObject->propertyCount(); i++) { QMetaProperty property = metaObject->property(i); if (property.isStored()) { - property.write(newObject, property.read(this)); + if (property.userType() == qMetaTypeId()) { + SharedObject* value = property.read(this).value().data(); + property.write(target, QVariant::fromValue(value ? value->clone(withID) : value)); + } else { + property.write(target, property.read(this)); + } } } foreach (const QByteArray& propertyName, dynamicPropertyNames()) { - newObject->setProperty(propertyName, property(propertyName)); + target->setProperty(propertyName, property(propertyName)); } if (withID) { - newObject->setID(_id); + target->setOriginID(_originID); } - return newObject; + return target; } -bool SharedObject::equals(const SharedObject* other) const { +bool SharedObject::equals(const SharedObject* other, bool sharedAncestry) const { if (!other) { return false; } @@ -67,7 +76,7 @@ bool SharedObject::equals(const SharedObject* other) const { } // default behavior is to compare the properties const QMetaObject* metaObject = this->metaObject(); - if (metaObject != other->metaObject()) { + if (metaObject != other->metaObject() && !sharedAncestry) { return false; } for (int i = 0; i < metaObject->propertyCount(); i++) { @@ -92,13 +101,15 @@ void SharedObject::dump(QDebug debug) const { debug << this; const QMetaObject* metaObject = this->metaObject(); for (int i = 0; i < metaObject->propertyCount(); i++) { - debug << metaObject->property(i).name() << metaObject->property(i).read(this); + QMetaProperty property = metaObject->property(i); + if (property.isStored()) { + debug << property.name() << property.read(this); + } + } + QList dynamicPropertyNames = this->dynamicPropertyNames(); + foreach (const QByteArray& propertyName, dynamicPropertyNames) { + debug << propertyName << property(propertyName); } -} - -void SharedObject::setID(int id) { - _weakHash.remove(_id); - _weakHash.insert(_id = id, this); } int SharedObject::_lastID = 0; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index aba6b86bea..41c3c01ffe 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -41,31 +41,44 @@ public: /// Returns the unique local ID for this object. int getID() const { return _id; } + /// Returns the local origin ID for this object. + int getOriginID() const { return _originID; } + + void setOriginID(int originID) { _originID = originID; } + /// Returns the unique remote ID for this object, or zero if this is a local object. int getRemoteID() const { return _remoteID; } void setRemoteID(int remoteID) { _remoteID = remoteID; } + /// Returns the remote origin ID for this object, or zero if this is a local object. + int getRemoteOriginID() const { return _remoteOriginID; } + + void setRemoteOriginID(int remoteOriginID) { _remoteOriginID = remoteOriginID; } + int getReferenceCount() const { return _referenceCount.load(); } void incrementReferenceCount(); void decrementReferenceCount(); /// Creates a new clone of this object. - /// \param withID if true, give the clone the same ID as this object - virtual SharedObject* clone(bool withID = false) const; + /// \param withID if true, give the clone the same origin ID as this object + /// \target if non-NULL, a target object to populate (as opposed to creating a new instance of this object's class) + virtual SharedObject* clone(bool withID = false, SharedObject* target = NULL) const; /// Tests this object for equality with another. - virtual bool equals(const SharedObject* other) const; + /// \param sharedAncestry if true and the classes of the objects differ, compare their shared ancestry (assuming that + /// this is an instance of a superclass of the other object's class) rather than simply returning false. + virtual bool equals(const SharedObject* other, bool sharedAncestry = false) const; // Dumps the contents of this object to the debug output. virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const; private: - void setID(int id); - int _id; + int _originID; int _remoteID; + int _remoteOriginID; QAtomicInt _referenceCount; static int _lastID; From ac7d23bf54af5e5e4d4df9bd776b813cfc802263 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 2 Jun 2014 19:00:48 -0700 Subject: [PATCH 05/71] Working on support for streaming Qt enums/flags. --- libraries/metavoxels/src/Bitstream.cpp | 14 +++++++++++ libraries/metavoxels/src/Bitstream.h | 15 +++++++++++ tests/metavoxels/src/MetavoxelTests.cpp | 33 ++++++++++++++++++++++--- tests/metavoxels/src/MetavoxelTests.h | 19 +++++++++++++- 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index b3d5817fe9..f3ba1cca4d 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -1203,6 +1203,20 @@ void PropertyReader::readDelta(Bitstream& in, QObject* object, const QObject* re } } +PropertyWriter::PropertyWriter(const QMetaProperty& property, const TypeStreamer* streamer) : + _property(property), + _streamer(streamer) { +} + +void PropertyWriter::write(Bitstream& out, const QObject* object) const { + _streamer->write(out, _property.read(object)); +} + +void PropertyWriter::writeDelta(Bitstream& out, const QObject* object, const QObject* reference) const { + _streamer->writeDelta(out, _property.read(object), reference && object->metaObject() == reference->metaObject() ? + _property.read(reference) : QVariant()); +} + MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) : _name(name), _streamer(streamer) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 544d6dbd78..7e1551346a 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -804,6 +804,21 @@ private: QMetaProperty _property; }; +/// Contains the information necessary to obtain an object property and write it to the stream. +class PropertyWriter { +public: + + PropertyWriter(const QMetaProperty& property = QMetaProperty(), const TypeStreamer* streamer = NULL); + + void write(Bitstream& out, const QObject* object) const; + void writeDelta(Bitstream& out, const QObject* object, const QObject* reference) const; + +private: + + QMetaProperty _property; + const TypeStreamer* _streamer; +}; + /// Describes a metatype field. class MetaField { public: diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 2400e086eb..1b7eaf9a22 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -51,6 +51,29 @@ static QByteArray createRandomBytes() { return createRandomBytes(MIN_BYTES, MAX_BYTES); } +static TestSharedObjectA::TestEnum getRandomTestEnum() { + switch (randIntInRange(0, 2)) { + case 0: return TestSharedObjectA::FIRST_TEST_ENUM; + case 1: return TestSharedObjectA::SECOND_TEST_ENUM; + case 2: + default: return TestSharedObjectA::THIRD_TEST_ENUM; + } +} + +static TestSharedObjectA::TestFlags getRandomTestFlags() { + TestSharedObjectA::TestFlags flags = 0; + if (randomBoolean()) { + flags |= TestSharedObjectA::FIRST_TEST_FLAG; + } + if (randomBoolean()) { + flags |= TestSharedObjectA::SECOND_TEST_FLAG; + } + if (randomBoolean()) { + flags |= TestSharedObjectA::THIRD_TEST_FLAG; + } + return flags; +} + static TestMessageC createRandomMessageC() { TestMessageC message; message.foo = randomBoolean(); @@ -64,7 +87,7 @@ static bool testSerialization(Bitstream::MetadataType metadataType) { QByteArray array; QDataStream outStream(&array, QIODevice::WriteOnly); Bitstream out(outStream, metadataType); - SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat()); + SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat(), getRandomTestEnum(), getRandomTestFlags()); out << testObjectWrittenA; SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes()); out << testObjectWrittenB; @@ -175,7 +198,7 @@ bool MetavoxelTests::run() { static SharedObjectPointer createRandomSharedObject() { switch (randIntInRange(0, 2)) { - case 0: return new TestSharedObjectA(randFloat()); + case 0: return new TestSharedObjectA(randFloat(), getRandomTestEnum(), getRandomTestFlags()); case 1: return new TestSharedObjectB(); case 2: default: return SharedObjectPointer(); @@ -393,8 +416,10 @@ void Endpoint::readReliableChannel() { streamedBytesReceived += bytes.size(); } -TestSharedObjectA::TestSharedObjectA(float foo) : - _foo(foo) { +TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) : + _foo(foo), + _baz(baz), + _bong(bong) { sharedObjectsCreated++; } diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 206c818c6e..6e0b857328 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -70,16 +70,31 @@ private: /// A simple shared object. class TestSharedObjectA : public SharedObject { Q_OBJECT + Q_ENUMS(TestEnum) + Q_FLAGS(TestFlag TestFlags) Q_PROPERTY(float foo READ getFoo WRITE setFoo NOTIFY fooChanged) + Q_PROPERTY(TestEnum baz READ getBaz WRITE setBaz) + Q_PROPERTY(TestFlags bong READ getBong WRITE setBong) public: - Q_INVOKABLE TestSharedObjectA(float foo = 0.0f); + enum TestEnum { FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM }; + + enum TestFlag { NO_TEST_FLAGS = 0x0, FIRST_TEST_FLAG = 0x01, SECOND_TEST_FLAG = 0x02, THIRD_TEST_FLAG = 0x03 }; + Q_DECLARE_FLAGS(TestFlags, TestFlag) + + Q_INVOKABLE TestSharedObjectA(float foo = 0.0f, TestEnum baz = FIRST_TEST_ENUM, TestFlags bong = 0); virtual ~TestSharedObjectA(); void setFoo(float foo); float getFoo() const { return _foo; } + void setBaz(TestEnum baz) { _baz = baz; } + TestEnum getBaz() const { return _baz; } + + void setBong(TestFlags bong) { _bong = bong; } + TestFlags getBong() const { return _bong; } + signals: void fooChanged(float foo); @@ -87,6 +102,8 @@ signals: private: float _foo; + TestEnum _baz; + TestFlags _bong; }; /// Another simple shared object. From f99489c157814968ec948bf54c4e93378f0fdfaa Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 3 Jun 2014 10:40:30 -0700 Subject: [PATCH 06/71] rolling back previous change for IK instability --- interface/src/avatar/SkeletonModel.cpp | 10 +++++----- interface/src/renderer/Model.cpp | 15 ++++++++------- interface/src/renderer/Model.h | 6 +++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index de9c413017..48efbdc4dc 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -147,7 +147,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) return; } JointState& state = _jointStates[jointIndex]; - glm::quat handRotation = state.getRotationFromBindToModelFrame(); + glm::quat handRotation = state.getJointRotation(); // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; @@ -170,10 +170,10 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { JointState parentState = _jointStates[parentJointIndex]; - palmRotation = parentState.getRotationFromBindToModelFrame(); + palmRotation = parentState.getJointRotation(); } else { JointState state = _jointStates[jointIndex]; - palmRotation = state.getRotationFromBindToModelFrame(); + palmRotation = state.getJointRotation(); } palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; @@ -414,7 +414,7 @@ bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { if (geometry.neckJointIndex == -1) { return false; } - return getJointRotationFromBindToWorldFrame(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); + return getJointRotationInWorldFrame(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); } bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { @@ -433,7 +433,7 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco const float EYE_PROPORTION = 0.6f; glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION); glm::quat headRotation; - getJointRotationFromBindToWorldFrame(geometry.headJointIndex, headRotation); + getJointRotationInWorldFrame(geometry.headJointIndex, headRotation); const float EYES_FORWARD = 0.25f; const float EYE_SEPARATION = 0.1f; float headHeight = glm::distance(neckPosition, headPosition); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 11cd4678e3..e3be11c5d2 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -756,11 +756,11 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { return true; } -bool Model::getJointRotationFromBindToWorldFrame(int jointIndex, glm::quat& rotation) const { +bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _rotation * _jointStates[jointIndex].getRotationFromBindToModelFrame(); + rotation = _jointStates[jointIndex].getJointRotation(); return true; } @@ -1227,7 +1227,7 @@ void Model::simulateInternal(float deltaTime) { glm::vec3 jointTranslation = _translation; glm::quat jointRotation = _rotation; getJointPosition(attachment.jointIndex, jointTranslation); - getJointRotationFromBindToWorldFrame(attachment.jointIndex, jointRotation); + getJointRotationInWorldFrame(attachment.jointIndex, jointRotation); model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); @@ -1306,9 +1306,9 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const JointState& state = _jointStates[jointIndex]; // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = _rotation * state.getRotationFromBindToModelFrame(); + endRotation = state.getJointRotation(); state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); - endRotation = _rotation * state.getRotationFromBindToModelFrame(); + endRotation = state.getJointRotation(); } // then, we go from the joint upwards, rotating the end as close as possible to the target @@ -2067,8 +2067,9 @@ void JointState::computeTransforms(const glm::mat4& parentTransform, const glm:: _combinedRotation = baseRotation * modifiedRotation; } -glm::quat JointState::getRotationFromBindToModelFrame() const { - return _rotationInModelFrame * _fbxJoint->inverseBindRotation; +glm::quat JointState::getJointRotation() const { + assert(_fbxJoint != NULL); + return _combinedRotation * _fbxJoint->inverseBindRotation; } void JointState::restoreRotation(float fraction, float priority) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 2577953a3a..b6ae6c9012 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -52,8 +52,8 @@ public: /// computes new _transform and _combinedRotation void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); - /// \return rotation that moves a vector given in this joint's bind-frame to the model-frame - glm::quat getRotationFromBindToModelFrame() const; + /// \return rotation from the joint's default (or bind) frame to world frame + glm::quat getJointRotation() const; void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); @@ -173,7 +173,7 @@ public: int getLastFreeJointIndex(int jointIndex) const; bool getJointPosition(int jointIndex, glm::vec3& position) const; - bool getJointRotationFromBindToWorldFrame(int jointIndex, glm::quat& rotation) const; + bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; QStringList getJointNames() const; From 03bf1fe69df74167d514e62de551a572589457bf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 3 Jun 2014 14:04:09 -0700 Subject: [PATCH 07/71] Add joint manipulations in model-frame --- interface/src/avatar/SkeletonModel.cpp | 121 ++++++++++++++++++++++++- interface/src/avatar/SkeletonModel.h | 2 + interface/src/renderer/Model.cpp | 112 ++++++++++++++++++++++- interface/src/renderer/Model.h | 9 ++ 4 files changed, 238 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 48efbdc4dc..1f2f502b44 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -73,8 +73,8 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { - applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); - applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); + applyPalmDataInModelFrame(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); + applyPalmDataInModelFrame(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); } } @@ -194,13 +194,64 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { parentState.setRotation(palmRotation, PALM_PRIORITY); // slam parent-relative rotation to identity _jointStates[jointIndex]._rotation = glm::quat(); - } else { setJointPosition(jointIndex, palm.getPosition(), palmRotation, true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); } } +void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { + if (jointIndex == -1 || jointIndex >= _jointStates.size()) { + return; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; + int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; + if (parentJointIndex == -1) { + return; + } + + // rotate palm to align with its normal (normal points out of hand's palm) + glm::quat palmRotation; + glm::quat r0, r1; + if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && + Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { + JointState parentState = _jointStates[parentJointIndex]; + palmRotation = parentState.getRotationFromBindToModelFrame(); + r0 = palmRotation; + } else { + JointState state = _jointStates[jointIndex]; + palmRotation = state.getRotationFromBindToModelFrame(); + } + glm::quat inverseRotation = glm::inverse(_rotation); + glm::vec3 palmNormal = inverseRotation * palm.getNormal(); + palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palmNormal) * palmRotation; + r1 = palmRotation; + + // rotate palm to align with finger direction + glm::vec3 direction = inverseRotation * palm.getFingerDirection(); + palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; + + // set hand position, rotation + glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); + if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { + setHandPositionInModelFrame(jointIndex, palmPosition, palmRotation); + + } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { + glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); + setJointPositionInModelFrame(parentJointIndex, palmPosition + forearmVector * + geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), + glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + JointState& parentState = _jointStates[parentJointIndex]; + parentState.setRotationInModelFrame(palmRotation, PALM_PRIORITY); + // slam parent-relative rotation to identity + _jointStates[jointIndex]._rotation = glm::quat(); + } else { + setJointPositionInModelFrame(jointIndex, palmPosition, palmRotation, + true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + } +} + void SkeletonModel::updateJointState(int index) { JointState& state = _jointStates[index]; const FBXJoint& joint = state.getFBXJoint(); @@ -365,6 +416,70 @@ void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, c JointState& handState = _jointStates[jointIndex]; handState.setRotation(rotation, PALM_PRIORITY); } + +void SkeletonModel::setHandPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation) { + // this algorithm is from sample code from sixense + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + int elbowJointIndex = geometry.joints.at(jointIndex).parentIndex; + if (elbowJointIndex == -1) { + return; + } + int shoulderJointIndex = geometry.joints.at(elbowJointIndex).parentIndex; + glm::vec3 shoulderPosition; + if (!getJointPositionInModelFrame(shoulderJointIndex, shoulderPosition)) { + return; + } + // precomputed lengths + float scale = extractUniformScale(_scale); + float upperArmLength = geometry.joints.at(elbowJointIndex).distanceToParent * scale; + float lowerArmLength = geometry.joints.at(jointIndex).distanceToParent * scale; + + // first set wrist position + glm::vec3 wristPosition = position; + + glm::vec3 shoulderToWrist = wristPosition - shoulderPosition; + float distanceToWrist = glm::length(shoulderToWrist); + + // prevent gimbal lock + if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) { + distanceToWrist = upperArmLength + lowerArmLength - EPSILON; + shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist; + wristPosition = shoulderPosition + shoulderToWrist; + } + + // cosine of angle from upper arm to hand vector + float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) / + (2 * upperArmLength * distanceToWrist); + float mid = upperArmLength * cosA; + float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA); + + // direction of the elbow + glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist + glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down + const float NORMAL_WEIGHT = 0.5f; + glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT); + + bool rightHand = (jointIndex == geometry.rightHandJointIndex); + if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) { + finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis) + } + + glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal)); + + // ik solution + glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height; + glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f); + glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); + + JointState& shoulderState = _jointStates[shoulderJointIndex]; + shoulderState.setRotationInModelFrame(shoulderRotation, PALM_PRIORITY); + + JointState& elbowState = _jointStates[elbowJointIndex]; + elbowState.setRotationInModelFrame(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); + + JointState& handState = _jointStates[jointIndex]; + handState.setRotationInModelFrame(rotation, PALM_PRIORITY); +} bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { return getJointPosition(getLeftHandJointIndex(), position); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 91070e4ad6..183ba899b8 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -94,6 +94,7 @@ protected: void applyHandPosition(int jointIndex, const glm::vec3& position); void applyPalmData(int jointIndex, PalmData& palm); + void applyPalmDataInModelFrame(int jointIndex, PalmData& palm); /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); @@ -106,6 +107,7 @@ private: void renderJointConstraints(int jointIndex); void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation); + void setHandPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation); Avatar* _owningAvatar; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index e3be11c5d2..2616ded481 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -756,6 +756,14 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { return true; } +bool Model::getJointPositionInModelFrame(int jointIndex, glm::vec3& position) const { + if (jointIndex == -1 || jointIndex >= _jointStates.size()) { + return false; + } + position = extractTranslation(_jointStates[jointIndex].getTransformInModelFrame()); + return true; +} + bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; @@ -1369,6 +1377,94 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const return true; } +bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, + int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { + if (jointIndex == -1 || _jointStates.isEmpty()) { + return false; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; + if (freeLineage.isEmpty()) { + return false; + } + if (lastFreeIndex == -1) { + lastFreeIndex = freeLineage.last(); + } + + // this is a cyclic coordinate descent algorithm: see + // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d + const int ITERATION_COUNT = 1; + glm::vec3 worldAlignment = alignment; + for (int i = 0; i < ITERATION_COUNT; i++) { + // first, try to rotate the end effector as close as possible to the target rotation, if any + glm::quat endRotation; + if (useRotation) { + JointState& state = _jointStates[jointIndex]; + + // TODO: figure out what this is trying to do and combine it into one JointState method + endRotation = state.getJointRotation(); + state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); + endRotation = state.getJointRotation(); + } + + // then, we go from the joint upwards, rotating the end as close as possible to the target + glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].getTransformInModelFrame()); + for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { + int index = freeLineage.at(j); + JointState& state = _jointStates[index]; + const FBXJoint& joint = state.getFBXJoint(); + if (!(joint.isFree || allIntermediatesFree)) { + continue; + } + glm::vec3 jointPosition = extractTranslation(state.getTransformInModelFrame()); + glm::vec3 jointVector = endPosition - jointPosition; + glm::quat oldCombinedRotation = state.getRotationInModelFrame(); + glm::quat combinedDelta; + float combinedWeight; + if (useRotation) { + combinedDelta = safeMix(rotation * glm::inverse(endRotation), + rotationBetween(jointVector, position - jointPosition), 0.5f); + combinedWeight = 2.0f; + + } else { + combinedDelta = rotationBetween(jointVector, position - jointPosition); + combinedWeight = 1.0f; + } + if (alignment != glm::vec3() && j > 1) { + jointVector = endPosition - jointPosition; + glm::vec3 positionSum; + for (int k = j - 1; k > 0; k--) { + int index = freeLineage.at(k); + updateJointState(index); + positionSum += extractTranslation(_jointStates.at(index).getTransformInModelFrame()); + } + glm::vec3 projectedCenterOfMass = glm::cross(jointVector, + glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); + glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); + const float LENGTH_EPSILON = 0.001f; + if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { + combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), + 1.0f / (combinedWeight + 1.0f)); + } + } + state.applyRotationDeltaInModelFrame(combinedDelta, true, priority); + glm::quat actualDelta = state.getRotationInModelFrame() * glm::inverse(oldCombinedRotation); + endPosition = actualDelta * jointVector + jointPosition; + if (useRotation) { + endRotation = actualDelta * endRotation; + } + } + } + + // now update the joint states from the top + for (int j = freeLineage.size() - 1; j >= 0; j--) { + updateJointState(freeLineage.at(j)); + } + _shapesAreDirty = true; + + return true; +} + bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; @@ -2072,6 +2168,10 @@ glm::quat JointState::getJointRotation() const { return _combinedRotation * _fbxJoint->inverseBindRotation; } +glm::quat JointState::getRotationFromBindToModelFrame() const { + return _rotationInModelFrame * _fbxJoint->inverseBindRotation; +} + void JointState::restoreRotation(float fraction, float priority) { assert(_fbxJoint != NULL); if (priority == _animationPriority) { @@ -2088,6 +2188,14 @@ void JointState::setRotation(const glm::quat& rotation, float priority) { } } +void JointState::setRotationInModelFrame(const glm::quat& rotation, float priority) { + assert(_fbxJoint != NULL); + if (priority >= _animationPriority) { + _rotation = _rotation * glm::inverse(_rotationInModelFrame) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); + _animationPriority = priority; + } +} + void JointState::clearTransformTranslation() { _transform[3][0] = 0.0f; _transform[3][1] = 0.0f; @@ -2117,8 +2225,7 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa _rotation = newRotation; } -/* -void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { +void JointState::applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain, float priority) { assert(_fbxJoint != NULL); if (priority < _animationPriority) { return; @@ -2137,7 +2244,6 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa _rotationInModelFrame = _rotationInModelFrame * glm::inverse(_rotation) * newRotation; _rotation = newRotation; } -*/ const glm::vec3& JointState::getDefaultTranslationInParentFrame() const { assert(_fbxJoint != NULL); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b6ae6c9012..37f0ffbc60 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -54,8 +54,10 @@ public: /// \return rotation from the joint's default (or bind) frame to world frame glm::quat getJointRotation() const; + glm::quat getRotationFromBindToModelFrame() const; void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); + void applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain = true, float priority = 1.0f); const glm::vec3& getDefaultTranslationInParentFrame() const; @@ -65,6 +67,7 @@ public: /// computes parent relative _rotation and sets that /// \warning no combined transforms are updated! void setRotation(const glm::quat& rotation, float priority); + void setRotationInModelFrame(const glm::quat& rotation, float priority); const glm::mat4& getHybridTransform() const { return _transform; } //const glm::quat& getRotationInWorldFrame() const { return _combinedRotation; } @@ -176,6 +179,8 @@ public: bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; + bool getJointPositionInModelFrame(int jointIndex, glm::vec3& position) const; + QStringList getJointNames() const; AnimationHandlePointer createAnimationHandle(); @@ -266,6 +271,10 @@ protected: bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); + + bool setJointPositionInModelFrame(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), + bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, + const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); /// Restores the indexed joint to its default position. /// \param fraction the fraction of the default position to apply (i.e., 0.25f to slerp one fourth of the way to From 05af9932621fc604a79a6840055d1a91bd97e049 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 3 Jun 2014 14:24:04 -0700 Subject: [PATCH 08/71] Add more model-frame methods --- interface/src/avatar/SkeletonModel.cpp | 26 +++++++++++++++++++++++++- interface/src/avatar/SkeletonModel.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 1f2f502b44..8a3082d89a 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -63,7 +63,8 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { if (_owningAvatar->getHandState() == HAND_STATE_NULL) { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { - applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); + glm::vec3 handPosition = glm::inverse(_rotation) * (_owningAvatar->getHandPosition() - _translation); + applyHandPositionInModelFrame(geometry.rightHandJointIndex, handPosition); } restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); @@ -154,6 +155,29 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) state.applyRotationDelta(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); } +void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec3& position) { + if (jointIndex == -1 || jointIndex >= _jointStates.size()) { + return; + } + setJointPositionInModelFrame(jointIndex, position, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + glm::vec3 handPosition, elbowPosition; + getJointPositionInModelFrame(jointIndex, handPosition); + getJointPositionInModelFrame(geometry.joints.at(jointIndex).parentIndex, elbowPosition); + glm::vec3 forearmVector = handPosition - elbowPosition; + float forearmLength = glm::length(forearmVector); + if (forearmLength < EPSILON) { + return; + } + JointState& state = _jointStates[jointIndex]; + glm::quat handRotation = state.getRotationInModelFrame(); + + // align hand with forearm + float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; + state.applyRotationDeltaInModelFrame(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); +} + void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 183ba899b8..5447027d96 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -92,6 +92,7 @@ public: protected: void applyHandPosition(int jointIndex, const glm::vec3& position); + void applyHandPositionInModelFrame(int jointIndex, const glm::vec3& position); void applyPalmData(int jointIndex, PalmData& palm); void applyPalmDataInModelFrame(int jointIndex, PalmData& palm); From e7f32c211bfb3ea802cc13c2673d886ab50852e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 3 Jun 2014 14:48:57 -0700 Subject: [PATCH 09/71] remove world-frame hand/palm set methods --- interface/src/avatar/SkeletonModel.cpp | 135 +------------------------ interface/src/avatar/SkeletonModel.h | 3 - interface/src/renderer/Model.cpp | 94 +---------------- interface/src/renderer/Model.h | 5 +- 4 files changed, 5 insertions(+), 232 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8a3082d89a..4c2c80d11a 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -70,7 +70,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { } else if (leftPalmIndex == rightPalmIndex) { // right hand only - applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); + applyPalmDataInModelFrame(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { @@ -132,29 +132,6 @@ bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) { return firstIndex.value < secondIndex.value; } -void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) { - if (jointIndex == -1 || jointIndex >= _jointStates.size()) { - return; - } - setJointPosition(jointIndex, position, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); - - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::vec3 handPosition, elbowPosition; - getJointPosition(jointIndex, handPosition); - getJointPosition(geometry.joints.at(jointIndex).parentIndex, elbowPosition); - glm::vec3 forearmVector = handPosition - elbowPosition; - float forearmLength = glm::length(forearmVector); - if (forearmLength < EPSILON) { - return; - } - JointState& state = _jointStates[jointIndex]; - glm::quat handRotation = state.getJointRotation(); - - // align hand with forearm - float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - state.applyRotationDelta(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); -} - void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec3& position) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; @@ -178,52 +155,6 @@ void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec state.applyRotationDeltaInModelFrame(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); } -void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { - if (jointIndex == -1 || jointIndex >= _jointStates.size()) { - return; - } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; - if (parentJointIndex == -1) { - return; - } - - // rotate palm to align with its normal (normal points out of hand's palm) - glm::quat palmRotation; - if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && - Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { - JointState parentState = _jointStates[parentJointIndex]; - palmRotation = parentState.getJointRotation(); - } else { - JointState state = _jointStates[jointIndex]; - palmRotation = state.getJointRotation(); - } - palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; - - // rotate palm to align with finger direction - glm::vec3 direction = palm.getFingerDirection(); - palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; - - // set hand position, rotation - if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { - setHandPosition(jointIndex, palm.getPosition(), palmRotation); - - } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { - glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), - glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); - JointState& parentState = _jointStates[parentJointIndex]; - parentState.setRotation(palmRotation, PALM_PRIORITY); - // slam parent-relative rotation to identity - _jointStates[jointIndex]._rotation = glm::quat(); - } else { - setJointPosition(jointIndex, palm.getPosition(), palmRotation, - true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); - } -} - void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; @@ -377,70 +308,6 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { glLineWidth(1.0f); } -void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation) { - // this algorithm is from sample code from sixense - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - int elbowJointIndex = geometry.joints.at(jointIndex).parentIndex; - if (elbowJointIndex == -1) { - return; - } - int shoulderJointIndex = geometry.joints.at(elbowJointIndex).parentIndex; - glm::vec3 shoulderPosition; - if (!getJointPosition(shoulderJointIndex, shoulderPosition)) { - return; - } - // precomputed lengths - float scale = extractUniformScale(_scale); - float upperArmLength = geometry.joints.at(elbowJointIndex).distanceToParent * scale; - float lowerArmLength = geometry.joints.at(jointIndex).distanceToParent * scale; - - // first set wrist position - glm::vec3 wristPosition = position; - - glm::vec3 shoulderToWrist = wristPosition - shoulderPosition; - float distanceToWrist = glm::length(shoulderToWrist); - - // prevent gimbal lock - if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) { - distanceToWrist = upperArmLength + lowerArmLength - EPSILON; - shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist; - wristPosition = shoulderPosition + shoulderToWrist; - } - - // cosine of angle from upper arm to hand vector - float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) / - (2 * upperArmLength * distanceToWrist); - float mid = upperArmLength * cosA; - float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA); - - // direction of the elbow - glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist - glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down - const float NORMAL_WEIGHT = 0.5f; - glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT); - - bool rightHand = (jointIndex == geometry.rightHandJointIndex); - if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) { - finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis) - } - - glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal)); - - // ik solution - glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height; - glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f); - glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); - - JointState& shoulderState = _jointStates[shoulderJointIndex]; - shoulderState.setRotation(shoulderRotation, PALM_PRIORITY); - - JointState& elbowState = _jointStates[elbowJointIndex]; - elbowState.setRotation(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); - - JointState& handState = _jointStates[jointIndex]; - handState.setRotation(rotation, PALM_PRIORITY); -} - void SkeletonModel::setHandPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation) { // this algorithm is from sample code from sixense const FBXGeometry& geometry = _geometry->getFBXGeometry(); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 5447027d96..092722fd40 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -91,10 +91,8 @@ public: protected: - void applyHandPosition(int jointIndex, const glm::vec3& position); void applyHandPositionInModelFrame(int jointIndex, const glm::vec3& position); - void applyPalmData(int jointIndex, PalmData& palm); void applyPalmDataInModelFrame(int jointIndex, PalmData& palm); /// Updates the state of the joint at the specified index. @@ -107,7 +105,6 @@ protected: private: void renderJointConstraints(int jointIndex); - void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation); void setHandPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation); Avatar* _owningAvatar; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 2616ded481..65c9f1e691 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1288,95 +1288,6 @@ void Model::updateJointState(int index) { } } -bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation, bool useRotation, - int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { - if (jointIndex == -1 || _jointStates.isEmpty()) { - return false; - } - glm::vec3 relativePosition = translation - _translation; - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; - if (freeLineage.isEmpty()) { - return false; - } - if (lastFreeIndex == -1) { - lastFreeIndex = freeLineage.last(); - } - - // this is a cyclic coordinate descent algorithm: see - // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d - const int ITERATION_COUNT = 1; - glm::vec3 worldAlignment = _rotation * alignment; - for (int i = 0; i < ITERATION_COUNT; i++) { - // first, try to rotate the end effector as close as possible to the target rotation, if any - glm::quat endRotation; - if (useRotation) { - JointState& state = _jointStates[jointIndex]; - - // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = state.getJointRotation(); - state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); - endRotation = state.getJointRotation(); - } - - // then, we go from the joint upwards, rotating the end as close as possible to the target - glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].getHybridTransform()); - for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { - int index = freeLineage.at(j); - JointState& state = _jointStates[index]; - const FBXJoint& joint = state.getFBXJoint(); - if (!(joint.isFree || allIntermediatesFree)) { - continue; - } - glm::vec3 jointPosition = extractTranslation(state.getHybridTransform()); - glm::vec3 jointVector = endPosition - jointPosition; - glm::quat oldCombinedRotation = _rotation * state.getRotationInModelFrame(); - glm::quat combinedDelta; - float combinedWeight; - if (useRotation) { - combinedDelta = safeMix(rotation * glm::inverse(endRotation), - rotationBetween(jointVector, relativePosition - jointPosition), 0.5f); - combinedWeight = 2.0f; - - } else { - combinedDelta = rotationBetween(jointVector, relativePosition - jointPosition); - combinedWeight = 1.0f; - } - if (alignment != glm::vec3() && j > 1) { - jointVector = endPosition - jointPosition; - glm::vec3 positionSum; - for (int k = j - 1; k > 0; k--) { - int index = freeLineage.at(k); - updateJointState(index); - positionSum += extractTranslation(_jointStates.at(index).getHybridTransform()); - } - glm::vec3 projectedCenterOfMass = glm::cross(jointVector, - glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); - glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); - const float LENGTH_EPSILON = 0.001f; - if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { - combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), - 1.0f / (combinedWeight + 1.0f)); - } - } - state.applyRotationDelta(combinedDelta, true, priority); - glm::quat actualDelta = _rotation * state.getRotationInModelFrame() * glm::inverse(oldCombinedRotation); - endPosition = actualDelta * jointVector + jointPosition; - if (useRotation) { - endRotation = actualDelta * endRotation; - } - } - } - - // now update the joint states from the top - for (int j = freeLineage.size() - 1; j >= 0; j--) { - updateJointState(freeLineage.at(j)); - } - _shapesAreDirty = true; - - return true; -} - bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { @@ -1614,9 +1525,10 @@ void Model::applyCollision(CollisionInfo& collision) { axis = glm::normalize(axis); glm::vec3 end; getJointPosition(jointIndex, end); - glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start); + // transform into model-frame + glm::vec3 newEnd = glm::inverse(_rotation) * (start + glm::angleAxis(angle, axis) * (end - start) - _translation); // try to move it - setJointPosition(jointIndex, newEnd, glm::quat(), false, -1, true); + setJointPositionInModelFrame(jointIndex, newEnd, glm::quat(), false, -1, true); } } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 37f0ffbc60..31d59d7c3e 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -176,6 +176,7 @@ public: int getLastFreeJointIndex(int jointIndex) const; bool getJointPosition(int jointIndex, glm::vec3& position) const; + bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; @@ -268,10 +269,6 @@ protected: /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); - bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), - bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, - const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); - bool setJointPositionInModelFrame(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); From 7f46e9d514931310bef6a18b850caba80a5ba5d5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 3 Jun 2014 15:42:38 -0700 Subject: [PATCH 10/71] remove JointState::getJointRotation() (use getRotationModelFrame() instead) --- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/renderer/Model.cpp | 13 ++++--------- interface/src/renderer/Model.h | 3 +-- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 4c2c80d11a..8b229590fd 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -199,7 +199,7 @@ void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; parentState.setRotationInModelFrame(palmRotation, PALM_PRIORITY); - // slam parent-relative rotation to identity + // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex]._rotation = glm::quat(); } else { setJointPositionInModelFrame(jointIndex, palmPosition, palmRotation, diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 65c9f1e691..626b66ed99 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -768,7 +768,7 @@ bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) co if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _jointStates[jointIndex].getJointRotation(); + rotation = _rotation * _jointStates[jointIndex].getRotationInModelFrame(); return true; } @@ -1313,9 +1313,9 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi JointState& state = _jointStates[jointIndex]; // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = state.getJointRotation(); - state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); - endRotation = state.getJointRotation(); + endRotation = state.getRotationInModelFrame(); + state.applyRotationDeltaInModelFrame(rotation * glm::inverse(endRotation), true, priority); + endRotation = state.getRotationInModelFrame(); } // then, we go from the joint upwards, rotating the end as close as possible to the target @@ -2075,11 +2075,6 @@ void JointState::computeTransforms(const glm::mat4& parentTransform, const glm:: _combinedRotation = baseRotation * modifiedRotation; } -glm::quat JointState::getJointRotation() const { - assert(_fbxJoint != NULL); - return _combinedRotation * _fbxJoint->inverseBindRotation; -} - glm::quat JointState::getRotationFromBindToModelFrame() const { return _rotationInModelFrame * _fbxJoint->inverseBindRotation; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 31d59d7c3e..7e4f60816b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -52,8 +52,7 @@ public: /// computes new _transform and _combinedRotation void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); - /// \return rotation from the joint's default (or bind) frame to world frame - glm::quat getJointRotation() const; + /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); From a1afcfd42c7cceff3741780cb7eedbb95bb3bc3f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 3 Jun 2014 15:57:16 -0700 Subject: [PATCH 11/71] remove JointState::applyRotationDelta() (use JointState::applyRotationDeltaInModelFrame()) instead) --- interface/src/renderer/Model.cpp | 20 -------------------- interface/src/renderer/Model.h | 1 - 2 files changed, 21 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 626b66ed99..a345a32707 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -2112,26 +2112,6 @@ void JointState::clearTransformTranslation() { _transformInModelFrame[3][2] = 0.0f; } -void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { - assert(_fbxJoint != NULL); - if (priority < _animationPriority) { - return; - } - _animationPriority = priority; - if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && - _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { - // no constraints - _rotation = _rotation * glm::inverse(_combinedRotation) * delta * _combinedRotation; - _combinedRotation = delta * _combinedRotation; - return; - } - glm::quat targetRotation = delta * _combinedRotation; - glm::vec3 eulers = safeEulerAngles(_rotation * glm::inverse(_combinedRotation) * targetRotation); - glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax)); - _combinedRotation = _combinedRotation * glm::inverse(_rotation) * newRotation; - _rotation = newRotation; -} - void JointState::applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain, float priority) { assert(_fbxJoint != NULL); if (priority < _animationPriority) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 7e4f60816b..eb5b4cd7c8 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -55,7 +55,6 @@ public: /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; - void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); void applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain = true, float priority = 1.0f); const glm::vec3& getDefaultTranslationInParentFrame() const; From c851edd0efbf003e844309960b7e6f6513bdf673 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 3 Jun 2014 16:18:40 -0700 Subject: [PATCH 12/71] added MovingMedian class, but not using it added packet type/time data collection to DatagramProcessor and post-execution prints of that info. --- libraries/networking/src/Node.cpp | 11 +++- libraries/networking/src/Node.h | 6 +- libraries/networking/src/NodeList.cpp | 18 ++++-- libraries/shared/src/MovingMedian.cpp | 87 +++++++++++++++++++++++++++ libraries/shared/src/MovingMedian.h | 26 ++++++++ 5 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 libraries/shared/src/MovingMedian.cpp create mode 100644 libraries/shared/src/MovingMedian.h diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 05f425374b..9c482b9d58 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -57,7 +57,9 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, _linkedData(NULL), _isAlive(true), _clockSkewUsec(0), - _mutex() + _mutex(), + + _clockSkewMovingMedian(31) { } @@ -133,6 +135,13 @@ float Node::getAverageKilobitsPerSecond() { } } +void Node::setClockSkewUsec(int clockSkew) { + //_clockSkewMovingMedian.updateMedian((float)clockSkew); + //_clockSkewUsec = (int)_clockSkewMovingMedian.getMedian(); + +_clockSkewUsec = clockSkew; +} + QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._type; out << node._uuid; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index f52cda0d0d..7a8fcad0bb 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -24,6 +24,8 @@ #include "NodeData.h" #include "SimpleMovingAverage.h" +#include "MovingMedian.h" + typedef quint8 NodeType_t; namespace NodeType { @@ -94,7 +96,7 @@ public: void setPingMs(int pingMs) { _pingMs = pingMs; } int getClockSkewUsec() const { return _clockSkewUsec; } - void setClockSkewUsec(int clockSkew) { _clockSkewUsec = clockSkew; } + void setClockSkewUsec(int clockSkew); QMutex& getMutex() { return _mutex; } friend QDataStream& operator<<(QDataStream& out, const Node& node); @@ -120,6 +122,8 @@ private: int _pingMs; int _clockSkewUsec; QMutex _mutex; + + MovingMedian _clockSkewMovingMedian; }; QDebug operator<<(QDebug debug, const Node &message); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index ebd33ef132..f91ee3df28 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -77,7 +77,7 @@ qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) { return writeUnverifiedDatagram(statsPacket, _domainHandler.getSockAddr()); } -void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { +int NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); @@ -97,7 +97,10 @@ void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode->setPingMs(pingTime / 1000); sendingNode->setClockSkewUsec(clockSkew); - + +//printf("\t\t clock skew sample: %d median: %d\n", clockSkew, sendingNode->getClockSkewUsec()); + + const bool wantDebug = false; if (wantDebug) { @@ -110,9 +113,14 @@ void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& " othersExprectedReply: " << othersExprectedReply << "\n" << " clockSkew: " << clockSkew; } + + if (abs(clockSkew) > 1000) + printf("clockskew = %d \n", clockSkew); + +return clockSkew; } -void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) { +int NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) { switch (packetTypeForPacket(packet)) { case PacketTypeDomainList: { processDomainServerList(packet); @@ -152,7 +160,8 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr activateSocketFromNodeCommunication(packet, sendingNode); // set the ping time for this node for stat collection - timePingReply(packet, sendingNode); + return timePingReply(packet, sendingNode); + } break; @@ -167,6 +176,7 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr LimitedNodeList::processNodeData(senderSockAddr, packet); break; } +return 1234567890; } void NodeList::reset() { diff --git a/libraries/shared/src/MovingMedian.cpp b/libraries/shared/src/MovingMedian.cpp new file mode 100644 index 0000000000..f3cd4cbd16 --- /dev/null +++ b/libraries/shared/src/MovingMedian.cpp @@ -0,0 +1,87 @@ +#include "MovingMedian.h" +//#include "stdio.h"// DEBUG + +MovingMedian::MovingMedian(int numSamples) + : _numSamples(numSamples), + _numExistingSamples(0), + _median(0.0f) +{ + _samplesSorted = new float[numSamples]; + _sampleAges = new int[numSamples]; +} + +MovingMedian::~MovingMedian() { + delete[] _samplesSorted; + delete[] _sampleAges; +} + +void MovingMedian::updateMedian(float sample) { + +//printf("\nnew sample: %2.2f ", sample); + + // find index in _samplesSorted to insert new sample. + // if samples have not been filled yet, this will be the next empty spot + // otherwise, it will be the spot of the oldest sample + int newSampleIndex; + if (_numExistingSamples < _numSamples) { + newSampleIndex = _numExistingSamples; + _numExistingSamples++; + } + else { + for (int i = 0; i < _numExistingSamples; i++) { + if (_sampleAges[i] == _numExistingSamples - 1) { + newSampleIndex = i; + break; + } + } + } + +//printf("will be inserted at index %d\n", newSampleIndex); + + // update _sampleAges to reflect new sample (age all samples by 1) + for (int i = 0; i < _numExistingSamples; i++) { + _sampleAges[i]++; + } + + // insert new sample at that index + _samplesSorted[newSampleIndex] = sample; + _sampleAges[newSampleIndex] = 0; + + // swap new sample with neighboring elements in _samplesSorted until it's in sorted order + // try swapping up first, then down. element will only be swapped one direction. + + float neighborSample; + while (newSampleIndex < _numExistingSamples-1 && sample > (neighborSample = _samplesSorted[newSampleIndex+1])) { +//printf("\t swapping up...\n"); + _samplesSorted[newSampleIndex] = neighborSample; + _samplesSorted[newSampleIndex+1] = sample; + + _sampleAges[newSampleIndex] = _sampleAges[newSampleIndex+1]; + _sampleAges[newSampleIndex+1] = 0; + + newSampleIndex++; + } + while (newSampleIndex > 0 && sample < (neighborSample = _samplesSorted[newSampleIndex - 1])) { +//printf("\t swapping down...\n"); + _samplesSorted[newSampleIndex] = neighborSample; + _samplesSorted[newSampleIndex - 1] = sample; + + _sampleAges[newSampleIndex] = _sampleAges[newSampleIndex - 1]; + _sampleAges[newSampleIndex - 1] = 0; + + newSampleIndex--; + } + + + // find new median + _median = _samplesSorted[_numExistingSamples/2]; +/* +printf(" new median: %f\n", _median); + +// debug: +for (int i = 0; i < _numExistingSamples; i++) { + printf("%2.2f (%d), ", _samplesSorted[i], _sampleAges[i]); +} +printf("\n\n"); +*/ +} \ No newline at end of file diff --git a/libraries/shared/src/MovingMedian.h b/libraries/shared/src/MovingMedian.h new file mode 100644 index 0000000000..813fd42235 --- /dev/null +++ b/libraries/shared/src/MovingMedian.h @@ -0,0 +1,26 @@ + +#ifndef hifi_MovingMedian_h +#define hifi_MovingMedian_h + + +class MovingMedian { + +public: + MovingMedian(int numSamples = 11); + ~MovingMedian(); + + void updateMedian(float sample); + float getMedian() const { return _median; } + + +private: + float* _samplesSorted; + int _numSamples; + + int* _sampleAges; // _sampleAges[i] is the "age" of the sample _sampleSorted[i] (higher means older) + int _numExistingSamples; + + float _median; +}; + +#endif \ No newline at end of file From 50746a65402b3cec60f191eb0318c96961ed53a1 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 3 Jun 2014 16:19:12 -0700 Subject: [PATCH 13/71] extra commit of previous commit? --- .../src/octree/OctreeSendThread.cpp | 2 +- interface/src/DatagramProcessor.cpp | 112 +++++++++++++++++- interface/src/DatagramProcessor.h | 26 ++++ interface/src/main.cpp | 23 ++++ libraries/networking/src/NodeList.h | 4 +- 5 files changed, 162 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 9e4dbcd347..f5f9a90339 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -149,7 +149,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes int piggyBackSize = nodeData->getPacketLength() + statsMessageLength; // If the size of the stats message and the voxel message will fit in a packet, then piggyback them - if (piggyBackSize < MAX_PACKET_SIZE) { +if (false && piggyBackSize < MAX_PACKET_SIZE) { // copy voxel message to back of stats message memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 56078c1a8d..47836638dd 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -25,7 +25,39 @@ DatagramProcessor::DatagramProcessor(QObject* parent) : } + +// DEBUG + +int DatagramProcessor::skewsI[10000]; +int DatagramProcessor::S = 0; + +unsigned char DatagramProcessor::typesI[10000]; +int DatagramProcessor::diffsI[10000]; +int DatagramProcessor::I = 0; + + + +quint64 DatagramProcessor::prevTime = 0; + +unsigned char DatagramProcessor::typesA[100]; +quint64 DatagramProcessor::timesA[100]; +int DatagramProcessor::A = 1; + +unsigned char DatagramProcessor::typesB[100]; +quint64 DatagramProcessor::timesB[100]; +int DatagramProcessor::B = 1; + +unsigned char* DatagramProcessor::currTypes = typesA; +unsigned char* DatagramProcessor::prevTypes = typesB; +quint64* DatagramProcessor::currTimes = timesA; +quint64* DatagramProcessor::prevTimes = timesB; +int* DatagramProcessor::currN = &A; +int* DatagramProcessor::prevN = &B; + + + void DatagramProcessor::processDatagrams() { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "DatagramProcessor::processDatagrams()"); @@ -35,6 +67,30 @@ void DatagramProcessor::processDatagrams() { Application* application = Application::getInstance(); NodeList* nodeList = NodeList::getInstance(); + + + +prevTime = prevTimes[*prevN-1]; + +// swap +unsigned char* temp = currTypes; +currTypes = prevTypes; +prevTypes = temp; +// swap +quint64* temp2 = currTimes; +currTimes = prevTimes; +prevTimes = temp2; +// swap +int* temp3 = currN; +currN = prevN; +prevN = temp3; + +// reset +*currN = 0; + +int skew = 0; + + while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) { incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); @@ -45,8 +101,15 @@ void DatagramProcessor::processDatagrams() { _byteCount += incomingPacket.size(); if (nodeList->packetVersionAndHashMatch(incomingPacket)) { + +PacketType type = packetTypeForPacket(incomingPacket); +currTimes[*currN] = usecTimestampNow(); +currTypes[*currN] = (unsigned char)type; +(*currN)++; + + // only process this packet if we have a match on the packet version - switch (packetTypeForPacket(incomingPacket)) { + switch (type) { //packetTypeForPacket(incomingPacket)) { case PacketTypeMixedAudio: QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection, Q_ARG(QByteArray, incomingPacket)); @@ -146,9 +209,54 @@ void DatagramProcessor::processDatagrams() { break; } default: - nodeList->processNodeData(senderSockAddr, incomingPacket); + int s = nodeList->processNodeData(senderSockAddr, incomingPacket); + if (s!=1234567890) + skew = s; break; } } } + + if (abs(skew) > 1000) { + + printf("large skew! %d ----------------------------\n", skew); + + skewsI[S++] = skew; + + /* + printf("prev:::::::::::::::::::::::::::::::::::::\n"); + + printf("\t type: %d time: %llu diff: %llu\n", prevTypes[0], prevTimes[0] % 100000000, prevTimes[0] - prevTime); + for (int i = 1; i < *prevN; i++) { + printf("\t type: %d time: %llu diff: %llu\n", prevTypes[i], prevTimes[i] % 100000000, prevTimes[i] - prevTimes[i - 1]); + } + + printf("curr:::::::::::::::::::::::::::::::::::::\n"); + + printf("\t type: %d time: %llu diff: %llu\n", currTypes[0], currTimes[0] % 100000000, currTimes[0] - prevTimes[*prevN - 1]); + for (int i = 1; i < *currN; i++) { + printf("\t type: %d time: %llu diff: %llu\n", currTypes[i], currTimes[i] % 100000000, currTimes[i] - currTimes[i - 1]); + }*/ + + diffsI[I++] = -2; // prev marker + + typesI[I] = prevTypes[0]; + diffsI[I++] = prevTimes[0] - prevTime; + for (int i = 1; i < *prevN; i++) { + typesI[I] = prevTypes[i]; + diffsI[I++] = prevTimes[i] - prevTimes[i - 1]; + } + + + diffsI[I++] = -1; // curr marker + + typesI[I] = currTypes[0]; + diffsI[I++] = currTimes[0] - prevTimes[*prevN - 1]; + for (int i = 1; i < *currN; i++) { + typesI[I] = currTypes[i]; + diffsI[I++] = currTimes[i] - currTimes[i - 1]; + } + } + + skew = 0; } diff --git a/interface/src/DatagramProcessor.h b/interface/src/DatagramProcessor.h index 7d337ec02b..245b2235b4 100644 --- a/interface/src/DatagramProcessor.h +++ b/interface/src/DatagramProcessor.h @@ -29,6 +29,32 @@ public slots: private: int _packetCount; int _byteCount; + +public: + // DEBUG + + static int skewsI[]; + static int S; + + static unsigned char typesI[]; + static int diffsI[]; + static int I; + + + static quint64 prevTime; + + static unsigned char typesA[]; + static quint64 timesA[]; + static int A; + + static unsigned char typesB[]; + static quint64 timesB[]; + static int B; + + + static unsigned char* currTypes, *prevTypes; + static quint64* currTimes, *prevTimes; + static int* currN, *prevN; }; #endif // hifi_DatagramProcessor_h diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 2bb0633f24..59e0b0b3dd 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -15,6 +15,9 @@ #include #include +// DEBUG!!!!!! +#include "DatagramProcessor.h" + int main(int argc, const char * argv[]) { QElapsedTimer startupTime; startupTime.start(); @@ -43,5 +46,25 @@ int main(int argc, const char * argv[]) { exitCode = app.exec(); } qDebug("Normal exit."); + +int s = 0; +for (int i = 0; i < DatagramProcessor::I; i++) { + + switch (DatagramProcessor::diffsI[i]) { + case -2: + printf("\nskew: %d\n", DatagramProcessor::skewsI[s++]); + printf("prev:::::::::::::::::::::::::::::::\n"); + break; + case -1: + printf("curr:::::::::::::::::::::::::::::::\n"); + break; + default: + printf("\t type: %d diff: %d\n", DatagramProcessor::typesI[i], DatagramProcessor::diffsI[i]); + break; + } +} + + + return exitCode; } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index af0bfeb368..8609dce589 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -63,7 +63,7 @@ public: void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes); void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); } - void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet); +int processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet); int processDomainServerList(const QByteArray& packet); @@ -95,7 +95,7 @@ private: void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); - void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); +int timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); NodeType_t _ownerType; NodeSet _nodeTypesOfInterest; From f7cd4d78ad35293c93a322946637ab7807c39feb Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Jun 2014 17:02:52 -0700 Subject: [PATCH 14/71] Fix crazylegs.js to newer joint names --- examples/crazylegs.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/crazylegs.js b/examples/crazylegs.js index b0f8e937bc..7a6fb68520 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -20,21 +20,21 @@ var jointMappings = "\n# Joint list start"; for (var i = 0; i < jointList.length; i++) { jointMappings = jointMappings + "\njointIndex = " + jointList[i] + " = " + i; } -print(jointMappings + "\n# Joint list end"); +print(jointMappings + "\n# Joint list end"); Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; - MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_L_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, -AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_R_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, - AMPLITUDE * (1.0 + Math.sin(cumulativeTime * FREQUENCY)))); - MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, - AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)))); + MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees(AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY), 0.0, 0.0)); + MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees(-AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY), 0.0, 0.0)); + MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( + AMPLITUDE * (1.0 + Math.sin(cumulativeTime * FREQUENCY)),0.0, 0.0)); + MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( + AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)),0.0, 0.0)); }); Script.scriptEnding.connect(function() { - MyAvatar.clearJointData("joint_R_hip"); - MyAvatar.clearJointData("joint_L_hip"); - MyAvatar.clearJointData("joint_R_knee"); - MyAvatar.clearJointData("joint_L_knee"); + MyAvatar.clearJointData("RightUpLeg"); + MyAvatar.clearJointData("LeftUpLeg"); + MyAvatar.clearJointData("RightLeg"); + MyAvatar.clearJointData("LeftLeg"); }); From 038b0de46e18a1d4749e259ca20b05dddc2c0c69 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Jun 2014 17:08:24 -0700 Subject: [PATCH 15/71] starting fist squeezing --- examples/squeezeFist.js | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/squeezeFist.js diff --git a/examples/squeezeFist.js b/examples/squeezeFist.js new file mode 100644 index 0000000000..85f817c964 --- /dev/null +++ b/examples/squeezeFist.js @@ -0,0 +1,47 @@ +// +// squeezeFist.js +// examples +// +// Created by Philip Rosedale on 03-June-2014 +// Copyright 2014 High Fidelity, Inc. +// +// This is an example script that demonstrates an NPC avatar running an FBX animation loop. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var animation = AnimationCache.getAnimation("https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"); + +var jointMapping; + +var frameIndex = 0.0; + +var FRAME_RATE = 30.0; // frames per second + +Script.update.connect(function(deltaTime) { + var triggerValue = Controller.getTriggerValue(0); + print(triggerValue); + if (!jointMapping) { + var avatarJointNames = MyAvatar.jointNames; + var animationJointNames = animation.jointNames; + if (avatarJointNames.length === 0 || animationJointNames.length === 0) { + return; + } + jointMapping = new Array(avatarJointNames.length); + for (var i = 0; i < avatarJointNames.length; i++) { + jointMapping[i] = animationJointNames.indexOf(avatarJointNames[i]); + } + } + frameIndex += deltaTime * FRAME_RATE; + var frames = animation.frames; + var rotations = frames[Math.floor(frameIndex) % frames.length].rotations; + for (var j = 0; j < jointMapping.length; j++) { + var rotationIndex = jointMapping[j]; + if (rotationIndex != -1) { + MyAvatar.setJointData(j, rotations[rotationIndex]); + } + } +}); + + From 90e2145fc4d3bed08ea824a6857926b359cb3339 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 3 Jun 2014 17:17:02 -0700 Subject: [PATCH 16/71] Working on enum streaming. --- libraries/metavoxels/src/Bitstream.cpp | 230 ++++++++++++++++++------- libraries/metavoxels/src/Bitstream.h | 40 ++++- tests/metavoxels/src/MetavoxelTests.h | 2 +- 3 files changed, 208 insertions(+), 64 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index f3ba1cca4d..5ce04b272a 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -78,6 +78,21 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta for (const QMetaObject* superClass = metaObject; superClass; superClass = superClass->superClass()) { getMetaObjectSubClasses().insert(superClass, metaObject); } + + // register the streamers for all enumerators + for (int i = 0; i < metaObject->enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject->enumerator(i); + const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; + if (!streamer) { + int highestValue = 0; + for (int j = 0; j < metaEnum.keyCount(); j++) { + highestValue = qMax(highestValue, metaEnum.value(j)); + } + streamer = new EnumTypeStreamer(QByteArray(metaEnum.scope()) + "::" + metaEnum.name(), + highestValue == 0 ? 0 : 1 + (int)(log(highestValue) / log(2.0))); + } + } + return 0; } @@ -280,16 +295,8 @@ void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) { } const QMetaObject* metaObject = value->metaObject(); _metaObjectStreamer << metaObject; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored(value)) { - continue; - } - const TypeStreamer* streamer = getTypeStreamers().value(property.userType()); - if (streamer) { - streamer->writeDelta(*this, property.read(value), reference && metaObject == reference->metaObject() ? - property.read(reference) : QVariant()); - } + foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + propertyWriter.writeDelta(*this, value, reference); } } @@ -466,15 +473,8 @@ Bitstream& Bitstream::operator<<(const QObject* object) { } const QMetaObject* metaObject = object->metaObject(); _metaObjectStreamer << metaObject; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored(object)) { - continue; - } - const TypeStreamer* streamer = getTypeStreamers().value(property.userType()); - if (streamer) { - streamer->write(*this, property.read(object)); - } + foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + propertyWriter.write(*this, object); } return *this; } @@ -558,25 +558,12 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) { if (_metadataType == NO_METADATA) { return *this; } - int storedPropertyCount = 0; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (property.isStored() && getTypeStreamers().contains(property.userType())) { - storedPropertyCount++; - } - } - *this << storedPropertyCount; + const QVector& propertyWriters = getPropertyWriters(metaObject); + *this << propertyWriters.size(); QCryptographicHash hash(QCryptographicHash::Md5); - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; - } - const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType()); - if (!typeStreamer) { - continue; - } - _typeStreamerStreamer << typeStreamer; + foreach (const PropertyWriter& propertyWriter, propertyWriters) { + _typeStreamerStreamer << propertyWriter.getStreamer(); + const QMetaProperty& property = propertyWriter.getProperty(); if (_metadataType == FULL_METADATA) { *this << QByteArray::fromRawData(property.name(), strlen(property.name())); } else { @@ -629,25 +616,18 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; if (metaObject) { - int propertyIndex = 0; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; + const QVector& propertyWriters = getPropertyWriters(metaObject); + if (propertyWriters.size() == properties.size()) { + for (int i = 0; i < propertyWriters.size(); i++) { + const PropertyWriter& propertyWriter = propertyWriters.at(i); + if (!properties.at(i).getReader().matchesExactly(propertyWriter.getStreamer())) { + matches = false; + break; + } + const QMetaProperty& property = propertyWriter.getProperty(); + hash.addData(property.name(), strlen(property.name()) + 1); } - const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType()); - if (!typeStreamer) { - continue; - } - if (propertyIndex >= properties.size() || - !properties.at(propertyIndex).getReader().matchesExactly(typeStreamer)) { - matches = false; - break; - } - hash.addData(property.name(), strlen(property.name()) + 1); - propertyIndex++; - } - if (propertyIndex != properties.size()) { + } else { matches = false; } } @@ -668,7 +648,7 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { *this << QByteArray(); return *this; } - const char* typeName = QMetaType::typeName(streamer->getType()); + const char* typeName = streamer->getName(); *this << QByteArray::fromRawData(typeName, strlen(typeName)); if (_metadataType == NO_METADATA) { return *this; @@ -679,6 +659,9 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { case TypeReader::SIMPLE_TYPE: return *this; + case TypeReader::ENUM_TYPE: + return *this << streamer->getBits(); + case TypeReader::LIST_TYPE: case TypeReader::SET_TYPE: return *this << streamer->getValueStreamer(); @@ -720,7 +703,15 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { } const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); if (!streamer) { - streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + int index = typeName.indexOf("::"); + if (index == -1) { + streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + } else { + int postIndex = index + 2; + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(typeName.constData(), index), + QByteArray::fromRawData(typeName.constData() + postIndex, typeName.size() - postIndex))); + } } if (!streamer) { qWarning() << "Unknown type name: " << typeName << "\n"; @@ -735,7 +726,13 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { case TypeReader::SIMPLE_TYPE: reader = TypeReader(typeName, streamer); return *this; - + + case TypeReader::ENUM_TYPE: { + int bits; + *this >> bits; + reader = TypeReader(typeName, streamer); + return *this; + } case TypeReader::LIST_TYPE: case TypeReader::SET_TYPE: { TypeReader valueReader; @@ -923,6 +920,31 @@ void Bitstream::clearSharedObject(QObject* object) { } } +const QVector& Bitstream::getPropertyWriters(const QMetaObject* metaObject) { + QVector& propertyWriters = _propertyWriters[metaObject]; + if (propertyWriters.isEmpty()) { + for (int i = 0; i < metaObject->propertyCount(); i++) { + QMetaProperty property = metaObject->property(i); + if (!property.isStored()) { + continue; + } + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + propertyWriters.append(PropertyWriter(property, streamer)); + } + } + } + return propertyWriters; +} + QHash& Bitstream::getMetaObjects() { static QHash metaObjects; return metaObjects; @@ -938,6 +960,11 @@ QHash& Bitstream::getTypeStreamers() { return typeStreamers; } +QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { + static QHash, const TypeStreamer*> enumStreamers; + return enumStreamers; +} + QVector Bitstream::getPropertyReaders(const QMetaObject* metaObject) { QVector propertyReaders; if (!metaObject) { @@ -948,9 +975,17 @@ QVector Bitstream::getPropertyReaders(const QMetaObject* metaObj if (!property.isStored()) { continue; } - const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType()); - if (typeStreamer) { - propertyReaders.append(PropertyReader(TypeReader(QByteArray(), typeStreamer), property)); + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + propertyReaders.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); } } return propertyReaders; @@ -1225,6 +1260,10 @@ MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) : TypeStreamer::~TypeStreamer() { } +const char* TypeStreamer::getName() const { + return QMetaType::typeName(_type); +} + const QVector& TypeStreamer::getMetaFields() const { static QVector emptyMetaFields; return emptyMetaFields; @@ -1246,6 +1285,10 @@ TypeReader::Type TypeStreamer::getReaderType() const { return TypeReader::SIMPLE_TYPE; } +int TypeStreamer::getBits() const { + return 0; +} + const TypeStreamer* TypeStreamer::getKeyStreamer() const { return NULL; } @@ -1290,3 +1333,68 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { return debug << (metaObject ? metaObject->className() : "null"); } +EnumTypeStreamer::EnumTypeStreamer(const QByteArray& name, int bits) : + _name(name), + _bits(bits) { +} + +const char* EnumTypeStreamer::getName() const { + return _name.constData(); +} + +TypeReader::Type EnumTypeStreamer::getReaderType() const { + return TypeReader::ENUM_TYPE; +} + +int EnumTypeStreamer::getBits() const { + return _bits; +} + +bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) const { + return first.toInt() == second.toInt(); +} + +void EnumTypeStreamer::write(Bitstream& out, const QVariant& value) const { + int intValue = value.toInt(); + out.write(&intValue, _bits); +} + +QVariant EnumTypeStreamer::read(Bitstream& in) const { + int intValue = 0; + in.read(&intValue, _bits); + return intValue; +} + +void EnumTypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + int intValue = value.toInt(), intReference = reference.toInt(); + if (intValue == intReference) { + out << false; + } else { + out << true; + out.write(&intValue, _bits); + } +} + +void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + bool changed; + in >> changed; + if (changed) { + int intValue = 0; + in.read(&intValue, _bits); + value = intValue; + } else { + value = reference; + } +} + +void EnumTypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + int intValue = value.toInt(); + out.write(&intValue, _bits); +} + +void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + int intValue = 0; + in.read(&intValue, _bits); + value = intValue; +} + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 7e1551346a..3ea5eb7150 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -38,6 +38,7 @@ class FieldReader; class ObjectReader; class OwnedAttributeValue; class PropertyReader; +class PropertyWriter; class TypeReader; class TypeStreamer; @@ -396,6 +397,8 @@ private slots: private: + const QVector& getPropertyWriters(const QMetaObject* metaObject); + QDataStream& _underlying; quint8 _byte; int _position; @@ -415,9 +418,12 @@ private: QHash _metaObjectSubstitutions; QHash _typeStreamerSubstitutions; + QHash > _propertyWriters; + static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); + static QHash, const TypeStreamer*>& getEnumStreamers(); static QVector getPropertyReaders(const QMetaObject* metaObject); }; @@ -708,7 +714,7 @@ typedef QSharedPointer TypeReaderPointer; class TypeReader { public: - enum Type { SIMPLE_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; + enum Type { SIMPLE_TYPE, ENUM_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true, Type type = SIMPLE_TYPE, const TypeReaderPointer& keyReader = TypeReaderPointer(), @@ -804,12 +810,15 @@ private: QMetaProperty _property; }; -/// Contains the information necessary to obtain an object property and write it to the stream. +/// Contains the information required to obtain an object property and write it to the stream. class PropertyWriter { public: PropertyWriter(const QMetaProperty& property = QMetaProperty(), const TypeStreamer* streamer = NULL); + const QMetaProperty& getProperty() const { return _property; } + const TypeStreamer* getStreamer() const { return _streamer; } + void write(Bitstream& out, const QObject* object) const; void writeDelta(Bitstream& out, const QObject* object, const QObject* reference) const; @@ -848,6 +857,8 @@ public: void setType(int type) { _type = type; } int getType() const { return _type; } + virtual const char* getName() const; + virtual bool equal(const QVariant& first, const QVariant& second) const = 0; virtual void write(Bitstream& out, const QVariant& value) const = 0; @@ -866,6 +877,8 @@ public: virtual TypeReader::Type getReaderType() const; + virtual int getBits() const; + virtual const TypeStreamer* getKeyStreamer() const; virtual const TypeStreamer* getValueStreamer() const; @@ -905,6 +918,29 @@ public: T rawValue; in.readRawDelta(rawValue, reference.value()); value = QVariant::fromValue(rawValue); } }; +/// A streamer class for enumerated types. +class EnumTypeStreamer : public TypeStreamer { +public: + + EnumTypeStreamer(const QByteArray& name, int bits); + + virtual const char* getName() const; + virtual TypeReader::Type getReaderType() const; + virtual int getBits() const; + virtual bool equal(const QVariant& first, const QVariant& second) const; + virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; + virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; + virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; + virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; + virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; + +private: + + QByteArray _name; + int _bits; +}; + /// A streamer for types compiled by mtc. template class StreamableTypeStreamer : public SimpleTypeStreamer { public: diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 6e0b857328..a4aa428a1e 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -80,7 +80,7 @@ public: enum TestEnum { FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM }; - enum TestFlag { NO_TEST_FLAGS = 0x0, FIRST_TEST_FLAG = 0x01, SECOND_TEST_FLAG = 0x02, THIRD_TEST_FLAG = 0x03 }; + enum TestFlag { NO_TEST_FLAGS = 0x0, FIRST_TEST_FLAG = 0x01, SECOND_TEST_FLAG = 0x02, THIRD_TEST_FLAG = 0x04 }; Q_DECLARE_FLAGS(TestFlags, TestFlag) Q_INVOKABLE TestSharedObjectA(float foo = 0.0f, TestEnum baz = FIRST_TEST_ENUM, TestFlags bong = 0); From 1f2a75fc453a6b6c16693ad2ec650c425313e691 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 3 Jun 2014 18:27:56 -0700 Subject: [PATCH 17/71] More enum streaming bits. --- libraries/metavoxels/src/Bitstream.cpp | 19 ++++++++++++------- libraries/metavoxels/src/Bitstream.h | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 5ce04b272a..0093e419f8 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -730,7 +730,11 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { case TypeReader::ENUM_TYPE: { int bits; *this >> bits; - reader = TypeReader(typeName, streamer); + if (streamer && streamer->getReaderType() == type) { + reader = TypeReader(typeName, streamer); + } else { + reader = TypeReader(typeName, streamer, false, TypeReader::ENUM_TYPE, bits); + } return *this; } case TypeReader::LIST_TYPE: @@ -741,7 +745,7 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { valueReader.matchesExactly(streamer->getValueStreamer())) { reader = TypeReader(typeName, streamer); } else { - reader = TypeReader(typeName, streamer, false, (TypeReader::Type)type, TypeReaderPointer(), + reader = TypeReader(typeName, streamer, false, (TypeReader::Type)type, 0, TypeReaderPointer(), TypeReaderPointer(new TypeReader(valueReader))); } return *this; @@ -754,7 +758,7 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { valueReader.matchesExactly(streamer->getValueStreamer())) { reader = TypeReader(typeName, streamer); } else { - reader = TypeReader(typeName, streamer, false, TypeReader::MAP_TYPE, + reader = TypeReader(typeName, streamer, false, TypeReader::MAP_TYPE, 0, TypeReaderPointer(new TypeReader(keyReader)), TypeReaderPointer(new TypeReader(valueReader))); } return *this; @@ -814,14 +818,14 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { const QVector& localFields = streamer->getMetaFields(); if (fieldCount != localFields.size()) { reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE, - TypeReaderPointer(), TypeReaderPointer(), fields); + 0, TypeReaderPointer(), TypeReaderPointer(), fields); return *this; } for (int i = 0; i < fieldCount; i++) { const FieldReader& fieldReader = fields.at(i); if (!fieldReader.getReader().matchesExactly(localFields.at(i).getStreamer()) || fieldReader.getIndex() != i) { reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE, - TypeReaderPointer(), TypeReaderPointer(), fields); + 0, TypeReaderPointer(), TypeReaderPointer(), fields); return *this; } } @@ -829,7 +833,7 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { return *this; } reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE, - TypeReaderPointer(), TypeReaderPointer(), fields); + 0, TypeReaderPointer(), TypeReaderPointer(), fields); return *this; } @@ -991,12 +995,13 @@ QVector Bitstream::getPropertyReaders(const QMetaObject* metaObj return propertyReaders; } -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch, Type type, +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch, Type type, int bits, const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader, const QVector& fields) : _typeName(typeName), _streamer(streamer), _exactMatch(exactMatch), _type(type), + _bits(bits), _keyReader(keyReader), _valueReader(valueReader), _fields(fields) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 3ea5eb7150..02be736e02 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -717,7 +717,7 @@ public: enum Type { SIMPLE_TYPE, ENUM_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true, - Type type = SIMPLE_TYPE, const TypeReaderPointer& keyReader = TypeReaderPointer(), + Type type = SIMPLE_TYPE, int bits = 0, const TypeReaderPointer& keyReader = TypeReaderPointer(), const TypeReaderPointer& valueReader = TypeReaderPointer(), const QVector& fields = QVector()); @@ -739,6 +739,7 @@ private: const TypeStreamer* _streamer; bool _exactMatch; Type _type; + int _bits; TypeReaderPointer _keyReader; TypeReaderPointer _valueReader; QVector _fields; From 23ef5b5404bc295f68723aa558f97a2fadf65e6a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 10:22:19 -0700 Subject: [PATCH 18/71] added some comments --- libraries/octree/src/Octree.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3ec1871023..cbdc4753dc 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -602,7 +602,6 @@ public: bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); - bool keepSearching = true; if (element->findRayIntersection(args->origin, args->direction, keepSearching, args->element, args->distance, args->face, args->intersectedObject)) { @@ -1336,14 +1335,23 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, } } - // write the color data... + // write the child element data... if (continueThisLevel && params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { OctreeElement* childElement = element->getChildAtIndex(i); if (childElement) { + int bytesBeforeChild = packetData->getUncompressedSize(); + + // TODO: we want to support the ability for a childElement to "partially" write it's data. + // for example, consider the case of the model server where the entire contents of the + // element may be larger than can fit in a single MTU/packetData. In this case, we want + // to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. In the case that an element was partially written, we need to continueThisLevel = childElement->appendElementData(packetData, params); + int bytesAfterChild = packetData->getUncompressedSize(); if (!continueThisLevel) { From 8d4a8f7e67aa1ee28a1f33e1058a5de9b66afd83 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 10:22:49 -0700 Subject: [PATCH 19/71] first cut at partial model elements --- libraries/models/src/ModelTreeElement.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index b87557d073..3fc2537dc7 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -55,6 +55,7 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit // write our models out... first determine which of the models are in view based on our params uint16_t numberOfModels = 0; + uint16_t actualNumberOfModels = 0; QVector indexesOfModelsToInclude; for (uint16_t i = 0; i < _modelItems->size(); i++) { @@ -72,17 +73,35 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit } } + int numberOfModelsOffset = packetData->getUncompressedByteOffset(); success = packetData->appendValue(numberOfModels); if (success) { foreach (uint16_t i, indexesOfModelsToInclude) { const ModelItem& model = (*_modelItems)[i]; + + LevelDetails modelLevel = packetData->startLevel(); + success = model.appendModelData(packetData); + + if (success) { + packetData->endLevel(modelLevel); + actualNumberOfModels++; + } if (!success) { + qDebug() << "ModelTreeElement::appendElementData()... model i=" << i << "didn't fit..."; + packetData->discardLevel(modelLevel); break; } } } + + if (!success) { + qDebug() << "ModelTreeElement::appendElementData()... updatePriorBytes()... actualNumberOfModels=" << actualNumberOfModels; + success = packetData->updatePriorBytes(numberOfModelsOffset, + (const unsigned char*)&actualNumberOfModels, sizeof(actualNumberOfModels)); + } + return success; } @@ -433,6 +452,7 @@ int ModelTreeElement::readElementDataFromBuffer(const unsigned char* data, int b if (bytesLeftToRead >= (int)sizeof(numberOfModels)) { // read our models in.... numberOfModels = *(uint16_t*)dataAt; + dataAt += sizeof(numberOfModels); bytesLeftToRead -= (int)sizeof(numberOfModels); bytesRead += sizeof(numberOfModels); From b48c70a7f7d3a5c1acf3dacfea7906d614a695fa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 10:23:50 -0700 Subject: [PATCH 20/71] first cut at PropertyFlags template class --- libraries/shared/src/PropertyFlags.cpp | 11 ++ libraries/shared/src/PropertyFlags.h | 245 +++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 libraries/shared/src/PropertyFlags.cpp create mode 100644 libraries/shared/src/PropertyFlags.h diff --git a/libraries/shared/src/PropertyFlags.cpp b/libraries/shared/src/PropertyFlags.cpp new file mode 100644 index 0000000000..8413ce8172 --- /dev/null +++ b/libraries/shared/src/PropertyFlags.cpp @@ -0,0 +1,11 @@ +// +// PropertyFlags.cpp +// libraries/shared/src +// +// Created by Brad Hefta-Gaub on 6/3/14. +// Copyright 2014 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 +// + diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h new file mode 100644 index 0000000000..b5758f2206 --- /dev/null +++ b/libraries/shared/src/PropertyFlags.h @@ -0,0 +1,245 @@ +// +// PropertyFlags.h +// libraries/shared/src +// +// Created by Brad Hefta-Gaub on 6/3/14. +// Copyright 2014 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 +// +// +// TODO: +// * implement decode +// * add operators + +#ifndef hifi_PropertyFlags_h +#define hifi_PropertyFlags_h + +#include +#include + +templateclass PropertyFlags { +public: + typedef Enum enum_type; + inline PropertyFlags() : _maxFlag(-1) { }; + inline PropertyFlags(const PropertyFlags& other) : _flags(other._flags), _maxFlag(other._maxFlag) {} + inline PropertyFlags(Enum flag) : _maxFlag(-1) { setHasProperty(flag); } + + void clear() { _flags.clear(); _maxFlag = -1; } + + void setHasProperty(Enum flag, bool value = true); + bool getHasProperty(Enum flag); + QByteArray encode(); + void decode(const QByteArray& fromEncoded); + + + inline PropertyFlags& operator=(const PropertyFlags &other) { _flags = other._flags; _maxFlag = other._maxFlag; return *this; } + + inline PropertyFlags& operator|=(PropertyFlags other) { _flags |= other._flags; _maxFlag = max(_maxFlag, other._maxFlag); return *this; } + inline PropertyFlags& operator|=(Enum flag) { PropertyFlags other(flag); _flags |= other._flags; _maxFlag = max(_maxFlag, other._maxFlag); return *this; } + + inline PropertyFlags& operator&=(PropertyFlags other) { _flags &= other._flags; shinkIfNeeded(); return *this; } + inline PropertyFlags& operator&=(Enum flag) { PropertyFlags other(flag); _flags &= other._flags; shinkIfNeeded(); return *this; } + + inline PropertyFlags& operator^=(PropertyFlags other) { _flags ^= other._flags; shinkIfNeeded(); return *this; } + inline PropertyFlags& operator^=(Enum flag) { PropertyFlags other(flag); _flags ^= other._flags; shinkIfNeeded(); return *this; } + + + inline PropertyFlags operator|(PropertyFlags other) const { PropertyFlags result(*this); result |= other; return result; } + inline PropertyFlags operator|(Enum flag) const { PropertyFlags result(*this); PropertyFlags other(flag); result |= other; return result; } + + inline PropertyFlags operator^(PropertyFlags other) const { PropertyFlags result(*this); result ^= other; return result; } + inline PropertyFlags operator^(Enum flag) const { PropertyFlags result(*this); PropertyFlags other(flag); result ^= other; return result; } + + inline PropertyFlags operator&(PropertyFlags other) const { PropertyFlags result(*this); result &= other; return result; } + inline PropertyFlags operator&(Enum flag) const { PropertyFlags result(*this); PropertyFlags other(flag); result &= other; return result; } + + /* + inline PropertyFlags operator~() const { return PropertyFlags(Enum(~i)); } + inline bool operator!() const { return !i; } + */ + + +private: + void shinkIfNeeded(); + + QBitArray _flags; + int _maxFlag; +}; + + +template inline void PropertyFlags::setHasProperty(Enum flag, bool value) { + if (flag > _maxFlag) { + if (value) { + _maxFlag = flag; + _flags.resize(_maxFlag + 1); + } else { + return; // bail early, we're setting a flag outside of our current _maxFlag to false, which is already the default + } + } + qDebug() << "_flags.setBit("< inline bool PropertyFlags::getHasProperty(Enum flag) { + if (flag > _maxFlag) { + return false; + } + return _flags.testBit(flag); +} + +const int BITS_PER_BYTE = 8; + +template inline QByteArray PropertyFlags::encode() { + const bool debug = false; + QByteArray output; + + outputBufferBits((const unsigned char*)output.constData(), output.size()); + + if (debug) qDebug() << "PropertyFlags::encode()"; + + // we should size the array to the correct size. + int lengthInBytes = (_maxFlag / (BITS_PER_BYTE - 1)) + 1; + + if (debug) qDebug() << " lengthInBytes=" << lengthInBytes; + + output.fill(0, lengthInBytes); + + if (debug) outputBufferBits((const unsigned char*)output.constData(), output.size()); + + // next pack the number of header bits in, the first N-1 to be set to 1, the last to be set to 0 + for(int i = 0; i < lengthInBytes; i++) { + int outputIndex = i; + if (debug) qDebug() << "outputIndex:" << outputIndex; + int bitValue = (i < (lengthInBytes - 1) ? 1 : 0); + + if (debug) qDebug() << " length code bit["<< outputIndex << "]=" << bitValue; + + char original = output.at(outputIndex / BITS_PER_BYTE); + int shiftBy = BITS_PER_BYTE - ((outputIndex % BITS_PER_BYTE) + 1); + char thisBit = ( bitValue << shiftBy); + + if (debug) { + qDebug() << "bitValue:" << bitValue; + qDebug() << "shiftBy:" << shiftBy; + qDebug() << "original:"; + outputBits(original); + + qDebug() << "thisBit:"; + outputBits(thisBit); + } + + output[i / BITS_PER_BYTE] = (original | thisBit); + } + + if (debug) outputBufferBits((const unsigned char*)output.constData(), output.size()); + + // finally pack the the actual bits from the bit array + for(int i = lengthInBytes; i < (lengthInBytes + _maxFlag + 1); i++) { + int flagIndex = i - lengthInBytes; + int outputIndex = i; + if (debug) qDebug() << "flagIndex:" << flagIndex; + if (debug) qDebug() << "outputIndex:" << outputIndex; + + + int bitValue = ( _flags[flagIndex] ? 1 : 0); + + if (debug) qDebug() << " encode bit["< inline void PropertyFlags::decode(const QByteArray& fromEncoded) { +} + +template inline void PropertyFlags::shinkIfNeeded() { + bool maxFlagWas = _maxFlag; + while (_maxFlag >= 0) { + if (_flags.testBit(_maxFlag)) { + break; + } + _maxFlag--; + } + if (maxFlagWas != _maxFlag) { + _flags.resize(_maxFlag + 1); + } +} + + + +/*** + +BitArr.resize(8*byteArr.count()); +for(int i=0; i +class QFlags +{ + typedef void **Zero; + int i; +public: + typedef Enum enum_type; + Q_DECL_CONSTEXPR inline QFlags(const QFlags &f) : i(f.i) {} + Q_DECL_CONSTEXPR inline QFlags(Enum f) : i(f) {} + Q_DECL_CONSTEXPR inline QFlags(Zero = 0) : i(0) {} + inline QFlags(QFlag f) : i(f) {} + + inline QFlags &operator=(const QFlags &f) { i = f.i; return *this; } + inline QFlags &operator&=(int mask) { i &= mask; return *this; } + inline QFlags &operator&=(uint mask) { i &= mask; return *this; } + inline QFlags &operator|=(QFlags f) { i |= f.i; return *this; } + inline QFlags &operator|=(Enum f) { i |= f; return *this; } + inline QFlags &operator^=(QFlags f) { i ^= f.i; return *this; } + inline QFlags &operator^=(Enum f) { i ^= f; return *this; } + + Q_DECL_CONSTEXPR inline operator int() const { return i; } + + Q_DECL_CONSTEXPR inline QFlags operator|(QFlags f) const { return QFlags(Enum(i | f.i)); } + Q_DECL_CONSTEXPR inline QFlags operator|(Enum f) const { return QFlags(Enum(i | f)); } + Q_DECL_CONSTEXPR inline QFlags operator^(QFlags f) const { return QFlags(Enum(i ^ f.i)); } + Q_DECL_CONSTEXPR inline QFlags operator^(Enum f) const { return QFlags(Enum(i ^ f)); } + Q_DECL_CONSTEXPR inline QFlags operator&(int mask) const { return QFlags(Enum(i & mask)); } + Q_DECL_CONSTEXPR inline QFlags operator&(uint mask) const { return QFlags(Enum(i & mask)); } + Q_DECL_CONSTEXPR inline QFlags operator&(Enum f) const { return QFlags(Enum(i & f)); } + Q_DECL_CONSTEXPR inline QFlags operator~() const { return QFlags(Enum(~i)); } + + Q_DECL_CONSTEXPR inline bool operator!() const { return !i; } + + inline bool testFlag(Enum f) const { return (i & f) == f && (f != 0 || i == int(f) ); } +}; + +***/ + +#endif // hifi_PropertyFlags_h + From d3f51fe38e0ed3f6a7b77e461557bc373fccf5fc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 10:41:17 -0700 Subject: [PATCH 21/71] FinalOrientation -> FinalOrientationInWorldFrame --- interface/src/Application.cpp | 3 ++- interface/src/Audio.cpp | 2 +- interface/src/AudioReflector.cpp | 2 +- interface/src/avatar/Head.cpp | 9 ++++++--- interface/src/avatar/Head.h | 8 ++++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e731fde79..10201c5c88 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1841,7 +1841,8 @@ void Application::updateMyAvatarLookAtPosition() { } } else { // I am not looking at anyone else, so just look forward - lookAtSpot = _myAvatar->getHead()->calculateAverageEyePosition() + (_myAvatar->getHead()->getFinalOrientation() * glm::vec3(0.f, 0.f, -TREE_SCALE)); + lookAtSpot = _myAvatar->getHead()->calculateAverageEyePosition() + + (_myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.f, 0.f, -TREE_SCALE)); } // TODO: Add saccade to mouse pointer when stable, IF not looking at someone (since we know we are looking at it) /* diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 50ab720450..ea93d78a25 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -603,7 +603,7 @@ void Audio::handleAudioInput() { if (audioMixer && audioMixer->getActiveSocket()) { MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); - glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientation(); + glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientationInWorldFrame(); // we need the amount of bytes in the buffer + 1 for type // + 12 for 3 floats for position + float for bearing + 1 attenuation byte diff --git a/interface/src/AudioReflector.cpp b/interface/src/AudioReflector.cpp index 52d23b4fee..e18a0ad36e 100644 --- a/interface/src/AudioReflector.cpp +++ b/interface/src/AudioReflector.cpp @@ -459,7 +459,7 @@ void AudioReflector::calculateAllReflections() { // only recalculate when we've moved, or if the attributes have changed // TODO: what about case where new voxels are added in front of us??? bool wantHeadOrientation = Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingHeadOriented); - glm::quat orientation = wantHeadOrientation ? _myAvatar->getHead()->getFinalOrientation() : _myAvatar->getOrientation(); + glm::quat orientation = wantHeadOrientation ? _myAvatar->getHead()->getFinalOrientationInWorldFrame() : _myAvatar->getOrientation(); glm::vec3 origin = _myAvatar->getHead()->getPosition(); glm::vec3 listenerPosition = _myAvatar->getHead()->getPosition(); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 6f09007b31..ee242d179a 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -188,9 +188,12 @@ void Head::setScale (float scale) { _scale = scale; } -glm::quat Head::getFinalOrientation() const { - return _owningAvatar->getOrientation() * glm::quat(glm::radians( - glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() ))); +glm::quat Head::getFinalOrientationInWorldFrame() const { + return _owningAvatar->getOrientation() * getFinalOrientationInLocalFrame(); +} + +glm::quat Head::getFinalOrientationInLocalFrame() const { + return glm::quat(glm::radians(glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() ))); } glm::quat Head::getCameraOrientation () const { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index cd7abeb9de..36df51fa6f 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -50,9 +50,13 @@ public: void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; } void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } void setLeanForward(float leanForward) { _leanForward = leanForward; } + + /// \return orientationBase+Delta + glm::quat getFinalOrientationInLocalFrame() const; - /// \return orientationBody * orientationBase+Delta - glm::quat getFinalOrientation() const; + /// \return orientationBody * (orientationBase+Delta) + glm::quat getFinalOrientationInWorldFrame() const; + /// \return orientationBody * orientationBasePitch glm::quat getCameraOrientation () const; From 14e782e4391c3ff10dc309d4ff5f65ce5d913417 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 10:42:04 -0700 Subject: [PATCH 22/71] remove some JointState::getHybridTransform() calls --- interface/src/avatar/FaceModel.cpp | 12 +++++++----- interface/src/avatar/MyAvatar.cpp | 5 +++-- interface/src/avatar/SkeletonModel.cpp | 6 +++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 080603ac7e..4fb2faf5cf 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -48,8 +48,8 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(_rotation); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getHybridTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat3 axes = glm::mat3_cast(glm::quat()); + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransformInModelFrame() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation))); state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1])) @@ -59,9 +59,11 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // likewise with the eye joints - glm::mat4 inverse = glm::inverse(parentState.getHybridTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * - joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); - glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientation() * IDENTITY_FRONT, 0.0f)); + // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. + glm::mat4 inverse = glm::inverse(glm::mat4_cast(_rotation) * parentState.getTransformInModelFrame() * + glm::translate(state.getDefaultTranslationInParentFrame()) * + joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); + glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() + _owningHead->getSaccade() - _translation, 1.0f)); glm::quat between = rotationBetween(front, lookAt); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c13950e520..f761729417 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -236,7 +236,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); } } - + // Rotate the body if the head is turned beyond the screen if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f; @@ -724,7 +724,8 @@ void MyAvatar::updateLookAtTargetAvatar() { Avatar* avatar = static_cast(avatarPointer.data()); avatar->setIsLookAtTarget(false); if (!avatar->isMyAvatar()) { - float angleTo = glm::angle(getHead()->getFinalOrientation() * glm::vec3(0.0f, 0.0f, -1.0f), + glm::vec3 DEFAULT_GAZE_IN_HEAD_FRAME = glm::vec3(0.0f, 0.0f, -1.0f); + float angleTo = glm::angle(getHead()->getFinalOrientationInWorldFrame() * DEFAULT_GAZE_IN_HEAD_FRAME, glm::normalize(avatar->getHead()->getEyePosition() - getHead()->getEyePosition())); if (angleTo < smallestAngleTo) { _lookAtTargetAvatar = avatarPointer; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8b229590fd..f46f9a6336 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -236,8 +236,8 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const return; } // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(_rotation); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getHybridTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat3 axes = glm::mat3_cast(glm::quat()); + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransformInModelFrame() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), @@ -263,7 +263,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { do { const FBXJoint& joint = geometry.joints.at(jointIndex); const JointState& jointState = _jointStates.at(jointIndex); - glm::vec3 position = extractTranslation(jointState.getHybridTransform()) + _translation; + glm::vec3 position = _rotation * jointState.getPositionInModelFrame() + _translation; glPushMatrix(); glTranslatef(position.x, position.y, position.z); From 30d936c15b39abe58ea52e35933abac105f657b0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 10:52:10 -0700 Subject: [PATCH 23/71] getJointPosition -> getJointPositionInWorldFrame --- interface/src/avatar/Avatar.cpp | 6 +++--- interface/src/avatar/FaceModel.cpp | 4 ++-- interface/src/avatar/SkeletonModel.cpp | 20 ++++++++++---------- interface/src/devices/PrioVR.cpp | 2 +- interface/src/renderer/Model.cpp | 13 ++++++------- interface/src/renderer/Model.h | 2 +- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 870d5b1a53..baf46605fd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -377,7 +377,7 @@ void Avatar::simulateAttachments(float deltaTime) { if (!isMyAvatar()) { model->setLODDistance(getLODDistance()); } - if (_skeletonModel.getJointPosition(jointIndex, jointPosition) && + if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); @@ -713,7 +713,7 @@ glm::vec3 Avatar::getJointPosition(int index) const { return position; } glm::vec3 position; - _skeletonModel.getJointPosition(index, position); + _skeletonModel.getJointPositionInWorldFrame(index, position); return position; } @@ -725,7 +725,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const { return position; } glm::vec3 position; - _skeletonModel.getJointPosition(getJointIndex(name), position); + _skeletonModel.getJointPositionInWorldFrame(getJointIndex(name), position); return position; } diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 4fb2faf5cf..93cd93b71c 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -94,6 +94,6 @@ bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEy return false; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && - getJointPosition(geometry.rightEyeJointIndex, secondEyePosition); + return getJointPositionInWorldFrame(geometry.leftEyeJointIndex, firstEyePosition) && + getJointPositionInWorldFrame(geometry.rightEyeJointIndex, secondEyePosition); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f46f9a6336..7004d12ffe 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -373,11 +373,11 @@ void SkeletonModel::setHandPositionInModelFrame(int jointIndex, const glm::vec3& } bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { - return getJointPosition(getLeftHandJointIndex(), position); + return getJointPositionInWorldFrame(getLeftHandJointIndex(), position); } bool SkeletonModel::getRightHandPosition(glm::vec3& position) const { - return getJointPosition(getRightHandJointIndex(), position); + return getJointPositionInWorldFrame(getRightHandJointIndex(), position); } bool SkeletonModel::restoreLeftHandPosition(float fraction, float priority) { @@ -385,7 +385,7 @@ bool SkeletonModel::restoreLeftHandPosition(float fraction, float priority) { } bool SkeletonModel::getLeftShoulderPosition(glm::vec3& position) const { - return getJointPosition(getLastFreeJointIndex(getLeftHandJointIndex()), position); + return getJointPositionInWorldFrame(getLastFreeJointIndex(getLeftHandJointIndex()), position); } float SkeletonModel::getLeftArmLength() const { @@ -397,7 +397,7 @@ bool SkeletonModel::restoreRightHandPosition(float fraction, float priority) { } bool SkeletonModel::getRightShoulderPosition(glm::vec3& position) const { - return getJointPosition(getLastFreeJointIndex(getRightHandJointIndex()), position); + return getJointPositionInWorldFrame(getLastFreeJointIndex(getRightHandJointIndex()), position); } float SkeletonModel::getRightArmLength() const { @@ -405,11 +405,11 @@ float SkeletonModel::getRightArmLength() const { } bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { - return isActive() && getJointPosition(_geometry->getFBXGeometry().headJointIndex, headPosition); + return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().headJointIndex, headPosition); } bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { - return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition); + return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); } bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { @@ -428,14 +428,14 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco return false; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && - getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) { + if (getJointPositionInWorldFrame(geometry.leftEyeJointIndex, firstEyePosition) && + getJointPositionInWorldFrame(geometry.rightEyeJointIndex, secondEyePosition)) { return true; } // no eye joints; try to estimate based on head/neck joints glm::vec3 neckPosition, headPosition; - if (getJointPosition(geometry.neckJointIndex, neckPosition) && - getJointPosition(geometry.headJointIndex, headPosition)) { + if (getJointPositionInWorldFrame(geometry.neckJointIndex, neckPosition) && + getJointPositionInWorldFrame(geometry.headJointIndex, headPosition)) { const float EYE_PROPORTION = 0.6f; glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION); glm::quat headRotation; diff --git a/interface/src/devices/PrioVR.cpp b/interface/src/devices/PrioVR.cpp index ab29fc004b..65cdb962e1 100644 --- a/interface/src/devices/PrioVR.cpp +++ b/interface/src/devices/PrioVR.cpp @@ -92,7 +92,7 @@ static void setPalm(float deltaTime, int index) { skeletonModel->getJointRotation(jointIndex, rotation, true); rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f)); } - skeletonModel->getJointPosition(jointIndex, position); + skeletonModel->getJointPositionInWorldFrame(jointIndex, position); position = inverseRotation * (position - skeletonModel->getTranslation()); palm->setRawRotation(rotation); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a345a32707..f603dea55a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -747,12 +747,11 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo } } -bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { +bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - position = _translation + extractTranslation(_jointStates[jointIndex].getHybridTransform()); - //position = _translation + _rotation * _jointState[jointIndex].getPositionInModelFrame(); + position = _translation + _rotation * _jointStates[jointIndex].getPositionInModelFrame(); return true; } @@ -1234,7 +1233,7 @@ void Model::simulateInternal(float deltaTime) { glm::vec3 jointTranslation = _translation; glm::quat jointRotation = _rotation; - getJointPosition(attachment.jointIndex, jointTranslation); + getJointPositionInWorldFrame(attachment.jointIndex, jointTranslation); getJointRotationInWorldFrame(attachment.jointIndex, jointRotation); model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); @@ -1508,12 +1507,12 @@ void Model::applyCollision(CollisionInfo& collision) { glm::vec3 jointPosition(0.0f); int jointIndex = collision._intData; - if (getJointPosition(jointIndex, jointPosition)) { + if (getJointPositionInWorldFrame(jointIndex, jointPosition)) { const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; if (joint.parentIndex != -1) { // compute the approximate distance (travel) that the joint needs to move glm::vec3 start; - getJointPosition(joint.parentIndex, start); + getJointPositionInWorldFrame(joint.parentIndex, start); glm::vec3 contactPoint = collision._contactPoint - start; glm::vec3 penetrationEnd = contactPoint + collision._penetration; glm::vec3 axis = glm::cross(contactPoint, penetrationEnd); @@ -1524,7 +1523,7 @@ void Model::applyCollision(CollisionInfo& collision) { float angle = asinf(travel / (glm::length(contactPoint) * glm::length(penetrationEnd))); axis = glm::normalize(axis); glm::vec3 end; - getJointPosition(jointIndex, end); + getJointPositionInWorldFrame(jointIndex, end); // transform into model-frame glm::vec3 newEnd = glm::inverse(_rotation) * (start + glm::angleAxis(angle, axis) * (end - start) - _translation); // try to move it diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index eb5b4cd7c8..e4c25c8937 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -173,7 +173,7 @@ public: /// Returns the index of the last free ancestor of the indexed joint, or -1 if not found. int getLastFreeJointIndex(int jointIndex) const; - bool getJointPosition(int jointIndex, glm::vec3& position) const; + bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; From 12ac6105f1fe373c74339b9d3c2fad7e2b7466b1 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 10:59:32 -0700 Subject: [PATCH 24/71] changed MovingMedian to MovingPercentile --- interface/src/DatagramProcessor.cpp | 6 ++-- libraries/networking/src/LimitedNodeList.cpp | 25 +++++++++++++++- libraries/networking/src/Node.cpp | 9 +++--- libraries/networking/src/Node.h | 4 +-- libraries/networking/src/NodeList.cpp | 11 ++++--- libraries/shared/src/MovingMedian.h | 26 ----------------- ...{MovingMedian.cpp => MovingPercentile.cpp} | 22 +++++++++----- libraries/shared/src/MovingPercentile.h | 29 +++++++++++++++++++ 8 files changed, 83 insertions(+), 49 deletions(-) delete mode 100644 libraries/shared/src/MovingMedian.h rename libraries/shared/src/{MovingMedian.cpp => MovingPercentile.cpp} (81%) create mode 100644 libraries/shared/src/MovingPercentile.h diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 47836638dd..898c4dcd53 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -90,7 +90,6 @@ prevN = temp3; int skew = 0; - while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) { incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); @@ -210,14 +209,15 @@ currTypes[*currN] = (unsigned char)type; } default: int s = nodeList->processNodeData(senderSockAddr, incomingPacket); - if (s!=1234567890) + if (s!=1234567890 && abs(s) > abs(skew)) skew = s; break; } } } - if (abs(skew) > 1000) { + + if (abs(skew) > 3000) { printf("large skew! %d ----------------------------\n", skew); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c0d7941edf..cc11c2d322 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -151,6 +151,10 @@ void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { } bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { + +quint64 start = usecTimestampNow(); +quint64 end; + PacketType checkType = packetTypeForPacket(packet); int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data()); @@ -169,6 +173,11 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { versionDebugSuppressMap.insert(senderUUID, checkType); } + + if ((end=usecTimestampNow()) - start > 100) { + printf("\t\t\t\t version and hash match long diff: %d\n", end-start); + } + return false; } @@ -178,6 +187,11 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { if (sendingNode) { // check if the md5 hash in the header matches the hash we would expect if (hashFromPacketHeader(packet) == hashForPacketAndConnectionUUID(packet, sendingNode->getConnectionSecret())) { + + if ((end = usecTimestampNow()) - start > 100) { + printf("\t\t\t\t version and hash match long diff: %d\n", end - start); + } + return true; } else { qDebug() << "Packet hash mismatch on" << checkType << "- Sender" @@ -188,9 +202,18 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { + + if ((end = usecTimestampNow()) - start > 100) { + printf("\t\t\t\t version and hash match long diff: %d\n", end - start); + } + return true; } - + + + if ((end = usecTimestampNow()) - start > 100) { + printf("\t\t\t\t version and hash match long diff: %d\n", end - start); + } return false; } diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 9c482b9d58..b241031e2d 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -58,8 +58,7 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, _isAlive(true), _clockSkewUsec(0), _mutex(), - - _clockSkewMovingMedian(31) + _clockSkewMovingPercentile(30, 0.8f) // moving upper quartile of 21 samples { } @@ -136,10 +135,10 @@ float Node::getAverageKilobitsPerSecond() { } void Node::setClockSkewUsec(int clockSkew) { - //_clockSkewMovingMedian.updateMedian((float)clockSkew); - //_clockSkewUsec = (int)_clockSkewMovingMedian.getMedian(); + _clockSkewMovingPercentile.updatePercentile((float)clockSkew); + _clockSkewUsec = (int)_clockSkewMovingPercentile.getValueAtPercentile(); -_clockSkewUsec = clockSkew; + //_clockSkewUsec = clockSkew; } QDataStream& operator<<(QDataStream& out, const Node& node) { diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 7a8fcad0bb..033ae01380 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -24,7 +24,7 @@ #include "NodeData.h" #include "SimpleMovingAverage.h" -#include "MovingMedian.h" +#include "MovingPercentile.h" typedef quint8 NodeType_t; @@ -123,7 +123,7 @@ private: int _clockSkewUsec; QMutex _mutex; - MovingMedian _clockSkewMovingMedian; + MovingPercentile _clockSkewMovingPercentile; }; QDebug operator<<(QDebug debug, const Node &message); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index f91ee3df28..43b4f56361 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -98,7 +98,7 @@ int NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& s sendingNode->setPingMs(pingTime / 1000); sendingNode->setClockSkewUsec(clockSkew); -//printf("\t\t clock skew sample: %d median: %d\n", clockSkew, sendingNode->getClockSkewUsec()); +printf("\t\t clock skew sample: %d val at percentile: %d\n", clockSkew, sendingNode->getClockSkewUsec()); const bool wantDebug = false; @@ -114,8 +114,8 @@ int NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& s " clockSkew: " << clockSkew; } - if (abs(clockSkew) > 1000) - printf("clockskew = %d \n", clockSkew); +///if (abs(clockSkew) > 1000) +//printf("clockskew = %d \n", clockSkew); return clockSkew; } @@ -489,8 +489,11 @@ QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) { QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypePingReply); QDataStream packetStream(&replyPacket, QIODevice::Append); - packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); +quint64 now; + packetStream << typeFromOriginalPing << timeFromOriginalPing << (now = usecTimestampNow()); + +printf("\n>>>>>>>> recv ping: %llu reply: %llu diff: %lld\n", timeFromOriginalPing, now, (qint64)now-(qint64)timeFromOriginalPing); return replyPacket; } diff --git a/libraries/shared/src/MovingMedian.h b/libraries/shared/src/MovingMedian.h deleted file mode 100644 index 813fd42235..0000000000 --- a/libraries/shared/src/MovingMedian.h +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef hifi_MovingMedian_h -#define hifi_MovingMedian_h - - -class MovingMedian { - -public: - MovingMedian(int numSamples = 11); - ~MovingMedian(); - - void updateMedian(float sample); - float getMedian() const { return _median; } - - -private: - float* _samplesSorted; - int _numSamples; - - int* _sampleAges; // _sampleAges[i] is the "age" of the sample _sampleSorted[i] (higher means older) - int _numExistingSamples; - - float _median; -}; - -#endif \ No newline at end of file diff --git a/libraries/shared/src/MovingMedian.cpp b/libraries/shared/src/MovingPercentile.cpp similarity index 81% rename from libraries/shared/src/MovingMedian.cpp rename to libraries/shared/src/MovingPercentile.cpp index f3cd4cbd16..063fd641e9 100644 --- a/libraries/shared/src/MovingMedian.cpp +++ b/libraries/shared/src/MovingPercentile.cpp @@ -1,21 +1,23 @@ -#include "MovingMedian.h" +#include "MovingPercentile.h" //#include "stdio.h"// DEBUG -MovingMedian::MovingMedian(int numSamples) +MovingPercentile::MovingPercentile(int numSamples, float percentile) : _numSamples(numSamples), + _percentile(percentile), _numExistingSamples(0), - _median(0.0f) + _valueAtPercentile(0.0f), + _indexOfPercentile(0) { _samplesSorted = new float[numSamples]; _sampleAges = new int[numSamples]; } -MovingMedian::~MovingMedian() { +MovingPercentile::~MovingPercentile() { delete[] _samplesSorted; delete[] _sampleAges; } -void MovingMedian::updateMedian(float sample) { +void MovingPercentile::updatePercentile(float sample) { //printf("\nnew sample: %2.2f ", sample); @@ -24,8 +26,13 @@ void MovingMedian::updateMedian(float sample) { // otherwise, it will be the spot of the oldest sample int newSampleIndex; if (_numExistingSamples < _numSamples) { + newSampleIndex = _numExistingSamples; _numExistingSamples++; + + // update _indexOfPercentile + float index = _percentile * (float)(_numExistingSamples - 1); + _indexOfPercentile = (int)(index + 0.5f); // round to int } else { for (int i = 0; i < _numExistingSamples; i++) { @@ -72,9 +79,8 @@ void MovingMedian::updateMedian(float sample) { newSampleIndex--; } - - // find new median - _median = _samplesSorted[_numExistingSamples/2]; + // find new value at percentile + _valueAtPercentile = _samplesSorted[_indexOfPercentile]; /* printf(" new median: %f\n", _median); diff --git a/libraries/shared/src/MovingPercentile.h b/libraries/shared/src/MovingPercentile.h new file mode 100644 index 0000000000..374b039985 --- /dev/null +++ b/libraries/shared/src/MovingPercentile.h @@ -0,0 +1,29 @@ + +#ifndef hifi_MovingPercentile_h +#define hifi_MovingPercentile_h + + +class MovingPercentile { + +public: + MovingPercentile(int numSamples, float percentile = 0.5f); + ~MovingPercentile(); + + void updatePercentile(float sample); + float getValueAtPercentile() const { return _valueAtPercentile; } + + +private: + const int _numSamples; + const float _percentile; + + float* _samplesSorted; + int* _sampleAges; // _sampleAges[i] is the "age" of the sample at _sampleSorted[i] (higher means older) + int _numExistingSamples; + + float _valueAtPercentile; + + int _indexOfPercentile; +}; + +#endif \ No newline at end of file From 6f4593911365f1e55f14e7f385158a51caf57a4f Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 11:02:31 -0700 Subject: [PATCH 25/71] re-enabled piggy-backing in OctreeSendThread --- assignment-client/src/octree/OctreeSendThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index f5f9a90339..9e4dbcd347 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -149,7 +149,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes int piggyBackSize = nodeData->getPacketLength() + statsMessageLength; // If the size of the stats message and the voxel message will fit in a packet, then piggyback them -if (false && piggyBackSize < MAX_PACKET_SIZE) { + if (piggyBackSize < MAX_PACKET_SIZE) { // copy voxel message to back of stats message memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); From b452d084955a4be20135e8c141af9d9f94136196 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 11:20:29 -0700 Subject: [PATCH 26/71] cleaned up debug statements also reorganized MovingPercentile a little bit --- interface/src/DatagramProcessor.cpp | 111 +------------------ interface/src/DatagramProcessor.h | 26 ----- interface/src/main.cpp | 20 ---- libraries/networking/src/LimitedNodeList.cpp | 14 --- libraries/networking/src/Node.cpp | 8 +- libraries/networking/src/Node.h | 3 +- libraries/networking/src/NodeList.cpp | 23 +--- libraries/networking/src/NodeList.h | 4 +- libraries/shared/src/MovingPercentile.cpp | 47 ++------ libraries/shared/src/MovingPercentile.h | 2 +- 10 files changed, 26 insertions(+), 232 deletions(-) diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 898c4dcd53..ccbd793e6b 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -25,39 +25,7 @@ DatagramProcessor::DatagramProcessor(QObject* parent) : } - -// DEBUG - -int DatagramProcessor::skewsI[10000]; -int DatagramProcessor::S = 0; - -unsigned char DatagramProcessor::typesI[10000]; -int DatagramProcessor::diffsI[10000]; -int DatagramProcessor::I = 0; - - - -quint64 DatagramProcessor::prevTime = 0; - -unsigned char DatagramProcessor::typesA[100]; -quint64 DatagramProcessor::timesA[100]; -int DatagramProcessor::A = 1; - -unsigned char DatagramProcessor::typesB[100]; -quint64 DatagramProcessor::timesB[100]; -int DatagramProcessor::B = 1; - -unsigned char* DatagramProcessor::currTypes = typesA; -unsigned char* DatagramProcessor::prevTypes = typesB; -quint64* DatagramProcessor::currTimes = timesA; -quint64* DatagramProcessor::prevTimes = timesB; -int* DatagramProcessor::currN = &A; -int* DatagramProcessor::prevN = &B; - - - void DatagramProcessor::processDatagrams() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "DatagramProcessor::processDatagrams()"); @@ -68,29 +36,6 @@ void DatagramProcessor::processDatagrams() { Application* application = Application::getInstance(); NodeList* nodeList = NodeList::getInstance(); - - -prevTime = prevTimes[*prevN-1]; - -// swap -unsigned char* temp = currTypes; -currTypes = prevTypes; -prevTypes = temp; -// swap -quint64* temp2 = currTimes; -currTimes = prevTimes; -prevTimes = temp2; -// swap -int* temp3 = currN; -currN = prevN; -prevN = temp3; - -// reset -*currN = 0; - -int skew = 0; - - while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) { incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(), @@ -101,14 +46,8 @@ int skew = 0; if (nodeList->packetVersionAndHashMatch(incomingPacket)) { -PacketType type = packetTypeForPacket(incomingPacket); -currTimes[*currN] = usecTimestampNow(); -currTypes[*currN] = (unsigned char)type; -(*currN)++; - - // only process this packet if we have a match on the packet version - switch (type) { //packetTypeForPacket(incomingPacket)) { + switch (packetTypeForPacket(incomingPacket)) { case PacketTypeMixedAudio: QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection, Q_ARG(QByteArray, incomingPacket)); @@ -208,55 +147,9 @@ currTypes[*currN] = (unsigned char)type; break; } default: - int s = nodeList->processNodeData(senderSockAddr, incomingPacket); - if (s!=1234567890 && abs(s) > abs(skew)) - skew = s; + nodeList->processNodeData(senderSockAddr, incomingPacket); break; } } } - - - if (abs(skew) > 3000) { - - printf("large skew! %d ----------------------------\n", skew); - - skewsI[S++] = skew; - - /* - printf("prev:::::::::::::::::::::::::::::::::::::\n"); - - printf("\t type: %d time: %llu diff: %llu\n", prevTypes[0], prevTimes[0] % 100000000, prevTimes[0] - prevTime); - for (int i = 1; i < *prevN; i++) { - printf("\t type: %d time: %llu diff: %llu\n", prevTypes[i], prevTimes[i] % 100000000, prevTimes[i] - prevTimes[i - 1]); - } - - printf("curr:::::::::::::::::::::::::::::::::::::\n"); - - printf("\t type: %d time: %llu diff: %llu\n", currTypes[0], currTimes[0] % 100000000, currTimes[0] - prevTimes[*prevN - 1]); - for (int i = 1; i < *currN; i++) { - printf("\t type: %d time: %llu diff: %llu\n", currTypes[i], currTimes[i] % 100000000, currTimes[i] - currTimes[i - 1]); - }*/ - - diffsI[I++] = -2; // prev marker - - typesI[I] = prevTypes[0]; - diffsI[I++] = prevTimes[0] - prevTime; - for (int i = 1; i < *prevN; i++) { - typesI[I] = prevTypes[i]; - diffsI[I++] = prevTimes[i] - prevTimes[i - 1]; - } - - - diffsI[I++] = -1; // curr marker - - typesI[I] = currTypes[0]; - diffsI[I++] = currTimes[0] - prevTimes[*prevN - 1]; - for (int i = 1; i < *currN; i++) { - typesI[I] = currTypes[i]; - diffsI[I++] = currTimes[i] - currTimes[i - 1]; - } - } - - skew = 0; } diff --git a/interface/src/DatagramProcessor.h b/interface/src/DatagramProcessor.h index 245b2235b4..7d337ec02b 100644 --- a/interface/src/DatagramProcessor.h +++ b/interface/src/DatagramProcessor.h @@ -29,32 +29,6 @@ public slots: private: int _packetCount; int _byteCount; - -public: - // DEBUG - - static int skewsI[]; - static int S; - - static unsigned char typesI[]; - static int diffsI[]; - static int I; - - - static quint64 prevTime; - - static unsigned char typesA[]; - static quint64 timesA[]; - static int A; - - static unsigned char typesB[]; - static quint64 timesB[]; - static int B; - - - static unsigned char* currTypes, *prevTypes; - static quint64* currTimes, *prevTimes; - static int* currN, *prevN; }; #endif // hifi_DatagramProcessor_h diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 59e0b0b3dd..7e5b539eb1 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -46,25 +46,5 @@ int main(int argc, const char * argv[]) { exitCode = app.exec(); } qDebug("Normal exit."); - -int s = 0; -for (int i = 0; i < DatagramProcessor::I; i++) { - - switch (DatagramProcessor::diffsI[i]) { - case -2: - printf("\nskew: %d\n", DatagramProcessor::skewsI[s++]); - printf("prev:::::::::::::::::::::::::::::::\n"); - break; - case -1: - printf("curr:::::::::::::::::::::::::::::::\n"); - break; - default: - printf("\t type: %d diff: %d\n", DatagramProcessor::typesI[i], DatagramProcessor::diffsI[i]); - break; - } -} - - - return exitCode; } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index cc11c2d322..3823ddc426 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -172,11 +172,6 @@ quint64 end; versionDebugSuppressMap.insert(senderUUID, checkType); } - - - if ((end=usecTimestampNow()) - start > 100) { - printf("\t\t\t\t version and hash match long diff: %d\n", end-start); - } return false; } @@ -187,11 +182,6 @@ quint64 end; if (sendingNode) { // check if the md5 hash in the header matches the hash we would expect if (hashFromPacketHeader(packet) == hashForPacketAndConnectionUUID(packet, sendingNode->getConnectionSecret())) { - - if ((end = usecTimestampNow()) - start > 100) { - printf("\t\t\t\t version and hash match long diff: %d\n", end - start); - } - return true; } else { qDebug() << "Packet hash mismatch on" << checkType << "- Sender" @@ -210,10 +200,6 @@ quint64 end; return true; } - - if ((end = usecTimestampNow()) - start > 100) { - printf("\t\t\t\t version and hash match long diff: %d\n", end - start); - } return false; } diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index b241031e2d..360172efde 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -58,7 +58,7 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, _isAlive(true), _clockSkewUsec(0), _mutex(), - _clockSkewMovingPercentile(30, 0.8f) // moving upper quartile of 21 samples + _clockSkewMovingPercentile(30, 0.8f) // moving 80th percentile of 30 samples { } @@ -134,11 +134,9 @@ float Node::getAverageKilobitsPerSecond() { } } -void Node::setClockSkewUsec(int clockSkew) { - _clockSkewMovingPercentile.updatePercentile((float)clockSkew); +void Node::updateClockSkewUsec(int clockSkewSample) { + _clockSkewMovingPercentile.updatePercentile((float)clockSkewSample); _clockSkewUsec = (int)_clockSkewMovingPercentile.getValueAtPercentile(); - - //_clockSkewUsec = clockSkew; } QDataStream& operator<<(QDataStream& out, const Node& node) { diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 033ae01380..74f2fdfb70 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -96,7 +96,7 @@ public: void setPingMs(int pingMs) { _pingMs = pingMs; } int getClockSkewUsec() const { return _clockSkewUsec; } - void setClockSkewUsec(int clockSkew); + void updateClockSkewUsec(int clockSkewSample); QMutex& getMutex() { return _mutex; } friend QDataStream& operator<<(QDataStream& out, const Node& node); @@ -122,7 +122,6 @@ private: int _pingMs; int _clockSkewUsec; QMutex _mutex; - MovingPercentile _clockSkewMovingPercentile; }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 43b4f56361..9a298ce26c 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -77,7 +77,7 @@ qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) { return writeUnverifiedDatagram(statsPacket, _domainHandler.getSockAddr()); } -int NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { +void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); @@ -96,10 +96,7 @@ int NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& s int clockSkew = othersReplyTime - othersExprectedReply; sendingNode->setPingMs(pingTime / 1000); - sendingNode->setClockSkewUsec(clockSkew); - -printf("\t\t clock skew sample: %d val at percentile: %d\n", clockSkew, sendingNode->getClockSkewUsec()); - + sendingNode->updateClockSkewUsec(clockSkew); const bool wantDebug = false; @@ -113,14 +110,9 @@ printf("\t\t clock skew sample: %d val at percentile: %d\n", clockSkew, sending " othersExprectedReply: " << othersExprectedReply << "\n" << " clockSkew: " << clockSkew; } - -///if (abs(clockSkew) > 1000) -//printf("clockskew = %d \n", clockSkew); - -return clockSkew; } -int NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) { +void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) { switch (packetTypeForPacket(packet)) { case PacketTypeDomainList: { processDomainServerList(packet); @@ -160,8 +152,7 @@ int NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArr activateSocketFromNodeCommunication(packet, sendingNode); // set the ping time for this node for stat collection - return timePingReply(packet, sendingNode); - + timePingReply(packet, sendingNode); } break; @@ -176,7 +167,6 @@ int NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArr LimitedNodeList::processNodeData(senderSockAddr, packet); break; } -return 1234567890; } void NodeList::reset() { @@ -489,11 +479,8 @@ QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) { QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypePingReply); QDataStream packetStream(&replyPacket, QIODevice::Append); -quint64 now; - packetStream << typeFromOriginalPing << timeFromOriginalPing << (now = usecTimestampNow()); + packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); - -printf("\n>>>>>>>> recv ping: %llu reply: %llu diff: %lld\n", timeFromOriginalPing, now, (qint64)now-(qint64)timeFromOriginalPing); return replyPacket; } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 8609dce589..af0bfeb368 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -63,7 +63,7 @@ public: void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes); void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); } -int processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet); + void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet); int processDomainServerList(const QByteArray& packet); @@ -95,7 +95,7 @@ private: void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); -int timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); + void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); NodeType_t _ownerType; NodeSet _nodeTypesOfInterest; diff --git a/libraries/shared/src/MovingPercentile.cpp b/libraries/shared/src/MovingPercentile.cpp index 063fd641e9..ba2b919d32 100644 --- a/libraries/shared/src/MovingPercentile.cpp +++ b/libraries/shared/src/MovingPercentile.cpp @@ -1,5 +1,4 @@ #include "MovingPercentile.h" -//#include "stdio.h"// DEBUG MovingPercentile::MovingPercentile(int numSamples, float percentile) : _numSamples(numSamples), @@ -19,14 +18,15 @@ MovingPercentile::~MovingPercentile() { void MovingPercentile::updatePercentile(float sample) { -//printf("\nnew sample: %2.2f ", sample); + // age all current samples by 1 + for (int i = 0; i < _numExistingSamples; i++) { + _sampleAges[i]++; + } // find index in _samplesSorted to insert new sample. - // if samples have not been filled yet, this will be the next empty spot - // otherwise, it will be the spot of the oldest sample int newSampleIndex; if (_numExistingSamples < _numSamples) { - + // if samples have not been filled yet, this will be the next empty spot newSampleIndex = _numExistingSamples; _numExistingSamples++; @@ -35,19 +35,9 @@ void MovingPercentile::updatePercentile(float sample) { _indexOfPercentile = (int)(index + 0.5f); // round to int } else { - for (int i = 0; i < _numExistingSamples; i++) { - if (_sampleAges[i] == _numExistingSamples - 1) { - newSampleIndex = i; - break; - } - } - } - -//printf("will be inserted at index %d\n", newSampleIndex); - - // update _sampleAges to reflect new sample (age all samples by 1) - for (int i = 0; i < _numExistingSamples; i++) { - _sampleAges[i]++; + // if samples have been filled, it will be the spot of the oldest sample + newSampleIndex = 0; + while (_sampleAges[newSampleIndex] != _numExistingSamples) { newSampleIndex++; } } // insert new sample at that index @@ -56,11 +46,8 @@ void MovingPercentile::updatePercentile(float sample) { // swap new sample with neighboring elements in _samplesSorted until it's in sorted order // try swapping up first, then down. element will only be swapped one direction. - - float neighborSample; - while (newSampleIndex < _numExistingSamples-1 && sample > (neighborSample = _samplesSorted[newSampleIndex+1])) { -//printf("\t swapping up...\n"); - _samplesSorted[newSampleIndex] = neighborSample; + while (newSampleIndex < _numExistingSamples-1 && sample > _samplesSorted[newSampleIndex+1]) { + _samplesSorted[newSampleIndex] = _samplesSorted[newSampleIndex + 1]; _samplesSorted[newSampleIndex+1] = sample; _sampleAges[newSampleIndex] = _sampleAges[newSampleIndex+1]; @@ -68,9 +55,8 @@ void MovingPercentile::updatePercentile(float sample) { newSampleIndex++; } - while (newSampleIndex > 0 && sample < (neighborSample = _samplesSorted[newSampleIndex - 1])) { -//printf("\t swapping down...\n"); - _samplesSorted[newSampleIndex] = neighborSample; + while (newSampleIndex > 0 && sample < _samplesSorted[newSampleIndex - 1]) { + _samplesSorted[newSampleIndex] = _samplesSorted[newSampleIndex - 1]; _samplesSorted[newSampleIndex - 1] = sample; _sampleAges[newSampleIndex] = _sampleAges[newSampleIndex - 1]; @@ -81,13 +67,4 @@ void MovingPercentile::updatePercentile(float sample) { // find new value at percentile _valueAtPercentile = _samplesSorted[_indexOfPercentile]; -/* -printf(" new median: %f\n", _median); - -// debug: -for (int i = 0; i < _numExistingSamples; i++) { - printf("%2.2f (%d), ", _samplesSorted[i], _sampleAges[i]); } -printf("\n\n"); -*/ -} \ No newline at end of file diff --git a/libraries/shared/src/MovingPercentile.h b/libraries/shared/src/MovingPercentile.h index 374b039985..d4a43363e1 100644 --- a/libraries/shared/src/MovingPercentile.h +++ b/libraries/shared/src/MovingPercentile.h @@ -26,4 +26,4 @@ private: int _indexOfPercentile; }; -#endif \ No newline at end of file +#endif From 729c01ddbfacfd0b02be57adfcb5ed36e9c90d4c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 11:25:38 -0700 Subject: [PATCH 27/71] remove more getHybridTransform() calls --- interface/src/renderer/Model.cpp | 24 ++++++++++-------------- interface/src/renderer/Model.h | 2 -- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index f603dea55a..52037acb2f 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -987,16 +987,16 @@ void Model::updateShapePositions() { glm::vec3 rootPosition(0.0f); _boundingRadius = 0.0f; float uniformScale = extractUniformScale(_scale); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); for (int i = 0; i < _jointStates.size(); i++) { - const FBXJoint& joint = geometry.joints[i]; + const JointState& state = _jointStates[i]; + const FBXJoint& joint = state.getFBXJoint(); // shape position and rotation need to be in world-frame - glm::quat rotationInWorldFrame = _rotation * _jointStates[i].getRotationInModelFrame(); - glm::vec3 jointToShapeOffset = uniformScale * (rotationInWorldFrame * joint.shapePosition); - glm::vec3 worldPosition = extractTranslation(_jointStates[i].getHybridTransform()) + jointToShapeOffset + _translation; + glm::quat stateRotation = state.getRotationInModelFrame(); + glm::vec3 shapeOffset = uniformScale * (stateRotation * joint.shapePosition); + glm::vec3 worldPosition = _translation + _rotation * (state.getPositionInModelFrame() + shapeOffset); Shape* shape = _jointShapes[i]; shape->setPosition(worldPosition); - shape->setRotation(rotationInWorldFrame * joint.shapeRotation); + shape->setRotation(_rotation * stateRotation * joint.shapeRotation); float distance = glm::distance(worldPosition, _translation) + shape->getBoundingRadius(); if (distance > _boundingRadius) { _boundingRadius = distance; @@ -1018,12 +1018,12 @@ bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct float radiusScale = extractUniformScale(_scale); for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; - glm::vec3 end = extractTranslation(_jointStates[i].getHybridTransform()); + glm::vec3 end = _jointStates[i].getPositionInWorldFrame(_rotation, _translation); float endRadius = joint.boneRadius * radiusScale; glm::vec3 start = end; float startRadius = joint.boneRadius * radiusScale; if (joint.parentIndex != -1) { - start = extractTranslation(_jointStates[joint.parentIndex].getHybridTransform()); + start = _jointStates[joint.parentIndex].getPositionInWorldFrame(_rotation, _translation); startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale; } // for now, use average of start and end radii @@ -1245,12 +1245,13 @@ void Model::simulateInternal(float deltaTime) { } } + glm::mat4 modelToWorld = glm::mat4_cast(_rotation); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = _jointStates[cluster.jointIndex].getHybridTransform() * cluster.inverseBindMatrix; + state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransformInModelFrame() * cluster.inverseBindMatrix; } } @@ -2018,11 +2019,6 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) { } } -glm::mat4 Model::getBaseTransform(const glm::mat4& geometryOffset) const { - //return glm::translate(_translation) * glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometryOffset; - return glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometryOffset; -} - // ---------------------------------------------------------------------------- // JointState TODO: move this class to its own files // ---------------------------------------------------------------------------- diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index e4c25c8937..9004003d77 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -221,8 +221,6 @@ public: const CapsuleShape& getBoundingShape() const { return _boundingShape; } - glm::mat4 getBaseTransform(const glm::mat4& geometryOffset) const; - protected: QSharedPointer _geometry; From 25e2f28b024f15967940ab56a338359da2034a05 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 11:30:35 -0700 Subject: [PATCH 28/71] more cleanup --- interface/src/DatagramProcessor.cpp | 3 +-- interface/src/main.cpp | 3 --- libraries/networking/src/LimitedNodeList.cpp | 11 +---------- libraries/shared/src/MovingPercentile.cpp | 14 ++++++++++++-- libraries/shared/src/MovingPercentile.h | 10 +++++++++- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index ccbd793e6b..56078c1a8d 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -35,7 +35,7 @@ void DatagramProcessor::processDatagrams() { Application* application = Application::getInstance(); NodeList* nodeList = NodeList::getInstance(); - + while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) { incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(), @@ -45,7 +45,6 @@ void DatagramProcessor::processDatagrams() { _byteCount += incomingPacket.size(); if (nodeList->packetVersionAndHashMatch(incomingPacket)) { - // only process this packet if we have a match on the packet version switch (packetTypeForPacket(incomingPacket)) { case PacketTypeMixedAudio: diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 7e5b539eb1..2bb0633f24 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -15,9 +15,6 @@ #include #include -// DEBUG!!!!!! -#include "DatagramProcessor.h" - int main(int argc, const char * argv[]) { QElapsedTimer startupTime; startupTime.start(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 3823ddc426..8c24ef25a4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -151,10 +151,6 @@ void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { } bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { - -quint64 start = usecTimestampNow(); -quint64 end; - PacketType checkType = packetTypeForPacket(packet); int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data()); @@ -192,14 +188,9 @@ quint64 end; << uuidFromPacketHeader(packet); } } else { - - if ((end = usecTimestampNow()) - start > 100) { - printf("\t\t\t\t version and hash match long diff: %d\n", end - start); - } - return true; } - + return false; } diff --git a/libraries/shared/src/MovingPercentile.cpp b/libraries/shared/src/MovingPercentile.cpp index ba2b919d32..07b633e93e 100644 --- a/libraries/shared/src/MovingPercentile.cpp +++ b/libraries/shared/src/MovingPercentile.cpp @@ -1,3 +1,13 @@ +// +// MovingPercentile.cpp +// libraries/shared/src +// +// Created by Yixin Wang on 6/4/2014 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + #include "MovingPercentile.h" MovingPercentile::MovingPercentile(int numSamples, float percentile) @@ -23,7 +33,7 @@ void MovingPercentile::updatePercentile(float sample) { _sampleAges[i]++; } - // find index in _samplesSorted to insert new sample. + // find index at which to insert new sample in _samplesSorted int newSampleIndex; if (_numExistingSamples < _numSamples) { // if samples have not been filled yet, this will be the next empty spot @@ -40,7 +50,7 @@ void MovingPercentile::updatePercentile(float sample) { while (_sampleAges[newSampleIndex] != _numExistingSamples) { newSampleIndex++; } } - // insert new sample at that index + // insert new sample _samplesSorted[newSampleIndex] = sample; _sampleAges[newSampleIndex] = 0; diff --git a/libraries/shared/src/MovingPercentile.h b/libraries/shared/src/MovingPercentile.h index d4a43363e1..94a4f36da5 100644 --- a/libraries/shared/src/MovingPercentile.h +++ b/libraries/shared/src/MovingPercentile.h @@ -1,8 +1,16 @@ +// +// MovingPercentile.h +// libraries/shared/src +// +// Created by Yixin Wang on 6/4/2014 +// +// 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_MovingPercentile_h #define hifi_MovingPercentile_h - class MovingPercentile { public: From 480efcbe76c5153bad3954814bad1d879ab7236d Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 11:31:44 -0700 Subject: [PATCH 29/71] more cleanup again --- libraries/networking/src/Node.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 74f2fdfb70..85fe2e4458 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -23,7 +23,6 @@ #include "HifiSockAddr.h" #include "NodeData.h" #include "SimpleMovingAverage.h" - #include "MovingPercentile.h" typedef quint8 NodeType_t; From 5d8e3d447aadcd2dd041dd9feb12d722a511e23b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 11:36:00 -0700 Subject: [PATCH 30/71] remove JointState::getRota/PositionInWorldFrame() instead: use getRotat/PositionInModelFrame() and do math --- interface/src/renderer/Model.cpp | 14 +++----------- interface/src/renderer/Model.h | 3 --- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 52037acb2f..daf87486ac 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -775,7 +775,7 @@ bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _jointStates[jointIndex].getRotationInWorldFrame(_rotation); + rotation = _rotation * _jointStates[jointIndex].getRotationInModelFrame(); return true; } @@ -1018,12 +1018,12 @@ bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct float radiusScale = extractUniformScale(_scale); for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; - glm::vec3 end = _jointStates[i].getPositionInWorldFrame(_rotation, _translation); + glm::vec3 end = _translation + _rotation * _jointStates[i].getPositionInModelFrame(); float endRadius = joint.boneRadius * radiusScale; glm::vec3 start = end; float startRadius = joint.boneRadius * radiusScale; if (joint.parentIndex != -1) { - start = _jointStates[joint.parentIndex].getPositionInWorldFrame(_rotation, _translation); + start = _translation + _rotation * _jointStates[joint.parentIndex].getPositionInModelFrame(); startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale; } // for now, use average of start and end radii @@ -2053,14 +2053,6 @@ void JointState::computeTransformInModelFrame(const glm::mat4& parentTransform) _rotationInModelFrame = extractRotation(_transformInModelFrame); } -glm::quat JointState::getRotationInWorldFrame(const glm::quat& baseRotation) const { - return baseRotation * _rotationInModelFrame; -} - -glm::vec3 JointState::getPositionInWorldFrame(const glm::quat& baseRotation, const glm::vec3& basePosition) const { - return basePosition + baseRotation * extractTranslation(_transformInModelFrame); -} - void JointState::computeTransforms(const glm::mat4& parentTransform, const glm::quat& baseRotation) { assert(_fbxJoint != NULL); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 9004003d77..649f5ac069 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -46,9 +46,6 @@ public: glm::quat getRotationInModelFrame() const { return _rotationInModelFrame; } glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transformInModelFrame); } - glm::quat getRotationInWorldFrame(const glm::quat& baseRotation) const; - glm::vec3 getPositionInWorldFrame(const glm::quat& baseRotation, const glm::vec3& basePosition) const; - /// computes new _transform and _combinedRotation void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); From 2b851453255ed6ff8e42e9d27db88ac7d60ef6db Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 11:41:09 -0700 Subject: [PATCH 31/71] added test suite for PropertyFlags, latest work on PropertyFlags --- libraries/shared/src/PropertyFlags.h | 190 ++++++++++++++++++++++++--- tests/octree/CMakeLists.txt | 39 ++++++ tests/octree/src/OctreeTests.cpp | 143 ++++++++++++++++++++ tests/octree/src/OctreeTests.h | 22 ++++ tests/octree/src/main.cpp | 16 +++ 5 files changed, 392 insertions(+), 18 deletions(-) create mode 100644 tests/octree/CMakeLists.txt create mode 100644 tests/octree/src/OctreeTests.cpp create mode 100644 tests/octree/src/OctreeTests.h create mode 100644 tests/octree/src/main.cpp diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index b5758f2206..d8131d0c75 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -11,49 +11,65 @@ // // TODO: // * implement decode -// * add operators +// * more operators, operator==, operator!=, operator!, operator~ +// * iterator to enumerate the set values? +// * operator<<(enum) to work similar to set #ifndef hifi_PropertyFlags_h #define hifi_PropertyFlags_h +#include +#include + #include #include +#include + templateclass PropertyFlags { public: typedef Enum enum_type; - inline PropertyFlags() : _maxFlag(-1) { }; + inline PropertyFlags() : _maxFlag(INT_MIN), _minFlag(INT_MAX) { }; inline PropertyFlags(const PropertyFlags& other) : _flags(other._flags), _maxFlag(other._maxFlag) {} - inline PropertyFlags(Enum flag) : _maxFlag(-1) { setHasProperty(flag); } + inline PropertyFlags(Enum flag) : _maxFlag(INT_MIN), _minFlag(INT_MAX) { setHasProperty(flag); } - void clear() { _flags.clear(); _maxFlag = -1; } + void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; } + Enum firstFlag() const { return _minFlag; } + Enum lastFlag() const { return _maxFlag; } + void setHasProperty(Enum flag, bool value = true); bool getHasProperty(Enum flag); QByteArray encode(); void decode(const QByteArray& fromEncoded); - inline PropertyFlags& operator=(const PropertyFlags &other) { _flags = other._flags; _maxFlag = other._maxFlag; return *this; } + PropertyFlags& operator=(const PropertyFlags &other); - inline PropertyFlags& operator|=(PropertyFlags other) { _flags |= other._flags; _maxFlag = max(_maxFlag, other._maxFlag); return *this; } - inline PropertyFlags& operator|=(Enum flag) { PropertyFlags other(flag); _flags |= other._flags; _maxFlag = max(_maxFlag, other._maxFlag); return *this; } + PropertyFlags& operator|=(PropertyFlags other); + PropertyFlags& operator|=(Enum flag); - inline PropertyFlags& operator&=(PropertyFlags other) { _flags &= other._flags; shinkIfNeeded(); return *this; } - inline PropertyFlags& operator&=(Enum flag) { PropertyFlags other(flag); _flags &= other._flags; shinkIfNeeded(); return *this; } + PropertyFlags& operator&=(PropertyFlags other); + PropertyFlags& operator&=(Enum flag); - inline PropertyFlags& operator^=(PropertyFlags other) { _flags ^= other._flags; shinkIfNeeded(); return *this; } - inline PropertyFlags& operator^=(Enum flag) { PropertyFlags other(flag); _flags ^= other._flags; shinkIfNeeded(); return *this; } + PropertyFlags& operator^=(PropertyFlags other); + PropertyFlags& operator^=(Enum flag); + PropertyFlags& operator-=(PropertyFlags other); + PropertyFlags& operator-=(Enum flag); - inline PropertyFlags operator|(PropertyFlags other) const { PropertyFlags result(*this); result |= other; return result; } - inline PropertyFlags operator|(Enum flag) const { PropertyFlags result(*this); PropertyFlags other(flag); result |= other; return result; } + PropertyFlags operator|(PropertyFlags other) const; + PropertyFlags operator|(Enum flag) const; - inline PropertyFlags operator^(PropertyFlags other) const { PropertyFlags result(*this); result ^= other; return result; } - inline PropertyFlags operator^(Enum flag) const { PropertyFlags result(*this); PropertyFlags other(flag); result ^= other; return result; } + PropertyFlags operator&(PropertyFlags other) const; + PropertyFlags operator&(Enum flag) const; + + PropertyFlags operator^(PropertyFlags other) const; + PropertyFlags operator^(Enum flag) const; + + PropertyFlags operator-(PropertyFlags other) const; + PropertyFlags operator-(Enum flag) const; - inline PropertyFlags operator&(PropertyFlags other) const { PropertyFlags result(*this); result &= other; return result; } - inline PropertyFlags operator&(Enum flag) const { PropertyFlags result(*this); PropertyFlags other(flag); result &= other; return result; } /* inline PropertyFlags operator~() const { return PropertyFlags(Enum(~i)); } @@ -63,13 +79,21 @@ public: private: void shinkIfNeeded(); + void debugDumpBits(); QBitArray _flags; int _maxFlag; + int _minFlag; }; template inline void PropertyFlags::setHasProperty(Enum flag, bool value) { + // keep track of our min flag + if (flag < _minFlag) { + if (value) { + _minFlag = flag; + } + } if (flag > _maxFlag) { if (value) { _maxFlag = flag; @@ -78,7 +102,6 @@ template inline void PropertyFlags::setHasProperty(Enum fla return; // bail early, we're setting a flag outside of our current _maxFlag to false, which is already the default } } - qDebug() << "_flags.setBit("< inline QByteArray PropertyFlags::encode() { template inline void PropertyFlags::decode(const QByteArray& fromEncoded) { } +template inline void PropertyFlags::debugDumpBits() { + for(int i = 0; i < _flags.size(); i++) { + qDebug() << "bit[" << i << "]=" << _flags.at(i); + } +} + + +template inline PropertyFlags& PropertyFlags::operator=(const PropertyFlags &other) { + _flags = other._flags; + _maxFlag = other._maxFlag; + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator|=(PropertyFlags other) { + _flags |= other._flags; + _maxFlag = std::max(_maxFlag, other._maxFlag); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator|=(Enum flag) { + PropertyFlags other(flag); + _flags |= other._flags; + _maxFlag = std::max(_maxFlag, other._maxFlag); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator&=(PropertyFlags other) { + _flags &= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator&=(Enum flag) { + PropertyFlags other(flag); + _flags &= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator^=(PropertyFlags other) { + _flags ^= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator^=(Enum flag) { + PropertyFlags other(flag); + _flags ^= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { + for(int flag = other.firstFlag(); flag <= other.lastFlag(); flag++) { + //qDebug() << "checking other.getHasProperty(flag) flag=" << flag; + if (other.getHasProperty(flag)) { + //qDebug() << "setting setHasProperty(flag) flag=" << flag; + setHasProperty(flag, false); + } + } + + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator-=(Enum flag) { + bool debug = false; + if (debug) { + qDebug() << "operator-=(Enum flag) flag=" << flag << "before..."; + debugDumpBits(); + } + setHasProperty(flag, false); + + if (debug) { + qDebug() << "after..."; + debugDumpBits(); + } + + return *this; +} + +template inline PropertyFlags PropertyFlags::operator|(PropertyFlags other) const { + PropertyFlags result(*this); + result |= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator|(Enum flag) const { + PropertyFlags result(*this); + PropertyFlags other(flag); + result |= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator&(PropertyFlags other) const { + PropertyFlags result(*this); + result &= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator&(Enum flag) const { + PropertyFlags result(*this); + PropertyFlags other(flag); + result &= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator^(PropertyFlags other) const { + PropertyFlags result(*this); + result ^= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator^(Enum flag) const { + PropertyFlags result(*this); + PropertyFlags other(flag); + result ^= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator-(PropertyFlags other) const { + PropertyFlags result(*this); + result -= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator-(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, false); + return result; +} + template inline void PropertyFlags::shinkIfNeeded() { bool maxFlagWas = _maxFlag; while (_maxFlag >= 0) { diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt new file mode 100644 index 0000000000..cbdfd02054 --- /dev/null +++ b/tests/octree/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 2.8) + +if (WIN32) + cmake_policy (SET CMP0020 NEW) +endif (WIN32) + +set(TARGET_NAME octree-tests) + +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(Qt5Network REQUIRED) +#find_package(Qt5Script REQUIRED) +#find_package(Qt5Widgets REQUIRED) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +include(${MACRO_DIR}/AutoMTC.cmake) +auto_mtc(${TARGET_NAME} ${ROOT_DIR}) + +#qt5_use_modules(${TARGET_NAME} Network Script Widgets) + +#include glm +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link in the shared libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) + +IF (WIN32) + #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) +ENDIF(WIN32) + diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp new file mode 100644 index 0000000000..1a66a0b2ae --- /dev/null +++ b/tests/octree/src/OctreeTests.cpp @@ -0,0 +1,143 @@ +// +// OctreeTests.h +// tests/physics/src +// +// Created by Brad Hefta-Gaub on 06/04/2014. +// Copyright 2014 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 "OctreeTests.h" + +enum ModelPropertyList { + PROP_PAGED_PROPERTY, + PROP_CUSTOM_PROPERTIES_INCLUDED, + PROP_VISIBLE, + PROP_POSITION, + PROP_RADIUS, + PROP_MODEL_URL, + PROP_ROTATION, + PROP_COLOR, + PROP_SCRIPT, + PROP_ANIMATION_URL, + PROP_ANIMATION_FPS, + PROP_ANIMATION_FRAME_INDEX, + PROP_ANIMATION_PLAYING, + PROP_SHOULD_BE_DELETED +}; + +typedef PropertyFlags ModelPropertyFlags; + +enum ParticlePropertyList { + PARTICLE_PROP_PAGED_PROPERTY, + PARTICLE_PROP_CUSTOM_PROPERTIES_INCLUDED, + PARTICLE_PROP_VISIBLE, + PARTICLE_PROP_POSITION, + PARTICLE_PROP_RADIUS, + PARTICLE_PROP_MODEL_URL, + PARTICLE_PROP_ROTATION, + PARTICLE_PROP_COLOR, + PARTICLE_PROP_SCRIPT, + PARTICLE_PROP_ANIMATION_URL, + PARTICLE_PROP_ANIMATION_FPS, + PARTICLE_PROP_ANIMATION_FRAME_INDEX, + PARTICLE_PROP_ANIMATION_PLAYING, + PARTICLE_PROP_SHOULD_BE_DELETED, + PARTICLE_PROP_VELOCITY, + PARTICLE_PROP_GRAVITY, + PARTICLE_PROP_DAMPING, + PARTICLE_PROP_MASS, + PARTICLE_PROP_LIFETIME, + PARTICLE_PROP_PAUSE_SIMULATION, +}; + +typedef PropertyFlags ParticlePropertyFlags; + + +void OctreeTests::propertyFlagsTests() { + qDebug() << "******************************************************************************************"; + qDebug() << "OctreeTests::propertyFlagsTests()"; + + { + qDebug() << "Test 1: ModelProperties: PROP_VISIBLE, PROP_POSITION, PROP_RADIUS, PROP_MODEL_URL, PROP_ROTATION"; + ModelPropertyFlags props; + props.setHasProperty(PROP_VISIBLE); + props.setHasProperty(PROP_POSITION); + props.setHasProperty(PROP_RADIUS); + props.setHasProperty(PROP_MODEL_URL); + props.setHasProperty(PROP_ROTATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 2: ParticlePropertyFlags: PROP_VISIBLE, PARTICLE_PROP_ANIMATION_URL, PARTICLE_PROP_ANIMATION_FPS, " + "PARTICLE_PROP_ANIMATION_FRAME_INDEX, PARTICLE_PROP_ANIMATION_PLAYING, PARTICLE_PROP_PAUSE_SIMULATION"; + ParticlePropertyFlags props2; + props2.setHasProperty(PARTICLE_PROP_VISIBLE); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_URL); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_FPS); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_FRAME_INDEX); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_PLAYING); + props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props2.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "Test 2b: remove flag with setHasProperty() PARTICLE_PROP_PAUSE_SIMULATION"; + + props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION, false); + + encoded = props2.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + } + + { + qDebug() << "Test 3: ParticlePropertyFlags: using | operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + | ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "Test 3b: remove flag with -= PARTICLE_PROP_PAUSE_SIMULATION"; + props -= PARTICLE_PROP_PAUSE_SIMULATION; + + encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + } + + + + qDebug() << "******************************************************************************************"; +} + +void OctreeTests::runAllTests() { + propertyFlagsTests(); +} diff --git a/tests/octree/src/OctreeTests.h b/tests/octree/src/OctreeTests.h new file mode 100644 index 0000000000..53b0d9fb83 --- /dev/null +++ b/tests/octree/src/OctreeTests.h @@ -0,0 +1,22 @@ +// +// OctreeTests.h +// tests/physics/src +// +// Created by Brad Hefta-Gaub on 06/04/2014. +// Copyright 2014 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_OctreeTests_h +#define hifi_OctreeTests_h + +namespace OctreeTests { + + void propertyFlagsTests(); + + void runAllTests(); +} + +#endif // hifi_OctreeTests_h diff --git a/tests/octree/src/main.cpp b/tests/octree/src/main.cpp new file mode 100644 index 0000000000..ec3dc19e01 --- /dev/null +++ b/tests/octree/src/main.cpp @@ -0,0 +1,16 @@ +// +// main.cpp +// tests/octree/src +// +// Copyright 2014 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 "OctreeTests.h" + +int main(int argc, char** argv) { + OctreeTests::runAllTests(); + return 0; +} From 19f0f453a5376253d62aa2200ef9df0069f142c6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 11:52:07 -0700 Subject: [PATCH 32/71] remove JointState::setRotation() instead use JointState::setRotationInModelFrame() --- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/renderer/Model.cpp | 8 -------- interface/src/renderer/Model.h | 4 +--- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 7004d12ffe..93374ef3d0 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -46,7 +46,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex); if (jointIndex != -1) { JointState& state = _jointStates[jointIndex]; - state.setRotation(_rotation * prioVR->getJointRotations().at(i), PALM_PRIORITY); + state.setRotationInModelFrame(prioVR->getJointRotations().at(i), PALM_PRIORITY); } } return; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index daf87486ac..d32293b9c5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -2074,14 +2074,6 @@ void JointState::restoreRotation(float fraction, float priority) { } } -void JointState::setRotation(const glm::quat& rotation, float priority) { - assert(_fbxJoint != NULL); - if (priority >= _animationPriority) { - _rotation = _rotation * glm::inverse(_combinedRotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); - _animationPriority = priority; - } -} - void JointState::setRotationInModelFrame(const glm::quat& rotation, float priority) { assert(_fbxJoint != NULL); if (priority >= _animationPriority) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 649f5ac069..8619cf9c22 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -58,14 +58,12 @@ public: void restoreRotation(float fraction, float priority); - /// \param rotation is from bind- to world-frame + /// \param rotation is from bind-frame to model-frame /// computes parent relative _rotation and sets that /// \warning no combined transforms are updated! - void setRotation(const glm::quat& rotation, float priority); void setRotationInModelFrame(const glm::quat& rotation, float priority); const glm::mat4& getHybridTransform() const { return _transform; } - //const glm::quat& getRotationInWorldFrame() const { return _combinedRotation; } void clearTransformTranslation(); glm::quat _rotation; // rotation relative to parent From ebfc405d9dc0717d8ff625478b26962e22db64cb Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 11:55:20 -0700 Subject: [PATCH 33/71] more cleanup 3 --- libraries/networking/src/LimitedNodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 8c24ef25a4..c0d7941edf 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -168,7 +168,7 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { versionDebugSuppressMap.insert(senderUUID, checkType); } - + return false; } From d46a90d7638f1533d13166e176e3a9b8f38dda9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 11:56:20 -0700 Subject: [PATCH 34/71] remove JointState::_combinedRotation instead use JointState::_rotationInModelFrame --- interface/src/renderer/Model.cpp | 14 +++++--------- interface/src/renderer/Model.h | 5 ++--- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d32293b9c5..3f2ac8c197 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -201,13 +201,12 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { if (parentIndex == -1) { _rootIndex = i; glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - state.computeTransforms(baseTransform, _rotation); + state.computeTransforms(baseTransform); ++numJointsSet; jointIsSet[i] = true; } else if (jointIsSet[parentIndex]) { const JointState& parentState = jointStates.at(parentIndex); - glm::quat parentRotation = _rotation * parentState.getRotationInModelFrame(); - state.computeTransforms(parentState.getHybridTransform(), parentRotation); + state.computeTransforms(parentState.getHybridTransform()); ++numJointsSet; jointIsSet[i] = true; } @@ -1280,11 +1279,10 @@ void Model::updateJointState(int index) { if (parentIndex == -1) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - state.computeTransforms(baseTransform, _rotation); + state.computeTransforms(baseTransform); } else { const JointState& parentState = _jointStates.at(parentIndex); - glm::quat parentRotation = _rotation * parentState.getRotationInModelFrame(); - state.computeTransforms(parentState.getHybridTransform(), parentRotation); + state.computeTransforms(parentState.getHybridTransform()); } } @@ -2039,7 +2037,6 @@ void JointState::copyState(const JointState& state) { _transformInModelFrame = state._transformInModelFrame; _rotationInModelFrame = extractRotation(_transformInModelFrame); - _combinedRotation = state._combinedRotation; _transform = state._transform; _animationPriority = state._animationPriority; @@ -2053,13 +2050,12 @@ void JointState::computeTransformInModelFrame(const glm::mat4& parentTransform) _rotationInModelFrame = extractRotation(_transformInModelFrame); } -void JointState::computeTransforms(const glm::mat4& parentTransform, const glm::quat& baseRotation) { +void JointState::computeTransforms(const glm::mat4& parentTransform) { assert(_fbxJoint != NULL); glm::quat modifiedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation; glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; - _combinedRotation = baseRotation * modifiedRotation; } glm::quat JointState::getRotationFromBindToModelFrame() const { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 8619cf9c22..e7fa2917ad 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -46,8 +46,8 @@ public: glm::quat getRotationInModelFrame() const { return _rotationInModelFrame; } glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transformInModelFrame); } - /// computes new _transform and _combinedRotation - void computeTransforms(const glm::mat4& baseTransform, const glm::quat& baseRotation); + /// computes new _transform + void computeTransforms(const glm::mat4& baseTransform); /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; @@ -72,7 +72,6 @@ public: private: glm::mat4 _transformInModelFrame; glm::quat _rotationInModelFrame; - glm::quat _combinedRotation; // rotation from joint local to world frame glm::mat4 _transform; // rotation to world frame + translation in model frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint From b1b7f6bdc48872b3ac611132ec247f6a36c1a4b7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 12:03:01 -0700 Subject: [PATCH 35/71] remove last world-frame transfoms from JointState --- interface/src/renderer/Model.cpp | 56 -------------------------------- interface/src/renderer/Model.h | 5 --- 2 files changed, 61 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3f2ac8c197..df6381d447 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -181,38 +181,6 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { state.computeTransformInModelFrame(parentState.getTransformInModelFrame()); } } - - // compute transforms - // Unfortunately, the joints are not neccessarily in order from parents to children, - // so we must iterate over the list multiple times until all are set correctly. - QVector jointIsSet; - jointIsSet.fill(false, numJoints); - int numJointsSet = 0; - int lastNumJointsSet = -1; - while (numJointsSet < numJoints && numJointsSet != lastNumJointsSet) { - lastNumJointsSet = numJointsSet; - for (int i = 0; i < numJoints; ++i) { - if (jointIsSet[i]) { - continue; - } - JointState& state = jointStates[i]; - const FBXJoint& joint = state.getFBXJoint(); - int parentIndex = joint.parentIndex; - if (parentIndex == -1) { - _rootIndex = i; - glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - state.computeTransforms(baseTransform); - ++numJointsSet; - jointIsSet[i] = true; - } else if (jointIsSet[parentIndex]) { - const JointState& parentState = jointStates.at(parentIndex); - state.computeTransforms(parentState.getHybridTransform()); - ++numJointsSet; - jointIsSet[i] = true; - } - } - } - return jointStates; } @@ -1274,16 +1242,6 @@ void Model::updateJointState(int index) { const JointState& parentState = _jointStates.at(parentIndex); state.computeTransformInModelFrame(parentState.getTransformInModelFrame()); } - - // compute hybrid transforms - if (parentIndex == -1) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - state.computeTransforms(baseTransform); - } else { - const JointState& parentState = _jointStates.at(parentIndex); - state.computeTransforms(parentState.getHybridTransform()); - } } bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, @@ -2034,11 +1992,8 @@ void JointState::setFBXJoint(const FBXJoint* joint) { void JointState::copyState(const JointState& state) { _rotation = state._rotation; - _transformInModelFrame = state._transformInModelFrame; _rotationInModelFrame = extractRotation(_transformInModelFrame); - _transform = state._transform; - _animationPriority = state._animationPriority; // DO NOT copy _fbxJoint } @@ -2050,14 +2005,6 @@ void JointState::computeTransformInModelFrame(const glm::mat4& parentTransform) _rotationInModelFrame = extractRotation(_transformInModelFrame); } -void JointState::computeTransforms(const glm::mat4& parentTransform) { - assert(_fbxJoint != NULL); - - glm::quat modifiedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation; - glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; - _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; -} - glm::quat JointState::getRotationFromBindToModelFrame() const { return _rotationInModelFrame * _fbxJoint->inverseBindRotation; } @@ -2079,9 +2026,6 @@ void JointState::setRotationInModelFrame(const glm::quat& rotation, float priori } void JointState::clearTransformTranslation() { - _transform[3][0] = 0.0f; - _transform[3][1] = 0.0f; - _transform[3][2] = 0.0f; _transformInModelFrame[3][0] = 0.0f; _transformInModelFrame[3][1] = 0.0f; _transformInModelFrame[3][2] = 0.0f; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index e7fa2917ad..9aeb6f68ba 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -46,9 +46,6 @@ public: glm::quat getRotationInModelFrame() const { return _rotationInModelFrame; } glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transformInModelFrame); } - /// computes new _transform - void computeTransforms(const glm::mat4& baseTransform); - /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; @@ -63,7 +60,6 @@ public: /// \warning no combined transforms are updated! void setRotationInModelFrame(const glm::quat& rotation, float priority); - const glm::mat4& getHybridTransform() const { return _transform; } void clearTransformTranslation(); glm::quat _rotation; // rotation relative to parent @@ -72,7 +68,6 @@ public: private: glm::mat4 _transformInModelFrame; glm::quat _rotationInModelFrame; - glm::mat4 _transform; // rotation to world frame + translation in model frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint }; From d32e14ca048e6667eef08d0b5c5fdad794b9596f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:27:28 -0700 Subject: [PATCH 36/71] renames of JointState data members --- interface/src/avatar/FaceModel.cpp | 4 +-- interface/src/avatar/SkeletonModel.cpp | 4 +-- interface/src/renderer/Model.cpp | 48 +++++++++++++------------- interface/src/renderer/Model.h | 18 +++++----- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 93cd93b71c..652ecdec32 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -51,7 +51,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX glm::mat3 axes = glm::mat3_cast(glm::quat()); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransformInModelFrame() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation))); - state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) + state._rotationInParentFrame = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0])) * joint.rotation; @@ -68,7 +68,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ _owningHead->getSaccade() - _translation, 1.0f)); glm::quat between = rotationBetween(front, lookAt); const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - state._rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * + state._rotationInParentFrame = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * joint.rotation; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 93374ef3d0..cf9b96cbd1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -200,7 +200,7 @@ void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { JointState& parentState = _jointStates[parentJointIndex]; parentState.setRotationInModelFrame(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity - _jointStates[jointIndex]._rotation = glm::quat(); + _jointStates[jointIndex]._rotationInParentFrame = glm::quat(); } else { setJointPositionInModelFrame(jointIndex, palmPosition, palmRotation, true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); @@ -239,7 +239,7 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::mat3 axes = glm::mat3_cast(glm::quat()); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransformInModelFrame() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); - state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), + state._rotationInParentFrame = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index df6381d447..d1a8587a5c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -459,7 +459,7 @@ void Model::reset() { } const FBXGeometry& geometry = _geometry->getFBXGeometry(); for (int i = 0; i < _jointStates.size(); i++) { - _jointStates[i]._rotation = geometry.joints.at(i).rotation; + _jointStates[i]._rotationInParentFrame = geometry.joints.at(i).rotation; } } @@ -669,7 +669,7 @@ bool Model::getJointState(int index, glm::quat& rotation) const { if (index == -1 || index >= _jointStates.size()) { return false; } - rotation = _jointStates.at(index)._rotation; + rotation = _jointStates.at(index)._rotationInParentFrame; const glm::quat& defaultRotation = _geometry->getFBXGeometry().joints.at(index).rotation; return glm::abs(rotation.x - defaultRotation.x) >= EPSILON || glm::abs(rotation.y - defaultRotation.y) >= EPSILON || @@ -682,7 +682,7 @@ void Model::setJointState(int index, bool valid, const glm::quat& rotation, floa JointState& state = _jointStates[index]; if (priority >= state._animationPriority) { if (valid) { - state._rotation = rotation; + state._rotationInParentFrame = rotation; state._animationPriority = priority; } else { state.restoreRotation(1.0f, priority); @@ -1932,7 +1932,7 @@ void AnimationHandle::simulate(float deltaTime) { if (mapping != -1) { JointState& state = _model->_jointStates[mapping]; if (_priority >= state._animationPriority) { - state._rotation = frame.rotations.at(i); + state._rotationInParentFrame = frame.rotations.at(i); state._animationPriority = _priority; } } @@ -1956,7 +1956,7 @@ void AnimationHandle::simulate(float deltaTime) { if (mapping != -1) { JointState& state = _model->_jointStates[mapping]; if (_priority >= state._animationPriority) { - state._rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction); + state._rotationInParentFrame = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction); state._animationPriority = _priority; } } @@ -1985,34 +1985,34 @@ JointState::JointState() : void JointState::setFBXJoint(const FBXJoint* joint) { assert(joint != NULL); - _rotation = joint->rotation; + _rotationInParentFrame = joint->rotation; // NOTE: JointState does not own the FBXJoint to which it points. _fbxJoint = joint; } void JointState::copyState(const JointState& state) { - _rotation = state._rotation; - _transformInModelFrame = state._transformInModelFrame; - _rotationInModelFrame = extractRotation(_transformInModelFrame); + _rotationInParentFrame = state._rotationInParentFrame; + _transform = state._transform; + _rotation = extractRotation(_transform); _animationPriority = state._animationPriority; // DO NOT copy _fbxJoint } void JointState::computeTransformInModelFrame(const glm::mat4& parentTransform) { - glm::quat modifiedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation; + glm::quat modifiedRotation = _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation; glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; - _transformInModelFrame = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; - _rotationInModelFrame = extractRotation(_transformInModelFrame); + _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; + _rotation = extractRotation(_transform); } glm::quat JointState::getRotationFromBindToModelFrame() const { - return _rotationInModelFrame * _fbxJoint->inverseBindRotation; + return _rotation * _fbxJoint->inverseBindRotation; } void JointState::restoreRotation(float fraction, float priority) { assert(_fbxJoint != NULL); if (priority == _animationPriority) { - _rotation = safeMix(_rotation, _fbxJoint->rotation, fraction); + _rotationInParentFrame = safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction); _animationPriority = 0.0f; } } @@ -2020,15 +2020,15 @@ void JointState::restoreRotation(float fraction, float priority) { void JointState::setRotationInModelFrame(const glm::quat& rotation, float priority) { assert(_fbxJoint != NULL); if (priority >= _animationPriority) { - _rotation = _rotation * glm::inverse(_rotationInModelFrame) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); + _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); _animationPriority = priority; } } void JointState::clearTransformTranslation() { - _transformInModelFrame[3][0] = 0.0f; - _transformInModelFrame[3][1] = 0.0f; - _transformInModelFrame[3][2] = 0.0f; + _transform[3][0] = 0.0f; + _transform[3][1] = 0.0f; + _transform[3][2] = 0.0f; } void JointState::applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain, float priority) { @@ -2040,15 +2040,15 @@ void JointState::applyRotationDeltaInModelFrame(const glm::quat& delta, bool con if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { // no constraints - _rotation = _rotation * glm::inverse(_rotationInModelFrame) * delta * _rotationInModelFrame; - _rotationInModelFrame = delta * _rotationInModelFrame; + _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation; + _rotation = delta * _rotation; return; } - glm::quat targetRotation = delta * _rotationInModelFrame; - glm::vec3 eulers = safeEulerAngles(_rotation * glm::inverse(_rotationInModelFrame) * targetRotation); + glm::quat targetRotation = delta * _rotation; + glm::vec3 eulers = safeEulerAngles(_rotationInParentFrame * glm::inverse(_rotation) * targetRotation); glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax)); - _rotationInModelFrame = _rotationInModelFrame * glm::inverse(_rotation) * newRotation; - _rotation = newRotation; + _rotation = _rotation * glm::inverse(_rotationInParentFrame) * newRotation; + _rotationInParentFrame = newRotation; } const glm::vec3& JointState::getDefaultTranslationInParentFrame() const { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 9aeb6f68ba..955207445b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -41,10 +41,10 @@ public: void copyState(const JointState& state); void computeTransformInModelFrame(const glm::mat4& parentTransform); - const glm::mat4& getTransformInModelFrame() const { return _transformInModelFrame; } + const glm::mat4& getTransformInModelFrame() const { return _transform; } - glm::quat getRotationInModelFrame() const { return _rotationInModelFrame; } - glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transformInModelFrame); } + glm::quat getRotationInModelFrame() const { return _rotation; } + glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transform); } /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; @@ -55,19 +55,19 @@ public: void restoreRotation(float fraction, float priority); - /// \param rotation is from bind-frame to model-frame - /// computes parent relative _rotation and sets that - /// \warning no combined transforms are updated! + /// \param rotation is from bind- to model-frame + /// computes and sets new _rotationInParentFrame + /// NOTE: the JointState's model-frame transform/rotation are NOT updated! void setRotationInModelFrame(const glm::quat& rotation, float priority); void clearTransformTranslation(); - glm::quat _rotation; // rotation relative to parent + glm::quat _rotationInParentFrame; // joint- to parentJoint-frame float _animationPriority; // the priority of the animation affecting this joint private: - glm::mat4 _transformInModelFrame; - glm::quat _rotationInModelFrame; + glm::mat4 _transform; // joint- to model-frame + glm::quat _rotation; // joint- to model-frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint }; From 4ae58153e0e8a4a2c87ea1f883650c7974ed6191 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:31:31 -0700 Subject: [PATCH 37/71] computeTransformInModelFrame -> computeTransform --- interface/src/avatar/FaceModel.cpp | 4 ++-- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/renderer/Model.cpp | 20 ++++++++++---------- interface/src/renderer/Model.h | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 652ecdec32..601dad5563 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -49,7 +49,7 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(glm::quat()); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransformInModelFrame() * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation))); state._rotationInParentFrame = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1])) @@ -60,7 +60,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { // likewise with the eye joints // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. - glm::mat4 inverse = glm::inverse(glm::mat4_cast(_rotation) * parentState.getTransformInModelFrame() * + glm::mat4 inverse = glm::inverse(glm::mat4_cast(_rotation) * parentState.getTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index cf9b96cbd1..e689deb0a8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -237,7 +237,7 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const } // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(glm::quat()); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransformInModelFrame() * glm::translate(state.getDefaultTranslationInParentFrame()) * + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); state._rotationInParentFrame = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d1a8587a5c..8206129c5b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -175,10 +175,10 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { if (parentIndex == -1) { _rootIndex = i; glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - state.computeTransformInModelFrame(parentTransform); + state.computeTransform(parentTransform); } else { const JointState& parentState = jointStates.at(parentIndex); - state.computeTransformInModelFrame(parentState.getTransformInModelFrame()); + state.computeTransform(parentState.getTransform()); } } return jointStates; @@ -726,7 +726,7 @@ bool Model::getJointPositionInModelFrame(int jointIndex, glm::vec3& position) co if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - position = extractTranslation(_jointStates[jointIndex].getTransformInModelFrame()); + position = extractTranslation(_jointStates[jointIndex].getTransform()); return true; } @@ -1218,7 +1218,7 @@ void Model::simulateInternal(float deltaTime) { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransformInModelFrame() * cluster.inverseBindMatrix; + state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransform() * cluster.inverseBindMatrix; } } @@ -1237,10 +1237,10 @@ void Model::updateJointState(int index) { if (parentIndex == -1) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - state.computeTransformInModelFrame(parentTransform); + state.computeTransform(parentTransform); } else { const JointState& parentState = _jointStates.at(parentIndex); - state.computeTransformInModelFrame(parentState.getTransformInModelFrame()); + state.computeTransform(parentState.getTransform()); } } @@ -1275,7 +1275,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi } // then, we go from the joint upwards, rotating the end as close as possible to the target - glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].getTransformInModelFrame()); + glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].getTransform()); for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); JointState& state = _jointStates[index]; @@ -1283,7 +1283,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi if (!(joint.isFree || allIntermediatesFree)) { continue; } - glm::vec3 jointPosition = extractTranslation(state.getTransformInModelFrame()); + glm::vec3 jointPosition = extractTranslation(state.getTransform()); glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.getRotationInModelFrame(); glm::quat combinedDelta; @@ -1303,7 +1303,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi for (int k = j - 1; k > 0; k--) { int index = freeLineage.at(k); updateJointState(index); - positionSum += extractTranslation(_jointStates.at(index).getTransformInModelFrame()); + positionSum += extractTranslation(_jointStates.at(index).getTransform()); } glm::vec3 projectedCenterOfMass = glm::cross(jointVector, glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); @@ -1998,7 +1998,7 @@ void JointState::copyState(const JointState& state) { // DO NOT copy _fbxJoint } -void JointState::computeTransformInModelFrame(const glm::mat4& parentTransform) { +void JointState::computeTransform(const glm::mat4& parentTransform) { glm::quat modifiedRotation = _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation; glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 955207445b..2dabd208af 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -40,8 +40,8 @@ public: void copyState(const JointState& state); - void computeTransformInModelFrame(const glm::mat4& parentTransform); - const glm::mat4& getTransformInModelFrame() const { return _transform; } + void computeTransform(const glm::mat4& parentTransform); + const glm::mat4& getTransform() const { return _transform; } glm::quat getRotationInModelFrame() const { return _rotation; } glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transform); } From 4a3fbfcdeec04379f133f4136d3b6138311d65d0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:34:58 -0700 Subject: [PATCH 38/71] getRotationInModelFrame -> getRotation --- interface/src/avatar/SkeletonModel.cpp | 6 +++--- interface/src/renderer/Model.cpp | 14 +++++++------- interface/src/renderer/Model.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e689deb0a8..c2e4c47a3f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -148,7 +148,7 @@ void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec return; } JointState& state = _jointStates[jointIndex]; - glm::quat handRotation = state.getRotationInModelFrame(); + glm::quat handRotation = state.getRotation(); // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; @@ -267,7 +267,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { glPushMatrix(); glTranslatef(position.x, position.y, position.z); - glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _rotation * _jointStates.at(joint.parentIndex).getRotationInModelFrame(); + glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _rotation * _jointStates.at(joint.parentIndex).getRotation(); glm::vec3 rotationAxis = glm::axis(parentRotation); glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z); float fanScale = directionSize * 0.75f; @@ -300,7 +300,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { } glPopMatrix(); - renderOrientationDirections(position, _rotation * jointState.getRotationInModelFrame(), directionSize); + renderOrientationDirections(position, _rotation * jointState.getRotation(), directionSize); jointIndex = joint.parentIndex; } while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 8206129c5b..305ad6753e 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -734,7 +734,7 @@ bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) co if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _rotation * _jointStates[jointIndex].getRotationInModelFrame(); + rotation = _rotation * _jointStates[jointIndex].getRotation(); return true; } @@ -742,7 +742,7 @@ bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = _rotation * _jointStates[jointIndex].getRotationInModelFrame(); + rotation = _rotation * _jointStates[jointIndex].getRotation(); return true; } @@ -958,7 +958,7 @@ void Model::updateShapePositions() { const JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); // shape position and rotation need to be in world-frame - glm::quat stateRotation = state.getRotationInModelFrame(); + glm::quat stateRotation = state.getRotation(); glm::vec3 shapeOffset = uniformScale * (stateRotation * joint.shapePosition); glm::vec3 worldPosition = _translation + _rotation * (state.getPositionInModelFrame() + shapeOffset); Shape* shape = _jointShapes[i]; @@ -1269,9 +1269,9 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi JointState& state = _jointStates[jointIndex]; // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = state.getRotationInModelFrame(); + endRotation = state.getRotation(); state.applyRotationDeltaInModelFrame(rotation * glm::inverse(endRotation), true, priority); - endRotation = state.getRotationInModelFrame(); + endRotation = state.getRotation(); } // then, we go from the joint upwards, rotating the end as close as possible to the target @@ -1285,7 +1285,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi } glm::vec3 jointPosition = extractTranslation(state.getTransform()); glm::vec3 jointVector = endPosition - jointPosition; - glm::quat oldCombinedRotation = state.getRotationInModelFrame(); + glm::quat oldCombinedRotation = state.getRotation(); glm::quat combinedDelta; float combinedWeight; if (useRotation) { @@ -1315,7 +1315,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi } } state.applyRotationDeltaInModelFrame(combinedDelta, true, priority); - glm::quat actualDelta = state.getRotationInModelFrame() * glm::inverse(oldCombinedRotation); + glm::quat actualDelta = state.getRotation() * glm::inverse(oldCombinedRotation); endPosition = actualDelta * jointVector + jointPosition; if (useRotation) { endRotation = actualDelta * endRotation; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 2dabd208af..23d40bb29e 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -43,7 +43,7 @@ public: void computeTransform(const glm::mat4& parentTransform); const glm::mat4& getTransform() const { return _transform; } - glm::quat getRotationInModelFrame() const { return _rotation; } + glm::quat getRotation() const { return _rotation; } glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transform); } /// \return rotation from bind to model frame From d8f5e10947bfe2ccbc0cdb19cb79523f92d89f74 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:36:54 -0700 Subject: [PATCH 39/71] getPositionInModelFrame -> getPosition --- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/renderer/Model.cpp | 8 ++++---- interface/src/renderer/Model.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c2e4c47a3f..3792ed531b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -263,7 +263,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { do { const FBXJoint& joint = geometry.joints.at(jointIndex); const JointState& jointState = _jointStates.at(jointIndex); - glm::vec3 position = _rotation * jointState.getPositionInModelFrame() + _translation; + glm::vec3 position = _rotation * jointState.getPosition() + _translation; glPushMatrix(); glTranslatef(position.x, position.y, position.z); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 305ad6753e..65b618deba 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -718,7 +718,7 @@ bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) co if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - position = _translation + _rotation * _jointStates[jointIndex].getPositionInModelFrame(); + position = _translation + _rotation * _jointStates[jointIndex].getPosition(); return true; } @@ -960,7 +960,7 @@ void Model::updateShapePositions() { // shape position and rotation need to be in world-frame glm::quat stateRotation = state.getRotation(); glm::vec3 shapeOffset = uniformScale * (stateRotation * joint.shapePosition); - glm::vec3 worldPosition = _translation + _rotation * (state.getPositionInModelFrame() + shapeOffset); + glm::vec3 worldPosition = _translation + _rotation * (state.getPosition() + shapeOffset); Shape* shape = _jointShapes[i]; shape->setPosition(worldPosition); shape->setRotation(_rotation * stateRotation * joint.shapeRotation); @@ -985,12 +985,12 @@ bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct float radiusScale = extractUniformScale(_scale); for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; - glm::vec3 end = _translation + _rotation * _jointStates[i].getPositionInModelFrame(); + glm::vec3 end = _translation + _rotation * _jointStates[i].getPosition(); float endRadius = joint.boneRadius * radiusScale; glm::vec3 start = end; float startRadius = joint.boneRadius * radiusScale; if (joint.parentIndex != -1) { - start = _translation + _rotation * _jointStates[joint.parentIndex].getPositionInModelFrame(); + start = _translation + _rotation * _jointStates[joint.parentIndex].getPosition(); startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale; } // for now, use average of start and end radii diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 23d40bb29e..1edebc00e0 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -44,7 +44,7 @@ public: const glm::mat4& getTransform() const { return _transform; } glm::quat getRotation() const { return _rotation; } - glm::vec3 getPositionInModelFrame() const { return extractTranslation(_transform); } + glm::vec3 getPosition() const { return extractTranslation(_transform); } /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; From b3cabb8156e9af740dd3f97387e0c905cf111e8d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:43:15 -0700 Subject: [PATCH 40/71] applyRotationDeltaInModelFrame -> applyRotationDelta --- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/renderer/Model.cpp | 7 ++++--- interface/src/renderer/Model.h | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 3792ed531b..529d2b43dc 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -152,7 +152,7 @@ void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - state.applyRotationDeltaInModelFrame(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); + state.applyRotationDelta(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); } void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 65b618deba..26376e6feb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1270,7 +1270,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi // TODO: figure out what this is trying to do and combine it into one JointState method endRotation = state.getRotation(); - state.applyRotationDeltaInModelFrame(rotation * glm::inverse(endRotation), true, priority); + state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); endRotation = state.getRotation(); } @@ -1314,7 +1314,7 @@ bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& positi 1.0f / (combinedWeight + 1.0f)); } } - state.applyRotationDeltaInModelFrame(combinedDelta, true, priority); + state.applyRotationDelta(combinedDelta, true, priority); glm::quat actualDelta = state.getRotation() * glm::inverse(oldCombinedRotation); endPosition = actualDelta * jointVector + jointPosition; if (useRotation) { @@ -2031,7 +2031,8 @@ void JointState::clearTransformTranslation() { _transform[3][2] = 0.0f; } -void JointState::applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain, float priority) { +void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { + // NOTE: delta is in jointParent-frame assert(_fbxJoint != NULL); if (priority < _animationPriority) { return; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 1edebc00e0..409f307363 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -49,7 +49,8 @@ public: /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; - void applyRotationDeltaInModelFrame(const glm::quat& delta, bool constrain = true, float priority = 1.0f); + /// \param delta is in the jointParent-frame + void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); const glm::vec3& getDefaultTranslationInParentFrame() const; From 971268d4f2f8b429a6ae1aaf22a5bb3e71bfd347 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:46:08 -0700 Subject: [PATCH 41/71] setRotationInModelFrame -> setRotation --- interface/src/avatar/SkeletonModel.cpp | 10 +++++----- interface/src/renderer/Model.cpp | 2 +- interface/src/renderer/Model.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 529d2b43dc..63a2859366 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -46,7 +46,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex); if (jointIndex != -1) { JointState& state = _jointStates[jointIndex]; - state.setRotationInModelFrame(prioVR->getJointRotations().at(i), PALM_PRIORITY); + state.setRotation(prioVR->getJointRotations().at(i), PALM_PRIORITY); } } return; @@ -198,7 +198,7 @@ void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; - parentState.setRotationInModelFrame(palmRotation, PALM_PRIORITY); + parentState.setRotation(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex]._rotationInParentFrame = glm::quat(); } else { @@ -363,13 +363,13 @@ void SkeletonModel::setHandPositionInModelFrame(int jointIndex, const glm::vec3& glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); JointState& shoulderState = _jointStates[shoulderJointIndex]; - shoulderState.setRotationInModelFrame(shoulderRotation, PALM_PRIORITY); + shoulderState.setRotation(shoulderRotation, PALM_PRIORITY); JointState& elbowState = _jointStates[elbowJointIndex]; - elbowState.setRotationInModelFrame(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); + elbowState.setRotation(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); JointState& handState = _jointStates[jointIndex]; - handState.setRotationInModelFrame(rotation, PALM_PRIORITY); + handState.setRotation(rotation, PALM_PRIORITY); } bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 26376e6feb..4f2bb79faf 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -2017,7 +2017,7 @@ void JointState::restoreRotation(float fraction, float priority) { } } -void JointState::setRotationInModelFrame(const glm::quat& rotation, float priority) { +void JointState::setRotation(const glm::quat& rotation, float priority) { assert(_fbxJoint != NULL); if (priority >= _animationPriority) { _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 409f307363..7a0e6b1dbb 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -59,7 +59,7 @@ public: /// \param rotation is from bind- to model-frame /// computes and sets new _rotationInParentFrame /// NOTE: the JointState's model-frame transform/rotation are NOT updated! - void setRotationInModelFrame(const glm::quat& rotation, float priority); + void setRotation(const glm::quat& rotation, float priority); void clearTransformTranslation(); From 3af4b1b33398fd90daf6d007b6448758c5aad255 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:51:43 -0700 Subject: [PATCH 42/71] getJointPositionInModelFrame -> getJointPosition --- interface/src/avatar/SkeletonModel.cpp | 6 +++--- interface/src/renderer/Model.cpp | 4 +++- interface/src/renderer/Model.h | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 63a2859366..008ea65557 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -140,8 +140,8 @@ void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::vec3 handPosition, elbowPosition; - getJointPositionInModelFrame(jointIndex, handPosition); - getJointPositionInModelFrame(geometry.joints.at(jointIndex).parentIndex, elbowPosition); + getJointPosition(jointIndex, handPosition); + getJointPosition(geometry.joints.at(jointIndex).parentIndex, elbowPosition); glm::vec3 forearmVector = handPosition - elbowPosition; float forearmLength = glm::length(forearmVector); if (forearmLength < EPSILON) { @@ -317,7 +317,7 @@ void SkeletonModel::setHandPositionInModelFrame(int jointIndex, const glm::vec3& } int shoulderJointIndex = geometry.joints.at(elbowJointIndex).parentIndex; glm::vec3 shoulderPosition; - if (!getJointPositionInModelFrame(shoulderJointIndex, shoulderPosition)) { + if (!getJointPosition(shoulderJointIndex, shoulderPosition)) { return; } // precomputed lengths diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 4f2bb79faf..66be7e4bfc 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -718,14 +718,16 @@ bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) co if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } + // position is in world-frame position = _translation + _rotation * _jointStates[jointIndex].getPosition(); return true; } -bool Model::getJointPositionInModelFrame(int jointIndex, glm::vec3& position) const { +bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } + // position is in model-frame position = extractTranslation(_jointStates[jointIndex].getTransform()); return true; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 7a0e6b1dbb..d6721d2bad 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -164,11 +164,13 @@ public: int getLastFreeJointIndex(int jointIndex) const; bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; - bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; - bool getJointPositionInModelFrame(int jointIndex, glm::vec3& position) const; + /// \param jointIndex index of joint in model structure + /// \param position[out] position of joint in model-frame + /// \return true if joint exists + bool getJointPosition(int jointIndex, glm::vec3& position) const; QStringList getJointNames() const; From ccfd620c842b91850a0617b21860b669f50f417a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 13:56:37 -0700 Subject: [PATCH 43/71] setJointPositionInModelFrame -> setJointPosition --- interface/src/avatar/SkeletonModel.cpp | 6 +++--- interface/src/renderer/Model.cpp | 4 ++-- interface/src/renderer/Model.h | 10 +++++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 008ea65557..385f11e185 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -136,7 +136,7 @@ void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; } - setJointPositionInModelFrame(jointIndex, position, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + setJointPosition(jointIndex, position, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::vec3 handPosition, elbowPosition; @@ -194,7 +194,7 @@ void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPositionInModelFrame(parentJointIndex, palmPosition + forearmVector * + setJointPosition(parentJointIndex, palmPosition + forearmVector * geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; @@ -202,7 +202,7 @@ void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex]._rotationInParentFrame = glm::quat(); } else { - setJointPositionInModelFrame(jointIndex, palmPosition, palmRotation, + setJointPosition(jointIndex, palmPosition, palmRotation, true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 66be7e4bfc..375927483a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1246,7 +1246,7 @@ void Model::updateJointState(int index) { } } -bool Model::setJointPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, +bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; @@ -1486,7 +1486,7 @@ void Model::applyCollision(CollisionInfo& collision) { // transform into model-frame glm::vec3 newEnd = glm::inverse(_rotation) * (start + glm::angleAxis(angle, axis) * (end - start) - _translation); // try to move it - setJointPositionInModelFrame(jointIndex, newEnd, glm::quat(), false, -1, true); + setJointPosition(jointIndex, newEnd, glm::quat(), false, -1, true); } } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index d6721d2bad..e73f3573f7 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -257,7 +257,15 @@ protected: /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); - bool setJointPositionInModelFrame(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), + /// \param jointIndex index of joint in model structure + /// \param position position of joint in model-frame + /// \param rotation rotation of joint in model-frame + /// \param useRotation false if rotation should be ignored + /// \param lastFreeIndex + /// \param allIntermediatesFree + /// \param alignment + /// \return true if joint exists + bool setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation = glm::quat(), bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); From 323fa70cf38cbb1e83b40b47134b29d1d9fe5629 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 14:03:29 -0700 Subject: [PATCH 44/71] remove last of "InModelFrame" qualifiers --- interface/src/avatar/SkeletonModel.cpp | 18 ++++++++++-------- interface/src/avatar/SkeletonModel.h | 12 +++++++++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 385f11e185..278b70bce4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -63,19 +63,20 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { if (_owningAvatar->getHandState() == HAND_STATE_NULL) { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { + // transform into model-frame glm::vec3 handPosition = glm::inverse(_rotation) * (_owningAvatar->getHandPosition() - _translation); - applyHandPositionInModelFrame(geometry.rightHandJointIndex, handPosition); + applyHandPosition(geometry.rightHandJointIndex, handPosition); } restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else if (leftPalmIndex == rightPalmIndex) { // right hand only - applyPalmDataInModelFrame(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); + applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { - applyPalmDataInModelFrame(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); - applyPalmDataInModelFrame(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); + applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); + applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); } } @@ -132,10 +133,11 @@ bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) { return firstIndex.value < secondIndex.value; } -void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec3& position) { +void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; } + // NOTE: 'position' is in model-frame setJointPosition(jointIndex, position, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); const FBXGeometry& geometry = _geometry->getFBXGeometry(); @@ -155,7 +157,7 @@ void SkeletonModel::applyHandPositionInModelFrame(int jointIndex, const glm::vec state.applyRotationDelta(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); } -void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { +void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; } @@ -190,7 +192,7 @@ void SkeletonModel::applyPalmDataInModelFrame(int jointIndex, PalmData& palm) { // set hand position, rotation glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { - setHandPositionInModelFrame(jointIndex, palmPosition, palmRotation); + setHandPosition(jointIndex, palmPosition, palmRotation); } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); @@ -308,7 +310,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) { glLineWidth(1.0f); } -void SkeletonModel::setHandPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation) { +void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation) { // this algorithm is from sample code from sixense const FBXGeometry& geometry = _geometry->getFBXGeometry(); int elbowJointIndex = geometry.joints.at(jointIndex).parentIndex; diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 092722fd40..4335dfc3ff 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -91,9 +91,11 @@ public: protected: - void applyHandPositionInModelFrame(int jointIndex, const glm::vec3& position); + /// \param jointIndex index of joint in model + /// \param position position of joint in model-frame + void applyHandPosition(int jointIndex, const glm::vec3& position); - void applyPalmDataInModelFrame(int jointIndex, PalmData& palm); + void applyPalmData(int jointIndex, PalmData& palm); /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); @@ -105,7 +107,11 @@ protected: private: void renderJointConstraints(int jointIndex); - void setHandPositionInModelFrame(int jointIndex, const glm::vec3& position, const glm::quat& rotation); + + /// \param jointIndex index of joint in model + /// \param position position of joint in model-frame + /// \param rotation rotation of joint in model-frame + void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation); Avatar* _owningAvatar; }; From 212ac13802ddad002bc63aa31838e114ef8c4c6a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 14:10:28 -0700 Subject: [PATCH 45/71] setRotation -> setJointRotationFromBindFrame --- interface/src/avatar/SkeletonModel.cpp | 10 +++++----- interface/src/renderer/Model.cpp | 2 +- interface/src/renderer/Model.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 278b70bce4..58151d25ab 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -46,7 +46,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex); if (jointIndex != -1) { JointState& state = _jointStates[jointIndex]; - state.setRotation(prioVR->getJointRotations().at(i), PALM_PRIORITY); + state.setRotationFromBindFrame(prioVR->getJointRotations().at(i), PALM_PRIORITY); } } return; @@ -200,7 +200,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; - parentState.setRotation(palmRotation, PALM_PRIORITY); + parentState.setRotationFromBindFrame(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex]._rotationInParentFrame = glm::quat(); } else { @@ -365,13 +365,13 @@ void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, c glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); JointState& shoulderState = _jointStates[shoulderJointIndex]; - shoulderState.setRotation(shoulderRotation, PALM_PRIORITY); + shoulderState.setRotationFromBindFrame(shoulderRotation, PALM_PRIORITY); JointState& elbowState = _jointStates[elbowJointIndex]; - elbowState.setRotation(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); + elbowState.setRotationFromBindFrame(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); JointState& handState = _jointStates[jointIndex]; - handState.setRotation(rotation, PALM_PRIORITY); + handState.setRotationFromBindFrame(rotation, PALM_PRIORITY); } bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 375927483a..beab69ecfb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -2019,7 +2019,7 @@ void JointState::restoreRotation(float fraction, float priority) { } } -void JointState::setRotation(const glm::quat& rotation, float priority) { +void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) { assert(_fbxJoint != NULL); if (priority >= _animationPriority) { _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index e73f3573f7..cb91d74b3b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -59,7 +59,7 @@ public: /// \param rotation is from bind- to model-frame /// computes and sets new _rotationInParentFrame /// NOTE: the JointState's model-frame transform/rotation are NOT updated! - void setRotation(const glm::quat& rotation, float priority); + void setRotationFromBindFrame(const glm::quat& rotation, float priority); void clearTransformTranslation(); From f19b562e881ce84fec020a83ebc3398060dd9ab1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 14:17:39 -0700 Subject: [PATCH 46/71] add JointState::setRotation(rotModelFrame) --- interface/src/renderer/Model.cpp | 8 +++++--- interface/src/renderer/Model.h | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index beab69ecfb..bc383149d8 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1270,9 +1270,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const gl if (useRotation) { JointState& state = _jointStates[jointIndex]; - // TODO: figure out what this is trying to do and combine it into one JointState method - endRotation = state.getRotation(); - state.applyRotationDelta(rotation * glm::inverse(endRotation), true, priority); + state.setRotation(rotation, true, priority); endRotation = state.getRotation(); } @@ -2033,6 +2031,10 @@ void JointState::clearTransformTranslation() { _transform[3][2] = 0.0f; } +void JointState::setRotation(const glm::quat& rotation, bool constrain, float priority) { + applyRotationDelta(rotation * glm::inverse(_rotation), true, priority); +} + void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { // NOTE: delta is in jointParent-frame assert(_fbxJoint != NULL); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index cb91d74b3b..7d7406fc42 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -49,6 +49,9 @@ public: /// \return rotation from bind to model frame glm::quat getRotationFromBindToModelFrame() const; + /// \param rotation rotation of joint in model-frame + void setRotation(const glm::quat& rotation, bool constrain, float priority); + /// \param delta is in the jointParent-frame void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); From 78d3f1454c222554d750d0ea70335d87d670fd84 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 14:19:35 -0700 Subject: [PATCH 47/71] more operators --- libraries/shared/src/PropertyFlags.h | 146 ++++++++++++---- tests/octree/src/OctreeTests.cpp | 241 ++++++++++++++++++++++++++- 2 files changed, 350 insertions(+), 37 deletions(-) diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index d8131d0c75..4c4dc6b386 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -11,9 +11,7 @@ // // TODO: // * implement decode -// * more operators, operator==, operator!=, operator!, operator~ // * iterator to enumerate the set values? -// * operator<<(enum) to work similar to set #ifndef hifi_PropertyFlags_h #define hifi_PropertyFlags_h @@ -29,14 +27,18 @@ templateclass PropertyFlags { public: typedef Enum enum_type; - inline PropertyFlags() : _maxFlag(INT_MIN), _minFlag(INT_MAX) { }; - inline PropertyFlags(const PropertyFlags& other) : _flags(other._flags), _maxFlag(other._maxFlag) {} - inline PropertyFlags(Enum flag) : _maxFlag(INT_MIN), _minFlag(INT_MAX) { setHasProperty(flag); } + inline PropertyFlags() : + _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { }; + inline PropertyFlags(const PropertyFlags& other) : + _flags(other._flags), _maxFlag(other._maxFlag), _minFlag(other._minFlag), + _trailingFlipped(other._trailingFlipped) {} + inline PropertyFlags(Enum flag) : + _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { setHasProperty(flag); } - void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; } + void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped = false; } - Enum firstFlag() const { return _minFlag; } - Enum lastFlag() const { return _maxFlag; } + Enum firstFlag() const { return (Enum)_minFlag; } + Enum lastFlag() const { return (Enum)_maxFlag; } void setHasProperty(Enum flag, bool value = true); bool getHasProperty(Enum flag); @@ -44,7 +46,12 @@ public: void decode(const QByteArray& fromEncoded); - PropertyFlags& operator=(const PropertyFlags &other); + bool operator==(const PropertyFlags& other) const { return _flags == other._flags; } + bool operator!=(const PropertyFlags& other) const { return _flags != other._flags; } + bool operator!() const { return _flags.size() == 0; } + + + PropertyFlags& operator=(const PropertyFlags& other); PropertyFlags& operator|=(PropertyFlags other); PropertyFlags& operator|=(Enum flag); @@ -55,9 +62,15 @@ public: PropertyFlags& operator^=(PropertyFlags other); PropertyFlags& operator^=(Enum flag); + PropertyFlags& operator+=(PropertyFlags other); + PropertyFlags& operator+=(Enum flag); + PropertyFlags& operator-=(PropertyFlags other); PropertyFlags& operator-=(Enum flag); + PropertyFlags& operator<<=(PropertyFlags other); + PropertyFlags& operator<<=(Enum flag); + PropertyFlags operator|(PropertyFlags other) const; PropertyFlags operator|(Enum flag) const; @@ -67,25 +80,38 @@ public: PropertyFlags operator^(PropertyFlags other) const; PropertyFlags operator^(Enum flag) const; + PropertyFlags operator+(PropertyFlags other) const; + PropertyFlags operator+(Enum flag) const; + PropertyFlags operator-(PropertyFlags other) const; PropertyFlags operator-(Enum flag) const; + PropertyFlags operator<<(PropertyFlags other) const; + PropertyFlags operator<<(Enum flag) const; - /* - inline PropertyFlags operator~() const { return PropertyFlags(Enum(~i)); } - inline bool operator!() const { return !i; } - */ + + PropertyFlags operator~() const; + + void debugDumpBits(); private: void shinkIfNeeded(); - void debugDumpBits(); QBitArray _flags; int _maxFlag; int _minFlag; + bool _trailingFlipped; /// are the trailing properties flipping in their state (e.g. assumed true, instead of false) }; +template PropertyFlags& operator<<(PropertyFlags& out, const PropertyFlags& other) { + return out <<= other; +} + +template PropertyFlags& operator<<(PropertyFlags& out, Enum flag) { + return out <<= flag; +} + template inline void PropertyFlags::setHasProperty(Enum flag, bool value) { // keep track of our min flag @@ -111,7 +137,7 @@ template inline void PropertyFlags::setHasProperty(Enum fla template inline bool PropertyFlags::getHasProperty(Enum flag) { if (flag > _maxFlag) { - return false; + return _trailingFlipped; // usually false } return _flags.testBit(flag); } @@ -121,6 +147,11 @@ const int BITS_PER_BYTE = 8; template inline QByteArray PropertyFlags::encode() { const bool debug = false; QByteArray output; + + if (_maxFlag < _minFlag) { + output.fill(0, 1); + return output; // no flags... nothing to encode + } outputBufferBits((const unsigned char*)output.constData(), output.size()); @@ -200,21 +231,26 @@ template inline void PropertyFlags::decode(const QByteArray } template inline void PropertyFlags::debugDumpBits() { + qDebug() << "_minFlag=" << _minFlag; + qDebug() << "_maxFlag=" << _maxFlag; + qDebug() << "_trailingFlipped=" << _trailingFlipped; for(int i = 0; i < _flags.size(); i++) { qDebug() << "bit[" << i << "]=" << _flags.at(i); } } -template inline PropertyFlags& PropertyFlags::operator=(const PropertyFlags &other) { +template inline PropertyFlags& PropertyFlags::operator=(const PropertyFlags& other) { _flags = other._flags; _maxFlag = other._maxFlag; + _minFlag = other._minFlag; return *this; } template inline PropertyFlags& PropertyFlags::operator|=(PropertyFlags other) { _flags |= other._flags; _maxFlag = std::max(_maxFlag, other._maxFlag); + _minFlag = std::min(_minFlag, other._minFlag); return *this; } @@ -222,6 +258,7 @@ template inline PropertyFlags& PropertyFlags::operato PropertyFlags other(flag); _flags |= other._flags; _maxFlag = std::max(_maxFlag, other._maxFlag); + _minFlag = std::min(_minFlag, other._minFlag); return *this; } @@ -251,31 +288,45 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { - for(int flag = other.firstFlag(); flag <= other.lastFlag(); flag++) { - //qDebug() << "checking other.getHasProperty(flag) flag=" << flag; - if (other.getHasProperty(flag)) { - //qDebug() << "setting setHasProperty(flag) flag=" << flag; - setHasProperty(flag, false); +template inline PropertyFlags& PropertyFlags::operator+=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, true); } } - return *this; } +template inline PropertyFlags& PropertyFlags::operator+=(Enum flag) { + setHasProperty(flag, true); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, false); + } + } + return *this; +} + template inline PropertyFlags& PropertyFlags::operator-=(Enum flag) { - bool debug = false; - if (debug) { - qDebug() << "operator-=(Enum flag) flag=" << flag << "before..."; - debugDumpBits(); - } setHasProperty(flag, false); + return *this; +} - if (debug) { - qDebug() << "after..."; - debugDumpBits(); +template inline PropertyFlags& PropertyFlags::operator<<=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, true); + } } + return *this; +} +template inline PropertyFlags& PropertyFlags::operator<<=(Enum flag) { + setHasProperty(flag, true); return *this; } @@ -318,6 +369,18 @@ template inline PropertyFlags PropertyFlags::operator return result; } +template inline PropertyFlags PropertyFlags::operator+(PropertyFlags other) const { + PropertyFlags result(*this); + result += other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator+(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, true); + return result; +} + template inline PropertyFlags PropertyFlags::operator-(PropertyFlags other) const { PropertyFlags result(*this); result -= other; @@ -330,6 +393,25 @@ template inline PropertyFlags PropertyFlags::operator return result; } +template inline PropertyFlags PropertyFlags::operator<<(PropertyFlags other) const { + PropertyFlags result(*this); + result <<= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator<<(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, true); + return result; +} + +template inline PropertyFlags PropertyFlags::operator~() const { + PropertyFlags result(*this); + result._flags = ~_flags; + result._trailingFlipped = !_trailingFlipped; + return result; +} + template inline void PropertyFlags::shinkIfNeeded() { bool maxFlagWas = _maxFlag; while (_maxFlag >= 0) { @@ -343,8 +425,6 @@ template inline void PropertyFlags::shinkIfNeeded() { } } - - /*** BitArr.resize(8*byteArr.count()); diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 1a66a0b2ae..7143e6ca7a 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -66,7 +66,7 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "OctreeTests::propertyFlagsTests()"; { - qDebug() << "Test 1: ModelProperties: PROP_VISIBLE, PROP_POSITION, PROP_RADIUS, PROP_MODEL_URL, PROP_ROTATION"; + qDebug() << "Test 1: ModelProperties: using setHasProperty()"; ModelPropertyFlags props; props.setHasProperty(PROP_VISIBLE); props.setHasProperty(PROP_POSITION); @@ -81,8 +81,7 @@ void OctreeTests::propertyFlagsTests() { } { - qDebug() << "Test 2: ParticlePropertyFlags: PROP_VISIBLE, PARTICLE_PROP_ANIMATION_URL, PARTICLE_PROP_ANIMATION_FPS, " - "PARTICLE_PROP_ANIMATION_FRAME_INDEX, PARTICLE_PROP_ANIMATION_PLAYING, PARTICLE_PROP_PAUSE_SIMULATION"; + qDebug() << "Test 2: ParticlePropertyFlags: using setHasProperty()"; ParticlePropertyFlags props2; props2.setHasProperty(PARTICLE_PROP_VISIBLE); props2.setHasProperty(PARTICLE_PROP_ANIMATION_URL); @@ -130,11 +129,245 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "encoded="; outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 3c: ParticlePropertyFlags: using |= operator"; + ParticlePropertyFlags props; + + props |= PARTICLE_PROP_VISIBLE; + props |= PARTICLE_PROP_ANIMATION_URL; + props |= PARTICLE_PROP_ANIMATION_FPS; + props |= PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props |= PARTICLE_PROP_ANIMATION_PLAYING; + props |= PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 4: ParticlePropertyFlags: using + operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + + ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 4b: ParticlePropertyFlags: using += operator"; + ParticlePropertyFlags props; + + props += PARTICLE_PROP_VISIBLE; + props += PARTICLE_PROP_ANIMATION_URL; + props += PARTICLE_PROP_ANIMATION_FPS; + props += PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props += PARTICLE_PROP_ANIMATION_PLAYING; + props += PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5: ParticlePropertyFlags: using = ... << operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + << ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5b: ParticlePropertyFlags: using <<= operator"; + ParticlePropertyFlags props; + + props <<= PARTICLE_PROP_VISIBLE; + props <<= PARTICLE_PROP_ANIMATION_URL; + props <<= PARTICLE_PROP_ANIMATION_FPS; + props <<= PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props <<= PARTICLE_PROP_ANIMATION_PLAYING; + props <<= PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5c: ParticlePropertyFlags: using << enum operator"; + ParticlePropertyFlags props; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5d: ParticlePropertyFlags: using << flags operator "; + ParticlePropertyFlags props; + ParticlePropertyFlags props2; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + + props2 << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props2 << PARTICLE_PROP_ANIMATION_PLAYING; + props2 << PARTICLE_PROP_PAUSE_SIMULATION; + + props << props2; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 6: ParticlePropertyFlags comparison"; + ParticlePropertyFlags propsA; + + qDebug() << "!propsA:" << (!propsA) << "{ expect true }"; + + propsA << PARTICLE_PROP_VISIBLE; + propsA << PARTICLE_PROP_ANIMATION_URL; + propsA << PARTICLE_PROP_ANIMATION_FPS; + propsA << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + propsA << PARTICLE_PROP_ANIMATION_PLAYING; + propsA << PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "!propsA:" << (!propsA) << "{ expect false }"; + + ParticlePropertyFlags propsB; + qDebug() << "!propsB:" << (!propsB) << "{ expect true }"; + + + propsB << PARTICLE_PROP_VISIBLE; + propsB << PARTICLE_PROP_ANIMATION_URL; + propsB << PARTICLE_PROP_ANIMATION_FPS; + propsB << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + propsB << PARTICLE_PROP_ANIMATION_PLAYING; + propsB << PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "!propsB:" << (!propsB) << "{ expect false }"; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }"; + + + qDebug() << "AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION..."; + propsB -= PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect false }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect true }"; + + qDebug() << "AFTER propsB = propsA..."; + propsB = propsA; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }"; } + { + qDebug() << "Test 7: ParticlePropertyFlags testing individual properties"; + ParticlePropertyFlags props; + + qDebug() << "ParticlePropertyFlags props;"; + QByteArray encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect false }"; + + qDebug() << "props << PARTICLE_PROP_VISIBLE;"; + props << PARTICLE_PROP_VISIBLE; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "props << PARTICLE_PROP_ANIMATION_URL;"; + props << PARTICLE_PROP_ANIMATION_URL; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "props << ... more ..."; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;"; + ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE; + + qDebug() << "propsB.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsB.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + encoded = propsB.encode(); + qDebug() << "propsB... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "propsB..."; + propsB.debugDumpBits(); + + qDebug() << "ParticlePropertyFlags propsC = ~propsB;"; + ParticlePropertyFlags propsC = ~propsB; + qDebug() << "propsC..."; + propsC.debugDumpBits(); + + qDebug() << "propsC.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsC.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect false }"; + + encoded = propsC.encode(); + qDebug() << "propsC... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } - qDebug() << "******************************************************************************************"; } From e1cb88471f655d54d5da4c71333c99027345f8d2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 4 Jun 2014 14:19:45 -0700 Subject: [PATCH 48/71] add a comment --- interface/src/renderer/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index bc383149d8..ca340808e5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -2020,6 +2020,7 @@ void JointState::restoreRotation(float fraction, float priority) { void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) { assert(_fbxJoint != NULL); if (priority >= _animationPriority) { + // rotation is from bind- to model-frame _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); _animationPriority = priority; } From e2d3fcc518ee00ba600e5cb5a0072fef28afa6ed Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 14:24:23 -0700 Subject: [PATCH 49/71] changed MovingPercentile to use QList --- libraries/shared/src/MovingPercentile.cpp | 64 ++++++++--------------- libraries/shared/src/MovingPercentile.h | 13 +++-- 2 files changed, 29 insertions(+), 48 deletions(-) diff --git a/libraries/shared/src/MovingPercentile.cpp b/libraries/shared/src/MovingPercentile.cpp index 07b633e93e..34657110d3 100644 --- a/libraries/shared/src/MovingPercentile.cpp +++ b/libraries/shared/src/MovingPercentile.cpp @@ -13,65 +13,47 @@ MovingPercentile::MovingPercentile(int numSamples, float percentile) : _numSamples(numSamples), _percentile(percentile), - _numExistingSamples(0), - _valueAtPercentile(0.0f), - _indexOfPercentile(0) + _samplesSorted(), + _sampleIds(), + _newSampleId(0), + _indexOfPercentile(0), + _valueAtPercentile(0.0f) { - _samplesSorted = new float[numSamples]; - _sampleAges = new int[numSamples]; -} - -MovingPercentile::~MovingPercentile() { - delete[] _samplesSorted; - delete[] _sampleAges; } void MovingPercentile::updatePercentile(float sample) { - // age all current samples by 1 - for (int i = 0; i < _numExistingSamples; i++) { - _sampleAges[i]++; - } - - // find index at which to insert new sample in _samplesSorted + // insert the new sample into _samplesSorted int newSampleIndex; - if (_numExistingSamples < _numSamples) { - // if samples have not been filled yet, this will be the next empty spot - newSampleIndex = _numExistingSamples; - _numExistingSamples++; + if (_sampleIds.size() < _numSamples) { + // if not all samples have been filled yet, simply append it + newSampleIndex = _samplesSorted.size(); + _samplesSorted.append(sample); + _sampleIds.append(_newSampleId); // update _indexOfPercentile - float index = _percentile * (float)(_numExistingSamples - 1); + float index = _percentile * (float)(_sampleIds.size() - 1); _indexOfPercentile = (int)(index + 0.5f); // round to int } else { - // if samples have been filled, it will be the spot of the oldest sample - newSampleIndex = 0; - while (_sampleAges[newSampleIndex] != _numExistingSamples) { newSampleIndex++; } + // find index of sample with id = _newSampleId and replace it with new sample + newSampleIndex = _sampleIds.indexOf(_newSampleId); + _samplesSorted[newSampleIndex] = sample; } - // insert new sample - _samplesSorted[newSampleIndex] = sample; - _sampleAges[newSampleIndex] = 0; + // increment _newSampleId. cycles from 0 thru N-1 + _newSampleId = (_newSampleId == _numSamples - 1) ? 0 : _newSampleId + 1; - // swap new sample with neighboring elements in _samplesSorted until it's in sorted order + // swap new sample with neighbors in _samplesSorted until it's in sorted order // try swapping up first, then down. element will only be swapped one direction. - while (newSampleIndex < _numExistingSamples-1 && sample > _samplesSorted[newSampleIndex+1]) { - _samplesSorted[newSampleIndex] = _samplesSorted[newSampleIndex + 1]; - _samplesSorted[newSampleIndex+1] = sample; - - _sampleAges[newSampleIndex] = _sampleAges[newSampleIndex+1]; - _sampleAges[newSampleIndex+1] = 0; - + while (newSampleIndex < _sampleIds.size() - 1 && sample > _samplesSorted[newSampleIndex + 1]) { + _samplesSorted.swap(newSampleIndex, newSampleIndex + 1); + _sampleIds.swap(newSampleIndex, newSampleIndex + 1); newSampleIndex++; } while (newSampleIndex > 0 && sample < _samplesSorted[newSampleIndex - 1]) { - _samplesSorted[newSampleIndex] = _samplesSorted[newSampleIndex - 1]; - _samplesSorted[newSampleIndex - 1] = sample; - - _sampleAges[newSampleIndex] = _sampleAges[newSampleIndex - 1]; - _sampleAges[newSampleIndex - 1] = 0; - + _samplesSorted.swap(newSampleIndex, newSampleIndex - 1); + _sampleIds.swap(newSampleIndex, newSampleIndex - 1); newSampleIndex--; } diff --git a/libraries/shared/src/MovingPercentile.h b/libraries/shared/src/MovingPercentile.h index 94a4f36da5..284ed9d890 100644 --- a/libraries/shared/src/MovingPercentile.h +++ b/libraries/shared/src/MovingPercentile.h @@ -11,27 +11,26 @@ #ifndef hifi_MovingPercentile_h #define hifi_MovingPercentile_h +#include + class MovingPercentile { public: MovingPercentile(int numSamples, float percentile = 0.5f); - ~MovingPercentile(); void updatePercentile(float sample); float getValueAtPercentile() const { return _valueAtPercentile; } - private: const int _numSamples; const float _percentile; - float* _samplesSorted; - int* _sampleAges; // _sampleAges[i] is the "age" of the sample at _sampleSorted[i] (higher means older) - int _numExistingSamples; - - float _valueAtPercentile; + QList _samplesSorted; + QList _sampleIds; // incrementally assigned, is cyclic + int _newSampleId; int _indexOfPercentile; + float _valueAtPercentile; }; #endif From 0da6374e19549622c9b8537dd852dedba05f3d0f Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 14:31:58 -0700 Subject: [PATCH 50/71] MovingPercentile .size() consistency --- libraries/shared/src/MovingPercentile.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/MovingPercentile.cpp b/libraries/shared/src/MovingPercentile.cpp index 34657110d3..c5c6f4284d 100644 --- a/libraries/shared/src/MovingPercentile.cpp +++ b/libraries/shared/src/MovingPercentile.cpp @@ -25,14 +25,14 @@ void MovingPercentile::updatePercentile(float sample) { // insert the new sample into _samplesSorted int newSampleIndex; - if (_sampleIds.size() < _numSamples) { + if (_samplesSorted.size() < _numSamples) { // if not all samples have been filled yet, simply append it newSampleIndex = _samplesSorted.size(); _samplesSorted.append(sample); _sampleIds.append(_newSampleId); // update _indexOfPercentile - float index = _percentile * (float)(_sampleIds.size() - 1); + float index = _percentile * (float)(_samplesSorted.size() - 1); _indexOfPercentile = (int)(index + 0.5f); // round to int } else { @@ -46,7 +46,7 @@ void MovingPercentile::updatePercentile(float sample) { // swap new sample with neighbors in _samplesSorted until it's in sorted order // try swapping up first, then down. element will only be swapped one direction. - while (newSampleIndex < _sampleIds.size() - 1 && sample > _samplesSorted[newSampleIndex + 1]) { + while (newSampleIndex < _samplesSorted.size() - 1 && sample > _samplesSorted[newSampleIndex + 1]) { _samplesSorted.swap(newSampleIndex, newSampleIndex + 1); _sampleIds.swap(newSampleIndex, newSampleIndex + 1); newSampleIndex++; From 10f7eae7a0d44a344d9238b69cb7c0bd10efa8e9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 14:56:13 -0700 Subject: [PATCH 51/71] implemented decode --- libraries/shared/src/PropertyFlags.h | 60 +++++++++++++++++++++------- tests/octree/src/OctreeTests.cpp | 28 +++++++++++++ 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index 4c4dc6b386..d19f52a846 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -10,7 +10,6 @@ // // // TODO: -// * implement decode // * iterator to enumerate the set values? #ifndef hifi_PropertyFlags_h @@ -50,7 +49,6 @@ public: bool operator!=(const PropertyFlags& other) const { return _flags != other._flags; } bool operator!() const { return _flags.size() == 0; } - PropertyFlags& operator=(const PropertyFlags& other); PropertyFlags& operator|=(PropertyFlags other); @@ -59,9 +57,6 @@ public: PropertyFlags& operator&=(PropertyFlags other); PropertyFlags& operator&=(Enum flag); - PropertyFlags& operator^=(PropertyFlags other); - PropertyFlags& operator^=(Enum flag); - PropertyFlags& operator+=(PropertyFlags other); PropertyFlags& operator+=(Enum flag); @@ -77,9 +72,6 @@ public: PropertyFlags operator&(PropertyFlags other) const; PropertyFlags operator&(Enum flag) const; - PropertyFlags operator^(PropertyFlags other) const; - PropertyFlags operator^(Enum flag) const; - PropertyFlags operator+(PropertyFlags other) const; PropertyFlags operator+(Enum flag) const; @@ -89,7 +81,13 @@ public: PropertyFlags operator<<(PropertyFlags other) const; PropertyFlags operator<<(Enum flag) const; - + // NOTE: due to the nature of the compact storage of these property flags, and the fact that the upper bound of the + // enum is not know, these operators will only perform their bitwise operations on the set of properties that have + // been previously set + PropertyFlags& operator^=(PropertyFlags other); + PropertyFlags& operator^=(Enum flag); + PropertyFlags operator^(PropertyFlags other) const; + PropertyFlags operator^(Enum flag) const; PropertyFlags operator~() const; void debugDumpBits(); @@ -227,7 +225,45 @@ template inline QByteArray PropertyFlags::encode() { return output; } -template inline void PropertyFlags::decode(const QByteArray& fromEncoded) { +template inline void PropertyFlags::decode(const QByteArray& fromEncodedBytes) { + + clear(); // we are cleared out! + + // first convert the ByteArray into a BitArray... + QBitArray encodedBits; + int bitCount = BITS_PER_BYTE * fromEncodedBytes.count(); + encodedBits.resize(bitCount); + + for(int byte = 0; byte < fromEncodedBytes.count(); byte++) { + char originalByte = fromEncodedBytes.at(byte); + for(int bit = 0; bit < BITS_PER_BYTE; bit++) { + int shiftBy = BITS_PER_BYTE - (bit + 1); + char maskBit = ( 1 << shiftBy); + bool bitValue = originalByte & maskBit; + encodedBits.setBit(byte * BITS_PER_BYTE + bit, bitValue); + } + } + + // next, read the leading bits to determine the correct number of bytes to decode (may not match the QByteArray) + int encodedByteCount = 0; + int bitAt; + for (bitAt = 0; bitAt < bitCount; bitAt++) { + if (encodedBits.at(bitAt)) { + encodedByteCount++; + } else { + break; + } + } + encodedByteCount++; // always at least one byte + int expectedBitCount = encodedByteCount * BITS_PER_BYTE; + + // Now, keep reading... + int flagsStartAt = bitAt + 1; + for (bitAt = flagsStartAt; bitAt < expectedBitCount; bitAt++) { + if (encodedBits.at(bitAt)) { + setHasProperty((Enum)(bitAt - flagsStartAt)); + } + } } template inline void PropertyFlags::debugDumpBits() { @@ -431,10 +467,6 @@ BitArr.resize(8*byteArr.count()); for(int i=0; i diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 7143e6ca7a..d15b77a53a 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -367,6 +367,34 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "propsC... encoded="; outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); } + + { + qDebug() << "Test 8: ParticlePropertyFlags: decode tests"; + ParticlePropertyFlags props; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + ParticlePropertyFlags propsDecoded; + + propsDecoded.decode(encoded); + + qDebug() << "propsDecoded == props:" << (propsDecoded == props) << "{ expect true }"; + + QByteArray encodedAfterDecoded = propsDecoded.encode(); + + qDebug() << "encodedAfterDecoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + } qDebug() << "******************************************************************************************"; } From 5251057ed62d95a308f3f80b0cc865d0aa210e0d Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 15:13:16 -0700 Subject: [PATCH 52/71] MovingPercentile moved else to same line as } --- libraries/shared/src/MovingPercentile.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/shared/src/MovingPercentile.cpp b/libraries/shared/src/MovingPercentile.cpp index c5c6f4284d..ec007b5c22 100644 --- a/libraries/shared/src/MovingPercentile.cpp +++ b/libraries/shared/src/MovingPercentile.cpp @@ -34,8 +34,7 @@ void MovingPercentile::updatePercentile(float sample) { // update _indexOfPercentile float index = _percentile * (float)(_samplesSorted.size() - 1); _indexOfPercentile = (int)(index + 0.5f); // round to int - } - else { + } else { // find index of sample with id = _newSampleId and replace it with new sample newSampleIndex = _sampleIds.indexOf(_newSampleId); _samplesSorted[newSampleIndex] = sample; From 2066dbcec78903535384c5ef3dc47a48d312ab86 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 15:16:51 -0700 Subject: [PATCH 53/71] cleanup --- libraries/shared/src/PropertyFlags.h | 95 +--------------------------- tests/octree/src/OctreeTests.cpp | 5 -- 2 files changed, 1 insertion(+), 99 deletions(-) diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index d19f52a846..b9253379c6 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -10,7 +10,7 @@ // // // TODO: -// * iterator to enumerate the set values? +// * consider adding iterator to enumerate the properties that have been set? #ifndef hifi_PropertyFlags_h #define hifi_PropertyFlags_h @@ -143,7 +143,6 @@ template inline bool PropertyFlags::getHasProperty(Enum fla const int BITS_PER_BYTE = 8; template inline QByteArray PropertyFlags::encode() { - const bool debug = false; QByteArray output; if (_maxFlag < _minFlag) { @@ -151,77 +150,31 @@ template inline QByteArray PropertyFlags::encode() { return output; // no flags... nothing to encode } - outputBufferBits((const unsigned char*)output.constData(), output.size()); - - if (debug) qDebug() << "PropertyFlags::encode()"; - // we should size the array to the correct size. int lengthInBytes = (_maxFlag / (BITS_PER_BYTE - 1)) + 1; - if (debug) qDebug() << " lengthInBytes=" << lengthInBytes; - output.fill(0, lengthInBytes); - if (debug) outputBufferBits((const unsigned char*)output.constData(), output.size()); - // next pack the number of header bits in, the first N-1 to be set to 1, the last to be set to 0 for(int i = 0; i < lengthInBytes; i++) { int outputIndex = i; - if (debug) qDebug() << "outputIndex:" << outputIndex; int bitValue = (i < (lengthInBytes - 1) ? 1 : 0); - - if (debug) qDebug() << " length code bit["<< outputIndex << "]=" << bitValue; - char original = output.at(outputIndex / BITS_PER_BYTE); int shiftBy = BITS_PER_BYTE - ((outputIndex % BITS_PER_BYTE) + 1); char thisBit = ( bitValue << shiftBy); - - if (debug) { - qDebug() << "bitValue:" << bitValue; - qDebug() << "shiftBy:" << shiftBy; - qDebug() << "original:"; - outputBits(original); - - qDebug() << "thisBit:"; - outputBits(thisBit); - } - output[i / BITS_PER_BYTE] = (original | thisBit); } - if (debug) outputBufferBits((const unsigned char*)output.constData(), output.size()); - // finally pack the the actual bits from the bit array for(int i = lengthInBytes; i < (lengthInBytes + _maxFlag + 1); i++) { int flagIndex = i - lengthInBytes; int outputIndex = i; - if (debug) qDebug() << "flagIndex:" << flagIndex; - if (debug) qDebug() << "outputIndex:" << outputIndex; - - int bitValue = ( _flags[flagIndex] ? 1 : 0); - - if (debug) qDebug() << " encode bit["< inline void PropertyFlags::shinkIfNeeded() { } } -/*** - -BitArr.resize(8*byteArr.count()); -for(int i=0; i -class QFlags -{ - typedef void **Zero; - int i; -public: - typedef Enum enum_type; - Q_DECL_CONSTEXPR inline QFlags(const QFlags &f) : i(f.i) {} - Q_DECL_CONSTEXPR inline QFlags(Enum f) : i(f) {} - Q_DECL_CONSTEXPR inline QFlags(Zero = 0) : i(0) {} - inline QFlags(QFlag f) : i(f) {} - - inline QFlags &operator=(const QFlags &f) { i = f.i; return *this; } - inline QFlags &operator&=(int mask) { i &= mask; return *this; } - inline QFlags &operator&=(uint mask) { i &= mask; return *this; } - inline QFlags &operator|=(QFlags f) { i |= f.i; return *this; } - inline QFlags &operator|=(Enum f) { i |= f; return *this; } - inline QFlags &operator^=(QFlags f) { i ^= f.i; return *this; } - inline QFlags &operator^=(Enum f) { i ^= f; return *this; } - - Q_DECL_CONSTEXPR inline operator int() const { return i; } - - Q_DECL_CONSTEXPR inline QFlags operator|(QFlags f) const { return QFlags(Enum(i | f.i)); } - Q_DECL_CONSTEXPR inline QFlags operator|(Enum f) const { return QFlags(Enum(i | f)); } - Q_DECL_CONSTEXPR inline QFlags operator^(QFlags f) const { return QFlags(Enum(i ^ f.i)); } - Q_DECL_CONSTEXPR inline QFlags operator^(Enum f) const { return QFlags(Enum(i ^ f)); } - Q_DECL_CONSTEXPR inline QFlags operator&(int mask) const { return QFlags(Enum(i & mask)); } - Q_DECL_CONSTEXPR inline QFlags operator&(uint mask) const { return QFlags(Enum(i & mask)); } - Q_DECL_CONSTEXPR inline QFlags operator&(Enum f) const { return QFlags(Enum(i & f)); } - Q_DECL_CONSTEXPR inline QFlags operator~() const { return QFlags(Enum(~i)); } - - Q_DECL_CONSTEXPR inline bool operator!() const { return !i; } - - inline bool testFlag(Enum f) const { return (i & f) == f && (f != 0 || i == int(f) ); } -}; - -***/ - #endif // hifi_PropertyFlags_h diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index d15b77a53a..436973ba52 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -352,13 +352,8 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "propsB... encoded="; outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); - qDebug() << "propsB..."; - propsB.debugDumpBits(); - qDebug() << "ParticlePropertyFlags propsC = ~propsB;"; ParticlePropertyFlags propsC = ~propsB; - qDebug() << "propsC..."; - propsC.debugDumpBits(); qDebug() << "propsC.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsC.getHasProperty(PARTICLE_PROP_VISIBLE)) << "{ expect false }"; From e8fa75b4f3d2bcb07f31b1682e18f3e3ba8aa5d9 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 4 Jun 2014 15:17:17 -0700 Subject: [PATCH 54/71] Added squeezeHands.js --- examples/squeezeFist.js | 47 -------------------------------------- examples/squeezeHands.js | 49 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 47 deletions(-) delete mode 100644 examples/squeezeFist.js create mode 100644 examples/squeezeHands.js diff --git a/examples/squeezeFist.js b/examples/squeezeFist.js deleted file mode 100644 index 85f817c964..0000000000 --- a/examples/squeezeFist.js +++ /dev/null @@ -1,47 +0,0 @@ -// -// squeezeFist.js -// examples -// -// Created by Philip Rosedale on 03-June-2014 -// Copyright 2014 High Fidelity, Inc. -// -// This is an example script that demonstrates an NPC avatar running an FBX animation loop. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var animation = AnimationCache.getAnimation("https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"); - -var jointMapping; - -var frameIndex = 0.0; - -var FRAME_RATE = 30.0; // frames per second - -Script.update.connect(function(deltaTime) { - var triggerValue = Controller.getTriggerValue(0); - print(triggerValue); - if (!jointMapping) { - var avatarJointNames = MyAvatar.jointNames; - var animationJointNames = animation.jointNames; - if (avatarJointNames.length === 0 || animationJointNames.length === 0) { - return; - } - jointMapping = new Array(avatarJointNames.length); - for (var i = 0; i < avatarJointNames.length; i++) { - jointMapping[i] = animationJointNames.indexOf(avatarJointNames[i]); - } - } - frameIndex += deltaTime * FRAME_RATE; - var frames = animation.frames; - var rotations = frames[Math.floor(frameIndex) % frames.length].rotations; - for (var j = 0; j < jointMapping.length; j++) { - var rotationIndex = jointMapping[j]; - if (rotationIndex != -1) { - MyAvatar.setJointData(j, rotations[rotationIndex]); - } - } -}); - - diff --git a/examples/squeezeHands.js b/examples/squeezeHands.js new file mode 100644 index 0000000000..8f2baf12b7 --- /dev/null +++ b/examples/squeezeHands.js @@ -0,0 +1,49 @@ +// +// squeezeHands.js +// examples +// +// Created by Philip Rosedale on June 4, 2014 +// Copyright 2014 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 +// + +var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"; +var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"; + +var LEFT = 0; +var RIGHT = 1; + +var lastLeftFrame = 0; +var lastRightFrame = 0; + +var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation? + +Script.update.connect(function(deltaTime) { + var leftTriggerValue = Controller.getTriggerValue(LEFT); + var rightTriggerValue = Controller.getTriggerValue(RIGHT); + + var leftFrame, rightFrame; + + // Average last two trigger frames together for a bit of smoothing + leftFrame = (leftTriggerValue * LAST_FRAME) * 0.5 + lastLeftFrame * 0.5; + rightFrame = (rightTriggerValue * LAST_FRAME) * 0.5 + lastRightFrame * 0.5; + + if (leftFrame != lastLeftFrame) { + MyAvatar.stopAnimation(leftHandAnimation); + MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); + } + if (rightFrame != lastRightFrame) { + MyAvatar.stopAnimation(rightHandAnimation); + MyAvatar.startAnimation(rightHandAnimation, 30.0, 1.0, false, true, rightFrame, rightFrame); + } + + lastLeftFrame = leftFrame; + lastRightFrame = rightFrame; +}); + +Script.scriptEnding.connect(function() { + MyAvatar.stopAnimation(leftHandAnimation); + MyAvatar.stopAnimation(rightHandAnimation); +}); \ No newline at end of file From c7a502e2c9437bf783dc551229a7517a5a7b1423 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 15:18:11 -0700 Subject: [PATCH 55/71] removed empty file --- libraries/shared/src/PropertyFlags.cpp | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 libraries/shared/src/PropertyFlags.cpp diff --git a/libraries/shared/src/PropertyFlags.cpp b/libraries/shared/src/PropertyFlags.cpp deleted file mode 100644 index 8413ce8172..0000000000 --- a/libraries/shared/src/PropertyFlags.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// PropertyFlags.cpp -// libraries/shared/src -// -// Created by Brad Hefta-Gaub on 6/3/14. -// Copyright 2014 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 -// - From 8bce7127aa207a5365782028969c558ca558932a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 4 Jun 2014 15:19:49 -0700 Subject: [PATCH 56/71] support for both hands, but no script for now in the left one --- examples/squeezeHands.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/squeezeHands.js b/examples/squeezeHands.js index 8f2baf12b7..3f24fa86b7 100644 --- a/examples/squeezeHands.js +++ b/examples/squeezeHands.js @@ -10,7 +10,7 @@ // var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"; -var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"; +var leftHandAnimation = ""; var LEFT = 0; var RIGHT = 1; @@ -30,11 +30,11 @@ Script.update.connect(function(deltaTime) { leftFrame = (leftTriggerValue * LAST_FRAME) * 0.5 + lastLeftFrame * 0.5; rightFrame = (rightTriggerValue * LAST_FRAME) * 0.5 + lastRightFrame * 0.5; - if (leftFrame != lastLeftFrame) { + if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){ MyAvatar.stopAnimation(leftHandAnimation); MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); } - if (rightFrame != lastRightFrame) { + if ((rightFrame != lastRightFrame) && rightHandAnimation.length) { MyAvatar.stopAnimation(rightHandAnimation); MyAvatar.startAnimation(rightHandAnimation, 30.0, 1.0, false, true, rightFrame, rightFrame); } From 152d99d8102fb34d95d007645678c8691d8287a0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 15:23:17 -0700 Subject: [PATCH 57/71] removed some old debug code and updated a comment --- libraries/models/src/ModelTreeElement.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index 3fc2537dc7..b0c7e125b4 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -50,6 +50,10 @@ ModelTreeElement* ModelTreeElement::addChildAtIndex(int index) { } +// TODO: This will attempt to store as many models as will fit in the packetData, if an individual model won't +// fit, but some models did fit, then the element outputs what can fit. Once the general Octree::encodeXXX() +// process supports partial encoding of an octree element, this will need to be updated to handle spanning its +// contents across multiple packets. bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = true; // assume the best... @@ -89,7 +93,6 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit actualNumberOfModels++; } if (!success) { - qDebug() << "ModelTreeElement::appendElementData()... model i=" << i << "didn't fit..."; packetData->discardLevel(modelLevel); break; } @@ -97,7 +100,6 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit } if (!success) { - qDebug() << "ModelTreeElement::appendElementData()... updatePriorBytes()... actualNumberOfModels=" << actualNumberOfModels; success = packetData->updatePriorBytes(numberOfModelsOffset, (const unsigned char*)&actualNumberOfModels, sizeof(actualNumberOfModels)); } From b74676de0d5af68f634f8b90485b7b97f61f6778 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Jun 2014 15:33:22 -0700 Subject: [PATCH 58/71] add more tests for decode --- tests/octree/src/OctreeTests.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 436973ba52..ddc3f2c74d 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -378,8 +378,9 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "encoded="; outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "encoded.size()=" << encoded.size(); + ParticlePropertyFlags propsDecoded; - propsDecoded.decode(encoded); qDebug() << "propsDecoded == props:" << (propsDecoded == props) << "{ expect true }"; @@ -387,7 +388,23 @@ void OctreeTests::propertyFlagsTests() { QByteArray encodedAfterDecoded = propsDecoded.encode(); qDebug() << "encodedAfterDecoded="; - outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + outputBufferBits((const unsigned char*)encodedAfterDecoded.constData(), encodedAfterDecoded.size()); + + qDebug() << "fill encoded byte array with extra garbage (as if it was bitstream with more content)"; + QByteArray extraContent; + extraContent.fill(0xba, 10); + encoded.append(extraContent); + qDebug() << "encoded.size()=" << encoded.size() << "includes extra garbage"; + + ParticlePropertyFlags propsDecodedExtra; + propsDecodedExtra.decode(encoded); + + qDebug() << "propsDecodedExtra == props:" << (propsDecodedExtra == props) << "{ expect true }"; + + QByteArray encodedAfterDecodedExtra = propsDecodedExtra.encode(); + + qDebug() << "encodedAfterDecodedExtra="; + outputBufferBits((const unsigned char*)encodedAfterDecodedExtra.constData(), encodedAfterDecodedExtra.size()); } From 864db25f4f2484bcb7d6f8a5e74e536d020e3e47 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 4 Jun 2014 15:43:33 -0700 Subject: [PATCH 59/71] remove unused variables causing warning --- interface/src/ui/ApplicationOverlay.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5869394f04..47aea70df9 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -324,7 +324,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { // Get vertical FoV of the displayed overlay texture const float halfVerticalAngle = _oculusAngle / 2.0f; - const float verticalAngle = halfVerticalAngle * 2.0f; const float overlayAspectRatio = glWidget->width() / (float)glWidget->height(); const float halfOverlayHeight = _distance * tan(halfVerticalAngle); @@ -393,7 +392,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { float newWidth = magnifyWidth * magnification; float newHeight = magnifyHeight * magnification; - float tmp; // Magnification Texture Coordinates float magnifyULeft = mouseX / (float)widgetWidth; @@ -409,8 +407,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { float leftAngle = (newMouseX / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; float rightAngle = ((newMouseX + newWidth) / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; - float halfMagnifyHeight = magnifyHeight / 2.0f; - float leftX, rightX, leftZ, rightZ; // Get position on hemisphere using angle From 124bd88b01d3264df7d13f96eef6cfa85539d280 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 4 Jun 2014 17:23:44 -0700 Subject: [PATCH 60/71] added tests for MovingPercentile --- tests/shared/CMakeLists.txt | 38 +++++ tests/shared/src/MovingPercentileTests.cpp | 169 +++++++++++++++++++++ tests/shared/src/MovingPercentileTests.h | 22 +++ tests/shared/src/main.cpp | 16 ++ 4 files changed, 245 insertions(+) create mode 100644 tests/shared/CMakeLists.txt create mode 100644 tests/shared/src/MovingPercentileTests.cpp create mode 100644 tests/shared/src/MovingPercentileTests.h create mode 100644 tests/shared/src/main.cpp diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt new file mode 100644 index 0000000000..b9513e3f26 --- /dev/null +++ b/tests/shared/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 2.8) + +if (WIN32) + cmake_policy (SET CMP0020 NEW) +endif (WIN32) + +set(TARGET_NAME shared-tests) + +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(Qt5Network REQUIRED) +#find_package(Qt5Script REQUIRED) +#find_package(Qt5Widgets REQUIRED) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +include(${MACRO_DIR}/AutoMTC.cmake) +auto_mtc(${TARGET_NAME} ${ROOT_DIR}) + +#qt5_use_modules(${TARGET_NAME} Network Script Widgets) + +#include glm +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link in the shared libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +IF (WIN32) + #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) +ENDIF(WIN32) + diff --git a/tests/shared/src/MovingPercentileTests.cpp b/tests/shared/src/MovingPercentileTests.cpp new file mode 100644 index 0000000000..26870717ca --- /dev/null +++ b/tests/shared/src/MovingPercentileTests.cpp @@ -0,0 +1,169 @@ +// +// MovingPercentileTests.cpp +// tests/shared/src +// +// Created by Yixin Wang on 6/4/2014 +// Copyright 2014 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 "MovingPercentileTests.h" + +#include "SharedUtil.h" +#include "MovingPercentile.h" + +#include + +float MovingPercentileTests::random() { + return rand() / (float)RAND_MAX; +} + +void MovingPercentileTests::runAllTests() { + + QVector valuesForN; + + valuesForN.append(1); + valuesForN.append(2); + valuesForN.append(3); + valuesForN.append(4); + valuesForN.append(5); + valuesForN.append(10); + valuesForN.append(100); + + + QQueue lastNSamples; + + for (int i=0; i N) { + lastNSamples.pop_front(); + } + + movingMin.updatePercentile(sample); + + float experimentMin = movingMin.getValueAtPercentile(); + + float actualMin = lastNSamples[0]; + for (int j = 0; j < lastNSamples.size(); j++) { + if (lastNSamples.at(j) < actualMin) { + actualMin = lastNSamples.at(j); + } + } + + if (experimentMin != actualMin) { + qDebug() << "\t\t FAIL at sample" << s; + fail = true; + break; + } + } + if (!fail) { + qDebug() << "\t\t PASS"; + } + } + + + { + bool fail = false; + + qDebug() << "\t testing running max..."; + + lastNSamples.clear(); + MovingPercentile movingMax(N, 1.0f); + + for (int s = 0; s < 10000; s++) { + + float sample = random(); + + lastNSamples.push_back(sample); + if (lastNSamples.size() > N) { + lastNSamples.pop_front(); + } + + movingMax.updatePercentile(sample); + + float experimentMax = movingMax.getValueAtPercentile(); + + float actualMax = lastNSamples[0]; + for (int j = 0; j < lastNSamples.size(); j++) { + if (lastNSamples.at(j) > actualMax) { + actualMax = lastNSamples.at(j); + } + } + + if (experimentMax != actualMax) { + qDebug() << "\t\t FAIL at sample" << s; + fail = true; + break; + } + } + if (!fail) { + qDebug() << "\t\t PASS"; + } + } + + + { + bool fail = false; + + qDebug() << "\t testing running median..."; + + lastNSamples.clear(); + MovingPercentile movingMedian(N, 0.5f); + + for (int s = 0; s < 10000; s++) { + + float sample = random(); + + lastNSamples.push_back(sample); + if (lastNSamples.size() > N) { + lastNSamples.pop_front(); + } + + movingMedian.updatePercentile(sample); + + float experimentMedian = movingMedian.getValueAtPercentile(); + + int samplesLessThan = 0; + int samplesMoreThan = 0; + + for (int j=0; j experimentMedian) { + samplesMoreThan++; + } + } + + + if (!(samplesLessThan <= N/2 && samplesMoreThan <= N-1/2)) { + qDebug() << "\t\t FAIL at sample" << s; + fail = true; + break; + } + } + if (!fail) { + qDebug() << "\t\t PASS"; + } + } + } +} + diff --git a/tests/shared/src/MovingPercentileTests.h b/tests/shared/src/MovingPercentileTests.h new file mode 100644 index 0000000000..34460880fb --- /dev/null +++ b/tests/shared/src/MovingPercentileTests.h @@ -0,0 +1,22 @@ +// +// MovingPercentileTests.h +// tests/shared/src +// +// Created by Yixin Wang on 6/4/2014 +// Copyright 2014 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_MovingPercentileTests_h +#define hifi_MovingPercentileTests_h + +namespace MovingPercentileTests { + + float random(); + + void runAllTests(); +} + +#endif // hifi_MovingPercentileTests_h diff --git a/tests/shared/src/main.cpp b/tests/shared/src/main.cpp new file mode 100644 index 0000000000..3ae1b7b34d --- /dev/null +++ b/tests/shared/src/main.cpp @@ -0,0 +1,16 @@ +// +// main.cpp +// tests/physics/src +// +// Copyright 2014 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 "MovingPercentileTests.h" + +int main(int argc, char** argv) { + MovingPercentileTests::runAllTests(); + return 0; +} From e60c671c0533395747138b3d7c74d7b503432666 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 4 Jun 2014 17:24:20 -0700 Subject: [PATCH 61/71] Switched Oculus UI to hemisphere. Added curved semicircle UI --- interface/src/Application.cpp | 6 - interface/src/ui/ApplicationOverlay.cpp | 239 ++++++++++++++++++++---- interface/src/ui/ApplicationOverlay.h | 14 +- 3 files changed, 215 insertions(+), 44 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c877822a45..721eb86410 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1007,12 +1007,6 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_At: Menu::getInstance()->goTo(); break; - case Qt::Key_B: - _applicationOverlay.setOculusAngle(_applicationOverlay.getOculusAngle() - RADIANS_PER_DEGREE); - break; - case Qt::Key_N: - _applicationOverlay.setOculusAngle(_applicationOverlay.getOculusAngle() + RADIANS_PER_DEGREE); - break; default: event->ignore(); break; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5869394f04..823e7b93e6 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -22,7 +22,8 @@ ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL), _oculusAngle(65.0f * RADIANS_PER_DEGREE), - _distance(0.5f) { + _distance(0.5f), + _uiType(HEMISPHERE) { } @@ -305,6 +306,8 @@ inline float min(float a, float b) { return (a < b) ? a : b; } +const float textureFov = PI / 2.5f; + // Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane. void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { @@ -316,8 +319,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { int mouseX = application->getMouseX(); int mouseY = application->getMouseY(); - int widgetWidth = glWidget->width(); - int widgetHeight = glWidget->height(); + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); float magnifyWidth = 80.0f; float magnifyHeight = 60.0f; const float magnification = 4.0f; @@ -327,17 +330,22 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { const float verticalAngle = halfVerticalAngle * 2.0f; const float overlayAspectRatio = glWidget->width() / (float)glWidget->height(); const float halfOverlayHeight = _distance * tan(halfVerticalAngle); + const float overlayHeight = halfOverlayHeight * 2.0f; // The more vertices, the better the curve const int numHorizontalVertices = 20; + const int numVerticalVertices = 20; // U texture coordinate width at each quad const float quadTexWidth = 1.0f / (numHorizontalVertices - 1); + const float quadTexHeight = 1.0f / (numVerticalVertices - 1); // Get horizontal angle and angle increment from vertical angle and aspect ratio const float horizontalAngle = halfVerticalAngle * 2.0f * overlayAspectRatio; const float angleIncrement = horizontalAngle / (numHorizontalVertices - 1); const float halfHorizontalAngle = horizontalAngle / 2; + const float verticalAngleIncrement = verticalAngle / (numVerticalVertices - 1); + glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); @@ -391,9 +399,10 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { magnifyHeight = widgetHeight - mouseY; } + const float halfMagnifyHeight = magnifyHeight / 2.0f; + float newWidth = magnifyWidth * magnification; float newHeight = magnifyHeight * magnification; - float tmp; // Magnification Texture Coordinates float magnifyULeft = mouseX / (float)widgetWidth; @@ -408,55 +417,118 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { // Get angle on the UI float leftAngle = (newMouseX / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; float rightAngle = ((newMouseX + newWidth) / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; - - float halfMagnifyHeight = magnifyHeight / 2.0f; + float bottomAngle = (newMouseY / (float)widgetHeight) * verticalAngle - halfVerticalAngle; + float topAngle = ((newMouseY - newHeight) / (float)widgetHeight) * verticalAngle - halfVerticalAngle; - float leftX, rightX, leftZ, rightZ; + + float leftX, rightX, leftZ, rightZ, topZ, bottomZ; // Get position on hemisphere using angle - leftX = sin(leftAngle) * _distance; - rightX = sin(rightAngle) * _distance; - leftZ = -cos(leftAngle) * _distance; - rightZ = -cos(rightAngle) * _distance; - - float bottomY = (1.0 - newMouseY / (float)widgetHeight) * halfOverlayHeight * 2.0f - halfOverlayHeight; - float topY = bottomY + (newHeight / widgetHeight) * halfOverlayHeight * 2; + if (_uiType == HEMISPHERE) { - //TODO: Remove immediate mode in favor of VBO - glBegin(GL_QUADS); + //Get new UV coordinates from our magnification window + float newULeft = newMouseX / widgetWidth; + float newURight = (newMouseX + newWidth) / widgetWidth; + float newVBottom = 1.0 - newMouseY / widgetHeight; + float newVTop = 1.0 - (newMouseY - newHeight) / widgetHeight; - glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(leftX, topY, leftZ); - glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rightX, topY, rightZ); - glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rightX, bottomY, rightZ); - glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(leftX, bottomY, leftZ); + // Project our position onto the hemisphere using the UV coordinates + float lX = sin((newULeft - 0.5f) * textureFov); + float rX = sin((newURight - 0.5f) * textureFov); + float bY = sin((newVBottom - 0.5f) * textureFov); + float tY = sin((newVTop - 0.5f) * textureFov); + + float dist; + //Bottom Left + dist = sqrt(lX * lX + bY * bY); + float blZ = sqrt(1.0f - dist * dist); + //Top Left + dist = sqrt(lX * lX + tY * tY); + float tlZ = sqrt(1.0f - dist * dist); + //Bottom Right + dist = sqrt(rX * rX + bY * bY); + float brZ = sqrt(1.0f - dist * dist); + //Top Right + dist = sqrt(rX * rX + tY * tY); + float trZ = sqrt(1.0f - dist * dist); - glEnd(); + glBegin(GL_QUADS); + glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(lX, tY, -tlZ); + glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rX, tY, -trZ); + glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rX, bY, -brZ); + glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(lX, bY, -blZ); + + glEnd(); + + } else { + leftX = sin(leftAngle) * _distance; + rightX = sin(rightAngle) * _distance; + leftZ = -cos(leftAngle) * _distance; + rightZ = -cos(rightAngle) * _distance; + if (_uiType == CURVED_SEMICIRCLE) { + topZ = -cos(topAngle * overlayAspectRatio) * _distance; + bottomZ = -cos(bottomAngle * overlayAspectRatio) * _distance; + } else { + // Dont want to use topZ or bottomZ for SEMICIRCLE + topZ = -99999; + bottomZ = -99999; + } + + float bottomY = (1.0 - newMouseY / (float)widgetHeight) * halfOverlayHeight * 2.0f - halfOverlayHeight; + float topY = bottomY + (newHeight / widgetHeight) * halfOverlayHeight * 2; + + //TODO: Remove immediate mode in favor of VBO + glBegin(GL_QUADS); + + glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(leftX, topY, max(topZ, leftZ)); + glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rightX, topY, max(topZ, rightZ)); + glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rightX, bottomY, max(bottomZ, rightZ)); + glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(leftX, bottomY, max(bottomZ, leftZ)); + + glEnd(); + } glDepthMask(GL_FALSE); glDisable(GL_ALPHA_TEST); //TODO: Remove immediate mode in favor of VBO - glBegin(GL_QUADS); - // Place the vertices in a semicircle curve around the camera - for (int i = 0; i < numHorizontalVertices-1; i++) { + if (_uiType == HEMISPHERE) { + renderTexturedHemisphere(); + } else{ + glBegin(GL_QUADS); + // Place the vertices in a semicircle curve around the camera + for (int i = 0; i < numHorizontalVertices - 1; i++) { + for (int j = 0; j < numVerticalVertices - 1; j++) { - // Calculate the X and Z coordinates from the angles and radius from camera - leftX = sin(angleIncrement * i - halfHorizontalAngle) * _distance; - rightX = sin(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance; - leftZ = -cos(angleIncrement * i - halfHorizontalAngle) * _distance; - rightZ = -cos(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance; + // Calculate the X and Z coordinates from the angles and radius from camera + leftX = sin(angleIncrement * i - halfHorizontalAngle) * _distance; + rightX = sin(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance; + leftZ = -cos(angleIncrement * i - halfHorizontalAngle) * _distance; + rightZ = -cos(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance; + if (_uiType == 2) { + topZ = -cos((verticalAngleIncrement * (j + 1) - halfVerticalAngle) * overlayAspectRatio) * _distance; + bottomZ = -cos((verticalAngleIncrement * j - halfVerticalAngle) * overlayAspectRatio) * _distance; + } else { + topZ = -99999; + bottomZ = -99999; + } - glTexCoord2f(quadTexWidth * i, 1); glVertex3f(leftX, halfOverlayHeight, leftZ); - glTexCoord2f(quadTexWidth * (i + 1), 1); glVertex3f(rightX, halfOverlayHeight, rightZ); - glTexCoord2f(quadTexWidth * (i + 1), 0); glVertex3f(rightX, -halfOverlayHeight, rightZ); - glTexCoord2f(quadTexWidth * i, 0); glVertex3f(leftX, -halfOverlayHeight, leftZ); + glTexCoord2f(quadTexWidth * i, (j + 1) * quadTexHeight); + glVertex3f(leftX, (j + 1) * quadTexHeight * overlayHeight - halfOverlayHeight, max(topZ, leftZ)); + glTexCoord2f(quadTexWidth * (i + 1), (j + 1) * quadTexHeight); + glVertex3f(rightX, (j + 1) * quadTexHeight * overlayHeight - halfOverlayHeight, max(topZ, rightZ)); + glTexCoord2f(quadTexWidth * (i + 1), j * quadTexHeight); + glVertex3f(rightX, j * quadTexHeight * overlayHeight - halfOverlayHeight, max(bottomZ, rightZ)); + glTexCoord2f(quadTexWidth * i, j * quadTexHeight); + glVertex3f(leftX, j * quadTexHeight * overlayHeight - halfOverlayHeight, max(bottomZ, leftZ)); + } + } + + glEnd(); } - - glEnd(); glPopMatrix(); - glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); @@ -466,13 +538,106 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { } +void ApplicationOverlay::renderTexturedHemisphere() { + const int slices = 80; + const int stacks = 80; + + static VerticesIndices vbo(0, 0); + int vertices = slices * (stacks - 1) + 1; + int indices = slices * 2 * 3 * (stacks - 2) + slices * 3; + if (vbo.first == 0) { + TextureVertex* vertexData = new TextureVertex[vertices]; + TextureVertex* vertex = vertexData; + for (int i = 0; i < stacks - 1; i++) { + float phi = PI_OVER_TWO * (float)i / (float)(stacks - 1); + float z = -sinf(phi), radius = cosf(phi); + + for (int j = 0; j < slices; j++) { + float theta = TWO_PI * (float)j / (float)slices; + + vertex->position.x = sinf(theta) * radius; + vertex->position.y = cosf(theta) * radius; + vertex->position.z = z; + vertex->uv.x = asin(vertex->position.x) / (textureFov) + 0.5f; + vertex->uv.y = asin(vertex->position.y) / (textureFov) + 0.5f; + vertex++; + } + } + vertex->position.x = 0.0f; + vertex->position.y = 0.0f; + vertex->position.z = -1.0f; + vertex->uv.x = 0.5f; + vertex->uv.y = 0.5f; + vertex++; + + glGenBuffers(1, &vbo.first); + glBindBuffer(GL_ARRAY_BUFFER, vbo.first); + const int BYTES_PER_VERTEX = sizeof(TextureVertex); + glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + delete[] vertexData; + + GLushort* indexData = new GLushort[indices]; + GLushort* index = indexData; + for (int i = 0; i < stacks - 2; i++) { + GLushort bottom = i * slices; + GLushort top = bottom + slices; + for (int j = 0; j < slices; j++) { + int next = (j + 1) % slices; + + *(index++) = bottom + j; + *(index++) = top + next; + *(index++) = top + j; + + *(index++) = bottom + j; + *(index++) = bottom + next; + *(index++) = top + next; + } + } + GLushort bottom = (stacks - 2) * slices; + GLushort top = bottom + slices; + for (int i = 0; i < slices; i++) { + *(index++) = bottom + i; + *(index++) = bottom + (i + 1) % slices; + *(index++) = top; + } + + glGenBuffers(1, &vbo.second); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); + const int BYTES_PER_INDEX = sizeof(GLushort); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + delete[] indexData; + + } else { + glBindBuffer(GL_ARRAY_BUFFER, vbo.first); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(3, GL_FLOAT, sizeof(TextureVertex), (void*)0); + glTexCoordPointer(2, GL_FLOAT, sizeof(TextureVertex), (void*)12); + + glDrawRangeElements(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + +} + QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() { if (!_framebufferObject) { _framebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); - glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); glBindTexture(GL_TEXTURE_2D, 0); } return _framebufferObject; diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 4faa0b69f5..84cdabae4a 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -19,6 +19,8 @@ class QOpenGLFramebufferObject; class ApplicationOverlay { public: + static enum UITYPES { HEMISPHERE, SEMICIRCLE, CURVED_SEMICIRCLE }; + ApplicationOverlay(); ~ApplicationOverlay(); @@ -32,14 +34,24 @@ public: // Setters void setOculusAngle(float oculusAngle) { _oculusAngle = oculusAngle; } + void setUiType(UITYPES uiType) { _uiType = uiType; } private: + // Interleaved vertex data + struct TextureVertex { + glm::vec3 position; + glm::vec2 uv; + }; + + typedef QPair VerticesIndices; + + void renderTexturedHemisphere(); - ProgramObject _textureProgram; QOpenGLFramebufferObject* _framebufferObject; float _trailingAudioLoudness; float _oculusAngle; float _distance; + int _uiType; }; #endif // hifi_ApplicationOverlay_h \ No newline at end of file From 54a5bc3a497d14dbbadb189ede1cbdfe46bfebb1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 4 Jun 2014 17:24:43 -0700 Subject: [PATCH 62/71] More enum stuff, with tests. --- libraries/metavoxels/src/Bitstream.cpp | 225 +++++++++++++++++++----- libraries/metavoxels/src/Bitstream.h | 28 ++- tests/metavoxels/src/MetavoxelTests.cpp | 29 ++- tests/metavoxels/src/MetavoxelTests.h | 23 ++- 4 files changed, 250 insertions(+), 55 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 0093e419f8..81ae371fb8 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -71,6 +71,10 @@ IDStreamer& IDStreamer::operator>>(int& value) { return *this; } +static QByteArray getEnumName(const QMetaEnum& metaEnum) { + return QByteArray(metaEnum.scope()) + "::" + metaEnum.name(); +} + int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) { getMetaObjects().insert(className, metaObject); @@ -84,12 +88,7 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta QMetaEnum metaEnum = metaObject->enumerator(i); const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; if (!streamer) { - int highestValue = 0; - for (int j = 0; j < metaEnum.keyCount(); j++) { - highestValue = qMax(highestValue, metaEnum.value(j)); - } - streamer = new EnumTypeStreamer(QByteArray(metaEnum.scope()) + "::" + metaEnum.name(), - highestValue == 0 ? 0 : 1 + (int)(log(highestValue) / log(2.0))); + getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); } } @@ -135,6 +134,14 @@ void Bitstream::addTypeSubstitution(const QByteArray& typeName, int type) { _typeStreamerSubstitutions.insert(typeName, getTypeStreamers().value(type)); } +void Bitstream::addTypeSubstitution(const QByteArray& typeName, const char* replacementTypeName) { + const TypeStreamer* streamer = getTypeStreamers().value(QMetaType::type(replacementTypeName)); + if (!streamer) { + streamer = getEnumStreamersByName().value(replacementTypeName); + } + _typeStreamerSubstitutions.insert(typeName, streamer); +} + const int LAST_BIT_POSITION = BITS_IN_BYTE - 1; Bitstream& Bitstream::write(const void* data, int bits, int offset) { @@ -659,9 +666,27 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { case TypeReader::SIMPLE_TYPE: return *this; - case TypeReader::ENUM_TYPE: - return *this << streamer->getBits(); - + case TypeReader::ENUM_TYPE: { + QMetaEnum metaEnum = streamer->getMetaEnum(); + if (_metadataType == FULL_METADATA) { + *this << metaEnum.keyCount(); + for (int i = 0; i < metaEnum.keyCount(); i++) { + *this << QByteArray::fromRawData(metaEnum.key(i), strlen(metaEnum.key(i))); + *this << metaEnum.value(i); + } + } else { + *this << streamer->getBits(); + QCryptographicHash hash(QCryptographicHash::Md5); + for (int i = 0; i < metaEnum.keyCount(); i++) { + hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1); + qint32 value = metaEnum.value(i); + hash.addData((const char*)&value, sizeof(qint32)); + } + QByteArray hashResult = hash.result(); + write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE); + } + return *this; + } case TypeReader::LIST_TYPE: case TypeReader::SET_TYPE: return *this << streamer->getValueStreamer(); @@ -694,6 +719,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { return *this; } +static int getBitsForHighestValue(int highestValue) { + return (highestValue == 0) ? 0 : 1 + (int)(log(highestValue) / log(2.0)); +} + Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray typeName; *this >> typeName; @@ -703,14 +732,9 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { } const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); if (!streamer) { - int index = typeName.indexOf("::"); - if (index == -1) { - streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); - } else { - int postIndex = index + 2; - streamer = getEnumStreamers().value(QPair( - QByteArray::fromRawData(typeName.constData(), index), - QByteArray::fromRawData(typeName.constData() + postIndex, typeName.size() - postIndex))); + streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + if (!streamer) { + streamer = getEnumStreamersByName().value(typeName); } } if (!streamer) { @@ -728,12 +752,50 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { return *this; case TypeReader::ENUM_TYPE: { - int bits; - *this >> bits; - if (streamer && streamer->getReaderType() == type) { - reader = TypeReader(typeName, streamer); + if (_metadataType == FULL_METADATA) { + int keyCount; + *this >> keyCount; + QMetaEnum metaEnum = (streamer && streamer->getReaderType() == TypeReader::ENUM_TYPE) ? + streamer->getMetaEnum() : QMetaEnum(); + QHash mappings; + bool matches = (keyCount == metaEnum.keyCount()); + int highestValue = 0; + for (int i = 0; i < keyCount; i++) { + QByteArray key; + int value; + *this >> key >> value; + highestValue = qMax(value, highestValue); + int localValue = metaEnum.keyToValue(key); + if (localValue != -1) { + mappings.insert(value, localValue); + } + matches &= (value == localValue); + } + if (matches) { + reader = TypeReader(typeName, streamer); + } else { + reader = TypeReader(typeName, streamer, getBitsForHighestValue(highestValue), mappings); + } } else { - reader = TypeReader(typeName, streamer, false, TypeReader::ENUM_TYPE, bits); + int bits; + *this >> bits; + QCryptographicHash hash(QCryptographicHash::Md5); + if (streamer && streamer->getReaderType() == TypeReader::ENUM_TYPE) { + QMetaEnum metaEnum = streamer->getMetaEnum(); + for (int i = 0; i < metaEnum.keyCount(); i++) { + hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1); + qint32 value = metaEnum.value(i); + hash.addData((const char*)&value, sizeof(qint32)); + } + } + QByteArray localHashResult = hash.result(); + QByteArray remoteHashResult(localHashResult.size(), 0); + read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); + if (localHashResult == remoteHashResult) { + reader = TypeReader(typeName, streamer); + } else { + reader = TypeReader(typeName, streamer, bits, QHash()); + } } return *this; } @@ -745,7 +807,7 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { valueReader.matchesExactly(streamer->getValueStreamer())) { reader = TypeReader(typeName, streamer); } else { - reader = TypeReader(typeName, streamer, false, (TypeReader::Type)type, 0, TypeReaderPointer(), + reader = TypeReader(typeName, streamer, (TypeReader::Type)type, TypeReaderPointer(new TypeReader(valueReader))); } return *this; @@ -758,8 +820,8 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { valueReader.matchesExactly(streamer->getValueStreamer())) { reader = TypeReader(typeName, streamer); } else { - reader = TypeReader(typeName, streamer, false, TypeReader::MAP_TYPE, 0, - TypeReaderPointer(new TypeReader(keyReader)), TypeReaderPointer(new TypeReader(valueReader))); + reader = TypeReader(typeName, streamer, TypeReaderPointer(new TypeReader(keyReader)), + TypeReaderPointer(new TypeReader(valueReader))); } return *this; } @@ -817,23 +879,20 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { // if all fields are the same type and in the right order, we can use the (more efficient) default streamer const QVector& localFields = streamer->getMetaFields(); if (fieldCount != localFields.size()) { - reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE, - 0, TypeReaderPointer(), TypeReaderPointer(), fields); + reader = TypeReader(typeName, streamer, fields); return *this; } for (int i = 0; i < fieldCount; i++) { const FieldReader& fieldReader = fields.at(i); if (!fieldReader.getReader().matchesExactly(localFields.at(i).getStreamer()) || fieldReader.getIndex() != i) { - reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE, - 0, TypeReaderPointer(), TypeReaderPointer(), fields); + reader = TypeReader(typeName, streamer, fields); return *this; } } reader = TypeReader(typeName, streamer); return *this; } - reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE, - 0, TypeReaderPointer(), TypeReaderPointer(), fields); + reader = TypeReader(typeName, streamer, fields); return *this; } @@ -969,6 +1028,11 @@ QHash, const TypeStreamer*>& Bitstream::getEnumStr return enumStreamers; } +QHash& Bitstream::getEnumStreamersByName() { + static QHash enumStreamersByName; + return enumStreamersByName; +} + QVector Bitstream::getPropertyReaders(const QMetaObject* metaObject) { QVector propertyReaders; if (!metaObject) { @@ -995,24 +1059,62 @@ QVector Bitstream::getPropertyReaders(const QMetaObject* metaObj return propertyReaders; } -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch, Type type, int bits, - const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader, const QVector& fields) : +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) : _typeName(typeName), _streamer(streamer), - _exactMatch(exactMatch), - _type(type), + _exactMatch(true) { +} + +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, int bits, const QHash& mappings) : + _typeName(typeName), + _streamer(streamer), + _exactMatch(false), + _type(ENUM_TYPE), _bits(bits), - _keyReader(keyReader), - _valueReader(valueReader), + _mappings(mappings) { +} + +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, const QVector& fields) : + _typeName(typeName), + _streamer(streamer), + _exactMatch(false), + _type(STREAMABLE_TYPE), _fields(fields) { } +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, + Type type, const TypeReaderPointer& valueReader) : + _typeName(typeName), + _streamer(streamer), + _exactMatch(false), + _type(type), + _valueReader(valueReader) { +} + +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, + const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader) : + _typeName(typeName), + _streamer(streamer), + _exactMatch(false), + _type(MAP_TYPE), + _keyReader(keyReader), + _valueReader(valueReader) { +} + QVariant TypeReader::read(Bitstream& in) const { if (_exactMatch) { return _streamer->read(in); } QVariant object = _streamer ? QVariant(_streamer->getType(), 0) : QVariant(); switch (_type) { + case ENUM_TYPE: { + int value = 0; + in.read(&value, _bits); + if (_streamer) { + _streamer->setEnumValue(object, value, _mappings); + } + break; + } case STREAMABLE_TYPE: { foreach (const FieldReader& field, _fields) { field.read(in, _streamer, object); @@ -1069,6 +1171,14 @@ void TypeReader::readRawDelta(Bitstream& in, QVariant& object, const QVariant& r return; } switch (_type) { + case ENUM_TYPE: { + int value = 0; + in.read(&value, _bits); + if (_streamer) { + _streamer->setEnumValue(object, value, _mappings); + } + break; + } case STREAMABLE_TYPE: { foreach (const FieldReader& field, _fields) { field.readDelta(in, _streamer, object, reference); @@ -1269,6 +1379,10 @@ const char* TypeStreamer::getName() const { return QMetaType::typeName(_type); } +void TypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) const { + // nothing by default +} + const QVector& TypeStreamer::getMetaFields() const { static QVector emptyMetaFields; return emptyMetaFields; @@ -1294,6 +1408,10 @@ int TypeStreamer::getBits() const { return 0; } +QMetaEnum TypeStreamer::getMetaEnum() const { + return QMetaEnum(); +} + const TypeStreamer* TypeStreamer::getKeyStreamer() const { return NULL; } @@ -1338,9 +1456,17 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { return debug << (metaObject ? metaObject->className() : "null"); } -EnumTypeStreamer::EnumTypeStreamer(const QByteArray& name, int bits) : - _name(name), - _bits(bits) { +EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) : + _metaEnum(metaEnum), + _name(getEnumName(metaEnum)) { + + setType(QMetaType::Int); + + int highestValue = 0; + for (int j = 0; j < metaEnum.keyCount(); j++) { + highestValue = qMax(highestValue, metaEnum.value(j)); + } + _bits = getBitsForHighestValue(highestValue); } const char* EnumTypeStreamer::getName() const { @@ -1355,6 +1481,10 @@ int EnumTypeStreamer::getBits() const { return _bits; } +QMetaEnum EnumTypeStreamer::getMetaEnum() const { + return _metaEnum; +} + bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) const { return first.toInt() == second.toInt(); } @@ -1403,3 +1533,18 @@ void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVaria value = intValue; } +void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) const { + if (_metaEnum.isFlag()) { + int combined = 0; + for (QHash::const_iterator it = mappings.constBegin(); it != mappings.constEnd(); it++) { + if (value & it.key()) { + combined |= it.value(); + } + } + object = combined; + + } else { + object = mappings.value(value); + } +} + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 02be736e02..146713910f 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -236,6 +236,9 @@ public: /// Substitutes the supplied type for the given type name's default mapping. void addTypeSubstitution(const QByteArray& typeName, int type); + /// Substitutes the named type for the given type name's default mapping. + void addTypeSubstitution(const QByteArray& typeName, const char* replacementTypeName); + /// Writes a set of bits to the underlying stream. /// \param bits the number of bits to write /// \param offset the offset of the first bit @@ -424,6 +427,7 @@ private: static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); static QHash, const TypeStreamer*>& getEnumStreamers(); + static QHash& getEnumStreamersByName(); static QVector getPropertyReaders(const QMetaObject* metaObject); }; @@ -716,11 +720,18 @@ public: enum Type { SIMPLE_TYPE, ENUM_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; - TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true, - Type type = SIMPLE_TYPE, int bits = 0, const TypeReaderPointer& keyReader = TypeReaderPointer(), - const TypeReaderPointer& valueReader = TypeReaderPointer(), - const QVector& fields = QVector()); + TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL); + + TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, int bits, const QHash& mappings); + + TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, const QVector& fields); + TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, Type type, + const TypeReaderPointer& valueReader); + + TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, + const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader); + const QByteArray& getTypeName() const { return _typeName; } const TypeStreamer* getStreamer() const { return _streamer; } @@ -740,6 +751,7 @@ private: bool _exactMatch; Type _type; int _bits; + QHash _mappings; TypeReaderPointer _keyReader; TypeReaderPointer _valueReader; QVector _fields; @@ -871,6 +883,8 @@ public: virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const = 0; virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const = 0; + virtual void setEnumValue(QVariant& object, int value, const QHash& mappings) const; + virtual const QVector& getMetaFields() const; virtual int getFieldIndex(const QByteArray& name) const; virtual void setField(QVariant& object, int index, const QVariant& value) const; @@ -879,6 +893,7 @@ public: virtual TypeReader::Type getReaderType() const; virtual int getBits() const; + virtual QMetaEnum getMetaEnum() const; virtual const TypeStreamer* getKeyStreamer() const; virtual const TypeStreamer* getValueStreamer() const; @@ -923,11 +938,12 @@ public: class EnumTypeStreamer : public TypeStreamer { public: - EnumTypeStreamer(const QByteArray& name, int bits); + EnumTypeStreamer(const QMetaEnum& metaEnum); virtual const char* getName() const; virtual TypeReader::Type getReaderType() const; virtual int getBits() const; + virtual QMetaEnum getMetaEnum() const; virtual bool equal(const QVariant& first, const QVariant& second) const; virtual void write(Bitstream& out, const QVariant& value) const; virtual QVariant read(Bitstream& in) const; @@ -935,9 +951,11 @@ public: virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; + virtual void setEnumValue(QVariant& object, int value, const QHash& mappings) const; private: + QMetaEnum _metaEnum; QByteArray _name; int _bits; }; diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 1b7eaf9a22..603f63b587 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -87,9 +87,11 @@ static bool testSerialization(Bitstream::MetadataType metadataType) { QByteArray array; QDataStream outStream(&array, QIODevice::WriteOnly); Bitstream out(outStream, metadataType); - SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat(), getRandomTestEnum(), getRandomTestFlags()); + SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat(), TestSharedObjectA::SECOND_TEST_ENUM, + TestSharedObjectA::TestFlags(TestSharedObjectA::FIRST_TEST_FLAG | TestSharedObjectA::THIRD_TEST_FLAG)); out << testObjectWrittenA; - SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes()); + SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes(), + TestSharedObjectB::THIRD_TEST_ENUM, TestSharedObjectB::SECOND_TEST_FLAG); out << testObjectWrittenB; TestMessageC messageWritten = createRandomMessageC(); out << QVariant::fromValue(messageWritten); @@ -102,6 +104,10 @@ static bool testSerialization(Bitstream::MetadataType metadataType) { in.addMetaObjectSubstitution("TestSharedObjectA", &TestSharedObjectB::staticMetaObject); in.addMetaObjectSubstitution("TestSharedObjectB", &TestSharedObjectA::staticMetaObject); in.addTypeSubstitution("TestMessageC", TestMessageA::Type); + in.addTypeSubstitution("TestSharedObjectA::TestEnum", "TestSharedObjectB::TestEnum"); + in.addTypeSubstitution("TestSharedObjectB::TestEnum", "TestSharedObjectA::TestEnum"); + in.addTypeSubstitution("TestSharedObjectA::TestFlags", "TestSharedObjectB::TestFlags"); + in.addTypeSubstitution("TestSharedObjectB::TestFlags", "TestSharedObjectA::TestFlags"); SharedObjectPointer testObjectReadA; in >> testObjectReadA; @@ -109,8 +115,11 @@ static bool testSerialization(Bitstream::MetadataType metadataType) { qDebug() << "Wrong class for A" << testObjectReadA << metadataType; return true; } - if (metadataType == Bitstream::FULL_METADATA && static_cast(testObjectWrittenA.data())->getFoo() != - static_cast(testObjectReadA.data())->getFoo()) { + if (metadataType == Bitstream::FULL_METADATA && (static_cast(testObjectWrittenA.data())->getFoo() != + static_cast(testObjectReadA.data())->getFoo() || + static_cast(testObjectReadA.data())->getBaz() != TestSharedObjectB::SECOND_TEST_ENUM || + static_cast(testObjectReadA.data())->getBong() != + TestSharedObjectB::TestFlags(TestSharedObjectB::FIRST_TEST_FLAG | TestSharedObjectB::THIRD_TEST_FLAG))) { QDebug debug = qDebug() << "Failed to transfer shared field from A to B"; testObjectWrittenA->dump(debug); testObjectReadA->dump(debug); @@ -123,8 +132,10 @@ static bool testSerialization(Bitstream::MetadataType metadataType) { qDebug() << "Wrong class for B" << testObjectReadB << metadataType; return true; } - if (metadataType == Bitstream::FULL_METADATA && static_cast(testObjectWrittenB.data())->getFoo() != - static_cast(testObjectReadB.data())->getFoo()) { + if (metadataType == Bitstream::FULL_METADATA && (static_cast(testObjectWrittenB.data())->getFoo() != + static_cast(testObjectReadB.data())->getFoo() || + static_cast(testObjectReadB.data())->getBaz() != TestSharedObjectA::THIRD_TEST_ENUM || + static_cast(testObjectReadB.data())->getBong() != TestSharedObjectA::SECOND_TEST_FLAG)) { QDebug debug = qDebug() << "Failed to transfer shared field from B to A"; testObjectWrittenB->dump(debug); testObjectReadB->dump(debug); @@ -433,9 +444,11 @@ void TestSharedObjectA::setFoo(float foo) { } } -TestSharedObjectB::TestSharedObjectB(float foo, const QByteArray& bar) : +TestSharedObjectB::TestSharedObjectB(float foo, const QByteArray& bar, TestEnum baz, TestFlags bong) : _foo(foo), - _bar(bar) { + _bar(bar), + _baz(baz), + _bong(bong) { sharedObjectsCreated++; } diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index a4aa428a1e..5e020b1e60 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -109,12 +109,23 @@ private: /// Another simple shared object. class TestSharedObjectB : public SharedObject { Q_OBJECT + Q_ENUMS(TestEnum) + Q_FLAGS(TestFlag TestFlags) Q_PROPERTY(float foo READ getFoo WRITE setFoo) Q_PROPERTY(QByteArray bar READ getBar WRITE setBar) - + Q_PROPERTY(TestEnum baz READ getBaz WRITE setBaz) + Q_PROPERTY(TestFlags bong READ getBong WRITE setBong) + public: - Q_INVOKABLE TestSharedObjectB(float foo = 0.0f, const QByteArray& bar = QByteArray()); + enum TestEnum { ZEROTH_TEST_ENUM, FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM, FOURTH_TEST_ENUM }; + + enum TestFlag { NO_TEST_FLAGS = 0x0, ZEROTH_TEST_FLAG = 0x01, FIRST_TEST_FLAG = 0x02, + SECOND_TEST_FLAG = 0x04, THIRD_TEST_FLAG = 0x08, FOURTH_TEST_FLAG = 0x10 }; + Q_DECLARE_FLAGS(TestFlags, TestFlag) + + Q_INVOKABLE TestSharedObjectB(float foo = 0.0f, const QByteArray& bar = QByteArray(), + TestEnum baz = FIRST_TEST_ENUM, TestFlags bong = 0); virtual ~TestSharedObjectB(); void setFoo(float foo) { _foo = foo; } @@ -123,10 +134,18 @@ public: void setBar(const QByteArray& bar) { _bar = bar; } const QByteArray& getBar() const { return _bar; } + void setBaz(TestEnum baz) { _baz = baz; } + TestEnum getBaz() const { return _baz; } + + void setBong(TestFlags bong) { _bong = bong; } + TestFlags getBong() const { return _bong; } + private: float _foo; QByteArray _bar; + TestEnum _baz; + TestFlags _bong; }; /// A simple test message. From 9ec2a5aec17b095db8648bc9abbae40351dace41 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 4 Jun 2014 17:39:42 -0700 Subject: [PATCH 63/71] Avoid ambiguous call to log on Windows. --- libraries/metavoxels/src/Bitstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 81ae371fb8..cf9fa25d96 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -720,7 +720,7 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { } static int getBitsForHighestValue(int highestValue) { - return (highestValue == 0) ? 0 : 1 + (int)(log(highestValue) / log(2.0)); + return (highestValue == 0) ? 0 : 1 + (int)(glm::log(highestValue) / glm::log(2.0)); } Bitstream& Bitstream::operator>(TypeReader& reader) { From 37382304f7d1501658a14e75b418e06fd339880c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 4 Jun 2014 17:41:36 -0700 Subject: [PATCH 64/71] Perhaps this will avoid the ambiguity in Windows. --- libraries/metavoxels/src/Bitstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index cf9fa25d96..dc74594816 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -720,7 +720,7 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { } static int getBitsForHighestValue(int highestValue) { - return (highestValue == 0) ? 0 : 1 + (int)(glm::log(highestValue) / glm::log(2.0)); + return (highestValue == 0) ? 0 : 1 + (int)(log((double)highestValue) / log(2.0)); } Bitstream& Bitstream::operator>(TypeReader& reader) { From fd2893bf6df8e6dba6d5b237a715180a557212d9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 4 Jun 2014 18:23:31 -0700 Subject: [PATCH 65/71] Get rid of the log calls entirely; use the same code that we use for the ID streamer. --- libraries/metavoxels/src/Bitstream.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index dc74594816..30d34580d7 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -47,11 +47,19 @@ IDStreamer::IDStreamer(Bitstream& stream) : _bits(1) { } -void IDStreamer::setBitsFromValue(int value) { - _bits = 1; - while (value >= (1 << _bits) - 1) { - _bits++; +static int getBitsForHighestValue(int highestValue) { + // if this turns out to be a bottleneck, there are fancier ways to do it (get the position of the highest set bit): + // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious + int bits = 0; + while (highestValue != 0) { + bits++; + highestValue >>= 1; } + return bits; +} + +void IDStreamer::setBitsFromValue(int value) { + _bits = getBitsForHighestValue(value + 1); } IDStreamer& IDStreamer::operator<<(int value) { @@ -719,10 +727,6 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { return *this; } -static int getBitsForHighestValue(int highestValue) { - return (highestValue == 0) ? 0 : 1 + (int)(log((double)highestValue) / log(2.0)); -} - Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray typeName; *this >> typeName; From 4e699c0f84fa101a89faf788020c4a566fbf4405 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Thu, 5 Jun 2014 10:34:06 -0700 Subject: [PATCH 66/71] Fixed coding standard and build error --- interface/src/ui/ApplicationOverlay.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 84cdabae4a..8817549277 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -19,7 +19,7 @@ class QOpenGLFramebufferObject; class ApplicationOverlay { public: - static enum UITYPES { HEMISPHERE, SEMICIRCLE, CURVED_SEMICIRCLE }; + enum UIType { HEMISPHERE, SEMICIRCLE, CURVED_SEMICIRCLE }; ApplicationOverlay(); ~ApplicationOverlay(); @@ -34,7 +34,7 @@ public: // Setters void setOculusAngle(float oculusAngle) { _oculusAngle = oculusAngle; } - void setUiType(UITYPES uiType) { _uiType = uiType; } + void setUIType(UIType uiType) { _uiType = uiType; } private: // Interleaved vertex data @@ -51,7 +51,7 @@ private: float _trailingAudioLoudness; float _oculusAngle; float _distance; - int _uiType; + UIType _uiType; }; #endif // hifi_ApplicationOverlay_h \ No newline at end of file From 1b2cd2e144f81e47046046ea87ac0e643e44b050 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 5 Jun 2014 11:07:35 -0700 Subject: [PATCH 67/71] adding RagDoll scaffold --- interface/src/avatar/SkeletonModel.cpp | 48 +++++++++ interface/src/avatar/SkeletonModel.h | 8 +- interface/src/renderer/JointState.cpp | 101 +++++++++++++++++++ interface/src/renderer/JointState.h | 66 +++++++++++++ interface/src/renderer/Model.cpp | 95 ++---------------- interface/src/renderer/Model.h | 48 +-------- interface/src/renderer/RagDoll.cpp | 131 +++++++++++++++++++++++++ interface/src/renderer/RagDoll.h | 78 +++++++++++++++ 8 files changed, 441 insertions(+), 134 deletions(-) create mode 100644 interface/src/renderer/JointState.cpp create mode 100644 interface/src/renderer/JointState.h create mode 100644 interface/src/renderer/RagDoll.cpp create mode 100644 interface/src/renderer/RagDoll.h diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 58151d25ab..f5ca1ab218 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -21,6 +21,11 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : _owningAvatar(owningAvatar) { } +void SkeletonModel::setJointStates(QVector states) { + Model::setJointStates(states); + _ragDoll.init(_jointStates); +} + const float PALM_PRIORITY = 3.0f; void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { @@ -78,6 +83,21 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); } + + simulateRagDoll(deltaTime); +} + +void SkeletonModel::simulateRagDoll(float deltaTime) { + _ragDoll.slaveToSkeleton(_jointStates, 0.5f); + + float MIN_CONSTRAINT_ERROR = 0.005f; // 5mm + int MAX_ITERATIONS = 4; + int iterations = 0; + float delta = 0.0f; + do { + delta = _ragDoll.enforceConstraints(); + ++iterations; + } while (delta > MIN_CONSTRAINT_ERROR && iterations < MAX_ITERATIONS); } void SkeletonModel::getHandShapes(int jointIndex, QVector& shapes) const { @@ -121,6 +141,7 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { void SkeletonModel::renderIKConstraints() { renderJointConstraints(getRightHandJointIndex()); renderJointConstraints(getLeftHandJointIndex()); + renderRagDoll(); } class IndexValue { @@ -452,3 +473,30 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco return false; } +void SkeletonModel::renderRagDoll() { + const int BALL_SUBDIVISIONS = 6; + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glPushMatrix(); + + Application::getInstance()->loadTranslatedViewMatrix(_translation); + QVector points = _ragDoll.getPoints(); + int numPoints = points.size(); + float alpha = 0.3f; + float radius1 = 0.008f; + float radius2 = 0.01f; + for (int i = 0; i < numPoints; ++i) { + glPushMatrix(); + // draw each point as a yellow hexagon with black border + glm::vec3 position = _rotation * points[i]; + glTranslatef(position.x, position.y, position.z); + glColor4f(0.0f, 0.0f, 0.0f, alpha); + glutSolidSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + glColor4f(1.0f, 1.0f, 0.0f, alpha); + glutSolidSphere(radius1, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + glPopMatrix(); + } + glPopMatrix(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); +} diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 4335dfc3ff..d733d937ee 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -13,6 +13,7 @@ #define hifi_SkeletonModel_h #include "renderer/Model.h" +#include "renderer/RagDoll.h" class Avatar; @@ -23,8 +24,11 @@ class SkeletonModel : public Model { public: SkeletonModel(Avatar* owningAvatar); - + + void setJointStates(QVector states); + void simulate(float deltaTime, bool fullUpdate = true); + void simulateRagDoll(float deltaTime); /// \param jointIndex index of hand joint /// \param shapes[out] list in which is stored pointers to hand shapes @@ -89,6 +93,7 @@ public: /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; + void renderRagDoll(); protected: /// \param jointIndex index of joint in model @@ -114,6 +119,7 @@ private: void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation); Avatar* _owningAvatar; + RagDoll _ragDoll; }; #endif // hifi_SkeletonModel_h diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp new file mode 100644 index 0000000000..e66a2f44e9 --- /dev/null +++ b/interface/src/renderer/JointState.cpp @@ -0,0 +1,101 @@ +// +// JointState.cpp +// interface/src/renderer +// +// Created by Andrzej Kapolka on 10/18/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +//#include +#include + +#include "JointState.h" + +JointState::JointState() : + _animationPriority(0.0f), + _fbxJoint(NULL) { +} + +void JointState::setFBXJoint(const FBXJoint* joint) { + assert(joint != NULL); + _rotationInParentFrame = joint->rotation; + // NOTE: JointState does not own the FBXJoint to which it points. + _fbxJoint = joint; +} + +void JointState::copyState(const JointState& state) { + _rotationInParentFrame = state._rotationInParentFrame; + _transform = state._transform; + _rotation = extractRotation(_transform); + _animationPriority = state._animationPriority; + // DO NOT copy _fbxJoint +} + +void JointState::computeTransform(const glm::mat4& parentTransform) { + glm::quat modifiedRotation = _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation; + glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; + _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; + _rotation = extractRotation(_transform); +} + +glm::quat JointState::getRotationFromBindToModelFrame() const { + return _rotation * _fbxJoint->inverseBindRotation; +} + +void JointState::restoreRotation(float fraction, float priority) { + assert(_fbxJoint != NULL); + if (priority == _animationPriority || _animationPriority == 0.0f) { + _rotationInParentFrame = safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction); + _animationPriority = 0.0f; + } +} + +void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) { + assert(_fbxJoint != NULL); + if (priority >= _animationPriority) { + // rotation is from bind- to model-frame + _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); + _animationPriority = priority; + } +} + +void JointState::clearTransformTranslation() { + _transform[3][0] = 0.0f; + _transform[3][1] = 0.0f; + _transform[3][2] = 0.0f; +} + +void JointState::setRotation(const glm::quat& rotation, bool constrain, float priority) { + applyRotationDelta(rotation * glm::inverse(_rotation), true, priority); +} + +void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { + // NOTE: delta is in jointParent-frame + assert(_fbxJoint != NULL); + if (priority < _animationPriority) { + return; + } + _animationPriority = priority; + if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && + _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { + // no constraints + _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation; + _rotation = delta * _rotation; + return; + } + glm::quat targetRotation = delta * _rotation; + glm::vec3 eulers = safeEulerAngles(_rotationInParentFrame * glm::inverse(_rotation) * targetRotation); + glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax)); + _rotation = _rotation * glm::inverse(_rotationInParentFrame) * newRotation; + _rotationInParentFrame = newRotation; +} + +const glm::vec3& JointState::getDefaultTranslationInParentFrame() const { + assert(_fbxJoint != NULL); + return _fbxJoint->translation; +} diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h new file mode 100644 index 0000000000..b1a584d4ec --- /dev/null +++ b/interface/src/renderer/JointState.h @@ -0,0 +1,66 @@ +// +// JointState.h +// interface/src/renderer +// +// Created by Andrzej Kapolka on 10/18/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_JointState_h +#define hifi_JointState_h + +#include +#include +#include + +#include + +class JointState { +public: + JointState(); + + void setFBXJoint(const FBXJoint* joint); + const FBXJoint& getFBXJoint() const { return *_fbxJoint; } + + void copyState(const JointState& state); + + void computeTransform(const glm::mat4& parentTransform); + const glm::mat4& getTransform() const { return _transform; } + + glm::quat getRotation() const { return _rotation; } + glm::vec3 getPosition() const { return extractTranslation(_transform); } + + /// \return rotation from bind to model frame + glm::quat getRotationFromBindToModelFrame() const; + + /// \param rotation rotation of joint in model-frame + void setRotation(const glm::quat& rotation, bool constrain, float priority); + + /// \param delta is in the jointParent-frame + void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); + + const glm::vec3& getDefaultTranslationInParentFrame() const; + + void restoreRotation(float fraction, float priority); + + /// \param rotation is from bind- to model-frame + /// computes and sets new _rotationInParentFrame + /// NOTE: the JointState's model-frame transform/rotation are NOT updated! + void setRotationFromBindFrame(const glm::quat& rotation, float priority); + + void clearTransformTranslation(); + + glm::quat _rotationInParentFrame; // joint- to parentJoint-frame + float _animationPriority; // the priority of the animation affecting this joint + +private: + glm::mat4 _transform; // joint- to model-frame + glm::quat _rotation; // joint- to model-frame + + const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint +}; + +#endif // hifi_JointState_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 2881d96d88..105301054b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -510,12 +510,12 @@ bool Model::updateGeometry() { deleteGeometry(); _dilatedTextures.clear(); _geometry = geometry; - _jointStates = newJointStates; + setJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); if (fbxGeometry.joints.size() > 0) { - _jointStates = createJointStates(fbxGeometry); + setJointStates(createJointStates(fbxGeometry)); needToRebuild = true; } } else if (!geometry->isLoaded()) { @@ -557,6 +557,11 @@ bool Model::updateGeometry() { return needFullUpdate; } +// virtual +void Model::setJointStates(QVector states) { + _jointStates = states; +} + bool Model::render(float alpha, RenderMode mode, bool receiveShadows) { // render the attachments foreach (Model* attachment, _attachments) { @@ -1974,89 +1979,3 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) { } } -// ---------------------------------------------------------------------------- -// JointState TODO: move this class to its own files -// ---------------------------------------------------------------------------- -JointState::JointState() : - _animationPriority(0.0f), - _fbxJoint(NULL) { -} - -void JointState::setFBXJoint(const FBXJoint* joint) { - assert(joint != NULL); - _rotationInParentFrame = joint->rotation; - // NOTE: JointState does not own the FBXJoint to which it points. - _fbxJoint = joint; -} - -void JointState::copyState(const JointState& state) { - _rotationInParentFrame = state._rotationInParentFrame; - _transform = state._transform; - _rotation = extractRotation(_transform); - _animationPriority = state._animationPriority; - // DO NOT copy _fbxJoint -} - -void JointState::computeTransform(const glm::mat4& parentTransform) { - glm::quat modifiedRotation = _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation; - glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform; - _transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform; - _rotation = extractRotation(_transform); -} - -glm::quat JointState::getRotationFromBindToModelFrame() const { - return _rotation * _fbxJoint->inverseBindRotation; -} - -void JointState::restoreRotation(float fraction, float priority) { - assert(_fbxJoint != NULL); - if (priority == _animationPriority || _animationPriority == 0.0f) { - _rotationInParentFrame = safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction); - _animationPriority = 0.0f; - } -} - -void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) { - assert(_fbxJoint != NULL); - if (priority >= _animationPriority) { - // rotation is from bind- to model-frame - _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); - _animationPriority = priority; - } -} - -void JointState::clearTransformTranslation() { - _transform[3][0] = 0.0f; - _transform[3][1] = 0.0f; - _transform[3][2] = 0.0f; -} - -void JointState::setRotation(const glm::quat& rotation, bool constrain, float priority) { - applyRotationDelta(rotation * glm::inverse(_rotation), true, priority); -} - -void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { - // NOTE: delta is in jointParent-frame - assert(_fbxJoint != NULL); - if (priority < _animationPriority) { - return; - } - _animationPriority = priority; - if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && - _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { - // no constraints - _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation; - _rotation = delta * _rotation; - return; - } - glm::quat targetRotation = delta * _rotation; - glm::vec3 eulers = safeEulerAngles(_rotationInParentFrame * glm::inverse(_rotation) * targetRotation); - glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax)); - _rotation = _rotation * glm::inverse(_rotationInParentFrame) * newRotation; - _rotationInParentFrame = newRotation; -} - -const glm::vec3& JointState::getDefaultTranslationInParentFrame() const { - assert(_fbxJoint != NULL); - return _fbxJoint->translation; -} diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 4bab2451c4..3bc261ed44 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -22,6 +22,7 @@ #include "GeometryCache.h" #include "InterfaceConfig.h" +#include "JointState.h" #include "ProgramObject.h" #include "TextureCache.h" @@ -30,51 +31,6 @@ class Shape; typedef QSharedPointer AnimationHandlePointer; typedef QWeakPointer WeakAnimationHandlePointer; - -class JointState { -public: - JointState(); - - void setFBXJoint(const FBXJoint* joint); - const FBXJoint& getFBXJoint() const { return *_fbxJoint; } - - void copyState(const JointState& state); - - void computeTransform(const glm::mat4& parentTransform); - const glm::mat4& getTransform() const { return _transform; } - - glm::quat getRotation() const { return _rotation; } - glm::vec3 getPosition() const { return extractTranslation(_transform); } - - /// \return rotation from bind to model frame - glm::quat getRotationFromBindToModelFrame() const; - - /// \param rotation rotation of joint in model-frame - void setRotation(const glm::quat& rotation, bool constrain, float priority); - - /// \param delta is in the jointParent-frame - void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); - - const glm::vec3& getDefaultTranslationInParentFrame() const; - - void restoreRotation(float fraction, float priority); - - /// \param rotation is from bind- to model-frame - /// computes and sets new _rotationInParentFrame - /// NOTE: the JointState's model-frame transform/rotation are NOT updated! - void setRotationFromBindFrame(const glm::quat& rotation, float priority); - - void clearTransformTranslation(); - - glm::quat _rotationInParentFrame; // joint- to parentJoint-frame - float _animationPriority; // the priority of the animation affecting this joint - -private: - glm::mat4 _transform; // joint- to model-frame - glm::quat _rotation; // joint- to model-frame - - const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint -}; /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject { @@ -250,6 +206,8 @@ protected: // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); + + virtual void setJointStates(QVector states); void setScaleInternal(const glm::vec3& scale); void scaleToFit(); diff --git a/interface/src/renderer/RagDoll.cpp b/interface/src/renderer/RagDoll.cpp new file mode 100644 index 0000000000..54fb776552 --- /dev/null +++ b/interface/src/renderer/RagDoll.cpp @@ -0,0 +1,131 @@ +// +// RagDoll.cpp +// interface/src/avatar +// +// Created by Andrew Meadows 2014.05.30 +// Copyright 2014 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 "RagDoll.h" + +// ---------------------------------------------------------------------------- +// FixedConstraint +// ---------------------------------------------------------------------------- +FixedConstraint::FixedConstraint() : _point(NULL), _anchor(0.0f, 0.0f, 0.0f) { +} + +float FixedConstraint::enforce() { + assert(_point != NULL); + float distance = glm::distance(_anchor, *_point); + *_point = _anchor; + return distance; +} + +void FixedConstraint::setPoint(glm::vec3* point) { + _point = point; +} + +void FixedConstraint::setAnchor(const glm::vec3& anchor) { + _anchor = anchor; +} + +// ---------------------------------------------------------------------------- +// DistanceConstraint +// ---------------------------------------------------------------------------- +DistanceConstraint::DistanceConstraint(glm::vec3* pointA, glm::vec3* pointB) : _distance(-1.0f) { + _points[0] = pointA; + _points[1] = pointB; + _distance = glm::distance(*(_points[0]), *(_points[1])); +} + +DistanceConstraint::DistanceConstraint(const DistanceConstraint& other) { + _distance = other._distance; + _points[0] = other._points[0]; + _points[1] = other._points[1]; +} + +void DistanceConstraint::setDistance(float distance) { + _distance = fabsf(distance); +} + +float DistanceConstraint::enforce() { + float newDistance = glm::distance(*(_points[0]), *(_points[1])); + glm::vec3 direction(0.0f, 1.0f, 0.0f); + if (newDistance > EPSILON) { + direction = (*(_points[0]) - *(_points[1])) / newDistance; + } + glm::vec3 center = 0.5f * (*(_points[0]) + *(_points[1])); + *(_points[0]) = center + (0.5f * _distance) * direction; + *(_points[1]) = center - (0.5f * _distance) * direction; + return glm::abs(newDistance - _distance); +} + +// ---------------------------------------------------------------------------- +// RagDoll +// ---------------------------------------------------------------------------- + +RagDoll::RagDoll() { +} + +RagDoll::~RagDoll() { + clear(); +} + +void RagDoll::init(const QVector& states) { + clear(); + const int numStates = states.size(); + _points.reserve(numStates); + for (int i = 0; i < numStates; ++i) { + const JointState& state = states[i]; + _points.push_back(state.getPosition()); + int parentIndex = state.getFBXJoint().parentIndex; + assert(parentIndex < i); + if (parentIndex != -1) { + DistanceConstraint* stick = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); + _constraints.push_back(stick); + } + } +} +/// Delete all data. +void RagDoll::clear() { + int numConstraints = _constraints.size(); + for (int i = 0; i < numConstraints; ++i) { + delete _constraints[i]; + } + _constraints.clear(); + _points.clear(); +} + +float RagDoll::slaveToSkeleton(const QVector& states, float fraction) { + const int numStates = states.size(); + assert(numStates == _points.size()); + fraction = glm::clamp(fraction, 0.0f, 1.0f); + float maxDistance = 0.0f; + for (int i = 0; i < numStates; ++i) { + glm::vec3 oldPoint = _points[i]; + _points[i] = (1.0f - fraction) * _points[i] + fraction * states[i].getPosition(); + maxDistance = glm::max(maxDistance, glm::distance(oldPoint, _points[i])); + } + return maxDistance; +} + +float RagDoll::enforceConstraints() { + float maxDistance = 0.0f; + const int numConstraints = _constraints.size(); + for (int i = 0; i < numConstraints; ++i) { + DistanceConstraint* c = static_cast(_constraints[i]); + //maxDistance = glm::max(maxDistance, _constraints[i]->enforce()); + maxDistance = glm::max(maxDistance, c->enforce()); + } + return maxDistance; +} diff --git a/interface/src/renderer/RagDoll.h b/interface/src/renderer/RagDoll.h new file mode 100644 index 0000000000..1d23973827 --- /dev/null +++ b/interface/src/renderer/RagDoll.h @@ -0,0 +1,78 @@ +// +// RagDoll.h +// interface/src/avatar +// +// Created by Andrew Meadows 2014.05.30 +// Copyright 2014 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_RagDoll_h +#define hifi_RagDoll_h + +#include "renderer/Model.h" + +class Constraint { +public: + Constraint() {} + virtual ~Constraint() {} + + /// Enforce contraint by moving relevant points. + /// \return max distance of point movement + virtual float enforce() = 0; +}; + +class FixedConstraint : public Constraint { +public: + FixedConstraint(); + float enforce(); + void setPoint(glm::vec3* point); + void setAnchor(const glm::vec3& anchor); +private: + glm::vec3* _point; + glm::vec3 _anchor; +}; + +class DistanceConstraint : public Constraint { +public: + DistanceConstraint(glm::vec3* pointA, glm::vec3* pointB); + DistanceConstraint(const DistanceConstraint& other); + float enforce(); + void setDistance(float distance); +private: + float _distance; + glm::vec3* _points[2]; +}; + +class RagDoll { +public: + + RagDoll(); + virtual ~RagDoll(); + + /// Create points and constraints based on topology of collection of joints + /// \param joints list of connected joint states + void init(const QVector& states); + + /// Delete all data. + void clear(); + + /// \param states list of joint states + /// \param fraction range from 0.0 (no movement) to 1.0 (use joint locations) + /// \return max distance of point movement + float slaveToSkeleton(const QVector& states, float fraction); + + /// Enforce contraints. + /// \return max distance of point movement + float enforceConstraints(); + + const QVector& getPoints() const { return _points; } + +private: + QVector _constraints; + QVector _points; +}; + +#endif // hifi_RagDoll_h From 8d908a12a30b11b3dbc1a225999b4d9f2005df66 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 12:28:02 -0700 Subject: [PATCH 68/71] Fix build. --- interface/src/ui/ApplicationOverlay.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index bfd3e63ea9..49ec8ecddb 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -343,7 +343,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { const float angleIncrement = horizontalAngle / (numHorizontalVertices - 1); const float halfHorizontalAngle = horizontalAngle / 2; - const float verticalAngleIncrement = verticalAngle / (numVerticalVertices - 1); + const float verticalAngleIncrement = _oculusAngle / (numVerticalVertices - 1); glActiveTexture(GL_TEXTURE0); @@ -417,8 +417,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { float leftAngle = (newMouseX / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; float rightAngle = ((newMouseX + newWidth) / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; - float bottomAngle = (newMouseY / (float)widgetHeight) * verticalAngle - halfVerticalAngle; - float topAngle = ((newMouseY - newHeight) / (float)widgetHeight) * verticalAngle - halfVerticalAngle; + float bottomAngle = (newMouseY / (float)widgetHeight) * _oculusAngle - halfVerticalAngle; + float topAngle = ((newMouseY - newHeight) / (float)widgetHeight) * _oculusAngle - halfVerticalAngle; float leftX, rightX, leftZ, rightZ, topZ, bottomZ; From c689d826f4498208bfc94da411cf5e9bbfe389b6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 5 Jun 2014 15:48:18 -0700 Subject: [PATCH 69/71] fix for broken windows build with PrioVR libs The Model API changed but this code path was not updated. --- interface/src/devices/PrioVR.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/devices/PrioVR.cpp b/interface/src/devices/PrioVR.cpp index 65cdb962e1..e96f4f04d5 100644 --- a/interface/src/devices/PrioVR.cpp +++ b/interface/src/devices/PrioVR.cpp @@ -76,20 +76,21 @@ static void setPalm(float deltaTime, int index) { } } + // NOTE: this math is done in the worl-frame with unecessary complexity. + // TODO: transfom this to stay in the model-frame. glm::vec3 position; glm::quat rotation; - SkeletonModel* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel(); int jointIndex; glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation()); if (index == LEFT_HAND_INDEX) { jointIndex = skeletonModel->getLeftHandJointIndex(); - skeletonModel->getJointRotation(jointIndex, rotation, true); + skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation); rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f)); } else { jointIndex = skeletonModel->getRightHandJointIndex(); - skeletonModel->getJointRotation(jointIndex, rotation, true); + skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation); rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f)); } skeletonModel->getJointPositionInWorldFrame(jointIndex, position); From 6bef0c1a6a72f00e4bd7db25af9a7ded43cf8313 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 5 Jun 2014 17:03:58 -0700 Subject: [PATCH 70/71] both left and right hands in animation --- examples/squeezeHands.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/squeezeHands.js b/examples/squeezeHands.js index 3f24fa86b7..e53dd9569c 100644 --- a/examples/squeezeHands.js +++ b/examples/squeezeHands.js @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx"; -var leftHandAnimation = ""; +var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/RightHandAnim.fbx"; +var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/LeftHandAnim.fbx"; var LEFT = 0; var RIGHT = 1; @@ -18,17 +18,20 @@ var RIGHT = 1; var lastLeftFrame = 0; var lastRightFrame = 0; -var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation? +var LAST_FRAME = 11.0; // What is the number of the last frame we want to use in the animation? +var SMOOTH_FACTOR = 0.80; + Script.update.connect(function(deltaTime) { - var leftTriggerValue = Controller.getTriggerValue(LEFT); - var rightTriggerValue = Controller.getTriggerValue(RIGHT); + var leftTriggerValue = Math.sqrt(Controller.getTriggerValue(LEFT)); + var rightTriggerValue = Math.sqrt(Controller.getTriggerValue(RIGHT)); var leftFrame, rightFrame; - // Average last two trigger frames together for a bit of smoothing - leftFrame = (leftTriggerValue * LAST_FRAME) * 0.5 + lastLeftFrame * 0.5; - rightFrame = (rightTriggerValue * LAST_FRAME) * 0.5 + lastRightFrame * 0.5; + // Average last few trigger frames together for a bit of smoothing + leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR; + rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR; + if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){ MyAvatar.stopAnimation(leftHandAnimation); From 83c2938c2ea2e0a75340962167e680bb7eb7920c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 17:05:57 -0700 Subject: [PATCH 71/71] Temporarily disable enum streamers, which are crashing on Windows startup. --- interface/src/devices/PrioVR.cpp | 4 ++-- libraries/metavoxels/src/Bitstream.cpp | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/interface/src/devices/PrioVR.cpp b/interface/src/devices/PrioVR.cpp index 65cdb962e1..0cfe127b2f 100644 --- a/interface/src/devices/PrioVR.cpp +++ b/interface/src/devices/PrioVR.cpp @@ -84,12 +84,12 @@ static void setPalm(float deltaTime, int index) { glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation()); if (index == LEFT_HAND_INDEX) { jointIndex = skeletonModel->getLeftHandJointIndex(); - skeletonModel->getJointRotation(jointIndex, rotation, true); + skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation); rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f)); } else { jointIndex = skeletonModel->getRightHandJointIndex(); - skeletonModel->getJointRotation(jointIndex, rotation, true); + skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation); rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f)); } skeletonModel->getJointPositionInWorldFrame(jointIndex, position); diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 30d34580d7..387b41a839 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -92,13 +92,14 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta } // register the streamers for all enumerators - for (int i = 0; i < metaObject->enumeratorCount(); i++) { - QMetaEnum metaEnum = metaObject->enumerator(i); - const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; - if (!streamer) { - getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); - } - } + // temporarily disabled: crashes on Windows + //for (int i = 0; i < metaObject->enumeratorCount(); i++) { + // QMetaEnum metaEnum = metaObject->enumerator(i); + // const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; + // if (!streamer) { + // getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); + // } + //} return 0; }