From f2cc227331d4f1ae4f1f3b48e5be470c898c62b3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 10:17:32 -0700 Subject: [PATCH 1/8] Ryan's requested change for rotation smoothing. --- interface/resources/visage/tracker.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/visage/tracker.cfg b/interface/resources/visage/tracker.cfg index b5ed3302fa..10744da6e5 100644 --- a/interface/resources/visage/tracker.cfg +++ b/interface/resources/visage/tracker.cfg @@ -40,7 +40,7 @@ detect_strip_roi_width 2 detect_strip_roi_height 4 smoothing_factors - 150 15 -2 100 -1 50 50 0 + 150 5 -2 100 -1 50 50 0 #translation rotation action_units eyebrows mouth gaze eye_closure other process_eyes 1 From 299dbb93eaedee17696c496e72338e171a2fd15b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 13:57:36 -0700 Subject: [PATCH 2/8] Removed "springiness" bits. --- interface/src/renderer/FBXReader.cpp | 48 +----- interface/src/renderer/FBXReader.h | 4 - interface/src/renderer/GeometryCache.cpp | 19 +-- interface/src/renderer/Model.cpp | 195 ++++++----------------- interface/src/renderer/Model.h | 3 - 5 files changed, 58 insertions(+), 211 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8bf5583a02..22cd44408e 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1331,14 +1331,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.staticExtents.reset(); geometry.meshExtents.reset(); - QVariantHash springs = mapping.value("spring").toHash(); - QVariant defaultSpring = springs.value("default"); for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { ExtractedMesh& extracted = it.value(); // accumulate local transforms QString modelID = models.contains(it.key()) ? it.key() : parentMap.value(it.key()); - extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat(); glm::mat4 modelTransform = getGlobalTransform(parentMap, models, modelID); // compute the mesh extents from the transformed vertices @@ -1591,49 +1588,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); - - // extract spring edges, connections if springy - if (extracted.mesh.springiness > 0.0f) { - QSet > edges; - - extracted.mesh.vertexConnections.resize(extracted.mesh.vertices.size()); - foreach (const FBXMeshPart& part, extracted.mesh.parts) { - for (int i = 0; i < part.quadIndices.size(); i += 4) { - int index0 = part.quadIndices.at(i); - int index1 = part.quadIndices.at(i + 1); - int index2 = part.quadIndices.at(i + 2); - int index3 = part.quadIndices.at(i + 3); - - edges.insert(QPair(qMin(index0, index1), qMax(index0, index1))); - edges.insert(QPair(qMin(index1, index2), qMax(index1, index2))); - edges.insert(QPair(qMin(index2, index3), qMax(index2, index3))); - edges.insert(QPair(qMin(index3, index0), qMax(index3, index0))); - - extracted.mesh.vertexConnections[index0].append(QPair(index3, index1)); - extracted.mesh.vertexConnections[index1].append(QPair(index0, index2)); - extracted.mesh.vertexConnections[index2].append(QPair(index1, index3)); - extracted.mesh.vertexConnections[index3].append(QPair(index2, index0)); - } - for (int i = 0; i < part.triangleIndices.size(); i += 3) { - int index0 = part.triangleIndices.at(i); - int index1 = part.triangleIndices.at(i + 1); - int index2 = part.triangleIndices.at(i + 2); - - edges.insert(QPair(qMin(index0, index1), qMax(index0, index1))); - edges.insert(QPair(qMin(index1, index2), qMax(index1, index2))); - edges.insert(QPair(qMin(index2, index0), qMax(index2, index0))); - - extracted.mesh.vertexConnections[index0].append(QPair(index2, index1)); - extracted.mesh.vertexConnections[index1].append(QPair(index0, index2)); - extracted.mesh.vertexConnections[index2].append(QPair(index1, index0)); - } - } - - for (QSet >::const_iterator edge = edges.constBegin(); edge != edges.constEnd(); edge++) { - extracted.mesh.springEdges.append(*edge); - } - } - + geometry.meshes.append(extracted.mesh); } @@ -1797,7 +1752,6 @@ FBXGeometry readSVO(const QByteArray& model) { // and one mesh with one cluster and one part FBXMesh mesh; mesh.isEye = false; - mesh.springiness = 0.0f; FBXCluster cluster = { 0 }; mesh.clusters.append(cluster); diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 3f0fc3e580..ead75e6517 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -130,10 +130,6 @@ public: bool isEye; QVector blendshapes; - - float springiness; - QVector > springEdges; - QVector, 4> > vertexConnections; }; /// An attachment to an FBX document. diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index c815eda030..bd5915397b 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -565,8 +565,8 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkMesh.vertexBuffer.bind(); networkMesh.vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); - // if we don't need to do any blending or springing, then the positions/normals can be static - if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { + // if we don't need to do any blending, the positions/normals can be static + if (mesh.blendshapes.isEmpty()) { int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); @@ -587,8 +587,8 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(), mesh.clusterWeights.size() * sizeof(glm::vec4)); - // if there's no springiness, then the cluster indices/weights can be static - } else if (mesh.springiness == 0.0f) { + // otherwise, at least the cluster indices/weights can be static + } else { int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); @@ -601,16 +601,7 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(), mesh.clusterIndices.size() * sizeof(glm::vec4)); networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(), - mesh.clusterWeights.size() * sizeof(glm::vec4)); - - } else { - int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - networkMesh.vertexBuffer.allocate(texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2)); - networkMesh.vertexBuffer.write(0, mesh.tangents.constData(), mesh.tangents.size() * sizeof(glm::vec3)); - networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3)); - networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(), - mesh.texCoords.size() * sizeof(glm::vec2)); + mesh.clusterWeights.size() * sizeof(glm::vec4)); } networkMesh.vertexBuffer.release(); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 60fae5e596..df6d41ebbc 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -175,7 +175,7 @@ bool Model::render(float alpha) { if (_blendedVertexBufferIDs.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { GLuint id = 0; - if (!mesh.blendshapes.isEmpty() || mesh.springiness > 0.0f) { + if (!mesh.blendshapes.isEmpty()) { glGenBuffers(1, &id); glBindBuffer(GL_ARRAY_BUFFER, id); glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), @@ -490,11 +490,6 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector 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) { @@ -541,80 +536,6 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector 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; } @@ -980,34 +901,30 @@ void Model::renderMeshes(float alpha, bool translucent) { const MeshState& state = _meshStates.at(i); ProgramObject* activeProgram = program; int tangentLocation = _normalMapTangentLocation; - if (state.worldSpaceVertices.isEmpty()) { - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); - - if (state.clusterMatrices.size() > 1) { - skinProgram->bind(); - glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, - (const float*)state.clusterMatrices.constData()); - int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) + - mesh.texCoords.size() * sizeof(glm::vec2) + - (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); - skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); - skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, - offset + vertexCount * sizeof(glm::vec4), 4); - skinProgram->enableAttributeArray(skinLocations->clusterIndices); - skinProgram->enableAttributeArray(skinLocations->clusterWeights); - activeProgram = skinProgram; - tangentLocation = skinLocations->tangent; - - } else { - glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); - program->bind(); - } - } else { + glPushMatrix(); + Application::getInstance()->loadTranslatedViewMatrix(_translation); + + if (state.clusterMatrices.size() > 1) { + skinProgram->bind(); + glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, + (const float*)state.clusterMatrices.constData()); + int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) + + mesh.texCoords.size() * sizeof(glm::vec2) + + (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); + skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); + skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, + offset + vertexCount * sizeof(glm::vec4), 4); + skinProgram->enableAttributeArray(skinLocations->clusterIndices); + skinProgram->enableAttributeArray(skinLocations->clusterWeights); + activeProgram = skinProgram; + tangentLocation = skinLocations->tangent; + + } else { + glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); program->bind(); } - if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { + if (mesh.blendshapes.isEmpty()) { if (!mesh.tangents.isEmpty()) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); activeProgram->enableAttributeArray(tangentLocation); @@ -1026,38 +943,31 @@ void Model::renderMeshes(float alpha, bool translucent) { glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); - if (!state.worldSpaceVertices.isEmpty()) { - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData()); - - } else { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - _blendedNormals.resize(_blendedVertices.size()); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), mesh.normals.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 float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + _blendedNormals.resize(_blendedVertices.size()); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + memcpy(_blendedNormals.data(), mesh.normals.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 float NORMAL_COEFFICIENT_SCALE = 0.01f; + float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { + _blendedVertices[*index] += *vertex * coefficient; + _blendedNormals[*index] += *normal * normalCoefficient; } - - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); } + + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), + vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); } glVertexPointer(3, GL_FLOAT, 0, 0); glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); @@ -1126,14 +1036,13 @@ void Model::renderMeshes(float alpha, bool translucent) { activeProgram->disableAttributeArray(tangentLocation); } - - if (state.worldSpaceVertices.isEmpty()) { - if (state.clusterMatrices.size() > 1) { - skinProgram->disableAttributeArray(skinLocations->clusterIndices); - skinProgram->disableAttributeArray(skinLocations->clusterWeights); - } - glPopMatrix(); - } + + if (state.clusterMatrices.size() > 1) { + skinProgram->disableAttributeArray(skinLocations->clusterIndices); + skinProgram->disableAttributeArray(skinLocations->clusterWeights); + } + glPopMatrix(); + activeProgram->release(); } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 165465d2cc..5b1fbb3eea 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -219,9 +219,6 @@ protected: class MeshState { public: QVector clusterMatrices; - QVector worldSpaceVertices; - QVector vertexVelocities; - QVector worldSpaceNormals; }; QVector _meshStates; From 07497ea4f7e8a8faa51e06506f866698af47c893 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 18 Mar 2014 15:35:25 -0700 Subject: [PATCH 3/8] removing fly to voxel option --- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ca059a53da..c23b312d3a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -165,7 +165,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false); - addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly); + addAvatarCollisionSubMenu(editMenu); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index df622be6ac..f99ebe0685 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -272,7 +272,6 @@ namespace MenuOption { const QString OffAxisProjection = "Off-Axis Projection"; const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString TurnWithHead = "Turn using Head"; - const QString ClickToFly = "Fly to voxel on click"; const QString LoadScript = "Open and Run Script..."; const QString Oscilloscope = "Audio Oscilloscope"; const QString Pair = "Pair"; From 635f3b6dc387fd6bd1e47cc14bb750f2cfd4eaa3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 16:38:05 -0700 Subject: [PATCH 4/8] Perform the mesh blending in worker threads and only when we've actually received new data. Closes #2075. Closes #2348. --- interface/src/avatar/MyAvatar.cpp | 5 - interface/src/devices/Faceshift.cpp | 4 +- interface/src/devices/Faceshift.h | 8 +- interface/src/devices/Visage.h | 6 +- interface/src/renderer/GeometryCache.cpp | 8 ++ interface/src/renderer/GeometryCache.h | 12 +- interface/src/renderer/Model.cpp | 161 ++++++++++++++++------- interface/src/renderer/Model.h | 20 +-- interface/src/renderer/TextureCache.h | 2 +- libraries/avatars/src/HeadData.h | 7 +- 10 files changed, 155 insertions(+), 78 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6c51026097..fb0d704c6a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -424,11 +424,6 @@ void MyAvatar::updateFromGyros(float deltaTime) { } } -static TextRenderer* textRenderer() { - static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); - return renderer; -} - void MyAvatar::renderDebugBodyPoints() { glm::vec3 torsoPosition(getPosition()); glm::vec3 headPosition(getHead()->getEyePosition()); diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 88974ce493..9f1734c7e5 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -103,7 +103,7 @@ void Faceshift::reset() { } void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, std::vector& coefficients) const { + float jawOpen, QVector& coefficients) const { coefficients.resize(max((int)coefficients.size(), _jawOpenIndex + 1)); qFill(coefficients.begin(), coefficients.end(), 0.0f); coefficients[_leftBlinkIndex] = leftBlink; @@ -204,7 +204,7 @@ void Faceshift::receive(const QByteArray& buffer) { _eyeGazeLeftYaw = data.m_eyeGazeLeftYaw; _eyeGazeRightPitch = -data.m_eyeGazeRightPitch; _eyeGazeRightYaw = data.m_eyeGazeRightYaw; - _blendshapeCoefficients = data.m_coeffs; + _blendshapeCoefficients = QVector::fromStdVector(data.m_coeffs); _lastTrackingStateReceived = usecTimestampNow(); } diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index a0898c446d..f878056b57 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -9,8 +9,6 @@ #ifndef __interface__Faceshift__ #define __interface__Faceshift__ -#include - #include #include @@ -47,7 +45,7 @@ public: float getEstimatedEyePitch() const { return _estimatedEyePitch; } float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } @@ -68,7 +66,7 @@ public: void reset(); void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, std::vector& coefficients) const; + float jawOpen, QVector& coefficients) const; signals: @@ -111,7 +109,7 @@ private: float _eyeGazeRightPitch; float _eyeGazeRightYaw; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; int _leftBlinkIndex; int _rightBlinkIndex; diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 7e50812ba7..6e98abbb61 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -9,8 +9,6 @@ #ifndef __interface__Visage__ #define __interface__Visage__ -#include - #include #include #include @@ -42,7 +40,7 @@ public: float getEstimatedEyePitch() const { return _estimatedEyePitch; } float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } void update(); void reset(); @@ -71,7 +69,7 @@ private: float _estimatedEyePitch; float _estimatedEyeYaw; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; }; #endif /* defined(__interface__Visage__) */ diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index bd5915397b..c4a0d15baa 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include "GeometryCache.h" +#include "Model.h" #include "world.h" GeometryCache::~GeometryCache() { @@ -291,6 +292,13 @@ QSharedPointer GeometryCache::getGeometry(const QUrl& url, cons return getResource(url, fallback, delayLoad).staticCast(); } +void GeometryCache::setBlendedVertices(const QPointer& model, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals) { + if (!model.isNull() && model->getGeometry() == geometry) { + model->setBlendedVertices(vertices, normals); + } +} + QSharedPointer GeometryCache::createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra) { diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index cc0775051a..252a0c401b 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -19,15 +19,18 @@ #include "FBXReader.h" +class Model; class NetworkGeometry; class NetworkMesh; class NetworkTexture; /// Stores cached geometry. class GeometryCache : public ResourceCache { + Q_OBJECT + public: - ~GeometryCache(); + virtual ~GeometryCache(); void renderHemisphere(int slices, int stacks); void renderSquare(int xDivisions, int yDivisions); @@ -38,7 +41,12 @@ public: /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested QSharedPointer getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); - + +public slots: + + void setBlendedVertices(const QPointer& model, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals); + protected: virtual QSharedPointer createResource(const QUrl& url, diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index df6d41ebbc..591cc4a021 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -6,6 +6,10 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include +#include +#include + #include #include @@ -19,6 +23,10 @@ using namespace std; +static int modelPointerTypeId = qRegisterMetaType >(); +static int weakNetworkGeometryPointerTypeId = qRegisterMetaType >(); +static int vec3VectorTypeId = qRegisterMetaType >(); + Model::Model(QObject* parent) : QObject(parent), _scale(1.0f, 1.0f, 1.0f), @@ -104,8 +112,6 @@ void Model::init() { } void Model::reset() { - _resetStates = true; - foreach (Model* attachment, _attachments) { attachment->reset(); } @@ -170,20 +176,10 @@ bool Model::render(float alpha) { return false; } - // set up blended buffer ids on first render after load/simulate + // set up dilated textures on first render after load/simulate const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (_blendedVertexBufferIDs.isEmpty()) { + if (_dilatedTextures.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { - GLuint id = 0; - if (!mesh.blendshapes.isEmpty()) { - glGenBuffers(1, &id); - glBindBuffer(GL_ARRAY_BUFFER, id); - glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), - NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - _blendedVertexBufferIDs.append(id); - QVector > dilated; dilated.resize(mesh.parts.size()); _dilatedTextures.append(dilated); @@ -478,6 +474,68 @@ QVector Model::updateGeometry() { return newJointStates; } +class Blender : public QRunnable { +public: + + Blender(Model* model, const QWeakPointer& geometry, + const QVector& meshes, const QVector& blendshapeCoefficients); + + virtual void run(); + +private: + + QPointer _model; + QWeakPointer _geometry; + QVector _meshes; + QVector _blendshapeCoefficients; +}; + +Blender::Blender(Model* model, const QWeakPointer& geometry, + const QVector& meshes, const QVector& blendshapeCoefficients) : + _model(model), + _geometry(geometry), + _meshes(meshes), + _blendshapeCoefficients(blendshapeCoefficients) { +} + +void Blender::run() { + // make sure the model/geometry still exists + if (_model.isNull() || _geometry.isNull()) { + return; + } + QVector vertices, normals; + int offset = 0; + foreach (const FBXMesh& mesh, _meshes) { + if (mesh.blendshapes.isEmpty()) { + continue; + } + vertices += mesh.vertices; + normals += mesh.normals; + glm::vec3* meshVertices = vertices.data() + offset; + glm::vec3* meshNormals = normals.data() + offset; + offset += mesh.vertices.size(); + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) { + float vertexCoefficient = _blendshapeCoefficients.at(i); + if (vertexCoefficient < EPSILON) { + continue; + } + float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE; + const FBXBlendshape& blendshape = mesh.blendshapes.at(i); + for (int j = 0; j < blendshape.indices.size(); j++) { + int index = blendshape.indices.at(j); + meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient; + meshNormals[index] += blendshape.normals.at(j) * normalCoefficient; + } + } + } + + // post the result to the geometry cache, which will dispatch to the model if still alive + QMetaObject::invokeMethod(Application::getInstance()->getGeometryCache(), "setBlendedVertices", + Q_ARG(const QPointer&, _model), Q_ARG(const QWeakPointer&, _geometry), + Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); +} + void Model::simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates) { if (!isActive()) { return; @@ -491,6 +549,19 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); _meshStates.append(state); + + QOpenGLBuffer buffer; + if (!mesh.blendshapes.isEmpty()) { + buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); + buffer.create(); + buffer.bind(); + buffer.allocate((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3)); + buffer.write(0, mesh.vertices.constData(), mesh.vertices.size() * sizeof(glm::vec3)); + buffer.write(mesh.vertices.size() * sizeof(glm::vec3), mesh.normals.constData(), + mesh.normals.size() * sizeof(glm::vec3)); + buffer.release(); + } + _blendedVertexBuffers.append(buffer); } foreach (const FBXAttachment& attachment, geometry.attachments) { Model* model = new Model(this); @@ -498,12 +569,12 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector model->setURL(attachment.url); _attachments.append(model); } - _resetStates = fullUpdate = true; + fullUpdate = true; createCollisionShapes(); } // exit early if we don't have to perform a full update - if (!(fullUpdate || _resetStates)) { + if (!fullUpdate) { return; } @@ -537,7 +608,9 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; } } - _resetStates = false; + + // post the blender + QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); } void Model::updateJointState(int index) { @@ -836,6 +909,27 @@ void Model::applyCollision(CollisionInfo& collision) { } } +void Model::setBlendedVertices(const QVector& vertices, const QVector& normals) { + if (_blendedVertexBuffers.isEmpty()) { + return; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + int index = 0; + for (int i = 0; i < geometry.meshes.size(); i++) { + const FBXMesh& mesh = geometry.meshes.at(i); + if (mesh.blendshapes.isEmpty()) { + continue; + } + QOpenGLBuffer& buffer = _blendedVertexBuffers[i]; + buffer.bind(); + buffer.write(0, vertices.constData() + index, mesh.vertices.size() * sizeof(glm::vec3)); + buffer.write(mesh.vertices.size() * sizeof(glm::vec3), normals.constData() + index, + mesh.normals.size() * sizeof(glm::vec3)); + buffer.release(); + index += mesh.vertices.size(); + } +} + void Model::applyNextGeometry() { // delete our local geometry and custom textures deleteGeometry(); @@ -854,10 +948,7 @@ void Model::deleteGeometry() { delete attachment; } _attachments.clear(); - foreach (GLuint id, _blendedVertexBufferIDs) { - glDeleteBuffers(1, &id); - } - _blendedVertexBufferIDs.clear(); + _blendedVertexBuffers.clear(); _jointStates.clear(); _meshStates.clear(); clearShapes(); @@ -941,33 +1032,7 @@ void Model::renderMeshes(float alpha, bool translucent) { } glColorPointer(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3))); glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); - glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); - - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - _blendedNormals.resize(_blendedVertices.size()); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), mesh.normals.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 float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } - } - - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); + _blendedVertexBuffers[i].bind(); } glVertexPointer(3, GL_FLOAT, 0, 0); glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5b1fbb3eea..f08a6b9fc2 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -43,8 +43,8 @@ public: void setPupilDilation(float dilation) { _pupilDilation = dilation; } float getPupilDilation() const { return _pupilDilation; } - void setBlendshapeCoefficients(const std::vector& coefficients) { _blendshapeCoefficients = coefficients; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } bool isActive() const { return _geometry && _geometry->isLoaded(); } @@ -195,6 +195,9 @@ public: /// Use the collision to affect the model void applyCollision(CollisionInfo& collision); + /// Sets blended vertices computed in a separate thread. + void setBlendedVertices(const QVector& vertices, const QVector& normals); + protected: QSharedPointer _geometry; @@ -268,16 +271,13 @@ private: float _nextLODHysteresis; float _pupilDilation; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; QUrl _url; - QVector _blendedVertexBufferIDs; - QVector > > _dilatedTextures; - bool _resetStates; + QVector _blendedVertexBuffers; - QVector _blendedVertices; - QVector _blendedNormals; + QVector > > _dilatedTextures; QVector _attachments; @@ -303,4 +303,8 @@ private: static QVector createJointStates(const FBXGeometry& geometry); }; +Q_DECLARE_METATYPE(QPointer) +Q_DECLARE_METATYPE(QWeakPointer) +Q_DECLARE_METATYPE(QVector) + #endif /* defined(__interface__Model__) */ diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index d7e61954ce..ebeb35119c 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -27,7 +27,7 @@ class TextureCache : public ResourceCache { public: TextureCache(); - ~TextureCache(); + virtual ~TextureCache(); /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 56dc5630d0..b199ff19d2 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -10,7 +10,8 @@ #define __hifi__HeadData__ #include -#include + +#include #include #include @@ -54,7 +55,7 @@ public: float getAudioAverageLoudness() const { return _audioAverageLoudness; } void setAudioAverageLoudness(float audioAverageLoudness) { _audioAverageLoudness = audioAverageLoudness; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } float getPupilDilation() const { return _pupilDilation; } void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } @@ -86,7 +87,7 @@ protected: float _averageLoudness; float _browAudioLift; float _audioAverageLoudness; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; float _pupilDilation; AvatarData* _owningAvatar; From f8c14a5717bdc3b565ef66ad04cdcc19c1a63b44 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:06:01 -0700 Subject: [PATCH 5/8] Remove unused variable, reorder includes. --- libraries/avatars/src/HandData.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index c84ed77dae..0f938b80b0 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -8,14 +8,11 @@ #include -#include "HandData.h" -#include "AvatarData.h" -#include #include +#include - -// When converting between fixed and float, use this as the radix. -const int fingerVectorRadix = 4; +#include "AvatarData.h" +#include "HandData.h" HandData::HandData(AvatarData* owningAvatar) : _owningAvatarData(owningAvatar) From f86b793c96e06a5c6f3b9cec10a3f5e68913ac82 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Mar 2014 17:14:57 -0700 Subject: [PATCH 6/8] only output version mismatch once per sender per packet --- libraries/shared/src/NodeList.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 1e7a8cfaf0..6d699322de 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -88,9 +88,16 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { PacketType mismatchType = packetTypeForPacket(packet); int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data()); - qDebug() << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender" + static QMultiMap versionDebugSuppressMap; + + QUuid senderUUID = uuidFromPacketHeader(packet); + if (!versionDebugSuppressMap.contains(senderUUID, checkType)) { + qDebug() << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender" << uuidFromPacketHeader(packet) << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but" << qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected."; + + versionDebugSuppressMap.insert(senderUUID, checkType); + } return false; } From 0fc0d50bdaa7b8114d637ffdb3047d8e0b392840 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:19:42 -0700 Subject: [PATCH 7/8] Only post the blender if we have blendable meshes to blend. --- interface/src/renderer/FBXReader.cpp | 9 +++++++++ interface/src/renderer/FBXReader.h | 2 ++ interface/src/renderer/Model.cpp | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 22cd44408e..53f4e04b0b 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -54,6 +54,15 @@ QStringList FBXGeometry::getJointNames() const { return names; } +bool FBXGeometry::hasBlendedMeshes() const { + foreach (const FBXMesh& mesh, meshes) { + if (!mesh.blendshapes.isEmpty()) { + return true; + } + } + return false; +} + static int fbxGeometryMetaTypeId = qRegisterMetaType(); template QVariant readBinaryArray(QDataStream& in) { diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index ead75e6517..5f6a4f51ba 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -181,6 +181,8 @@ public: int getJointIndex(const QString& name) const { return jointIndices.value(name) - 1; } QStringList getJointNames() const; + + bool hasBlendedMeshes() const; }; Q_DECLARE_METATYPE(FBXGeometry) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 591cc4a021..16b5c167d9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -610,7 +610,9 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector } // post the blender - QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); + if (geometry.hasBlendedMeshes()) { + QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); + } } void Model::updateJointState(int index) { From f9fd0d432f47b2bf0972b8427cf6d4016536982f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:48:57 -0700 Subject: [PATCH 8/8] Fix for reading aggregate avatar packets. --- libraries/avatars/src/AvatarData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8ed0ce51ec..e5e0e4b3d7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -176,8 +176,8 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { _handData = new HandData(this); } - const unsigned char* startPosition = reinterpret_cast(packet.data()); - const unsigned char* sourceBuffer = startPosition + offset; + const unsigned char* startPosition = reinterpret_cast(packet.data()) + offset; + const unsigned char* sourceBuffer = startPosition; // Body world position memcpy(&_position, sourceBuffer, sizeof(float) * 3);