From 43feef3ebdd7a871cbd7858f800054d255b37e89 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 12:03:02 -0700 Subject: [PATCH 01/17] Only update the full set of joints when we've received new data from the mixer. Closes #2274. --- interface/src/avatar/Avatar.cpp | 9 ++++++-- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/FaceModel.cpp | 6 +++--- interface/src/avatar/FaceModel.h | 2 +- interface/src/avatar/SkeletonModel.cpp | 4 ++-- interface/src/avatar/SkeletonModel.h | 2 +- interface/src/renderer/Model.cpp | 29 +++++++++++++------------- interface/src/renderer/Model.h | 4 ++-- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b7e3d675a5..8333b51aaf 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -56,7 +56,8 @@ Avatar::Avatar() : _owningAvatarMixer(), _collisionFlags(0), _initialized(false), - _shouldRenderBillboard(true) + _shouldRenderBillboard(true), + _modelsDirty(true) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -119,7 +120,8 @@ void Avatar::simulate(float deltaTime) { } glm::vec3 headPosition = _position; if (!_shouldRenderBillboard) { - _skeletonModel.simulate(deltaTime); + _skeletonModel.simulate(deltaTime, _modelsDirty); + _modelsDirty = false; _skeletonModel.getHeadPosition(headPosition); } Head* head = getHead(); @@ -618,6 +620,9 @@ int Avatar::parseData(const QByteArray& packet) { const float MOVE_DISTANCE_THRESHOLD = 0.001f; _moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD; + // note that we need to update our models + _modelsDirty = true; + return bytesRead; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index bba86828cb..b1812a12a9 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -187,6 +187,7 @@ private: bool _initialized; QScopedPointer _billboardTexture; bool _shouldRenderBillboard; + bool _modelsDirty; void renderBody(); void renderBillboard(); diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index eba8f7bf1a..f4ee6859ed 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -18,9 +18,9 @@ FaceModel::FaceModel(Head* owningHead) : { } -void FaceModel::simulate(float deltaTime, bool delayLoad) { +void FaceModel::simulate(float deltaTime) { if (!isActive()) { - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime); return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -41,7 +41,7 @@ void FaceModel::simulate(float deltaTime, bool delayLoad) { setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime); } bool FaceModel::render(float alpha) { diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 597075dc42..d0f0f6baef 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -21,7 +21,7 @@ public: FaceModel(Head* owningHead); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime); bool render(float alpha); protected: diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f405358710..44d1dd6d07 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -18,13 +18,13 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : _owningAvatar(owningAvatar) { } -void SkeletonModel::simulate(float deltaTime, bool delayLoad) { +void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getPosition()); setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime, fullUpdate); if (!(isActive() && _owningAvatar->isMyAvatar())) { return; // only simulate for own avatar diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 3d95d805ea..7018e331f0 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -22,7 +22,7 @@ public: SkeletonModel(Avatar* owningAvatar); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime, bool fullUpdate = true); bool render(float alpha); /// \param jointIndex index of hand joint diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 21fdc80858..9951a94dd5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -156,9 +156,9 @@ void Model::updateShapePositions() { } } -void Model::simulate(float deltaTime, bool delayLoad) { +void Model::simulate(float deltaTime, bool fullUpdate) { // update our LOD - QVector newJointStates = updateGeometry(delayLoad); + QVector newJointStates = updateGeometry(); if (!isActive()) { return; } @@ -183,10 +183,15 @@ void Model::simulate(float deltaTime, bool delayLoad) { model->setURL(attachment.url); _attachments.append(model); } - _resetStates = true; + _resetStates = fullUpdate = true; createCollisionShapes(); } + // exit early if we don't have to perform a full update + if (!(fullUpdate || _resetStates)) { + return; + } + // update the world space transforms for all joints for (int i = 0; i < _jointStates.size(); i++) { updateJointState(i); @@ -868,14 +873,12 @@ void Model::applyCollision(CollisionInfo& collision) { } } -QVector Model::updateGeometry(bool delayLoad) { +QVector Model::updateGeometry() { QVector newJointStates; if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis, delayLoad); - if (!delayLoad) { - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - } + _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); + _nextGeometry->setLoadPriority(this, -_lodDistance); + _nextGeometry->ensureLoading(); if (_nextGeometry->isLoaded()) { applyNextGeometry(); return newJointStates; @@ -884,7 +887,7 @@ QVector Model::updateGeometry(bool delayLoad) { if (!_geometry) { return newJointStates; } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis, delayLoad); + QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); if (_geometry != geometry) { if (!_jointStates.isEmpty()) { // copy the existing joint states @@ -904,10 +907,8 @@ QVector Model::updateGeometry(bool delayLoad) { _dilatedTextures.clear(); _geometry = geometry; } - if (!delayLoad) { - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); - } + _geometry->setLoadPriority(this, -_lodDistance); + _geometry->ensureLoading(); return newJointStates; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index c7aadee8dc..ae38423242 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -57,7 +57,7 @@ public: void clearShapes(); void createCollisionShapes(); void updateShapePositions(); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime, bool fullUpdate = true); bool render(float alpha); /// Sets the URL of the model to render. @@ -256,7 +256,7 @@ protected: private: - QVector updateGeometry(bool delayLoad); + QVector updateGeometry(); void applyNextGeometry(); void deleteGeometry(); void renderMeshes(float alpha, bool translucent); From b4cb1457a27ac51bd64411ad7fcbce93de346c34 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 13:29:18 -0700 Subject: [PATCH 02/17] Do a simple frustum check for rendering the avatar or doing a full joint update. Closes #2071. --- interface/src/avatar/Avatar.cpp | 19 +++++++++++++++++-- interface/src/avatar/Avatar.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8333b51aaf..bcf24a7bfb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -110,6 +110,11 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; } + // simple frustum check + float boundingRadius = getBillboardSize(); + bool inViewFrustum = Application::getInstance()->getViewFrustum()->sphereInFrustum(_position, boundingRadius) != + ViewFrustum::OUTSIDE; + getHand()->simulate(deltaTime, false); _skeletonModel.setLODDistance(getLODDistance()); @@ -119,7 +124,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.setJointState(i, data.valid, data.rotation); } glm::vec3 headPosition = _position; - if (!_shouldRenderBillboard) { + if (!_shouldRenderBillboard && inViewFrustum) { _skeletonModel.simulate(deltaTime, _modelsDirty); _modelsDirty = false; _skeletonModel.getHeadPosition(headPosition); @@ -185,6 +190,12 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(bool forShadowMap) { + // simple frustum check + float boundingRadius = getBillboardSize(); + if (Application::getInstance()->getViewFrustum()->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) { + return; + } + glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition(); float lengthToTarget = glm::length(toTarget); @@ -338,7 +349,7 @@ void Avatar::renderBillboard() { glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // compute the size from the billboard camera parameters and scale - float size = _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + float size = getBillboardSize(); glScalef(size, size, size); glColor3f(1.0f, 1.0f, 1.0f); @@ -363,6 +374,10 @@ void Avatar::renderBillboard() { glBindTexture(GL_TEXTURE_2D, 0); } +float Avatar::getBillboardSize() const { + return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); +} + void Avatar::renderDisplayName() { if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b1812a12a9..2bd7fc89e8 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -191,6 +191,8 @@ private: void renderBody(); void renderBillboard(); + + float getBillboardSize() const; }; #endif From 5b30f932c1e88d1ff6ccdc262477bac0456be384 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 14:09:12 -0700 Subject: [PATCH 03/17] Fix for slight graphical glitches on loading avatars. --- interface/src/avatar/FaceModel.cpp | 5 +- interface/src/renderer/Model.cpp | 361 +++++++++++++++-------------- interface/src/renderer/Model.h | 4 +- 3 files changed, 188 insertions(+), 182 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index f4ee6859ed..db6c3fe98d 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -19,8 +19,8 @@ FaceModel::FaceModel(Head* owningHead) : } void FaceModel::simulate(float deltaTime) { + QVector newJointStates = updateGeometry(); if (!isActive()) { - Model::simulate(deltaTime); return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -36,12 +36,13 @@ void FaceModel::simulate(float deltaTime) { setRotation(neckRotation); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE); + setOffset(-_geometry->getFBXGeometry().neckPivot); setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulate(deltaTime); + Model::simulate(deltaTime, true, newJointStates); } bool FaceModel::render(float alpha) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9951a94dd5..60fae5e596 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -157,146 +157,8 @@ void Model::updateShapePositions() { } void Model::simulate(float deltaTime, bool fullUpdate) { - // update our LOD - QVector newJointStates = updateGeometry(); - if (!isActive()) { - return; - } - - // set up world vertices on first simulate after load - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (_jointStates.isEmpty()) { - _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; - foreach (const FBXMesh& mesh, geometry.meshes) { - MeshState state; - state.clusterMatrices.resize(mesh.clusters.size()); - if (mesh.springiness > 0.0f) { - state.worldSpaceVertices.resize(mesh.vertices.size()); - state.vertexVelocities.resize(mesh.vertices.size()); - state.worldSpaceNormals.resize(mesh.vertices.size()); - } - _meshStates.append(state); - } - foreach (const FBXAttachment& attachment, geometry.attachments) { - Model* model = new Model(this); - model->init(); - model->setURL(attachment.url); - _attachments.append(model); - } - _resetStates = fullUpdate = true; - createCollisionShapes(); - } - - // exit early if we don't have to perform a full update - if (!(fullUpdate || _resetStates)) { - return; - } - - // update the world space transforms for all joints - for (int i = 0; i < _jointStates.size(); i++) { - updateJointState(i); - } - - // update the attachment transforms and simulate them - for (int i = 0; i < _attachments.size(); i++) { - const FBXAttachment& attachment = geometry.attachments.at(i); - Model* model = _attachments.at(i); - - glm::vec3 jointTranslation = _translation; - glm::quat jointRotation = _rotation; - getJointPosition(attachment.jointIndex, jointTranslation); - getJointRotation(attachment.jointIndex, jointRotation); - - model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); - model->setRotation(jointRotation * attachment.rotation); - model->setScale(_scale * attachment.scale); - - model->simulate(deltaTime); - } - - 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].transform * cluster.inverseBindMatrix; - } - int vertexCount = state.worldSpaceVertices.size(); - if (vertexCount == 0) { - continue; - } - glm::vec3* destVertices = state.worldSpaceVertices.data(); - glm::vec3* destVelocities = state.vertexVelocities.data(); - glm::vec3* destNormals = state.worldSpaceNormals.data(); - - const glm::vec3* sourceVertices = mesh.vertices.constData(); - if (!mesh.blendshapes.isEmpty()) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { - _blendedVertices[*index] += *vertex * coefficient; - } - } - sourceVertices = _blendedVertices.constData(); - } - glm::mat4 transform = glm::translate(_translation); - if (mesh.clusters.size() > 1) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - - // skin each vertex - const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); - const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); - for (int j = 0; j < vertexCount; j++) { - _blendedVertices[j] = - glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + - glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + - glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + - glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; - } - sourceVertices = _blendedVertices.constData(); - - } else { - transform = state.clusterMatrices[0]; - } - if (_resetStates) { - for (int j = 0; j < vertexCount; j++) { - destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); - destVelocities[j] = glm::vec3(); - } - } else { - const float SPRINGINESS_MULTIPLIER = 200.0f; - const float DAMPING = 5.0f; - for (int j = 0; j < vertexCount; j++) { - destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * - mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; - destVertices[j] += destVelocities[j] * deltaTime; - } - } - for (int j = 0; j < vertexCount; j++) { - destNormals[j] = glm::vec3(); - - const glm::vec3& middle = destVertices[j]; - for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); - connection != mesh.vertexConnections.at(j).constEnd(); connection++) { - destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, - destVertices[connection->first] - middle)); - } - } - } - _resetStates = false; + // update our LOD, then simulate + simulate(deltaTime, fullUpdate, updateGeometry()); } bool Model::render(float alpha) { @@ -577,6 +439,186 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi return collided; } +QVector Model::updateGeometry() { + QVector newJointStates; + if (_nextGeometry) { + _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); + _nextGeometry->setLoadPriority(this, -_lodDistance); + _nextGeometry->ensureLoading(); + if (_nextGeometry->isLoaded()) { + applyNextGeometry(); + return newJointStates; + } + } + if (!_geometry) { + return newJointStates; + } + QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); + if (_geometry != geometry) { + if (!_jointStates.isEmpty()) { + // copy the existing joint states + const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& newGeometry = geometry->getFBXGeometry(); + newJointStates = createJointStates(newGeometry); + for (QHash::const_iterator it = oldGeometry.jointIndices.constBegin(); + it != oldGeometry.jointIndices.constEnd(); it++) { + int oldIndex = it.value() - 1; + int newIndex = newGeometry.getJointIndex(it.key()); + if (newIndex != -1) { + newJointStates[newIndex] = _jointStates.at(oldIndex); + } + } + } + deleteGeometry(); + _dilatedTextures.clear(); + _geometry = geometry; + } + _geometry->setLoadPriority(this, -_lodDistance); + _geometry->ensureLoading(); + return newJointStates; +} + +void Model::simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates) { + if (!isActive()) { + return; + } + + // set up world vertices on first simulate after load + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + if (_jointStates.isEmpty()) { + _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; + foreach (const FBXMesh& mesh, geometry.meshes) { + MeshState state; + state.clusterMatrices.resize(mesh.clusters.size()); + if (mesh.springiness > 0.0f) { + state.worldSpaceVertices.resize(mesh.vertices.size()); + state.vertexVelocities.resize(mesh.vertices.size()); + state.worldSpaceNormals.resize(mesh.vertices.size()); + } + _meshStates.append(state); + } + foreach (const FBXAttachment& attachment, geometry.attachments) { + Model* model = new Model(this); + model->init(); + model->setURL(attachment.url); + _attachments.append(model); + } + _resetStates = fullUpdate = true; + createCollisionShapes(); + } + + // exit early if we don't have to perform a full update + if (!(fullUpdate || _resetStates)) { + return; + } + + // update the world space transforms for all joints + for (int i = 0; i < _jointStates.size(); i++) { + updateJointState(i); + } + + // update the attachment transforms and simulate them + for (int i = 0; i < _attachments.size(); i++) { + const FBXAttachment& attachment = geometry.attachments.at(i); + Model* model = _attachments.at(i); + + glm::vec3 jointTranslation = _translation; + glm::quat jointRotation = _rotation; + getJointPosition(attachment.jointIndex, jointTranslation); + getJointRotation(attachment.jointIndex, jointRotation); + + model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); + model->setRotation(jointRotation * attachment.rotation); + model->setScale(_scale * attachment.scale); + + model->simulate(deltaTime); + } + + 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].transform * cluster.inverseBindMatrix; + } + int vertexCount = state.worldSpaceVertices.size(); + if (vertexCount == 0) { + continue; + } + glm::vec3* destVertices = state.worldSpaceVertices.data(); + glm::vec3* destVelocities = state.vertexVelocities.data(); + glm::vec3* destNormals = state.worldSpaceNormals.data(); + + const glm::vec3* sourceVertices = mesh.vertices.constData(); + if (!mesh.blendshapes.isEmpty()) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { + float coefficient = _blendshapeCoefficients[j]; + if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { + _blendedVertices[*index] += *vertex * coefficient; + } + } + sourceVertices = _blendedVertices.constData(); + } + glm::mat4 transform = glm::translate(_translation); + if (mesh.clusters.size() > 1) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + + // skin each vertex + const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); + const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); + for (int j = 0; j < vertexCount; j++) { + _blendedVertices[j] = + glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + + glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + + glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + + glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; + } + sourceVertices = _blendedVertices.constData(); + + } else { + transform = state.clusterMatrices[0]; + } + if (_resetStates) { + for (int j = 0; j < vertexCount; j++) { + destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); + destVelocities[j] = glm::vec3(); + } + } else { + const float SPRINGINESS_MULTIPLIER = 200.0f; + const float DAMPING = 5.0f; + for (int j = 0; j < vertexCount; j++) { + destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * + mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; + destVertices[j] += destVelocities[j] * deltaTime; + } + } + for (int j = 0; j < vertexCount; j++) { + destNormals[j] = glm::vec3(); + + const glm::vec3& middle = destVertices[j]; + for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); + connection != mesh.vertexConnections.at(j).constEnd(); connection++) { + destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, + destVertices[connection->first] - middle)); + } + } + } + _resetStates = false; +} + void Model::updateJointState(int index) { _shapesAreDirty = true; JointState& state = _jointStates[index]; @@ -873,45 +915,6 @@ void Model::applyCollision(CollisionInfo& collision) { } } -QVector Model::updateGeometry() { - QVector newJointStates; - if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - if (_nextGeometry->isLoaded()) { - applyNextGeometry(); - return newJointStates; - } - } - if (!_geometry) { - return newJointStates; - } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); - if (_geometry != geometry) { - if (!_jointStates.isEmpty()) { - // copy the existing joint states - const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); - const FBXGeometry& newGeometry = geometry->getFBXGeometry(); - newJointStates = createJointStates(newGeometry); - for (QHash::const_iterator it = oldGeometry.jointIndices.constBegin(); - it != oldGeometry.jointIndices.constEnd(); it++) { - int oldIndex = it.value() - 1; - int newIndex = newGeometry.getJointIndex(it.key()); - if (newIndex != -1) { - newJointStates[newIndex] = _jointStates.at(oldIndex); - } - } - } - deleteGeometry(); - _dilatedTextures.clear(); - _geometry = geometry; - } - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); - return newJointStates; -} - void Model::applyNextGeometry() { // delete our local geometry and custom textures deleteGeometry(); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index ae38423242..165465d2cc 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -226,6 +226,9 @@ protected: QVector _meshStates; + QVector updateGeometry(); + void simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates); + /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); @@ -256,7 +259,6 @@ protected: private: - QVector updateGeometry(); void applyNextGeometry(); void deleteGeometry(); void renderMeshes(float alpha, bool translucent); From fc32d9581dda05e5586eb8bd3ec35ca989113137 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 15:17:16 -0700 Subject: [PATCH 04/17] Visage toggle bits. --- interface/interface_en.ts | 8 +++---- interface/src/Menu.cpp | 9 ++++++-- interface/src/Menu.h | 3 ++- interface/src/devices/Visage.cpp | 36 +++++++++++++++++++------------- interface/src/devices/Visage.h | 10 +++++++-- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 80433032dc..496e3a66e5 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 00ae0a3772..4e880f2512 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -270,11 +270,16 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, - MenuOption::FaceshiftTCP, + MenuOption::Faceshift, 0, - false, + true, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); +#ifdef HAVE_VISAGE + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, + appInstance->getVisage(), SLOT(setEnabled(bool))); +#endif + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 00ef51178a..f02db150ba 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -239,7 +239,7 @@ namespace MenuOption { const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; const QString HandsCollideWithSelf = "Collide With Self"; - const QString FaceshiftTCP = "Faceshift (TCP)"; + const QString Faceshift = "Faceshift"; const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; @@ -292,6 +292,7 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; + const QString Visage = "Visage"; const QString Quit = "Quit"; const QString Voxels = "Voxels"; const QString VoxelMode = "Cycle Voxel Mode"; diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 727c083265..745b543d87 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -40,25 +40,11 @@ Visage::Visage() : #ifdef HAVE_VISAGE QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; initializeLicenseManager(licensePath.data()); - _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); - if (_tracker->trackFromCam()) { - _data = new FaceData(); - - } else { - delete _tracker; - _tracker = NULL; - } #endif } Visage::~Visage() { -#ifdef HAVE_VISAGE - if (_tracker) { - _tracker->stop(); - delete _tracker; - delete _data; - } -#endif + setEnabled(false); } #ifdef HAVE_VISAGE @@ -160,3 +146,23 @@ void Visage::update() { void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } + +void Visage::setEnabled(bool enabled) { +#ifdef HAVE_VISAGE + if (enabled == (_tracker != NULL)) { + return; + } + if (enabled) { + _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); + _data = new FaceData(); + if (_tracker->trackFromCam()) { + return; + } + } + _tracker->stop(); + delete _tracker; + delete _data; + _tracker = NULL; + _data = NULL; +#endif +} diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index c238b3bb8c..28d990ae7a 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -24,11 +24,13 @@ namespace VisageSDK { } /// Handles input from the Visage webcam feature tracking software. -class Visage { +class Visage : public QObject { + Q_OBJECT + public: Visage(); - ~Visage(); + virtual ~Visage(); bool isActive() const { return _active; } @@ -42,6 +44,10 @@ public: void update(); void reset(); + +public slots: + + void setEnabled(bool enabled); private: From 007bfa8866ce3234f025110b617303610aacf896 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 15:26:07 -0700 Subject: [PATCH 05/17] Tweak to Visage toggle. --- interface/src/devices/Visage.cpp | 27 +++++++++++++-------------- interface/src/devices/Visage.h | 1 + 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 745b543d87..876a810431 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -32,6 +32,7 @@ using namespace VisageSDK; const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f); Visage::Visage() : + _enabled(false), _active(false), _headOrigin(DEFAULT_HEAD_ORIGIN), _estimatedEyePitch(0.0f), @@ -40,11 +41,16 @@ Visage::Visage() : #ifdef HAVE_VISAGE QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; initializeLicenseManager(licensePath.data()); + _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); + _data = new FaceData(); #endif } Visage::~Visage() { - setEnabled(false); +#ifdef HAVE_VISAGE + delete _tracker; + delete _data; +#endif } #ifdef HAVE_VISAGE @@ -105,7 +111,7 @@ const float TRANSLATION_SCALE = 20.0f; void Visage::update() { #ifdef HAVE_VISAGE - _active = (_tracker && _tracker->getTrackingData(_data) == TRACK_STAT_OK); + _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); if (!_active) { return; } @@ -149,20 +155,13 @@ void Visage::reset() { void Visage::setEnabled(bool enabled) { #ifdef HAVE_VISAGE - if (enabled == (_tracker != NULL)) { + if (_enabled == enabled) { return; } - if (enabled) { - _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); - _data = new FaceData(); - if (_tracker->trackFromCam()) { - return; - } + if (_enabled = enabled) { + _tracker->trackFromCam(); + } else { + _tracker->stop(); } - _tracker->stop(); - delete _tracker; - delete _data; - _tracker = NULL; - _data = NULL; #endif } diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 28d990ae7a..e71bdc0fb5 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -57,6 +57,7 @@ private: QMultiHash > _actionUnitIndexMap; #endif + bool _enabled; bool _active; glm::quat _headRotation; glm::vec3 _headTranslation; From 9d1278b6637415b821cc8ed7a23e9a2fc5a2b426 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:18:47 -0700 Subject: [PATCH 06/17] Wait until we know that Faceshift didn't connect before we attempt to initialize Visage. --- interface/interface_en.ts | 4 ++-- interface/src/Application.cpp | 3 +++ interface/src/Menu.cpp | 2 +- interface/src/devices/Faceshift.cpp | 6 ++++++ interface/src/devices/Faceshift.h | 6 ++++++ interface/src/devices/Visage.cpp | 13 ++++++++++++- interface/src/devices/Visage.h | 6 +++++- 7 files changed, 35 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 496e3a66e5..5eeacc67d8 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 96129e0161..a8b28f2c0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1525,6 +1525,9 @@ void Application::init() { } qDebug("Loaded settings"); + // initialize Visage after loading the menu settings + _visage.init(); + // fire off an immediate domain-server check in now that settings are loaded NodeList::getInstance()->sendDomainServerCheckIn(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4e880f2512..a42fe9da65 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -277,7 +277,7 @@ Menu::Menu() : SLOT(setTCPEnabled(bool))); #ifdef HAVE_VISAGE addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, - appInstance->getVisage(), SLOT(setEnabled(bool))); + appInstance->getVisage(), SLOT(updateEnabled())); #endif addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 4fe89ff98b..8aa57fa792 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -49,12 +49,18 @@ Faceshift::Faceshift() : connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected())); connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError))); connect(&_tcpSocket, SIGNAL(readyRead()), SLOT(readFromSocket())); + connect(&_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(connectionStateChanged())); connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); _udpSocket.bind(FACESHIFT_PORT); } +bool Faceshift::isConnectedOrConnecting() const { + return _tcpSocket.state() == QAbstractSocket::ConnectedState || + (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); +} + bool Faceshift::isActive() const { const quint64 ACTIVE_TIMEOUT_USECS = 1000000; return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS; diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 908354ae9d..66403715cd 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -27,6 +27,8 @@ public: Faceshift(); + bool isConnectedOrConnecting() const; + bool isActive() const; const glm::quat& getHeadRotation() const { return _headRotation; } @@ -66,6 +68,10 @@ public: void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, float jawOpen, std::vector& coefficients) const; +signals: + + void connectionStateChanged(); + public slots: void setTCPEnabled(bool enabled); diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 876a810431..51b7324568 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -109,6 +109,11 @@ static const QMultiHash >& getActionUnitNameMap() const float TRANSLATION_SCALE = 20.0f; +void Visage::init() { + connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); + updateEnabled(); +} + void Visage::update() { #ifdef HAVE_VISAGE _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); @@ -153,12 +158,18 @@ void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } +void Visage::updateEnabled() { + setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && + !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && + Application::getInstance()->getFaceshift()->isConnectedOrConnecting())); +} + void Visage::setEnabled(bool enabled) { #ifdef HAVE_VISAGE if (_enabled == enabled) { return; } - if (_enabled = enabled) { + if ((_enabled = enabled)) { _tracker->trackFromCam(); } else { _tracker->stop(); diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index e71bdc0fb5..7e50812ba7 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -32,6 +32,8 @@ public: Visage(); virtual ~Visage(); + void init(); + bool isActive() const { return _active; } const glm::quat& getHeadRotation() const { return _headRotation; } @@ -47,7 +49,7 @@ public: public slots: - void setEnabled(bool enabled); + void updateEnabled(); private: @@ -57,6 +59,8 @@ private: QMultiHash > _actionUnitIndexMap; #endif + void setEnabled(bool enabled); + bool _enabled; bool _active; glm::quat _headRotation; From 92bc675c97b03e8de2824150b166f2e6e9acbc91 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:21:45 -0700 Subject: [PATCH 07/17] Make sure to stop Visage before deleting it. --- interface/src/devices/Visage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 51b7324568..b96ef1ee72 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -48,6 +48,7 @@ Visage::Visage() : Visage::~Visage() { #ifdef HAVE_VISAGE + _tracker->stop(); delete _tracker; delete _data; #endif From 5f6f4b3d37480abf3b373e2946028d0336b45253 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:45:27 -0700 Subject: [PATCH 08/17] Fixes required since enabling Faceshift is now the default. --- interface/interface_en.ts | 4 ++-- interface/src/Application.cpp | 3 ++- interface/src/devices/Faceshift.cpp | 6 +++++- interface/src/devices/Faceshift.h | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 5eeacc67d8..53b8c8a0c5 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a8b28f2c0a..f616234cbc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1525,7 +1525,8 @@ void Application::init() { } qDebug("Loaded settings"); - // initialize Visage after loading the menu settings + // initialize Visage and Faceshift after loading the menu settings + _faceshift.init(); _visage.init(); // fire off an immediate domain-server check in now that settings are loaded diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 8aa57fa792..88974ce493 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -21,7 +21,7 @@ using namespace std; const quint16 FACESHIFT_PORT = 33433; Faceshift::Faceshift() : - _tcpEnabled(false), + _tcpEnabled(true), _tcpRetryCount(0), _lastTrackingStateReceived(0), _eyeGazeLeftPitch(0.0f), @@ -56,6 +56,10 @@ Faceshift::Faceshift() : _udpSocket.bind(FACESHIFT_PORT); } +void Faceshift::init() { + setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); +} + bool Faceshift::isConnectedOrConnecting() const { return _tcpSocket.state() == QAbstractSocket::ConnectedState || (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 66403715cd..a0898c446d 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -27,6 +27,8 @@ public: Faceshift(); + void init(); + bool isConnectedOrConnecting() const; bool isActive() const; From 38d03febbc7ccb1790119878c65550949782e2e9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:58:15 -0700 Subject: [PATCH 09/17] Add this file back. Hope it didn't have anything important! --- interface/interface_en.ts | 154 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 interface/interface_en.ts diff --git a/interface/interface_en.ts b/interface/interface_en.ts new file mode 100644 index 0000000000..531e8966dc --- /dev/null +++ b/interface/interface_en.ts @@ -0,0 +1,154 @@ + + + + + Application + + + Export Voxels + + + + + Sparse Voxel Octree Files (*.svo) + + + + + Open Script + + + + + JavaScript Files (*.js) + + + + + ChatWindow + + + + Chat + + + + + + Connecting to XMPP... + + + + + + online now: + + + + + day + + + + + + + + hour + + + + + + + + minute + + + + + + + + %1 online now: + + + + + Dialog + + + + + + Update Required + + + + + + Download + + + + + + Skip Version + + + + + + Close + + + + + Menu + + + Open .ini config file + + + + + + Text files (*.ini) + + + + + Save .ini config file + + + + + QObject + + + + Import Voxels + + + + + Loading ... + + + + + Place voxels + + + + + <b>Import</b> %1 as voxels + + + + + Cancel + + + + From 3f78ef40f1aef043d4f2cd811ceb9656ddf8ec59 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 17:08:23 -0700 Subject: [PATCH 10/17] Fixed the translation file. --- interface/interface_en.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 531e8966dc..c52ec91671 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -47,25 +47,32 @@ day - - - + + %n day + %n days hour - - - + + %n hour + %n hours minute - - - + + %n minute + %n minutes + + + + second + + %n second + %n seconds From b721533f0b934eb2ac77886a10ca3426e7da252f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:43:12 -0700 Subject: [PATCH 11/17] Make chat a dock widget, since that's the behavior it's emulating anyway (and for some reason, the current strategy causes a problem on at least Ryan's and my machine). --- interface/interface_en.ts | 16 ++++++++-------- interface/src/Application.cpp | 10 +--------- interface/src/Menu.cpp | 6 ++---- interface/src/ui/ChatWindow.cpp | 1 - interface/src/ui/ChatWindow.h | 4 ++-- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index c52ec91671..434acb80be 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fedde89a38..37b2810c68 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -292,14 +291,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : ResourceCache::setNetworkAccessManager(_networkAccessManager); ResourceCache::setRequestLimit(3); - QWidget* centralWidget = new QWidget(); - QHBoxLayout* mainLayout = new QHBoxLayout(); - mainLayout->setSpacing(0); - mainLayout->setContentsMargins(0, 0, 0, 0); - centralWidget->setLayout(mainLayout); - _glWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - centralWidget->layout()->addWidget(_glWidget); - _window->setCentralWidget(centralWidget); + _window->setCentralWidget(_glWidget); restoreSizeAndPosition(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 15cfb78cca..22b441d868 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1044,10 +1044,8 @@ void Menu::showMetavoxelEditor() { void Menu::showChat() { if (!_chatWindow) { - _chatWindow = new ChatWindow(); - QMainWindow* mainWindow = Application::getInstance()->getWindow(); - QBoxLayout* boxLayout = static_cast(mainWindow->centralWidget()->layout()); - boxLayout->addWidget(_chatWindow, 0, Qt::AlignRight); + Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); + } else { if (!_chatWindow->isVisible()) { _chatWindow->show(); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 103f045cfa..e28051f214 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -28,7 +28,6 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); ChatWindow::ChatWindow() : - QWidget(), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index fbf9fc0859..da8d423b9d 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -10,8 +10,8 @@ #define __interface__ChatWindow__ #include +#include #include -#include #include @@ -26,7 +26,7 @@ namespace Ui { class ChatWindow; } -class ChatWindow : public QWidget { +class ChatWindow : public QDockWidget { Q_OBJECT public: From a7d35944ccd22bad8cfbcf1b5c806ea284debada Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:48:57 -0700 Subject: [PATCH 12/17] Use an inner widget for the dock. --- interface/interface_en.ts | 8 ++++---- interface/src/ui/ChatWindow.cpp | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 434acb80be..9565d6e88a 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index e28051f214..b7587f9508 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -31,7 +31,10 @@ ChatWindow::ChatWindow() : ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { - ui->setupUi(this); + QWidget* widget = new QWidget(); + setWidget(widget); + + ui->setupUi(widget); FlowLayout* flowLayout = new FlowLayout(0, 4, 4); ui->usersWidget->setLayout(flowLayout); From 5f7e41b79bf59567f36d6c8ca709f1eb07ad9ee7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:55:27 -0700 Subject: [PATCH 13/17] More dock widget tweaks. --- interface/interface_en.ts | 8 ++++---- interface/src/Menu.cpp | 8 ++++---- interface/src/ui/ChatWindow.cpp | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 9565d6e88a..f07f50f287 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 22b441d868..c4b7fdcdd6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1047,8 +1047,8 @@ void Menu::showChat() { Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); } else { - if (!_chatWindow->isVisible()) { - _chatWindow->show(); + if (!_chatWindow->toggleViewAction()->isChecked()) { + _chatWindow->toggleViewAction()->trigger(); } } } @@ -1056,8 +1056,8 @@ void Menu::showChat() { void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); - if (!_chatAction->isEnabled() && _chatWindow) { - _chatWindow->hide(); + if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) { + _chatWindow->toggleViewAction()->trigger(); } #endif } diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index b7587f9508..55f32c5c7c 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -41,6 +41,8 @@ ChatWindow::ChatWindow() : ui->messagePlainTextEdit->installEventFilter(this); + ui->closeButton->hide(); + #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { From a045a87cca07c6e36d5ddc44fd4e26bd40827a3d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Mar 2014 11:11:00 -0700 Subject: [PATCH 14/17] Remove arm stretching, add sixense calibration --- interface/src/BuckyBalls.cpp | 1 + .../src/ControllerScriptingInterface.cpp | 1 + interface/src/avatar/SkeletonModel.cpp | 42 +--- interface/src/avatar/SkeletonModel.h | 4 - interface/src/devices/SixenseManager.cpp | 222 +++++++++++++++--- interface/src/devices/SixenseManager.h | 37 ++- libraries/avatars/src/HandData.cpp | 8 +- libraries/avatars/src/HandData.h | 20 +- libraries/shared/src/SharedUtil.h | 7 +- 9 files changed, 244 insertions(+), 98 deletions(-) diff --git a/interface/src/BuckyBalls.cpp b/interface/src/BuckyBalls.cpp index 14d4d0f1a8..8e489db74b 100644 --- a/interface/src/BuckyBalls.cpp +++ b/interface/src/BuckyBalls.cpp @@ -10,6 +10,7 @@ #include "Util.h" #include "world.h" +#include "devices/SixenseManager.h" const int NUM_ELEMENTS = 3; const float RANGE_BBALLS = 0.5f; diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index b60615f124..f5ab1653f5 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -8,6 +8,7 @@ #include #include "Application.h" +#include "devices/SixenseManager.h" #include "ControllerScriptingInterface.h" ControllerScriptingInterface::ControllerScriptingInterface() : diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f405358710..7edf48602e 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -123,6 +123,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); + setJointPosition(jointIndex, palm.getPosition()); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; glm::quat palmRotation; getJointRotation(jointIndex, palmRotation, true); @@ -154,7 +155,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // no point in continuing if there are no fingers if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) { - stretchArm(jointIndex, palm.getPosition()); return; } @@ -172,8 +172,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true); } - - stretchArm(jointIndex, palm.getPosition()); } void SkeletonModel::updateJointState(int index) { @@ -200,41 +198,3 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::normalize(inverse * axes[0])) * joint.rotation; } -void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) { - // find out where the hand is pointing - glm::quat handRotation; - getJointRotation(jointIndex, handRotation, true); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::vec3 forwardVector(jointIndex == geometry.rightHandJointIndex ? -1.0f : 1.0f, 0.0f, 0.0f); - glm::vec3 handVector = handRotation * forwardVector; - - // align elbow with hand - const FBXJoint& joint = geometry.joints.at(jointIndex); - if (joint.parentIndex == -1) { - return; - } - glm::quat elbowRotation; - getJointRotation(joint.parentIndex, elbowRotation, true); - applyRotationDelta(joint.parentIndex, rotationBetween(elbowRotation * forwardVector, handVector), false); - - // set position according to normal length - float scale = extractUniformScale(_scale); - glm::vec3 handPosition = position - _translation; - glm::vec3 elbowPosition = handPosition - handVector * joint.distanceToParent * scale; - - // set shoulder orientation to point to elbow - const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex); - if (parentJoint.parentIndex == -1) { - return; - } - glm::quat shoulderRotation; - getJointRotation(parentJoint.parentIndex, shoulderRotation, true); - applyRotationDelta(parentJoint.parentIndex, rotationBetween(shoulderRotation * forwardVector, - elbowPosition - extractTranslation(_jointStates.at(parentJoint.parentIndex).transform)), false); - - // update the shoulder state - updateJointState(parentJoint.parentIndex); - - // adjust the elbow's local translation - setJointTranslation(joint.parentIndex, elbowPosition); -} diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 3d95d805ea..533f22975f 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -43,10 +43,6 @@ protected: private: - /// Using the current position and rotation of the identified (hand) joint, computes a - /// reasonable stretched configuration for the connected arm. - void stretchArm(int jointIndex, const glm::vec3& position); - Avatar* _owningAvatar; }; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 0482dbf84c..8e54e034ac 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -6,17 +6,33 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#ifdef HAVE_SIXENSE - #include "sixense.h" -#endif +#include #include "Application.h" #include "SixenseManager.h" -using namespace std; - -SixenseManager::SixenseManager() : _lastMovement(0) { #ifdef HAVE_SIXENSE +const int CALIBRATION_STATE_IDLE = 0; +const int CALIBRATION_STATE_X = 1; +const int CALIBRATION_STATE_Y = 2; +const int CALIBRATION_STATE_Z = 3; +const int CALIBRATION_STATE_COMPLETE = 4; + +// default (expected) location of neck in sixense space +const float NECK_X = 250.f; // millimeters +const float NECK_Y = 300.f; // millimeters +const float NECK_Z = 300.f; // millimeters +#endif + +SixenseManager::SixenseManager() { +#ifdef HAVE_SIXENSE + _lastMovement = 0; + + _calibrationState = CALIBRATION_STATE_IDLE; + // By default we assume the _neckBase (in orb frame) is as high above the orb + // as the "torso" is below it. + _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); + sixenseInit(); #endif } @@ -48,12 +64,18 @@ void SixenseManager::update(float deltaTime) { Hand* hand = avatar->getHand(); int maxControllers = sixenseGetMaxControllers(); - for (int i = 0; i < maxControllers; i++) { + + // we only support two controllers + sixenseControllerData controllers[2]; + + int numActiveControllers = 0; + for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { if (!sixenseIsControllerEnabled(i)) { continue; } - sixenseControllerData data; - sixenseGetNewestData(i, &data); + sixenseControllerData* data = controllers + numActiveControllers; + ++numActiveControllers; + sixenseGetNewestData(i, data); // Set palm position and normal based on Hydra position/orientation @@ -61,7 +83,7 @@ void SixenseManager::update(float deltaTime) { PalmData* palm; bool foundHand = false; for (size_t j = 0; j < hand->getNumPalms(); j++) { - if (hand->getPalms()[j].getSixenseID() == data.controller_index) { + if (hand->getPalms()[j].getSixenseID() == data->controller_index) { palm = &(hand->getPalms()[j]); foundHand = true; } @@ -70,26 +92,27 @@ void SixenseManager::update(float deltaTime) { PalmData newPalm(hand); hand->getPalms().push_back(newPalm); palm = &(hand->getPalms()[hand->getNumPalms() - 1]); - palm->setSixenseID(data.controller_index); - printf("Found new Sixense controller, ID %i\n", data.controller_index); + palm->setSixenseID(data->controller_index); + printf("Found new Sixense controller, ID %i\n", data->controller_index); } palm->setActive(true); // Read controller buttons and joystick into the hand - palm->setControllerButtons(data.buttons); - palm->setTrigger(data.trigger); - palm->setJoystick(data.joystick_x, data.joystick_y); - - glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); - // Adjust for distance between acquisition 'orb' and the user's torso - // (distance to the right of body center, distance below torso, distance behind torso) - const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f); - position = SPHERE_TO_TORSO + position; - + palm->setControllerButtons(data->buttons); + palm->setTrigger(data->trigger); + palm->setJoystick(data->joystick_x, data->joystick_y); + + glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); + // Transform the measured position into body frame. + glm::vec3 neck = _neckBase; + // Zeroing y component of the "neck" effectively raises the measured position a little bit. + neck.y = 0.f; + position = _orbRotation * (position - neck); + // Rotation of Palm - glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); - rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * rotation; + glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); + rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _orbRotation * rotation; const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); glm::vec3 newNormal = rotation * PALM_VECTOR; palm->setRawNormal(newNormal); @@ -126,14 +149,159 @@ void SixenseManager::update(float deltaTime) { palm->getFingers().push_back(finger); palm->getFingers().push_back(finger); } - + + if (numActiveControllers == 2) { + updateCalibration(controllers); + } + // if the controllers haven't been moved in a while, disable const unsigned int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000; if (usecTimestampNow() - _lastMovement > MOVEMENT_DISABLE_DURATION) { - for (vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { + for (std::vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { it->setActive(false); } } -#endif +#endif // HAVE_SIXENSE } +#ifdef HAVE_SIXENSE + +// the calibration sequence is: +// (1) press BUTTON_FWD on both hands +// (2) reach arm straight out to the side (X) +// (3) lift arms staight up above head (Y) +// (4) move arms a bit forward (Z) +// (5) release BUTTON_FWD on both hands + +const float MINIMUM_ARM_REACH = 300.f; // millimeters +const float MAXIMUM_NOISE_LEVEL = 50.f; // millimeters +const quint64 LOCK_DURATION = USECS_PER_SECOND / 4; // time for lock to be acquired + +void SixenseManager::updateCalibration(const sixenseControllerData* controllers) { + const sixenseControllerData* dataLeft = controllers; + const sixenseControllerData* dataRight = controllers + 1; + + // calibration only happpens while both hands are holding BUTTON_FORWARD + if (dataLeft->buttons != BUTTON_FWD || dataRight->buttons != BUTTON_FWD) { + if (_calibrationState == CALIBRATION_STATE_IDLE) { + return; + } + switch (_calibrationState) { + case CALIBRATION_STATE_Y: + case CALIBRATION_STATE_Z: + case CALIBRATION_STATE_COMPLETE: + { + // compute calibration results + // ATM we only handle the case where the XAxis has been measured, and we assume the rest + // (i.e. that the orb is on a level surface) + // TODO: handle COMPLETE state where all three axes have been defined. This would allow us + // to also handle the case where left and right controllers have been reversed. + _neckBase = 0.5f * (_reachLeft + _reachRight); // neck is midway between right and left reaches + glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft); + glm::vec3 yAxis(0.f, 1.f, 0.f); + glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); + xAxis = glm::normalize(glm::cross(yAxis, zAxis)); + _orbRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); + qDebug("succeess: sixense calibration"); + } + break; + default: + qDebug("failed: sixense calibration"); + break; + } + + _calibrationState = CALIBRATION_STATE_IDLE; + return; + } + + const float* pos = dataLeft->pos; + glm::vec3 positionLeft(pos[0], pos[1], pos[2]); + pos = dataRight->pos; + glm::vec3 positionRight(pos[0], pos[1], pos[2]); + + if (_calibrationState == CALIBRATION_STATE_IDLE) { + float reach = glm::distance(positionLeft, positionRight); + if (reach > 2.f * MINIMUM_ARM_REACH) { + qDebug("started: sixense calibration"); + _averageLeft = positionLeft; + _averageRight = positionRight; + _reachLeft = _averageLeft; + _reachRight = _averageRight; + _lastDistance = reach; + _lockExpiry = usecTimestampNow() + LOCK_DURATION; + // move to next state + _calibrationState = CALIBRATION_STATE_X; + } + return; + } + + quint64 now = usecTimestampNow() + LOCK_DURATION; + // these are weighted running averages + _averageLeft = 0.9f * _averageLeft + 0.1f * positionLeft; + _averageRight = 0.9f * _averageRight + 0.1f * positionRight; + + if (_calibrationState == CALIBRATION_STATE_X) { + // compute new sliding average + float distance = glm::distance(_averageLeft, _averageRight); + if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { + // distance is increasing so acquire the data and push the expiry out + _reachLeft = _averageLeft; + _reachRight = _averageRight; + _lastDistance = distance; + _lockExpiry = now + LOCK_DURATION; + } else if (now > _lockExpiry) { + // lock has expired so clamp the data and move on + _lockExpiry = now + LOCK_DURATION; + _lastDistance = 0.f; + _reachUp = 0.5f * (_reachLeft + _reachRight); + _calibrationState = CALIBRATION_STATE_Y; + qDebug("success: sixense calibration: left"); + } + } + else if (_calibrationState == CALIBRATION_STATE_Y) { + glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); + glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); + float distance = (averagePosition - torso).y; + if (fabs(distance) > fabs(_lastDistance) + MAXIMUM_NOISE_LEVEL) { + // distance is increasing so acquire the data and push the expiry out + _reachUp = averagePosition; + _lastDistance = distance; + _lockExpiry = now + LOCK_DURATION; + } else if (now > _lockExpiry) { + if (_lastDistance > MINIMUM_ARM_REACH) { + // lock has expired so clamp the data and move on + _reachForward = _reachUp; + _lastDistance = 0.f; + _lockExpiry = now + LOCK_DURATION; + _calibrationState = CALIBRATION_STATE_Z; + qDebug("success: sixense calibration: up"); + } + } + } + else if (_calibrationState == CALIBRATION_STATE_Z) { + glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft); + glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); + //glm::vec3 yAxis = glm::normalize(_reachUp - torso); + glm::vec3 yAxis(0.f, 1.f, 0.f); + glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); + + glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); + float distance = glm::dot((averagePosition - torso), zAxis); + if (fabs(distance) > fabs(_lastDistance)) { + // distance is increasing so acquire the data and push the expiry out + _reachForward = averagePosition; + _lastDistance = distance; + _lockExpiry = now + LOCK_DURATION; + } else if (now > _lockExpiry) { + if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { + // lock has expired so clamp the data and move on + _calibrationState = CALIBRATION_STATE_COMPLETE; + qDebug("success: sixense calibration: forward"); + // TODO: it is theoretically possible to detect that the controllers have been + // accidentally switched (left hand is holding right controller) and to swap the order. + } + } + } +} +#endif // HAVE_SIXENSE + diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 1d8263ee30..de4cccb399 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -9,6 +9,21 @@ #ifndef __interface__SixenseManager__ #define __interface__SixenseManager__ +#include + +#ifdef HAVE_SIXENSE + #include + #include + #include "sixense.h" +#endif + +const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 +const unsigned int BUTTON_1 = 1U << 5; +const unsigned int BUTTON_2 = 1U << 6; +const unsigned int BUTTON_3 = 1U << 3; +const unsigned int BUTTON_4 = 1U << 4; +const unsigned int BUTTON_FWD = 1U << 7; + /// Handles interaction with the Sixense SDK (e.g., Razer Hydra). class SixenseManager : public QObject { Q_OBJECT @@ -24,7 +39,27 @@ public slots: void setFilter(bool filter); private: - +#ifdef HAVE_SIXENSE + void updateCalibration(const sixenseControllerData* controllers); + + int _calibrationState; + + // these are calibration results + glm::vec3 _neckBase; // midpoint between controllers during X-axis calibration + glm::quat _orbRotation; // rotates from orb frame into body frame + float _armLength; + + // these are measured values used to compute the calibration results + quint64 _lockExpiry; + glm::vec3 _averageLeft; + glm::vec3 _averageRight; + glm::vec3 _reachLeft; + glm::vec3 _reachRight; + glm::vec3 _reachUp; + glm::vec3 _reachForward; + float _lastDistance; + +#endif quint64 _lastMovement; }; diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 0355a4c86b..46dade6d64 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -25,10 +25,6 @@ HandData::HandData(AvatarData* owningAvatar) : addNewPalm(); } -glm::vec3 HandData::worldPositionToLeapPosition(const glm::vec3& worldPosition) const { - return glm::inverse(getBaseOrientation()) * (worldPosition - getBasePosition()) / LEAP_UNIT_SCALE; -} - glm::vec3 HandData::worldVectorToLeapVector(const glm::vec3& worldVector) const { return glm::inverse(getBaseOrientation()) * worldVector / LEAP_UNIT_SCALE; } @@ -272,9 +268,7 @@ glm::quat HandData::getBaseOrientation() const { } glm::vec3 HandData::getBasePosition() const { - const glm::vec3 LEAP_HANDS_OFFSET_FROM_TORSO(0.0, 0.3, -0.3); - return _owningAvatarData->getPosition() + getBaseOrientation() * LEAP_HANDS_OFFSET_FROM_TORSO * - _owningAvatarData->getTargetScale(); + return _owningAvatarData->getPosition(); } void FingerData::setTrailLength(unsigned int length) { diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index cdab9f71e9..f649faf080 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -28,13 +28,6 @@ const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND; const int LEAPID_INVALID = -1; const int SIXENSEID_INVALID = -1; -const int BUTTON_0 = 1; // the skinny button between 1 and 2 -const int BUTTON_1 = 32; -const int BUTTON_2 = 64; -const int BUTTON_3 = 8; -const int BUTTON_4 = 16; -const int BUTTON_FWD = 128; - const float LEAP_UNIT_SCALE = 0.001f; ///< convert mm to meters const int SIXENSE_CONTROLLER_ID_LEFT_HAND = 0; @@ -55,7 +48,6 @@ public: glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) { return getBaseOrientation() * leapDirection; } - glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const; glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const; std::vector& getPalms() { return _palms; } @@ -182,11 +174,11 @@ public: int getFramesWithoutData() const { return _numFramesWithoutData; } // Controller buttons - void setControllerButtons(int controllerButtons) { _controllerButtons = controllerButtons; } - void setLastControllerButtons(int controllerButtons) { _lastControllerButtons = controllerButtons; } + void setControllerButtons(unsigned int controllerButtons) { _controllerButtons = controllerButtons; } + void setLastControllerButtons(unsigned int controllerButtons) { _lastControllerButtons = controllerButtons; } - int getControllerButtons() const { return _controllerButtons; } - int getLastControllerButtons() const { return _lastControllerButtons; } + unsigned int getControllerButtons() const { return _controllerButtons; } + unsigned int getLastControllerButtons() const { return _lastControllerButtons; } void setTrigger(float trigger) { _trigger = trigger; } float getTrigger() const { return _trigger; } @@ -217,8 +209,8 @@ private: glm::vec3 _tipPosition; glm::vec3 _tipVelocity; - int _controllerButtons; - int _lastControllerButtons; + unsigned int _controllerButtons; + unsigned int _lastControllerButtons; float _trigger; float _joystickX, _joystickY; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 1695b3b253..439b85aa54 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -57,10 +57,9 @@ static const float DEGREES_PER_RADIAN = 180.0f / PI; static const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations static const float SQUARE_ROOT_OF_2 = (float)sqrt(2.f); static const float SQUARE_ROOT_OF_3 = (float)sqrt(3.f); -static const float METER = 1.0f; -static const float DECIMETER = 0.1f; -static const float CENTIMETER = 0.01f; -static const float MILLIIMETER = 0.001f; +static const float METERS_PER_DECIMETER = 0.1f; +static const float METERS_PER_CENTIMETER = 0.01f; +static const float METERS_PER_MILLIMETER = 0.001f; static const quint64 USECS_PER_MSEC = 1000; static const quint64 MSECS_PER_SECOND = 1000; static const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; From 4366b45445c79e1852a3772f87bacafa68780ec3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 11:13:15 -0700 Subject: [PATCH 15/17] Changed orientation tweak names, restore tweaked orientation rather than primary one. Closes #2310. --- interface/src/avatar/Head.cpp | 12 ++++++------ interface/src/avatar/Head.h | 17 +++++++++++------ interface/src/avatar/MyAvatar.cpp | 11 ++++++----- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 6c2bad865f..a9b85ffce2 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -36,9 +36,9 @@ Head::Head(Avatar* owningAvatar) : _leftEyeBlinkVelocity(0.0f), _rightEyeBlinkVelocity(0.0f), _timeWithoutTalking(0.0f), - _tweakedPitch(0.f), - _tweakedYaw(0.f), - _tweakedRoll(0.f), + _pitchTweak(0.f), + _yawTweak(0.f), + _rollTweak(0.f), _isCameraMoving(false), _faceModel(this) { @@ -202,15 +202,15 @@ glm::vec3 Head::getScalePivot() const { } float Head::getTweakedYaw() const { - return glm::clamp(_yaw + _tweakedYaw, MIN_HEAD_YAW, MAX_HEAD_YAW); + return glm::clamp(_yaw + _yawTweak, MIN_HEAD_YAW, MAX_HEAD_YAW); } float Head::getTweakedPitch() const { - return glm::clamp(_pitch + _tweakedPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); + return glm::clamp(_pitch + _pitchTweak, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } float Head::getTweakedRoll() const { - return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); + return glm::clamp(_roll + _rollTweak, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } void Head::applyCollision(CollisionInfo& collision) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 7e7a96a3a7..a9ea9b4cc6 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -70,10 +70,15 @@ public: /// Returns the point about which scaling occurs. glm::vec3 getScalePivot() const; - void tweakPitch(float pitch) { _tweakedPitch = pitch; } - void tweakYaw(float yaw) { _tweakedYaw = yaw; } - void tweakRoll(float roll) { _tweakedRoll = roll; } + void setPitchTweak(float pitch) { _pitchTweak = pitch; } + float getPitchTweak() const { return _pitchTweak; } + void setYawTweak(float yaw) { _yawTweak = yaw; } + float getYawTweak() const { return _yawTweak; } + + void setRollTweak(float roll) { _rollTweak = roll; } + float getRollTweak() const { return _rollTweak; } + virtual float getTweakedPitch() const; virtual float getTweakedYaw() const; virtual float getTweakedRoll() const; @@ -104,9 +109,9 @@ private: float _timeWithoutTalking; // tweaked angles affect the rendered head, but not the camera - float _tweakedPitch; - float _tweakedYaw; - float _tweakedRoll; + float _pitchTweak; + float _yawTweak; + float _rollTweak; bool _isCameraMoving; FaceModel _faceModel; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0a2462e656..e4aaa07a4b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -363,8 +363,9 @@ void MyAvatar::updateFromGyros(float deltaTime) { // restore rotation, lean to neutral positions const float RESTORE_PERIOD = 1.f; // seconds float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f); - head->setYaw(glm::mix(head->getYaw(), 0.0f, restorePercentage)); - head->setRoll(glm::mix(head->getRoll(), 0.0f, restorePercentage)); + head->setPitchTweak(glm::mix(head->getPitchTweak(), 0.0f, restorePercentage)); + head->setYawTweak(glm::mix(head->getYawTweak(), 0.0f, restorePercentage)); + head->setRollTweak(glm::mix(head->getRollTweak(), 0.0f, restorePercentage)); head->setLeanSideways(glm::mix(head->getLeanSideways(), 0.0f, restorePercentage)); head->setLeanForward(glm::mix(head->getLeanForward(), 0.0f, restorePercentage)); return; @@ -375,9 +376,9 @@ void MyAvatar::updateFromGyros(float deltaTime) { const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; - head->tweakPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); - head->tweakYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); - head->tweakRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); + head->setPitchTweak(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); + head->setYawTweak(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); + head->setRollTweak(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); // Update torso lean distance based on accelerometer data const float TORSO_LENGTH = 0.5f; From 8f200e917b78790874adc4268cd22f1ee67c73c1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 14 Mar 2014 13:03:14 -0700 Subject: [PATCH 16/17] fix JS radians vs degrees issues --- examples/cameraExample.js | 2 +- examples/crazylegs.js | 8 ++++---- examples/gun.js | 2 +- examples/hydraMove.js | 2 +- examples/lookWithMouse.js | 2 +- examples/lookWithTouch.js | 2 +- examples/multitouchExample.js | 2 +- examples/seeingVoxelsExample.js | 4 ++-- libraries/script-engine/src/Quat.cpp | 12 ++++++++++-- libraries/script-engine/src/Quat.h | 6 ++++-- 10 files changed, 26 insertions(+), 16 deletions(-) diff --git a/examples/cameraExample.js b/examples/cameraExample.js index ddfff15935..6e3c51a348 100644 --- a/examples/cameraExample.js +++ b/examples/cameraExample.js @@ -74,7 +74,7 @@ function checkCamera(deltaTime) { if (yaw < -360) { yaw += 360; } - var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll); + var orientation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll); Camera.setOrientation(orientation); } } diff --git a/examples/crazylegs.js b/examples/crazylegs.js index 0f26088ae0..0daf2275f3 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -14,10 +14,10 @@ var cumulativeTime = 0.0; Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; - MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRoll(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_L_hip", Quat.fromPitchYawRoll(0.0, 0.0, -AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_R_knee", Quat.fromPitchYawRoll(0.0, 0.0, + 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.fromPitchYawRoll(0.0, 0.0, + MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)))); }); diff --git a/examples/gun.js b/examples/gun.js index dee01fb84d..45b7487f25 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -78,7 +78,7 @@ function update(deltaTime) { // Check for mouseLook movement, update rotation // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); MyAvatar.orientation = newOrientation; yawFromMouse = 0; diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 1f9634a8e6..92c594df9e 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -184,7 +184,7 @@ function flyWithHydra(deltaTime) { // change the body yaw based on our x controller var orientation = MyAvatar.orientation; - var deltaOrientation = Quat.fromPitchYawRoll(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); + var deltaOrientation = Quat.fromPitchYawRollDegrees(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation); // change the headPitch based on our x controller diff --git a/examples/lookWithMouse.js b/examples/lookWithMouse.js index 878813a94a..ef8f11ec16 100644 --- a/examples/lookWithMouse.js +++ b/examples/lookWithMouse.js @@ -54,7 +54,7 @@ function update(deltaTime) { print("update()..."); } // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/lookWithTouch.js b/examples/lookWithTouch.js index ddc42c04c0..852573aea6 100644 --- a/examples/lookWithTouch.js +++ b/examples/lookWithTouch.js @@ -45,7 +45,7 @@ function touchUpdateEvent(event) { function update(deltaTime) { // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromMouse, 0)); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/multitouchExample.js b/examples/multitouchExample.js index 1041651c7b..51bbcc2c20 100644 --- a/examples/multitouchExample.js +++ b/examples/multitouchExample.js @@ -92,7 +92,7 @@ Controller.touchEndEvent.connect(touchEndEvent); function update(deltaTime) { // rotate body yaw for yaw received from multitouch rotate - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMultiTouch, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMultiTouch, z: 0 } )); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 62ebd599ee..257e869b5b 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -17,7 +17,7 @@ var yawMin = 20; var isLocal = false; // set up our VoxelViewer with a position and orientation -var orientation = Quat.fromPitchYawRoll(0, yaw, 0); +var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); function init() { if (isLocal) { @@ -40,7 +40,7 @@ function keepLooking(deltaTime) { count++; if (count % 10 == 0) { yaw += yawDirection; - orientation = Quat.fromPitchYawRoll(0, yaw, 0); + orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); if (yaw > yawMax || yaw < yawMin) { yawDirection = yawDirection * -1; } diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 14025f0c67..c939811db4 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -22,14 +22,22 @@ glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { return q1 * q2; } -glm::quat Quat::fromVec3(const glm::vec3& eulerAngles) { +glm::quat Quat::fromVec3Degrees(const glm::vec3& eulerAngles) { return glm::quat(glm::radians(eulerAngles)); } -glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) { +glm::quat Quat::fromVec3Radians(const glm::vec3& eulerAngles) { + return glm::quat(eulerAngles); +} + +glm::quat Quat::fromPitchYawRollDegrees(float pitch, float yaw, float roll) { return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll))); } +glm::quat Quat::fromPitchYawRollRadians(float pitch, float yaw, float roll) { + return glm::quat(glm::vec3(pitch, yaw, roll)); +} + glm::quat Quat::inverse(const glm::quat& q) { return glm::inverse(q); } diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 3e5f46682c..02c0a3e147 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -23,8 +23,10 @@ class Quat : public QObject { public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); - glm::quat fromVec3(const glm::vec3& vec3); - glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); // degrees + glm::quat fromVec3Degrees(const glm::vec3& vec3); // degrees + glm::quat fromVec3Radians(const glm::vec3& vec3); // radians + glm::quat fromPitchYawRollDegrees(float pitch, float yaw, float roll); // degrees + glm::quat fromPitchYawRollRadians(float pitch, float yaw, float roll); // radians glm::quat inverse(const glm::quat& q); glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation); From ab84526a1ba340c5b6e8a60c782b6a26fa2dad9c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Mar 2014 16:12:32 -0700 Subject: [PATCH 17/17] removing compile warnings --- interface/src/avatar/Hand.cpp | 4 ++-- interface/src/ui/BandwidthDialog.cpp | 6 +++--- interface/src/ui/LocalVoxelsOverlay.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 2 +- tests/physics/src/ShapeColliderTests.cpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 8f003d32d5..b4866c9478 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -206,8 +206,8 @@ void Hand::collideAgainstOurself() { } // ignoring everything below the parent of the parent of the last free joint int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( - skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : - (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); + skeletonModel.getLastFreeJointIndex(((int)i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : + ((int)i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); handCollisions.clear(); if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, handCollisions, skipIndex)) { diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index 15ca7c6423..8cefc9cf93 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -29,7 +29,7 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : this->QDialog::setLayout(form); // Setup labels - for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { + for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) { bool input = i % 2 == 0; BandwidthMeter::ChannelInfo& ch = _model->channelInfo(BandwidthMeter::ChannelIndex(i / 2)); QLabel* label = _labels[i] = new QLabel(); @@ -48,7 +48,7 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : } BandwidthDialog::~BandwidthDialog() { - for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { + for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) { delete _labels[i]; } } @@ -57,7 +57,7 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) { // Update labels char strBuf[64]; - for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { + for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) { BandwidthMeter::ChannelIndex chIdx = BandwidthMeter::ChannelIndex(i / 2); bool input = i % 2 == 0; BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx); diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/LocalVoxelsOverlay.cpp index 7eaf9ed5c5..9ad1428535 100644 --- a/interface/src/ui/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/LocalVoxelsOverlay.cpp @@ -41,7 +41,7 @@ void LocalVoxelsOverlay::update(float deltatime) { } _tree->lockForRead(); - if (_visible && _voxelCount != _tree->getOctreeElementsCount()) { + if (_visible && _voxelCount != (int)_tree->getOctreeElementsCount()) { _voxelCount = _tree->getOctreeElementsCount(); _voxelSystem->forceRedrawEntireTree(); } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index e42fe17df0..5cf906d82d 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -925,7 +925,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "(_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE):" << (_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE); } - if (missingItem <= std::max(0, (_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE))) { + if (missingItem <= (unsigned int)std::max(0, (int)_incomingLastSequence - (int)MAX_MISSING_SEQUENCE_OLD_AGE)) { if (wantExtraDebugging) { qDebug() << "pruning really old missing sequence:" << missingItem; } diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 79de9f9175..6d7e9a6db1 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -174,7 +174,7 @@ void ShapeColliderTests::sphereMissesCapsule() { CapsuleShape capsuleB(radiusB, halfHeightB); // give the capsule some arbirary transform - float angle = 37.8; + float angle = 37.8f; glm::vec3 axis = glm::normalize( glm::vec3(-7.f, 2.8f, 9.3f) ); glm::quat rotation = glm::angleAxis(angle, axis); glm::vec3 translation(15.1f, -27.1f, -38.6f);