diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index 37d7a30938..7d63a85a27 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -56,7 +56,7 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { #define AI_UPDATE_FLOAT(name, src, epsilon) \ { \ float val = src; \ - if (fabs(_##name - val) >= epsilon) { \ + if (fabsf(_##name - val) >= epsilon) { \ _##name = val; \ emit name##Changed(); \ } \ @@ -93,7 +93,7 @@ void AvatarInputs::update() { if (audioLevel > 1.0f) { audioLevel = 1.0; } - AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01); + AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01f); AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f))); AI_UPDATE(audioMuted, audioIO->isMuted()); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 509e63cbfe..4843afd5b1 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1045,7 +1045,7 @@ void EntityTreeRenderer::playEntityCollisionSound(EntityItemPointer entity, cons // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; - const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); + const float stretchFactor = logf(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / logf(2.0f); AudioInjector::playSound(collisionSound, volume, stretchFactor, collision.contactPoint); } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 718793fefa..64ee0bc869 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1631,13 +1631,15 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // whether we're skinned depends on how many clusters are attached const FBXCluster& firstFBXCluster = extracted.mesh.clusters.at(0); - int maxJointIndex = firstFBXCluster.jointIndex; glm::mat4 inverseModelTransform = glm::inverse(modelTransform); if (clusterIDs.size() > 1) { // this is a multi-mesh joint - extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size()); - extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size()); - float maxWeight = 0.0f; + const int WEIGHTS_PER_VERTEX = 4; + int numClusterIndices = extracted.mesh.vertices.size() * WEIGHTS_PER_VERTEX; + extracted.mesh.clusterIndices.fill(0, numClusterIndices); + QVector weightAccumulators; + weightAccumulators.fill(0.0f, numClusterIndices); + for (int i = 0; i < clusterIDs.size(); i++) { QString clusterID = clusterIDs.at(i); const Cluster& cluster = clusters[clusterID]; @@ -1662,61 +1664,69 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform; ShapeVertices& points = shapeVertices.at(jointIndex); - float totalWeight = 0.0f; for (int j = 0; j < cluster.indices.size(); j++) { int oldIndex = cluster.indices.at(j); float weight = cluster.weights.at(j); - totalWeight += weight; for (QMultiHash::const_iterator it = extracted.newIndices.constFind(oldIndex); it != extracted.newIndices.end() && it.key() == oldIndex; it++) { + int newIndex = it.value(); // remember vertices with at least 1/4 weight const float EXPANSION_WEIGHT_THRESHOLD = 0.99f; if (weight > EXPANSION_WEIGHT_THRESHOLD) { // transform to joint-frame and save for later - const glm::mat4 vertexTransform = meshToJoint * glm::translate(extracted.mesh.vertices.at(it.value())); + const glm::mat4 vertexTransform = meshToJoint * glm::translate(extracted.mesh.vertices.at(newIndex)); points.push_back(extractTranslation(vertexTransform) * clusterScale); } // look for an unused slot in the weights vector - glm::vec4& weights = extracted.mesh.clusterWeights[it.value()]; + int weightIndex = newIndex * WEIGHTS_PER_VERTEX; int lowestIndex = -1; float lowestWeight = FLT_MAX; int k = 0; - for (; k < 4; k++) { - if (weights[k] == 0.0f) { - extracted.mesh.clusterIndices[it.value()][k] = i; - weights[k] = weight; + for (; k < WEIGHTS_PER_VERTEX; k++) { + if (weightAccumulators[weightIndex + k] == 0.0f) { + extracted.mesh.clusterIndices[weightIndex + k] = i; + weightAccumulators[weightIndex + k] = weight; break; } - if (weights[k] < lowestWeight) { + if (weightAccumulators[weightIndex + k] < lowestWeight) { lowestIndex = k; - lowestWeight = weights[k]; + lowestWeight = weightAccumulators[weightIndex + k]; } } - if (k == 4 && weight > lowestWeight) { + if (k == WEIGHTS_PER_VERTEX && weight > lowestWeight) { // no space for an additional weight; we must replace the lowest - weights[lowestIndex] = weight; - extracted.mesh.clusterIndices[it.value()][lowestIndex] = i; + weightAccumulators[weightIndex + lowestIndex] = weight; + extracted.mesh.clusterIndices[weightIndex + lowestIndex] = i; } } } - if (totalWeight > maxWeight) { - maxWeight = totalWeight; - maxJointIndex = jointIndex; - } } - // normalize the weights if they don't add up to one - for (int i = 0; i < extracted.mesh.clusterWeights.size(); i++) { - glm::vec4& weights = extracted.mesh.clusterWeights[i]; - float total = weights.x + weights.y + weights.z + weights.w; - if (total != 1.0f && total != 0.0f) { - weights /= total; + + // now that we've accumulated the most relevant weights for each vertex + // normalize and compress to 8-bits + extracted.mesh.clusterWeights.fill(0, numClusterIndices); + int numVertices = extracted.mesh.vertices.size(); + for (int i = 0; i < numVertices; ++i) { + int j = i * WEIGHTS_PER_VERTEX; + + // normalize weights into uint8_t + float totalWeight = weightAccumulators[j]; + for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) { + totalWeight += weightAccumulators[k]; + } + if (totalWeight > 0.0f) { + const float ALMOST_HALF = 0.499f; + float weightScalingFactor = (float)(UINT8_MAX) / totalWeight; + for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { + extracted.mesh.clusterWeights[k] = (uint8_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF); + } } } } else { // this is a single-mesh joint - int jointIndex = maxJointIndex; + int jointIndex = firstFBXCluster.jointIndex; FBXJoint& joint = geometry.joints[jointIndex]; // transform cluster vertices to joint-frame and save for later @@ -1736,18 +1746,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } } } - extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); - buildModelMesh(extracted.mesh, url); - if (extracted.mesh.isEye) { - if (maxJointIndex == geometry.leftEyeJointIndex) { - geometry.leftEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale; - } else { - geometry.rightEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale; - } - } - geometry.meshes.append(extracted.mesh); int meshIndex = geometry.meshes.size() - 1; meshIDsToMeshIndices.insert(it.key(), meshIndex); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index fa047e512f..f73088e7a1 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -202,7 +202,7 @@ public: /// A single mesh (with optional blendshapes) extracted from an FBX document. class FBXMesh { public: - + QVector parts; QVector vertices; @@ -211,16 +211,14 @@ public: QVector colors; QVector texCoords; QVector texCoords1; - QVector clusterIndices; - QVector clusterWeights; - + QVector clusterIndices; + QVector clusterWeights; + QVector clusters; Extents meshExtents; glm::mat4 modelTransform; - bool isEye; - QVector blendshapes; unsigned int meshIndex; // the order the meshes appeared in the object file diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 8eb31b0731..4e153dfe3a 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -422,8 +422,13 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { int colorsSize = fbxMesh.colors.size() * sizeof(glm::vec3); int texCoordsSize = fbxMesh.texCoords.size() * sizeof(glm::vec2); int texCoords1Size = fbxMesh.texCoords1.size() * sizeof(glm::vec2); - int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(glm::vec4); - int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(glm::vec4); + + int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(uint8_t); + if (fbxMesh.clusters.size() > UINT8_MAX) { + // we need 16 bits instead of just 8 for clusterIndices + clusterIndicesSize *= 2; + } + int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint8_t); int normalsOffset = 0; int tangentsOffset = normalsOffset + normalsSize; @@ -442,7 +447,20 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { attribBuffer->setSubData(colorsOffset, colorsSize, (gpu::Byte*) fbxMesh.colors.constData()); attribBuffer->setSubData(texCoordsOffset, texCoordsSize, (gpu::Byte*) fbxMesh.texCoords.constData()); attribBuffer->setSubData(texCoords1Offset, texCoords1Size, (gpu::Byte*) fbxMesh.texCoords1.constData()); - attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) fbxMesh.clusterIndices.constData()); + + if (fbxMesh.clusters.size() < UINT8_MAX) { + // yay! we can fit the clusterIndices within 8-bits + int32_t numIndices = fbxMesh.clusterIndices.size(); + QVector clusterIndices; + clusterIndices.resize(numIndices); + for (int32_t i = 0; i < numIndices; ++i) { + assert(fbxMesh.clusterIndices[i] <= UINT8_MAX); + clusterIndices[i] = (uint8_t)(fbxMesh.clusterIndices[i]); + } + attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) clusterIndices.constData()); + } else { + attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) fbxMesh.clusterIndices.constData()); + } attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (gpu::Byte*) fbxMesh.clusterWeights.constData()); if (normalsSize) { @@ -476,14 +494,20 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { } if (clusterIndicesSize) { - mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, - model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, - gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); + if (fbxMesh.clusters.size() < UINT8_MAX) { + mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, + model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, + gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW))); + } else { + mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, + model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, + gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW))); + } } if (clusterWeightsSize) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, - gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); + gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::XYZW))); } diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index 65df5ed9dc..3e3853532a 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,6 +1,9 @@ set(TARGET_NAME gpu-gl) setup_hifi_library() link_hifi_libraries(shared gl gpu) +if (UNIX) + target_link_libraries(${TARGET_NAME} pthread) +endif(UNIX) GroupSources("src") target_opengl() diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index 638841b170..51a24563f3 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -99,8 +99,13 @@ void GL41Backend::updateInput() { GLboolean isNormalized = attrib._element.isNormalized(); for (size_t locNum = 0; locNum < locationCount; ++locNum) { - glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, - reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + if (attrib._element.isInteger()) { + glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + } else { + glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + } #ifdef GPU_STEREO_DRAWCALL_INSTANCED glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1)); #else diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp index 01bd2d7bce..ece62e15f1 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -61,8 +61,11 @@ void GL45Backend::updateInput() { _input._attributeActivation.set(attriNum); glEnableVertexAttribArray(attriNum); } - glVertexAttribFormat(attriNum, count, type, isNormalized, offset + locNum * perLocationSize); - // TODO: Support properly the IAttrib version + if (attrib._element.isInteger()) { + glVertexAttribIFormat(attriNum, count, type, offset + locNum * perLocationSize); + } else { + glVertexAttribFormat(attriNum, count, type, isNormalized, offset + locNum * perLocationSize); + } glVertexAttribBinding(attriNum, attrib._channel); } diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 493a2de3c2..4114ccb15c 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -75,12 +75,12 @@ static const bool TYPE_IS_INTEGER[NUM_TYPES] = { true, // Normalized values - true, - true, - true, - true, - true, - true + false, + false, + false, + false, + false, + false }; // Dimension of an Element diff --git a/libraries/gpu/src/gpu/Inputs.slh b/libraries/gpu/src/gpu/Inputs.slh index ce5e4227eb..843d1059f2 100644 --- a/libraries/gpu/src/gpu/Inputs.slh +++ b/libraries/gpu/src/gpu/Inputs.slh @@ -15,7 +15,7 @@ layout(location = 1) in vec4 inNormal; layout(location = 2) in vec4 inColor; layout(location = 3) in vec4 inTexCoord0; layout(location = 4) in vec4 inTangent; -layout(location = 5) in vec4 inSkinClusterIndex; +layout(location = 5) in ivec4 inSkinClusterIndex; layout(location = 6) in vec4 inSkinClusterWeight; layout(location = 7) in vec4 inTexCoord1; <@endif@> diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 687dab536b..2d1f010029 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -18,11 +18,11 @@ layout(std140) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; -void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { +void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; newPosition += clusterMatrix * inPosition * clusterWeight; } @@ -30,13 +30,13 @@ void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition skinnedPosition = newPosition; } -void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, +void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, out vec4 skinnedPosition, out vec3 skinnedNormal) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; newPosition += clusterMatrix * inPosition * clusterWeight; newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; @@ -46,14 +46,14 @@ void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPo skinnedNormal = newNormal.xyz; } -void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, +void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; newPosition += clusterMatrix * inPosition * clusterWeight; newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index a793942056..50833e90fc 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -471,10 +471,10 @@ void Menu::removeSeparator(const QString& menuName, const QString& separatorName int textAt = findPositionOfMenuItem(menu, separatorName); QList menuActions = menu->actions(); if (textAt > 0 && textAt < menuActions.size()) { - QAction* separatorText = menuActions[textAt]; QAction* separatorLine = menuActions[textAt - 1]; if (separatorLine) { if (separatorLine->isSeparator()) { + QAction* separatorText = menuActions[textAt]; menu->removeAction(separatorText); menu->removeAction(separatorLine); separatorRemoved = true; diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index 1c6c9af272..90f8ccb368 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -441,7 +441,12 @@ function getTeleportTargetType(intersection) { var props = Entities.getEntityProperties(intersection.entityID, ['userData', 'visible']); var data = parseJSON(props.userData); if (data !== undefined && data.seat !== undefined) { - return TARGET.SEAT; + var avatarUuid = Uuid.fromString(data.seat.user); + if (Uuid.isNull(avatarUuid) || !AvatarList.getAvatar(avatarUuid)) { + return TARGET.SEAT; + } else { + return TARGET.INVALID; + } } if (!props.visible) { diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 82afdc8974..3d3bc10fb1 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -1,5 +1,21 @@ +// +// sit.js +// +// Created by Clement Brisset on 3/3/17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + (function() { Script.include("/~/system/libraries/utils.js"); + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(searchString, position){ + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; + } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; var ANIMATION_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/animations/sitting_idle.fbx"; @@ -28,6 +44,10 @@ this.interval = null; this.sitDownSettlePeriod = null; this.lastTimeNoDriveKeys = null; + this.sittingDown = false; + + // Preload the animation file + this.animation = AnimationCache.prefetch(ANIMATION_URL); this.preload = function(entityID) { this.entityID = entityID; @@ -100,12 +120,19 @@ return seatUser !== null; } + this.rolesToOverride = function() { + return MyAvatar.getAnimationRoles().filter(function(role) { + return role === "fly" || role.startsWith("inAir"); + }); + } + this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); return; } print("Sitting down (" + this.entityID + ")"); + this.sittingDown = true; var now = Date.now(); this.sitDownSettlePeriod = now + IK_SETTLE_TIME; @@ -117,10 +144,15 @@ if (previousValue === "") { MyAvatar.characterControllerEnabled = false; MyAvatar.hmdLeanRecenterEnabled = false; - var ROLES = MyAvatar.getAnimationRoles(); - for (i in ROLES) { - MyAvatar.overrideRoleAnimation(ROLES[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); } + + for (var i in OVERRIDEN_DRIVE_KEYS) { + MyAvatar.disableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); + } + MyAvatar.resetSensorsAndBody(); } @@ -132,25 +164,27 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); - for (var i in OVERRIDEN_DRIVE_KEYS) { - MyAvatar.disableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); - } } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); - for (var i in OVERRIDEN_DRIVE_KEYS) { - MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); + + if (MyAvatar.sessionUUID === this.getSeatUser()) { + this.setSeatUser(null); } - this.setSeatUser(null); if (Settings.getValue(SETTING_KEY) === this.entityID) { Settings.setValue(SETTING_KEY, ""); - var ROLES = MyAvatar.getAnimationRoles(); - for (i in ROLES) { - MyAvatar.restoreRoleAnimation(ROLES[i]); + + for (var i in OVERRIDEN_DRIVE_KEYS) { + MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); + } + + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.restoreRoleAnimation(roles[i]); } MyAvatar.characterControllerEnabled = true; MyAvatar.hmdLeanRecenterEnabled = true; @@ -165,6 +199,7 @@ MyAvatar.bodyRoll = 0.0; }, SIT_DELAY); } + this.sittingDown = false; } // function called by teleport.js if it detects the appropriate userData @@ -215,7 +250,7 @@ } this.update = function(dt) { - if (MyAvatar.sessionUUID === this.getSeatUser()) { + if (this.sittingDown === true) { var properties = Entities.getEntityProperties(this.entityID); var avatarDistance = Vec3.distance(MyAvatar.position, properties.position); var ikError = MyAvatar.getIKErrorOnLastSolve(); @@ -244,6 +279,9 @@ shouldStandUp = true; } + if (MyAvatar.sessionUUID !== this.getSeatUser()) { + shouldStandUp = true; + } if (shouldStandUp || avatarDistance > RELEASE_DISTANCE) { print("IK error: " + ikError + ", distance from chair: " + avatarDistance); @@ -253,7 +291,11 @@ var offset = { x: 0, y: 1.0, z: -0.5 - properties.dimensions.z * properties.registrationPoint.z }; var position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.rotation, offset)); MyAvatar.position = position; - print("Moving Avatar in front of the chair.") + print("Moving Avatar in front of the chair."); + // Delay standing up by 1 cycle. + // This leaves times for the avatar to actually move since a lot + // of the stand up operations are threaded + return; } this.standUp();