mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 23:55:24 +02:00
Merge pull request #10035 from sethalves/tablet-ui
Tablet ui - merge from upstream
This commit is contained in:
commit
45e83906e7
15 changed files with 168 additions and 88 deletions
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<float> 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<int, int>::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);
|
||||
|
|
|
@ -202,7 +202,7 @@ public:
|
|||
/// A single mesh (with optional blendshapes) extracted from an FBX document.
|
||||
class FBXMesh {
|
||||
public:
|
||||
|
||||
|
||||
QVector<FBXMeshPart> parts;
|
||||
|
||||
QVector<glm::vec3> vertices;
|
||||
|
@ -211,16 +211,14 @@ public:
|
|||
QVector<glm::vec3> colors;
|
||||
QVector<glm::vec2> texCoords;
|
||||
QVector<glm::vec2> texCoords1;
|
||||
QVector<glm::vec4> clusterIndices;
|
||||
QVector<glm::vec4> clusterWeights;
|
||||
|
||||
QVector<uint16_t> clusterIndices;
|
||||
QVector<uint8_t> clusterWeights;
|
||||
|
||||
QVector<FBXCluster> clusters;
|
||||
|
||||
Extents meshExtents;
|
||||
glm::mat4 modelTransform;
|
||||
|
||||
bool isEye;
|
||||
|
||||
QVector<FBXBlendshape> blendshapes;
|
||||
|
||||
unsigned int meshIndex; // the order the meshes appeared in the object file
|
||||
|
|
|
@ -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<uint8_t> 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)));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
|
||||
if (attrib._element.isInteger()) {
|
||||
glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
|
||||
} else {
|
||||
glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
|
||||
}
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1));
|
||||
#else
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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@>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -471,10 +471,10 @@ void Menu::removeSeparator(const QString& menuName, const QString& separatorName
|
|||
int textAt = findPositionOfMenuItem(menu, separatorName);
|
||||
QList<QAction*> 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;
|
||||
|
|
|
@ -1181,7 +1181,7 @@ function MyController(hand) {
|
|||
|
||||
this.updateStylusTip();
|
||||
|
||||
var DEFAULT_USE_FINGER_AS_STYLUS = false;
|
||||
var DEFAULT_USE_FINGER_AS_STYLUS = true;
|
||||
var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus");
|
||||
if (USE_FINGER_AS_STYLUS === "") {
|
||||
USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue