Merge branch 'master' of https://github.com/highfidelity/hifi into smoothTeleport
|
@ -395,8 +395,18 @@ void Agent::executeScript() {
|
||||||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||||
scriptedAvatar->setRecordingBasis();
|
scriptedAvatar->setRecordingBasis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// these procedural movements are included in the recordings
|
||||||
|
scriptedAvatar->setHasProceduralEyeFaceMovement(false);
|
||||||
|
scriptedAvatar->setHasProceduralBlinkFaceMovement(false);
|
||||||
|
scriptedAvatar->setHasAudioEnabledFaceMovement(false);
|
||||||
} else {
|
} else {
|
||||||
scriptedAvatar->clearRecordingBasis();
|
scriptedAvatar->clearRecordingBasis();
|
||||||
|
|
||||||
|
// restore procedural blendshape movement
|
||||||
|
scriptedAvatar->setHasProceduralEyeFaceMovement(true);
|
||||||
|
scriptedAvatar->setHasProceduralBlinkFaceMovement(true);
|
||||||
|
scriptedAvatar->setHasAudioEnabledFaceMovement(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "AvatarMixerClientData.h"
|
#include "AvatarMixerClientData.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
@ -218,6 +219,10 @@ uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& node
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointer other) {
|
void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointer other) {
|
||||||
|
ignoreOther(self.data(), other.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarMixerClientData::ignoreOther(const Node* self, const Node* other) {
|
||||||
if (!isRadiusIgnoring(other->getUUID())) {
|
if (!isRadiusIgnoring(other->getUUID())) {
|
||||||
addToRadiusIgnoringSet(other->getUUID());
|
addToRadiusIgnoringSet(other->getUUID());
|
||||||
auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
|
auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
|
||||||
|
@ -235,9 +240,20 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self, const QUuid& other) {
|
bool AvatarMixerClientData::isRadiusIgnoring(const QUuid& other) const {
|
||||||
if (isRadiusIgnoring(other)) {
|
return std::find(_radiusIgnoredOthers.cbegin(), _radiusIgnoredOthers.cend(), other) != _radiusIgnoredOthers.cend();
|
||||||
_radiusIgnoredOthers.erase(other);
|
}
|
||||||
|
|
||||||
|
void AvatarMixerClientData::addToRadiusIgnoringSet(const QUuid& other) {
|
||||||
|
if (!isRadiusIgnoring(other)) {
|
||||||
|
_radiusIgnoredOthers.push_back(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarMixerClientData::removeFromRadiusIgnoringSet(const QUuid& other) {
|
||||||
|
auto ignoredOtherIter = std::find(_radiusIgnoredOthers.cbegin(), _radiusIgnoredOthers.cend(), other);
|
||||||
|
if (ignoredOtherIter != _radiusIgnoredOthers.cend()) {
|
||||||
|
_radiusIgnoredOthers.erase(ignoredOtherIter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
|
@ -45,6 +45,7 @@ public:
|
||||||
|
|
||||||
int parseData(ReceivedMessage& message) override;
|
int parseData(ReceivedMessage& message) override;
|
||||||
AvatarData& getAvatar() { return *_avatar; }
|
AvatarData& getAvatar() { return *_avatar; }
|
||||||
|
const AvatarData& getAvatar() const { return *_avatar; }
|
||||||
const AvatarData* getConstAvatarData() const { return _avatar.get(); }
|
const AvatarData* getConstAvatarData() const { return _avatar.get(); }
|
||||||
AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; }
|
AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; }
|
||||||
|
|
||||||
|
@ -90,11 +91,11 @@ public:
|
||||||
void loadJSONStats(QJsonObject& jsonObject) const;
|
void loadJSONStats(QJsonObject& jsonObject) const;
|
||||||
|
|
||||||
glm::vec3 getPosition() const { return _avatar ? _avatar->getWorldPosition() : glm::vec3(0); }
|
glm::vec3 getPosition() const { return _avatar ? _avatar->getWorldPosition() : glm::vec3(0); }
|
||||||
glm::vec3 getGlobalBoundingBoxCorner() const { return _avatar ? _avatar->getGlobalBoundingBoxCorner() : glm::vec3(0); }
|
bool isRadiusIgnoring(const QUuid& other) const;
|
||||||
bool isRadiusIgnoring(const QUuid& other) const { return _radiusIgnoredOthers.find(other) != _radiusIgnoredOthers.end(); }
|
void addToRadiusIgnoringSet(const QUuid& other);
|
||||||
void addToRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.insert(other); }
|
void removeFromRadiusIgnoringSet(const QUuid& other);
|
||||||
void removeFromRadiusIgnoringSet(SharedNodePointer self, const QUuid& other);
|
|
||||||
void ignoreOther(SharedNodePointer self, SharedNodePointer other);
|
void ignoreOther(SharedNodePointer self, SharedNodePointer other);
|
||||||
|
void ignoreOther(const Node* self, const Node* other);
|
||||||
|
|
||||||
void readViewFrustumPacket(const QByteArray& message);
|
void readViewFrustumPacket(const QByteArray& message);
|
||||||
|
|
||||||
|
@ -166,7 +167,7 @@ private:
|
||||||
int _numOutOfOrderSends = 0;
|
int _numOutOfOrderSends = 0;
|
||||||
|
|
||||||
SimpleMovingAverage _avgOtherAvatarDataRate;
|
SimpleMovingAverage _avgOtherAvatarDataRate;
|
||||||
std::unordered_set<QUuid> _radiusIgnoredOthers;
|
std::vector<QUuid> _radiusIgnoredOthers;
|
||||||
ConicalViewFrustums _currentViewFrustums;
|
ConicalViewFrustums _currentViewFrustums;
|
||||||
|
|
||||||
int _recentOtherAvatarsInView { 0 };
|
int _recentOtherAvatarsInView { 0 };
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
|
@ -33,6 +34,8 @@
|
||||||
#include "AvatarMixer.h"
|
#include "AvatarMixer.h"
|
||||||
#include "AvatarMixerClientData.h"
|
#include "AvatarMixerClientData.h"
|
||||||
|
|
||||||
|
namespace chrono = std::chrono;
|
||||||
|
|
||||||
void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) {
|
void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) {
|
||||||
_begin = begin;
|
_begin = begin;
|
||||||
_end = end;
|
_end = end;
|
||||||
|
@ -209,7 +212,18 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
_stats.jobElapsedTime += (end - start);
|
_stats.jobElapsedTime += (end - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AABox computeBubbleBox(const AvatarData& avatar, float bubbleExpansionFactor) {
|
||||||
|
AABox box = avatar.getGlobalBoundingBox();
|
||||||
|
glm::vec3 scale = box.getScale();
|
||||||
|
scale *= bubbleExpansionFactor;
|
||||||
|
const glm::vec3 MIN_BUBBLE_SCALE(0.3f, 1.3f, 0.3);
|
||||||
|
scale = glm::max(scale, MIN_BUBBLE_SCALE);
|
||||||
|
box.setScaleStayCentered(glm::max(scale, MIN_BUBBLE_SCALE));
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
||||||
|
const Node* destinationNode = node.data();
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
@ -220,7 +234,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
_stats.nodesBroadcastedTo++;
|
_stats.nodesBroadcastedTo++;
|
||||||
|
|
||||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(destinationNode->getLinkedData());
|
||||||
|
|
||||||
nodeData->resetInViewStats();
|
nodeData->resetInViewStats();
|
||||||
|
|
||||||
|
@ -242,12 +256,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
int traitBytesSent = 0;
|
int traitBytesSent = 0;
|
||||||
|
|
||||||
// max number of avatarBytes per frame
|
// max number of avatarBytes per frame
|
||||||
auto maxAvatarBytesPerFrame = (_maxKbpsPerNode * BYTES_PER_KILOBIT) / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND;
|
int maxAvatarBytesPerFrame = int(_maxKbpsPerNode * BYTES_PER_KILOBIT / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND);
|
||||||
|
|
||||||
// FIXME - find a way to not send the sessionID for every avatar
|
|
||||||
int minimumBytesPerAvatar = AvatarDataPacket::AVATAR_HAS_FLAGS_SIZE + NUM_BYTES_RFC4122_UUID;
|
|
||||||
|
|
||||||
int overBudgetAvatars = 0;
|
|
||||||
|
|
||||||
// keep track of the number of other avatars held back in this frame
|
// keep track of the number of other avatars held back in this frame
|
||||||
int numAvatarsHeldBack = 0;
|
int numAvatarsHeldBack = 0;
|
||||||
|
@ -260,66 +270,38 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
bool PALIsOpen = nodeData->getRequestsDomainListData();
|
bool PALIsOpen = nodeData->getRequestsDomainListData();
|
||||||
|
|
||||||
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them
|
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them
|
||||||
bool getsAnyIgnored = PALIsOpen && node->getCanKick();
|
bool getsAnyIgnored = PALIsOpen && destinationNode->getCanKick();
|
||||||
|
|
||||||
if (PALIsOpen) {
|
// Bandwidth allowance for data that must be sent.
|
||||||
// Increase minimumBytesPerAvatar if the PAL is open
|
int minimumBytesPerAvatar = PALIsOpen ? AvatarDataPacket::AVATAR_HAS_FLAGS_SIZE + NUM_BYTES_RFC4122_UUID +
|
||||||
minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) +
|
sizeof(AvatarDataPacket::AvatarGlobalPosition) + sizeof(AvatarDataPacket::AudioLoudness) : 0;
|
||||||
sizeof(AvatarDataPacket::AudioLoudness);
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup a PacketList for the avatarPackets
|
// setup a PacketList for the avatarPackets
|
||||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||||
|
static auto maxAvatarDataBytes = avatarPacketList->getMaxSegmentSize() - NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
// Define the minimum bubble size
|
// compute node bounding box
|
||||||
static const glm::vec3 minBubbleSize = avatar.getSensorToWorldScale() * glm::vec3(0.3f, 1.3f, 0.3f);
|
const float MY_AVATAR_BUBBLE_EXPANSION_FACTOR = 4.0f; // magic number determined emperically
|
||||||
// Define the scale of the box for the current node
|
AABox nodeBox = computeBubbleBox(avatar, MY_AVATAR_BUBBLE_EXPANSION_FACTOR);
|
||||||
glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f * avatar.getSensorToWorldScale();
|
|
||||||
// Set up the bounding box for the current node
|
|
||||||
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
|
||||||
// Clamp the size of the bounding box to a minimum scale
|
|
||||||
if (glm::any(glm::lessThan(nodeBoxScale, minBubbleSize))) {
|
|
||||||
nodeBox.setScaleStayCentered(minBubbleSize);
|
|
||||||
}
|
|
||||||
// Quadruple the scale of both bounding boxes
|
|
||||||
nodeBox.embiggen(4.0f);
|
|
||||||
|
|
||||||
|
|
||||||
// setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes
|
|
||||||
std::vector<AvatarSharedPointer> avatarsToSort;
|
|
||||||
std::unordered_map<AvatarSharedPointer, SharedNodePointer> avatarDataToNodes;
|
|
||||||
std::unordered_map<QUuid, uint64_t> avatarEncodeTimes;
|
|
||||||
std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) {
|
|
||||||
// make sure this is an agent that we have avatar data for before considering it for inclusion
|
|
||||||
if (otherNode->getType() == NodeType::Agent
|
|
||||||
&& otherNode->getLinkedData()) {
|
|
||||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
|
||||||
|
|
||||||
AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer();
|
|
||||||
avatarsToSort.push_back(otherAvatar);
|
|
||||||
avatarDataToNodes[otherAvatar] = otherNode;
|
|
||||||
QUuid id = otherAvatar->getSessionUUID();
|
|
||||||
avatarEncodeTimes[id] = nodeData->getLastOtherAvatarEncodeTime(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
class SortableAvatar: public PrioritySortUtil::Sortable {
|
class SortableAvatar: public PrioritySortUtil::Sortable {
|
||||||
public:
|
public:
|
||||||
SortableAvatar() = delete;
|
SortableAvatar() = delete;
|
||||||
SortableAvatar(const AvatarSharedPointer& avatar, uint64_t lastEncodeTime)
|
SortableAvatar(const AvatarData* avatar, const Node* avatarNode, uint64_t lastEncodeTime)
|
||||||
: _avatar(avatar), _lastEncodeTime(lastEncodeTime) {}
|
: _avatar(avatar), _node(avatarNode), _lastEncodeTime(lastEncodeTime) {}
|
||||||
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
glm::vec3 getPosition() const override { return _avatar->getClientGlobalPosition(); }
|
||||||
float getRadius() const override {
|
float getRadius() const override {
|
||||||
glm::vec3 nodeBoxHalfScale = (_avatar->getWorldPosition() - _avatar->getGlobalBoundingBoxCorner() * _avatar->getSensorToWorldScale());
|
glm::vec3 nodeBoxScale = _avatar->getGlobalBoundingBox().getScale();
|
||||||
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
return 0.5f * glm::max(nodeBoxScale.x, glm::max(nodeBoxScale.y, nodeBoxScale.z));
|
||||||
}
|
}
|
||||||
uint64_t getTimestamp() const override {
|
uint64_t getTimestamp() const override {
|
||||||
return _lastEncodeTime;
|
return _lastEncodeTime;
|
||||||
}
|
}
|
||||||
AvatarSharedPointer getAvatar() const { return _avatar; }
|
const Node* getNode() const { return _node; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AvatarSharedPointer _avatar;
|
const AvatarData* _avatar;
|
||||||
|
const Node* _node;
|
||||||
uint64_t _lastEncodeTime;
|
uint64_t _lastEncodeTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -329,16 +311,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
AvatarData::_avatarSortCoefficientSize,
|
AvatarData::_avatarSortCoefficientSize,
|
||||||
AvatarData::_avatarSortCoefficientCenter,
|
AvatarData::_avatarSortCoefficientCenter,
|
||||||
AvatarData::_avatarSortCoefficientAge);
|
AvatarData::_avatarSortCoefficientAge);
|
||||||
sortedAvatars.reserve(avatarsToSort.size());
|
sortedAvatars.reserve(_end - _begin);
|
||||||
|
|
||||||
// ignore or sort
|
for (auto listedNode = _begin; listedNode != _end; ++listedNode) {
|
||||||
const AvatarSharedPointer& thisAvatar = nodeData->getAvatarSharedPointer();
|
Node* otherNodeRaw = (*listedNode).data();
|
||||||
for (const auto& avatar : avatarsToSort) {
|
if (otherNodeRaw->getType() != NodeType::Agent
|
||||||
if (avatar == thisAvatar) {
|
|| !otherNodeRaw->getLinkedData()
|
||||||
// don't echo updates to self
|
|| otherNodeRaw == destinationNode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto avatarNode = otherNodeRaw;
|
||||||
|
|
||||||
bool shouldIgnore = false;
|
bool shouldIgnore = false;
|
||||||
// We ignore other nodes for a couple of reasons:
|
// We ignore other nodes for a couple of reasons:
|
||||||
// 1) ignore bubbles and ignore specific node
|
// 1) ignore bubbles and ignore specific node
|
||||||
|
@ -346,53 +330,39 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
// happen if for example the avatar is connected on a desktop and sending
|
// happen if for example the avatar is connected on a desktop and sending
|
||||||
// updates at ~30hz. So every 3 frames we skip a frame.
|
// updates at ~30hz. So every 3 frames we skip a frame.
|
||||||
|
|
||||||
auto avatarNode = avatarDataToNodes[avatar];
|
|
||||||
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
|
|
||||||
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
const AvatarMixerClientData* avatarClientNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||||
assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data
|
assert(avatarClientNodeData); // we can't have gotten here without avatarNode having valid data
|
||||||
quint64 startIgnoreCalculation = usecTimestampNow();
|
quint64 startIgnoreCalculation = usecTimestampNow();
|
||||||
|
|
||||||
// make sure we have data for this avatar, that it isn't the same node,
|
// make sure we have data for this avatar, that it isn't the same node,
|
||||||
// and isn't an avatar that the viewing node has ignored
|
// and isn't an avatar that the viewing node has ignored
|
||||||
// or that has ignored the viewing node
|
// or that has ignored the viewing node
|
||||||
if (!avatarNode->getLinkedData()
|
if ((destinationNode->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
||||||
|| avatarNode->getUUID() == node->getUUID()
|
|| (avatarNode->isIgnoringNodeWithID(destinationNode->getUUID()) && !getsAnyIgnored)) {
|
||||||
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
|
||||||
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
|
||||||
shouldIgnore = true;
|
shouldIgnore = true;
|
||||||
} else {
|
} else {
|
||||||
// Check to see if the space bubble is enabled
|
// Check to see if the space bubble is enabled
|
||||||
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
||||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
if (destinationNode->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||||
float sensorToWorldScale = avatarNodeData->getAvatarSharedPointer()->getSensorToWorldScale();
|
|
||||||
// Define the scale of the box for the current other node
|
|
||||||
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f * sensorToWorldScale;
|
|
||||||
// Set up the bounding box for the current other node
|
|
||||||
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
|
||||||
// Clamp the size of the bounding box to a minimum scale
|
|
||||||
if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) {
|
|
||||||
otherNodeBox.setScaleStayCentered(minBubbleSize);
|
|
||||||
}
|
|
||||||
// Change the scale of both bounding boxes
|
|
||||||
// (This is an arbitrary number determined empirically)
|
|
||||||
otherNodeBox.embiggen(2.4f);
|
|
||||||
|
|
||||||
// Perform the collision check between the two bounding boxes
|
// Perform the collision check between the two bounding boxes
|
||||||
|
const float OTHER_AVATAR_BUBBLE_EXPANSION_FACTOR = 2.4f; // magic number determined empirically
|
||||||
|
AABox otherNodeBox = computeBubbleBox(avatarClientNodeData->getAvatar(), OTHER_AVATAR_BUBBLE_EXPANSION_FACTOR);
|
||||||
if (nodeBox.touches(otherNodeBox)) {
|
if (nodeBox.touches(otherNodeBox)) {
|
||||||
nodeData->ignoreOther(node, avatarNode);
|
nodeData->ignoreOther(destinationNode, avatarNode);
|
||||||
shouldIgnore = !getsAnyIgnored;
|
shouldIgnore = !getsAnyIgnored;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not close enough to ignore
|
// Not close enough to ignore
|
||||||
if (!shouldIgnore) {
|
if (!shouldIgnore) {
|
||||||
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
nodeData->removeFromRadiusIgnoringSet(avatarNode->getUUID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldIgnore) {
|
if (!shouldIgnore) {
|
||||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
||||||
AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber();
|
AvatarDataSequenceNumber lastSeqFromSender = avatarClientNodeData->getLastReceivedSequenceNumber();
|
||||||
|
|
||||||
// FIXME - This code does appear to be working. But it seems brittle.
|
// FIXME - This code does appear to be working. But it seems brittle.
|
||||||
// It supports determining if the frame of data for this "other"
|
// It supports determining if the frame of data for this "other"
|
||||||
|
@ -417,12 +387,10 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
if (!shouldIgnore) {
|
if (!shouldIgnore) {
|
||||||
// sort this one for later
|
// sort this one for later
|
||||||
uint64_t lastEncodeTime = 0;
|
const AvatarData* avatarNodeData = avatarClientNodeData->getConstAvatarData();
|
||||||
std::unordered_map<QUuid, uint64_t>::const_iterator itr = avatarEncodeTimes.find(avatar->getSessionUUID());
|
auto lastEncodeTime = nodeData->getLastOtherAvatarEncodeTime(avatarNodeData->getSessionUUID());
|
||||||
if (itr != avatarEncodeTimes.end()) {
|
|
||||||
lastEncodeTime = itr->second;
|
sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
|
||||||
}
|
|
||||||
sortedAvatars.push(SortableAvatar(avatar, lastEncodeTime));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,19 +398,31 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
||||||
|
|
||||||
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
||||||
for (const auto& sortedAvatar : sortedAvatarVector) {
|
for (const auto& sortedAvatar : sortedAvatarVector) {
|
||||||
const auto& avatarData = sortedAvatar.getAvatar();
|
const Node* otherNode = sortedAvatar.getNode();
|
||||||
remainingAvatars--;
|
auto lastEncodeForOther = sortedAvatar.getTimestamp();
|
||||||
|
|
||||||
auto otherNode = avatarDataToNodes[avatarData];
|
|
||||||
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
|
|
||||||
// NOTE: Here's where we determine if we are over budget and drop to bare minimum data
|
AvatarData::AvatarDataDetail detail = AvatarData::NoData;
|
||||||
|
|
||||||
|
// NOTE: Here's where we determine if we are over budget and drop remaining avatars,
|
||||||
|
// or send minimal avatar data in uncommon case of PALIsOpen.
|
||||||
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
||||||
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
||||||
|
if (overBudget) {
|
||||||
|
if (PALIsOpen) {
|
||||||
|
_stats.overBudgetAvatars++;
|
||||||
|
detail = AvatarData::PALMinimum;
|
||||||
|
} else {
|
||||||
|
_stats.overBudgetAvatars += remainingAvatars;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quint64 startAvatarDataPacking = usecTimestampNow();
|
auto startAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
++numOtherAvatars;
|
++numOtherAvatars;
|
||||||
|
|
||||||
|
@ -459,32 +439,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
nodeData->setLastBroadcastTime(otherNode->getUUID(), usecTimestampNow());
|
nodeData->setLastBroadcastTime(otherNode->getUUID(), usecTimestampNow());
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if avatar is in view which determines how much data to send
|
// Typically all out-of-view avatars but such avatars' priorities will rise with time:
|
||||||
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
bool isLowerPriority = sortedAvatar.getPriority() <= OUT_OF_VIEW_THRESHOLD;
|
||||||
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f * otherAvatar->getSensorToWorldScale();
|
|
||||||
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
|
||||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
|
||||||
|
|
||||||
// start a new segment in the PacketList for this avatar
|
if (isLowerPriority) {
|
||||||
avatarPacketList->startSegment();
|
|
||||||
|
|
||||||
AvatarData::AvatarDataDetail detail;
|
|
||||||
|
|
||||||
if (overBudget) {
|
|
||||||
overBudgetAvatars++;
|
|
||||||
_stats.overBudgetAvatars++;
|
|
||||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
|
||||||
} else if (!isInView) {
|
|
||||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData;
|
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData;
|
||||||
nodeData->incrementAvatarOutOfView();
|
nodeData->incrementAvatarOutOfView();
|
||||||
} else {
|
} else if (!overBudget) {
|
||||||
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO ? AvatarData::SendAllData : AvatarData::CullSmallData;
|
||||||
? AvatarData::SendAllData : AvatarData::CullSmallData;
|
|
||||||
nodeData->incrementAvatarInView();
|
nodeData->incrementAvatarInView();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool includeThisAvatar = true;
|
bool includeThisAvatar = true;
|
||||||
auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID());
|
|
||||||
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
||||||
|
|
||||||
lastSentJointsForOther.resize(otherAvatar->getJointCount());
|
lastSentJointsForOther.resize(otherAvatar->getJointCount());
|
||||||
|
@ -494,14 +460,14 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray
|
AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray
|
||||||
bool dropFaceTracking = false;
|
bool dropFaceTracking = false;
|
||||||
|
|
||||||
quint64 start = usecTimestampNow();
|
auto startSerialize = chrono::high_resolution_clock::now();
|
||||||
QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
||||||
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition,
|
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition,
|
||||||
&lastSentJointsForOther);
|
&lastSentJointsForOther);
|
||||||
quint64 end = usecTimestampNow();
|
auto endSerialize = chrono::high_resolution_clock::now();
|
||||||
_stats.toByteArrayElapsedTime += (end - start);
|
_stats.toByteArrayElapsedTime +=
|
||||||
|
(quint64) chrono::duration_cast<chrono::microseconds>(endSerialize - startSerialize).count();
|
||||||
|
|
||||||
static auto maxAvatarDataBytes = avatarPacketList->getMaxSegmentSize() - NUM_BYTES_RFC4122_UUID;
|
|
||||||
if (bytes.size() > maxAvatarDataBytes) {
|
if (bytes.size() > maxAvatarDataBytes) {
|
||||||
qCWarning(avatars) << "otherAvatar.toByteArray() for" << otherNode->getUUID()
|
qCWarning(avatars) << "otherAvatar.toByteArray() for" << otherNode->getUUID()
|
||||||
<< "resulted in very large buffer of" << bytes.size() << "bytes - dropping facial data";
|
<< "resulted in very large buffer of" << bytes.size() << "bytes - dropping facial data";
|
||||||
|
@ -527,8 +493,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeThisAvatar) {
|
if (includeThisAvatar) {
|
||||||
|
// start a new segment in the PacketList for this avatar
|
||||||
|
avatarPacketList->startSegment();
|
||||||
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
||||||
numAvatarDataBytes += avatarPacketList->write(bytes);
|
numAvatarDataBytes += avatarPacketList->write(bytes);
|
||||||
|
avatarPacketList->endSegment();
|
||||||
|
|
||||||
if (detail != AvatarData::NoData) {
|
if (detail != AvatarData::NoData) {
|
||||||
_stats.numOthersIncluded++;
|
_stats.numOthersIncluded++;
|
||||||
|
@ -546,15 +515,13 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
// It would be nice if we could tweak its future sort priority to put it at the back of the list.
|
// It would be nice if we could tweak its future sort priority to put it at the back of the list.
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarPacketList->endSegment();
|
auto endAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||||
|
_stats.avatarDataPackingElapsedTime +=
|
||||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
(quint64) chrono::duration_cast<chrono::microseconds>(endAvatarDataPacking - startAvatarDataPacking).count();
|
||||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
|
||||||
|
|
||||||
// use helper to add any changed traits to our packet list
|
// use helper to add any changed traits to our packet list
|
||||||
traitBytesSent += addChangedTraitsToBulkPacket(nodeData, otherNodeData, *traitsPacketList);
|
traitBytesSent += addChangedTraitsToBulkPacket(nodeData, otherNodeData, *traitsPacketList);
|
||||||
|
remainingAvatars--;
|
||||||
traitsPacketList->getDataSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 startPacketSending = usecTimestampNow();
|
quint64 startPacketSending = usecTimestampNow();
|
||||||
|
@ -566,7 +533,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
_stats.numBytesSent += numAvatarDataBytes;
|
_stats.numBytesSent += numAvatarDataBytes;
|
||||||
|
|
||||||
// send the avatar data PacketList
|
// send the avatar data PacketList
|
||||||
nodeList->sendPacketList(std::move(avatarPacketList), *node);
|
nodeList->sendPacketList(std::move(avatarPacketList), *destinationNode);
|
||||||
|
|
||||||
// record the bytes sent for other avatar data in the AvatarMixerClientData
|
// record the bytes sent for other avatar data in the AvatarMixerClientData
|
||||||
nodeData->recordSentAvatarData(numAvatarDataBytes);
|
nodeData->recordSentAvatarData(numAvatarDataBytes);
|
||||||
|
@ -576,7 +543,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
if (traitsPacketList->getNumPackets() >= 1) {
|
if (traitsPacketList->getNumPackets() >= 1) {
|
||||||
// send the traits packet list
|
// send the traits packet list
|
||||||
nodeList->sendPacketList(std::move(traitsPacketList), *node);
|
nodeList->sendPacketList(std::move(traitsPacketList), *destinationNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// record the number of avatars held back this frame
|
// record the number of avatars held back this frame
|
||||||
|
|
|
@ -145,3 +145,15 @@ void ScriptableAvatar::update(float deltatime) {
|
||||||
|
|
||||||
_clientTraitsHandler->sendChangedTraitsToMixer();
|
_clientTraitsHandler->sendChangedTraitsToMixer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptableAvatar::setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement) {
|
||||||
|
_headData->setHasProceduralBlinkFaceMovement(hasProceduralBlinkFaceMovement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptableAvatar::setHasProceduralEyeFaceMovement(bool hasProceduralEyeFaceMovement) {
|
||||||
|
_headData->setHasProceduralEyeFaceMovement(hasProceduralEyeFaceMovement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptableAvatar::setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement) {
|
||||||
|
_headData->setHasAudioEnabledFaceMovement(hasAudioEnabledFaceMovement);
|
||||||
|
}
|
||||||
|
|
|
@ -157,9 +157,16 @@ public:
|
||||||
|
|
||||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false) override;
|
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false) override;
|
||||||
|
|
||||||
|
void setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement);
|
||||||
|
bool getHasProceduralBlinkFaceMovement() const override { return _headData->getHasProceduralBlinkFaceMovement(); }
|
||||||
|
void setHasProceduralEyeFaceMovement(bool hasProceduralEyeFaceMovement);
|
||||||
|
bool getHasProceduralEyeFaceMovement() const override { return _headData->getHasProceduralEyeFaceMovement(); }
|
||||||
|
void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement);
|
||||||
|
bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void update(float deltatime);
|
void update(float deltatime);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AnimationPointer _animation;
|
AnimationPointer _animation;
|
||||||
AnimationDetails _animationDetails;
|
AnimationDetails _animationDetails;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
macro(AUTOSCRIBE_SHADER)
|
macro(AUTOSCRIBE_SHADER)
|
||||||
message(STATUS "Processing shader ${SHADER_FILE}")
|
|
||||||
unset(SHADER_INCLUDE_FILES)
|
unset(SHADER_INCLUDE_FILES)
|
||||||
# Grab include files
|
# Grab include files
|
||||||
foreach(includeFile ${ARGN})
|
foreach(includeFile ${ARGN})
|
||||||
|
|
|
@ -8,6 +8,5 @@
|
||||||
macro(TARGET_JSON)
|
macro(TARGET_JSON)
|
||||||
add_dependency_external_projects(json)
|
add_dependency_external_projects(json)
|
||||||
find_package(JSON REQUIRED)
|
find_package(JSON REQUIRED)
|
||||||
message("JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIRS}")
|
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${JSON_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} PUBLIC ${JSON_INCLUDE_DIRS})
|
||||||
endmacro()
|
endmacro()
|
|
@ -332,6 +332,10 @@ if (APPLE)
|
||||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||||
"${RESOURCES_DEV_DIR}/fonts"
|
"${RESOURCES_DEV_DIR}/fonts"
|
||||||
|
# add redirect json to macOS builds.
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||||
|
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||||
|
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
# call the fixup_interface macro to add required bundling commands for installation
|
# call the fixup_interface macro to add required bundling commands for installation
|
||||||
|
@ -360,6 +364,9 @@ else()
|
||||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||||
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
||||||
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||||
|
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||||
|
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||||
# copy JSDoc files beside the executable
|
# copy JSDoc files beside the executable
|
||||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||||
|
|
BIN
interface/resources/avatar/animations/jog_bwd.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_standing_launch.fbx
Normal file
BIN
interface/resources/avatar/animations/run_bwd.fbx
Normal file
|
@ -585,149 +585,188 @@
|
||||||
"states": [
|
"states": [
|
||||||
{
|
{
|
||||||
"id": "idle",
|
"id": "idle",
|
||||||
"interpTarget": 0,
|
"interpTarget": 20,
|
||||||
"interpDuration": 4,
|
"interpDuration": 8,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isMovingForward", "state": "idleToWalkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "idleToWalkFwd",
|
"id": "idleToWalkFwd",
|
||||||
"interpTarget": 10,
|
"interpTarget": 12,
|
||||||
"interpDuration": 4,
|
"interpDuration": 8,
|
||||||
"interpType": "snapshotPrev",
|
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "idleToWalkFwdOnDone", "state": "walkFwd" },
|
{ "var": "idleToWalkFwdOnDone", "state": "WALKFWD" },
|
||||||
{ "var": "isNotMoving", "state": "idle" },
|
{ "var": "isNotMoving", "state": "idle" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "idleSettle",
|
"id": "idleSettle",
|
||||||
"interpTarget": 10,
|
"interpTarget": 15,
|
||||||
"interpDuration": 10,
|
"interpDuration": 8,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{"var": "idleSettleOnDone", "state": "idle" },
|
{"var": "idleSettleOnDone", "state": "idle" },
|
||||||
{"var": "isMovingForward", "state": "idleToWalkFwd" },
|
{"var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" },
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" }
|
{ "var": "isInAirRun", "state": "INAIRRUN" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkFwd",
|
"id": "WALKFWD",
|
||||||
"interpTarget": 16,
|
"interpTarget": 35,
|
||||||
"interpDuration": 6,
|
"interpDuration": 10,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkBwd",
|
"id": "WALKBWD",
|
||||||
"interpTarget": 8,
|
"interpTarget": 35,
|
||||||
"interpDuration": 6,
|
"interpDuration": 10,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeRight",
|
"id": "STRAFERIGHT",
|
||||||
"interpTarget": 5,
|
"interpTarget": 25,
|
||||||
"interpDuration": 8,
|
"interpDuration": 8,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeLeft",
|
"id": "STRAFELEFT",
|
||||||
"interpTarget": 5,
|
"interpTarget": 25,
|
||||||
"interpDuration": 8,
|
"interpDuration": 8,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "turnRight",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 8,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "isNotTurning", "state": "idle" },
|
||||||
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
|
{ "var": "isFlying", "state": "fly" },
|
||||||
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "turnLeft",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 8,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "isNotTurning", "state": "idle" },
|
||||||
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
|
{ "var": "isFlying", "state": "fly" },
|
||||||
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
|
@ -739,18 +778,18 @@
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" },
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" }
|
{ "var": "isInAirRun", "state": "INAIRRUN" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -760,60 +799,18 @@
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" }
|
{ "var": "isInAirRun", "state": "INAIRRUN" }
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "turnRight",
|
|
||||||
"interpTarget": 6,
|
|
||||||
"interpDuration": 8,
|
|
||||||
"interpType": "snapshotPrev",
|
|
||||||
"transitions": [
|
|
||||||
{ "var": "isNotTurning", "state": "idle" },
|
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
|
||||||
{ "var": "isFlying", "state": "fly" },
|
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "turnLeft",
|
|
||||||
"interpTarget": 6,
|
|
||||||
"interpDuration": 8,
|
|
||||||
"interpType": "snapshotPrev",
|
|
||||||
"transitions": [
|
|
||||||
{ "var": "isNotTurning", "state": "idle" },
|
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
|
||||||
{ "var": "isFlying", "state": "fly" },
|
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -826,79 +823,79 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "takeoffStand",
|
"id": "takeoffStand",
|
||||||
"interpTarget": 0,
|
"interpTarget": 2,
|
||||||
"interpDuration": 6,
|
"interpDuration": 2,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotTakeoff", "state": "inAirStand" }
|
{ "var": "isNotTakeoff", "state": "inAirStand" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "takeoffRun",
|
"id": "TAKEOFFRUN",
|
||||||
"interpTarget": 0,
|
"interpTarget": 2,
|
||||||
"interpDuration": 6,
|
"interpDuration": 2,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotTakeoff", "state": "inAirRun" }
|
{ "var": "isNotTakeoff", "state": "INAIRRUN" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "inAirStand",
|
"id": "inAirStand",
|
||||||
"interpTarget": 0,
|
"interpTarget": 3,
|
||||||
"interpDuration": 6,
|
"interpDuration": 3,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotInAir", "state": "landStandImpact" }
|
{ "var": "isNotInAir", "state": "landStandImpact" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "inAirRun",
|
"id": "INAIRRUN",
|
||||||
"interpTarget": 0,
|
"interpTarget": 3,
|
||||||
"interpDuration": 6,
|
"interpDuration": 3,
|
||||||
"interpType": "snapshotPrev",
|
"interpType": "snapshotPrev",
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotInAir", "state": "landRun" }
|
{ "var": "isNotInAir", "state": "WALKFWD" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "landStandImpact",
|
"id": "landStandImpact",
|
||||||
"interpTarget": 6,
|
"interpTarget": 1,
|
||||||
"interpDuration": 4,
|
"interpDuration": 1,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "landStandImpactOnDone", "state": "landStand" }
|
{ "var": "landStandImpactOnDone", "state": "landStand" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "landStand",
|
"id": "landStand",
|
||||||
"interpTarget": 0,
|
"interpTarget": 1,
|
||||||
"interpDuration": 1,
|
"interpDuration": 1,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isMovingForward", "state": "idleToWalkFwd" },
|
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||||
{ "var": "isTurningRight", "state": "turnRight" },
|
{ "var": "isTurningRight", "state": "turnRight" },
|
||||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||||
{ "var": "landStandOnDone", "state": "idle" },
|
{ "var": "landStandOnDone", "state": "idle" },
|
||||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "landRun",
|
"id": "LANDRUN",
|
||||||
"interpTarget": 1,
|
"interpTarget": 2,
|
||||||
"interpDuration": 7,
|
"interpDuration": 2,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isFlying", "state": "fly" },
|
{ "var": "isFlying", "state": "fly" },
|
||||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||||
{ "var": "landRunOnDone", "state": "walkFwd" }
|
{ "var": "landRunOnDone", "state": "WALKFWD" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -913,7 +910,7 @@
|
||||||
{
|
{
|
||||||
"id": "idleStand",
|
"id": "idleStand",
|
||||||
"interpTarget": 6,
|
"interpTarget": 6,
|
||||||
"interpDuration": 6,
|
"interpDuration": 10,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isTalking", "state": "idleTalk" }
|
{ "var": "isTalking", "state": "idleTalk" }
|
||||||
]
|
]
|
||||||
|
@ -921,7 +918,7 @@
|
||||||
{
|
{
|
||||||
"id": "idleTalk",
|
"id": "idleTalk",
|
||||||
"interpTarget": 6,
|
"interpTarget": 6,
|
||||||
"interpDuration": 6,
|
"interpDuration": 10,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "notIsTalking", "state": "idleStand" }
|
{ "var": "notIsTalking", "state": "idleStand" }
|
||||||
]
|
]
|
||||||
|
@ -956,12 +953,12 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkFwd",
|
"id": "WALKFWD",
|
||||||
"type": "blendLinearMove",
|
"type": "blendLinearMove",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"desiredSpeed": 1.4,
|
"desiredSpeed": 1.4,
|
||||||
"characteristicSpeeds": [0.5, 1.5, 2.5, 3.2, 4.5],
|
"characteristicSpeeds": [0.5, 1.8, 2.3, 3.2, 4.5],
|
||||||
"alphaVar": "moveForwardAlpha",
|
"alphaVar": "moveForwardAlpha",
|
||||||
"desiredSpeedVar": "moveForwardSpeed"
|
"desiredSpeedVar": "moveForwardSpeed"
|
||||||
},
|
},
|
||||||
|
@ -984,7 +981,7 @@
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/walk_fwd.fbx",
|
"url": "qrc:///avatar/animations/walk_fwd.fbx",
|
||||||
"startFrame": 0.0,
|
"startFrame": 0.0,
|
||||||
"endFrame": 35.0,
|
"endFrame": 30.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": true
|
"loopFlag": true
|
||||||
},
|
},
|
||||||
|
@ -1046,25 +1043,25 @@
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/settle_to_idle.fbx",
|
"url": "qrc:///avatar/animations/settle_to_idle.fbx",
|
||||||
"startFrame": 1.0,
|
"startFrame": 1.0,
|
||||||
"endFrame": 48.0,
|
"endFrame": 59.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkBwd",
|
"id": "WALKBWD",
|
||||||
"type": "blendLinearMove",
|
"type": "blendLinearMove",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"desiredSpeed": 1.4,
|
"desiredSpeed": 1.4,
|
||||||
"characteristicSpeeds": [0.6, 1.7],
|
"characteristicSpeeds": [0.6, 1.6, 2.3, 3.1],
|
||||||
"alphaVar": "moveBackwardAlpha",
|
"alphaVar": "moveBackwardAlpha",
|
||||||
"desiredSpeedVar": "moveBackwardSpeed"
|
"desiredSpeedVar": "moveBackwardSpeed"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "walkBwdShort",
|
"id": "walkBwdShort_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/walk_short_bwd.fbx",
|
"url": "qrc:///avatar/animations/walk_short_bwd.fbx",
|
||||||
|
@ -1076,7 +1073,7 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkBwdNormal",
|
"id": "walkBwdFast_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/walk_bwd_fast.fbx",
|
"url": "qrc:///avatar/animations/walk_bwd_fast.fbx",
|
||||||
|
@ -1086,6 +1083,30 @@
|
||||||
"loopFlag": true
|
"loopFlag": true
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jogBwd_c",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "qrc:///avatar/animations/jog_bwd.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 24.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "runBwd_c",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "qrc:///avatar/animations/run_bwd.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 16.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1115,18 +1136,18 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeLeft",
|
"id": "STRAFELEFT",
|
||||||
"type": "blendLinearMove",
|
"type": "blendLinearMove",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"desiredSpeed": 1.4,
|
"desiredSpeed": 1.4,
|
||||||
"characteristicSpeeds": [0, 0.5, 1.5, 2.6, 3.0],
|
"characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0],
|
||||||
"alphaVar": "moveLateralAlpha",
|
"alphaVar": "moveLateralAlpha",
|
||||||
"desiredSpeedVar": "moveLateralSpeed"
|
"desiredSpeedVar": "moveLateralSpeed"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "strafeLeftShort_c",
|
"id": "strafeLeftShortStep_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/side_step_short_left.fbx",
|
"url": "qrc:///avatar/animations/side_step_short_left.fbx",
|
||||||
|
@ -1138,7 +1159,7 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeLeft_c",
|
"id": "strafeLeftStep_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/side_step_left.fbx",
|
"url": "qrc:///avatar/animations/side_step_left.fbx",
|
||||||
|
@ -1150,19 +1171,19 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeLeftAnim_c",
|
"id": "strafeLeftWalk_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/walk_left.fbx",
|
"url": "qrc:///avatar/animations/walk_left.fbx",
|
||||||
"startFrame": 0.0,
|
"startFrame": 0.0,
|
||||||
"endFrame": 33.0,
|
"endFrame": 35.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": true
|
"loopFlag": true
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeLeftFast_c",
|
"id": "strafeLeftWalkFast_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/walk_left_fast.fbx",
|
"url": "qrc:///avatar/animations/walk_left_fast.fbx",
|
||||||
|
@ -1188,17 +1209,17 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeRight",
|
"id": "STRAFERIGHT",
|
||||||
"type": "blendLinearMove",
|
"type": "blendLinearMove",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"desiredSpeed": 1.4,
|
"desiredSpeed": 1.4,
|
||||||
"characteristicSpeeds": [0, 0.5, 1.5, 2.6, 3.0],
|
"characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0],
|
||||||
"alphaVar": "moveLateralAlpha",
|
"alphaVar": "moveLateralAlpha",
|
||||||
"desiredSpeedVar": "moveLateralSpeed"
|
"desiredSpeedVar": "moveLateralSpeed"
|
||||||
},
|
},
|
||||||
"children": [ {
|
"children": [ {
|
||||||
"id": "stepRightShort_c",
|
"id": "strafeRightShortStep_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/side_step_short_left.fbx",
|
"url": "qrc:///avatar/animations/side_step_short_left.fbx",
|
||||||
|
@ -1211,7 +1232,7 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "stepRight_c",
|
"id": "strafeRightStep_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/side_step_left.fbx",
|
"url": "qrc:///avatar/animations/side_step_left.fbx",
|
||||||
|
@ -1224,12 +1245,12 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeRight_c",
|
"id": "strafeRightWalk_c",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/walk_left.fbx",
|
"url": "qrc:///avatar/animations/walk_left.fbx",
|
||||||
"startFrame": 0.0,
|
"startFrame": 0.0,
|
||||||
"endFrame": 33.0,
|
"endFrame": 35.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": true,
|
"loopFlag": true,
|
||||||
"mirrorFlag": true
|
"mirrorFlag": true
|
||||||
|
@ -1381,22 +1402,22 @@
|
||||||
"id": "takeoffStand",
|
"id": "takeoffStand",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_standing_takeoff.fbx",
|
"url": "qrc:///avatar/animations/jump_standing_launch.fbx",
|
||||||
"startFrame": 17.0,
|
"startFrame": 2.0,
|
||||||
"endFrame": 25.0,
|
"endFrame": 16.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "takeoffRun",
|
"id": "TAKEOFFRUN",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_takeoff.fbx",
|
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||||
"startFrame": 1.0,
|
"startFrame": 4.0,
|
||||||
"endFrame": 2.5,
|
"endFrame": 15.0,
|
||||||
"timeScale": 0.01,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
@ -1416,7 +1437,7 @@
|
||||||
"url": "qrc:///avatar/animations/jump_standing_apex.fbx",
|
"url": "qrc:///avatar/animations/jump_standing_apex.fbx",
|
||||||
"startFrame": 0.0,
|
"startFrame": 0.0,
|
||||||
"endFrame": 0.0,
|
"endFrame": 0.0,
|
||||||
"timeScale": 0.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
@ -1448,7 +1469,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "inAirRun",
|
"id": "INAIRRUN",
|
||||||
"type": "blendLinear",
|
"type": "blendLinear",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
|
@ -1459,10 +1480,10 @@
|
||||||
"id": "inAirRunPreApex",
|
"id": "inAirRunPreApex",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_in_air.fbx",
|
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||||
"startFrame": 0.0,
|
"startFrame": 16.0,
|
||||||
"endFrame": 0.0,
|
"endFrame": 16.0,
|
||||||
"timeScale": 0.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
@ -1471,9 +1492,9 @@
|
||||||
"id": "inAirRunApex",
|
"id": "inAirRunApex",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_in_air.fbx",
|
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||||
"startFrame": 6.0,
|
"startFrame": 22.0,
|
||||||
"endFrame": 6.0,
|
"endFrame": 22.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
|
@ -1483,9 +1504,9 @@
|
||||||
"id": "inAirRunPostApex",
|
"id": "inAirRunPostApex",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_in_air.fbx",
|
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||||
"startFrame": 11.0,
|
"startFrame": 33.0,
|
||||||
"endFrame": 11.0,
|
"endFrame": 33.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
|
@ -1497,7 +1518,7 @@
|
||||||
"id": "landStandImpact",
|
"id": "landStandImpact",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_standing_land.fbx",
|
"url": "qrc:///avatar/animations/jump_standing_land_settle.fbx",
|
||||||
"startFrame": 1.0,
|
"startFrame": 1.0,
|
||||||
"endFrame": 6.0,
|
"endFrame": 6.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
|
@ -1509,22 +1530,22 @@
|
||||||
"id": "landStand",
|
"id": "landStand",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_standing_land.fbx",
|
"url": "qrc:///avatar/animations/jump_standing_land_settle.fbx",
|
||||||
"startFrame": 6.0,
|
"startFrame": 6.0,
|
||||||
"endFrame": 28.0,
|
"endFrame": 68.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "landRun",
|
"id": "LANDRUN",
|
||||||
"type": "clip",
|
"type": "clip",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "qrc:///avatar/animations/jump_land.fbx",
|
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||||
"startFrame": 1.0,
|
"startFrame": 29.0,
|
||||||
"endFrame": 6.0,
|
"endFrame": 40.0,
|
||||||
"timeScale": 0.65,
|
"timeScale": 1.0,
|
||||||
"loopFlag": false
|
"loopFlag": false
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
|
83
interface/resources/icons/tablet-icons/people-a-msg.svg
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 50 50"
|
||||||
|
style="enable-background:new 0 0 50 50;"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg2"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="people-a.svg"><metadata
|
||||||
|
id="metadata24"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs22" /><sodipodi:namedview
|
||||||
|
pagecolor="#ff0000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="852"
|
||||||
|
inkscape:window-height="480"
|
||||||
|
id="namedview20"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.72"
|
||||||
|
inkscape:cx="25"
|
||||||
|
inkscape:cy="25"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg2" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style4">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
.st1{fill:#EF3B4E;}
|
||||||
|
</style>
|
||||||
|
<circle class="st1" cx="44.1" cy="6" r="5.6"/>
|
||||||
|
<g
|
||||||
|
id="Layer_2" /><g
|
||||||
|
id="Layer_1"
|
||||||
|
style="fill:#000000;fill-opacity:1"><circle
|
||||||
|
class="st0"
|
||||||
|
cx="25.6"
|
||||||
|
cy="14.8"
|
||||||
|
r="8.1"
|
||||||
|
id="circle8"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><path
|
||||||
|
class="st0"
|
||||||
|
d="M31.4,27h-11c-4.6,0-8.2,3.9-8.2,8.5v4.3c3.8,2.8,8.1,4.5,13.1,4.5c5.6,0,10.6-2.1,14.4-5.6v-3.2 C39.6,30.9,35.9,27,31.4,27z"
|
||||||
|
id="path10"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><circle
|
||||||
|
class="st0"
|
||||||
|
cx="41.6"
|
||||||
|
cy="17.1"
|
||||||
|
r="3.5"
|
||||||
|
id="circle12"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><path
|
||||||
|
class="st0"
|
||||||
|
d="M43.9,23.9h-4.1c-0.9,0-1.7,0.4-2.3,1c1.2,0.6,2.3,1.6,3.1,2.5c1,1.2,1.5,2.7,1.7,4.3c0.3,0.9,0.4,1.8,0.2,2.8 v0.6c1.6-2.2,3.3-6,4-8.1v-0.3C46.5,25.7,45.3,23.9,43.9,23.9z"
|
||||||
|
id="path14"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><circle
|
||||||
|
class="st0"
|
||||||
|
cx="9.4"
|
||||||
|
cy="18"
|
||||||
|
r="3.5"
|
||||||
|
id="circle16"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><path
|
||||||
|
class="st0"
|
||||||
|
d="M8.5,35.7c-0.1-0.7-0.1-1.4,0-2.1l0.1-0.2c0-0.2,0-0.4,0-0.6c0-0.2,0-0.3,0.1-0.5c0-0.2,0-0.3,0-0.5 c0.2-2.1,1.6-4.4,3.2-5.7c0.4-0.4,0.9-0.6,1.4-0.9c-0.5-0.5-1.3-0.7-2-0.7H7c-1.4,0-2.6,1.8-2.4,2.7v0.3 C5.1,29.8,6.8,33.5,8.5,35.7z"
|
||||||
|
id="path18"
|
||||||
|
style="fill:#000000;fill-opacity:1" /></g></svg>
|
After Width: | Height: | Size: 2.9 KiB |
24
interface/resources/icons/tablet-icons/people-i-msg.svg
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
.st1{fill:#EF3B4E;}
|
||||||
|
</style>
|
||||||
|
<circle class="st1" cx="44.1" cy="6" r="5.6"/>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<g id="Layer_1">
|
||||||
|
<circle class="st0" cx="25.6" cy="14.8" r="8.1"/>
|
||||||
|
<path class="st0" d="M31.4,27h-11c-4.6,0-8.2,3.9-8.2,8.5v4.3c3.8,2.8,8.1,4.5,13.1,4.5c5.6,0,10.6-2.1,14.4-5.6v-3.2
|
||||||
|
C39.6,30.9,35.9,27,31.4,27z"/>
|
||||||
|
<circle class="st0" cx="41.6" cy="17.1" r="3.5"/>
|
||||||
|
<path class="st0" d="M43.9,23.9h-4.1c-0.9,0-1.7,0.4-2.3,1c1.2,0.6,2.3,1.6,3.1,2.5c1,1.2,1.5,2.7,1.7,4.3c0.3,0.9,0.4,1.8,0.2,2.8
|
||||||
|
v0.6c1.6-2.2,3.3-6,4-8.1v-0.3C46.5,25.7,45.3,23.9,43.9,23.9z"/>
|
||||||
|
<circle class="st0" cx="9.4" cy="18" r="3.5"/>
|
||||||
|
<path class="st0" d="M8.5,35.7c-0.1-0.7-0.1-1.4,0-2.1l0.1-0.2c0-0.2,0-0.4,0-0.6c0-0.2,0-0.3,0.1-0.5c0-0.2,0-0.3,0-0.5
|
||||||
|
c0.2-2.1,1.6-4.4,3.2-5.7c0.4-0.4,0.9-0.6,1.4-0.9c-0.5-0.5-1.3-0.7-2-0.7H7c-1.4,0-2.6,1.8-2.4,2.7v0.3
|
||||||
|
C5.1,29.8,6.8,33.5,8.5,35.7z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
5
interface/resources/images/eyeClosed.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="31" height="23" viewBox="0 0 31 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.59534 11.0156C6.16042 13.4128 9.65987 15.5898 13.6042 16.1774C17.686 16.7856 22.4164 15.7196 27.3057 11.0659C22.0721 6.07309 17.0642 5.14115 12.9153 5.90073C8.99427 6.61859 5.69298 8.87688 3.59534 11.0156ZM12.455 3.27591C17.7727 2.30235 23.9836 3.74895 30.1053 10.1333L31 11.0664L30.1053 11.9994C24.3636 17.9875 18.4774 19.5983 13.2276 18.8161C8.06048 18.0463 3.70384 14.9892 0.837069 11.9994L0 11.1265L0.778477 10.1986C3.05338 7.48717 7.2318 4.23217 12.455 3.27591Z" fill="#3D3D3D"/>
|
||||||
|
<ellipse cx="15.6539" cy="10.9218" rx="3.65386" ry="3.81061" fill="#3D3D3D"/>
|
||||||
|
<line x1="25" y1="2.12132" x2="7.12132" y2="20" stroke="#3D3D3D" stroke-width="3" stroke-linecap="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 825 B |
4
interface/resources/images/eyeOpen.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="31" height="16" viewBox="0 0 31 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.59534 8.01564C6.16042 10.4128 9.65987 12.5898 13.6042 13.1774C17.686 13.7856 22.4164 12.7196 27.3057 8.06585C22.0721 3.07309 17.0642 2.14115 12.9153 2.90073C8.99427 3.61859 5.69298 5.87688 3.59534 8.01564ZM12.455 0.275915C17.7727 -0.697651 23.9836 0.748949 30.1053 7.13329L31 8.06636L30.1053 8.99944C24.3636 14.9875 18.4774 16.5983 13.2276 15.8161C8.06048 15.0463 3.70384 11.9892 0.837069 8.99944L0 8.12646L0.778477 7.1986C3.05338 4.48717 7.2318 1.23217 12.455 0.275915Z" fill="#3D3D3D"/>
|
||||||
|
<ellipse cx="15.644" cy="7.92179" rx="3.65386" ry="3.81061" fill="#3D3D3D"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 721 B |
BIN
interface/resources/images/interstitialPage/goTo_button.png
Normal file
After Width: | Height: | Size: 9 KiB |
BIN
interface/resources/images/loadingBar_placard.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
interface/resources/images/loadingBar_progress.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_auth.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_auth.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_timeout.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_timeout.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_vague.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_vague.png
Normal file
After Width: | Height: | Size: 5 KiB |
|
@ -23,6 +23,7 @@ ModalWindow {
|
||||||
objectName: "LoginDialog"
|
objectName: "LoginDialog"
|
||||||
implicitWidth: 520
|
implicitWidth: 520
|
||||||
implicitHeight: 320
|
implicitHeight: 320
|
||||||
|
closeButtonVisible: true
|
||||||
destroyOnCloseButton: true
|
destroyOnCloseButton: true
|
||||||
destroyOnHidden: true
|
destroyOnHidden: true
|
||||||
visible: true
|
visible: true
|
||||||
|
|
|
@ -117,27 +117,27 @@ Item {
|
||||||
}
|
}
|
||||||
spacing: hifi.dimensions.contentSpacing.y / 2
|
spacing: hifi.dimensions.contentSpacing.y / 2
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: usernameField
|
id: usernameField
|
||||||
anchors {
|
anchors {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
|
||||||
width: 1080
|
|
||||||
placeholderText: qsTr("Username or Email")
|
|
||||||
}
|
}
|
||||||
|
width: 1080
|
||||||
|
placeholderText: qsTr("Username or Email")
|
||||||
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: passwordField
|
id: passwordField
|
||||||
anchors {
|
anchors {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
|
||||||
width: 1080
|
|
||||||
|
|
||||||
placeholderText: qsTr("Password")
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
|
|
||||||
Keys.onReturnPressed: linkAccountBody.login()
|
|
||||||
}
|
}
|
||||||
|
width: 1080
|
||||||
|
|
||||||
|
placeholderText: qsTr("Password")
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
|
||||||
|
Keys.onReturnPressed: linkAccountBody.login()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoItem {
|
InfoItem {
|
||||||
|
@ -176,7 +176,7 @@ Item {
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
top: form.bottom
|
top: form.bottom
|
||||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
|
@ -201,7 +201,7 @@ Item {
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
top: form.bottom
|
top: form.bottom
|
||||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||||
}
|
}
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
|
|
@ -15,7 +15,6 @@ import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||||
|
|
||||||
import "../controls-uit"
|
import "../controls-uit"
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: linkAccountBody
|
id: linkAccountBody
|
||||||
clip: true
|
clip: true
|
||||||
|
@ -87,6 +86,23 @@ Item {
|
||||||
height: 48
|
height: 48
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShortcutText {
|
||||||
|
id: flavorText
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
margins: 0
|
||||||
|
topMargin: hifi.dimensions.contentSpacing.y
|
||||||
|
}
|
||||||
|
|
||||||
|
text: qsTr("Sign in to High Fidelity to make friends, get HFC, and buy interesting things on the Marketplace!")
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
lineHeight: 1
|
||||||
|
lineHeightMode: Text.ProportionalHeight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
id: mainTextContainer
|
id: mainTextContainer
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -97,7 +113,6 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
text: qsTr("Username or password incorrect.")
|
text: qsTr("Username or password incorrect.")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
color: hifi.colors.redAccent
|
color: hifi.colors.redAccent
|
||||||
|
@ -117,22 +132,21 @@ Item {
|
||||||
}
|
}
|
||||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||||
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: usernameField
|
id: usernameField
|
||||||
text: Settings.getValue("wallet/savedUsername", "");
|
text: Settings.getValue("wallet/savedUsername", "");
|
||||||
width: parent.width
|
width: parent.width
|
||||||
focus: true
|
focus: true
|
||||||
label: "Username or Email"
|
placeholderText: "Username or Email"
|
||||||
activeFocusOnPress: true
|
activeFocusOnPress: true
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
z: 10
|
z: 10
|
||||||
|
y: usernameField.height
|
||||||
anchors {
|
anchors {
|
||||||
left: usernameField.left
|
right: usernameField.right
|
||||||
top: usernameField.top
|
top: usernameField.bottom
|
||||||
leftMargin: usernameField.textFieldLabel.contentWidth + 10
|
topMargin: 4
|
||||||
topMargin: -19
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||||
|
@ -143,26 +157,32 @@ Item {
|
||||||
|
|
||||||
onLinkActivated: loginDialog.openUrl(link)
|
onLinkActivated: loginDialog.openUrl(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocusChanged: {
|
onFocusChanged: {
|
||||||
root.text = "";
|
root.text = "";
|
||||||
}
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
var savedUsername = Settings.getValue("wallet/savedUsername", "");
|
||||||
|
usernameField.text = savedUsername === "Unknown user" ? "" : savedUsername;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: passwordField
|
id: passwordField
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
placeholderText: "Password"
|
||||||
label: "Password"
|
|
||||||
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
|
|
||||||
activeFocusOnPress: true
|
activeFocusOnPress: true
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
|
id: forgotPasswordShortcut
|
||||||
|
y: passwordField.height
|
||||||
z: 10
|
z: 10
|
||||||
anchors {
|
anchors {
|
||||||
left: passwordField.left
|
right: passwordField.right
|
||||||
top: passwordField.top
|
top: passwordField.bottom
|
||||||
leftMargin: passwordField.textFieldLabel.contentWidth + 10
|
topMargin: 4
|
||||||
topMargin: -19
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||||
|
@ -179,12 +199,45 @@ Item {
|
||||||
root.isPassword = true;
|
root.isPassword = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onReturnPressed: linkAccountBody.login()
|
Rectangle {
|
||||||
}
|
id: showPasswordHitbox
|
||||||
|
z: 10
|
||||||
|
x: passwordField.width - ((passwordField.height) * 31 / 23)
|
||||||
|
width: parent.width - (parent.width - (parent.height * 31/16))
|
||||||
|
height: parent.height
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
CheckBox {
|
Image {
|
||||||
id: showPassword
|
id: showPasswordImage
|
||||||
text: "Show password"
|
y: (passwordField.height - (passwordField.height * 16 / 23)) / 2
|
||||||
|
width: passwordField.width - (passwordField.width - (((passwordField.height) * 31/23)))
|
||||||
|
height: passwordField.height * 16 / 23
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: 3
|
||||||
|
}
|
||||||
|
source: "../../images/eyeOpen.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: passwordFieldMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
property bool showPassword: false
|
||||||
|
onClicked: {
|
||||||
|
showPassword = !showPassword;
|
||||||
|
passwordField.echoMode = showPassword ? TextInput.Normal : TextInput.Password;
|
||||||
|
showPasswordImage.source = showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg";
|
||||||
|
showPasswordImage.height = showPassword ? passwordField.height : passwordField.height * 16 / 23;
|
||||||
|
showPasswordImage.y = showPassword ? 0 : (passwordField.height - showPasswordImage.height) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: linkAccountBody.login()
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoItem {
|
InfoItem {
|
||||||
|
@ -206,6 +259,26 @@ Item {
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: autoLogoutCheckbox
|
||||||
|
checked: !Settings.getValue("wallet/autoLogout", true)
|
||||||
|
text: "Keep me signed in"
|
||||||
|
boxSize: 20;
|
||||||
|
labelFontSize: 15
|
||||||
|
color: hifi.colors.black
|
||||||
|
onCheckedChanged: {
|
||||||
|
Settings.setValue("wallet/autoLogout", !checked);
|
||||||
|
if (checked) {
|
||||||
|
Settings.setValue("wallet/savedUsername", Account.username);
|
||||||
|
} else {
|
||||||
|
Settings.setValue("wallet/savedUsername", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.onDestruction: {
|
||||||
|
Settings.setValue("wallet/autoLogout", !checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: linkAccountButton
|
id: linkAccountButton
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
@ -216,12 +289,6 @@ Item {
|
||||||
|
|
||||||
onClicked: linkAccountBody.login()
|
onClicked: linkAccountBody.login()
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
onClicked: root.tryDestroy()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
@ -234,7 +301,7 @@ Item {
|
||||||
RalewaySemiBold {
|
RalewaySemiBold {
|
||||||
size: hifi.fontSizes.inputLabel
|
size: hifi.fontSizes.inputLabel
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: qsTr("Don't have an account?")
|
text: qsTr("New to High Fidelity?")
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -279,7 +346,15 @@ Item {
|
||||||
target: loginDialog
|
target: loginDialog
|
||||||
onHandleLoginCompleted: {
|
onHandleLoginCompleted: {
|
||||||
console.log("Login Succeeded, linking steam account")
|
console.log("Login Succeeded, linking steam account")
|
||||||
|
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
|
||||||
|
if (poppedUp) {
|
||||||
|
console.log("[ENCOURAGELOGINDIALOG]: logging in")
|
||||||
|
var data = {
|
||||||
|
"action": "user logged in"
|
||||||
|
};
|
||||||
|
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||||
|
Settings.setValue("loginDialogPoppedUp", false);
|
||||||
|
}
|
||||||
if (loginDialog.isSteamRunning()) {
|
if (loginDialog.isSteamRunning()) {
|
||||||
loginDialog.linkSteam()
|
loginDialog.linkSteam()
|
||||||
} else {
|
} else {
|
||||||
|
@ -290,6 +365,15 @@ Item {
|
||||||
}
|
}
|
||||||
onHandleLoginFailed: {
|
onHandleLoginFailed: {
|
||||||
console.log("Login Failed")
|
console.log("Login Failed")
|
||||||
|
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
|
||||||
|
if (poppedUp) {
|
||||||
|
console.log("[ENCOURAGELOGINDIALOG]: failed logging in")
|
||||||
|
var data = {
|
||||||
|
"action": "user failed logging in"
|
||||||
|
};
|
||||||
|
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||||
|
Settings.setValue("loginDialogPoppedUp", false);
|
||||||
|
}
|
||||||
mainTextContainer.visible = true
|
mainTextContainer.visible = true
|
||||||
toggleLoading(false)
|
toggleLoading(false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property var jointNames;
|
property var jointNames: []
|
||||||
property var currentAvatarSettings;
|
property var currentAvatarSettings;
|
||||||
|
|
||||||
function fetchAvatarModelName(marketId, avatar) {
|
function fetchAvatarModelName(marketId, avatar) {
|
||||||
|
@ -175,7 +175,14 @@ Rectangle {
|
||||||
displayNameInput.text = getAvatarsData.displayName;
|
displayNameInput.text = getAvatarsData.displayName;
|
||||||
currentAvatarSettings = getAvatarsData.currentAvatarSettings;
|
currentAvatarSettings = getAvatarsData.currentAvatarSettings;
|
||||||
|
|
||||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
var bookmarkAvatarIndex = allAvatars.findAvatarIndexByValue(currentAvatar);
|
||||||
|
if (bookmarkAvatarIndex === -1) {
|
||||||
|
currentAvatar.name = '';
|
||||||
|
} else {
|
||||||
|
currentAvatar.name = allAvatars.get(bookmarkAvatarIndex).name;
|
||||||
|
allAvatars.move(bookmarkAvatarIndex, 0, 1);
|
||||||
|
}
|
||||||
|
view.setPage(0);
|
||||||
} else if (message.method === 'updateAvatarInBookmarks') {
|
} else if (message.method === 'updateAvatarInBookmarks') {
|
||||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||||
} else if (message.method === 'selectAvatarEntity') {
|
} else if (message.method === 'selectAvatarEntity') {
|
||||||
|
|
|
@ -271,6 +271,8 @@ Rectangle {
|
||||||
connectionsUserModel.getFirstPage();
|
connectionsUserModel.getFirstPage();
|
||||||
}
|
}
|
||||||
activeTab = "connectionsTab";
|
activeTab = "connectionsTab";
|
||||||
|
connectionsOnlineDot.visible = false;
|
||||||
|
pal.sendToScript({method: 'hideNotificationDot'});
|
||||||
connectionsHelpText.color = hifi.colors.blueAccent;
|
connectionsHelpText.color = hifi.colors.blueAccent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,6 +300,16 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: connectionsOnlineDot;
|
||||||
|
visible: false;
|
||||||
|
width: 10;
|
||||||
|
height: width;
|
||||||
|
radius: width;
|
||||||
|
color: "#EF3B4E"
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
}
|
||||||
// "CONNECTIONS" text
|
// "CONNECTIONS" text
|
||||||
RalewaySemiBold {
|
RalewaySemiBold {
|
||||||
id: connectionsTabSelectorText;
|
id: connectionsTabSelectorText;
|
||||||
|
@ -305,7 +317,11 @@ Rectangle {
|
||||||
// Text size
|
// Text size
|
||||||
size: hifi.fontSizes.tabularData;
|
size: hifi.fontSizes.tabularData;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.fill: parent;
|
anchors.left: connectionsOnlineDot.visible ? connectionsOnlineDot.right : parent.left;
|
||||||
|
anchors.leftMargin: connectionsOnlineDot.visible ? 4 : 0;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
anchors.right: parent.right;
|
||||||
// Style
|
// Style
|
||||||
font.capitalization: Font.AllUppercase;
|
font.capitalization: Font.AllUppercase;
|
||||||
color: activeTab === "connectionsTab" ? hifi.colors.blueAccent : hifi.colors.baseGray;
|
color: activeTab === "connectionsTab" ? hifi.colors.blueAccent : hifi.colors.baseGray;
|
||||||
|
@ -326,7 +342,7 @@ Rectangle {
|
||||||
anchors.left: connectionsTabSelectorTextContainer.left;
|
anchors.left: connectionsTabSelectorTextContainer.left;
|
||||||
anchors.top: connectionsTabSelectorTextContainer.top;
|
anchors.top: connectionsTabSelectorTextContainer.top;
|
||||||
anchors.topMargin: 1;
|
anchors.topMargin: 1;
|
||||||
anchors.leftMargin: connectionsTabSelectorTextMetrics.width + 42;
|
anchors.leftMargin: connectionsTabSelectorTextMetrics.width + 42 + connectionsOnlineDot.width + connectionsTabSelectorText.anchors.leftMargin;
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: connectionsHelpText;
|
id: connectionsHelpText;
|
||||||
text: "[?]";
|
text: "[?]";
|
||||||
|
@ -1267,6 +1283,9 @@ Rectangle {
|
||||||
case 'http.response':
|
case 'http.response':
|
||||||
http.handleHttpResponse(message);
|
http.handleHttpResponse(message);
|
||||||
break;
|
break;
|
||||||
|
case 'changeConnectionsDotStatus':
|
||||||
|
connectionsOnlineDot.visible = message.shouldShowDot;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('Unrecognized message:', JSON.stringify(message));
|
console.log('Unrecognized message:', JSON.stringify(message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ Rectangle {
|
||||||
HifiConstants { id: hifi; }
|
HifiConstants { id: hifi; }
|
||||||
|
|
||||||
property var eventBridge;
|
property var eventBridge;
|
||||||
property string title: "Audio Settings - " + AudioScriptingInterface.context;
|
property string title: "Audio Settings"
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
color: hifi.colors.baseGray;
|
color: hifi.colors.baseGray;
|
||||||
|
|
|
@ -25,7 +25,17 @@ Rectangle {
|
||||||
modified = false;
|
modified = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
property var jointNames;
|
property var jointNames: []
|
||||||
|
onJointNamesChanged: {
|
||||||
|
jointsModel.clear();
|
||||||
|
for (var i = 0; i < jointNames.length; ++i) {
|
||||||
|
var jointName = jointNames[i];
|
||||||
|
if (jointName !== 'LeftHand' && jointName !== 'RightHand') {
|
||||||
|
jointsModel.append({'text' : jointName, 'jointIndex' : i});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property string avatarName: ''
|
property string avatarName: ''
|
||||||
property var wearablesModel;
|
property var wearablesModel;
|
||||||
|
|
||||||
|
@ -268,20 +278,30 @@ Rectangle {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
enabled: getCurrentWearable() !== null && !isSoft.checked
|
enabled: getCurrentWearable() !== null && !isSoft.checked
|
||||||
comboBox.displayText: isSoft.checked ? 'Hips' : comboBox.currentText
|
comboBox.displayText: isSoft.checked ? 'Hips' : comboBox.currentText
|
||||||
|
comboBox.textRole: "text"
|
||||||
|
|
||||||
model: jointNames
|
model: ListModel {
|
||||||
|
id: jointsModel
|
||||||
|
}
|
||||||
property bool notify: false
|
property bool notify: false
|
||||||
|
|
||||||
function set(jointIndex) {
|
function set(jointIndex) {
|
||||||
notify = false;
|
notify = false;
|
||||||
currentIndex = jointIndex;
|
for (var i = 0; i < jointsModel.count; ++i) {
|
||||||
|
if (jointsModel.get(i).jointIndex === jointIndex) {
|
||||||
|
currentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
notify = true;
|
notify = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function notifyJointChanged() {
|
function notifyJointChanged() {
|
||||||
modified = true;
|
modified = true;
|
||||||
|
var jointIndex = jointsModel.get(jointsCombobox.currentIndex).jointIndex;
|
||||||
|
|
||||||
var properties = {
|
var properties = {
|
||||||
parentJointIndex: currentIndex,
|
parentJointIndex: jointIndex,
|
||||||
localPosition: {
|
localPosition: {
|
||||||
x: positionVector.xvalue,
|
x: positionVector.xvalue,
|
||||||
y: positionVector.yvalue,
|
y: positionVector.yvalue,
|
||||||
|
@ -294,7 +314,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
wearableUpdated(getCurrentWearable().id, wearablesCombobox.currentIndex, properties);
|
wearableUpdated(getCurrentWearable().id, jointIndex, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
|
|
|
@ -408,9 +408,7 @@ Rectangle {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToWallet: {
|
onSendSignalToWallet: {
|
||||||
if (msg.method === 'walletReset' || msg.method === 'passphraseReset') {
|
if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||||
sendToScript(msg);
|
|
||||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
|
||||||
securityImageChange.initModel();
|
securityImageChange.initModel();
|
||||||
root.activeView = "securityImageChange";
|
root.activeView = "securityImageChange";
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import "../../windows"
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
objectName: "DCConectionTiming"
|
objectName: "DCConectionTiming"
|
||||||
|
property string title: "Domain Connection Timing"
|
||||||
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
@ -33,7 +34,7 @@ Rectangle {
|
||||||
Row {
|
Row {
|
||||||
id: header
|
id: header
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: hifi.dimensions.tabletMenuHeader
|
anchors.topMargin: hifi.dimensions.contentMargin.y
|
||||||
anchors.leftMargin: 5
|
anchors.leftMargin: 5
|
||||||
anchors.rightMargin: 5
|
anchors.rightMargin: 5
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
|
@ -18,6 +18,7 @@ import "../../windows"
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
objectName: "EntityStatistics"
|
objectName: "EntityStatistics"
|
||||||
|
property string title: "Entity Statistics"
|
||||||
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
@ -40,6 +41,7 @@ Rectangle {
|
||||||
id: scrollView
|
id: scrollView
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: hifi.dimensions.contentMargin.y
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: hifi.dimensions.tabletMenuHeader
|
anchors.bottomMargin: hifi.dimensions.tabletMenuHeader
|
||||||
contentWidth: column.implicitWidth
|
contentWidth: column.implicitWidth
|
||||||
|
@ -48,10 +50,15 @@ Rectangle {
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: column
|
id: column
|
||||||
anchors.margins: 10
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
y: hifi.dimensions.tabletMenuHeader //-bgNavBar
|
anchors {
|
||||||
|
topMargin: 0
|
||||||
|
leftMargin: 10
|
||||||
|
rightMargin: 10
|
||||||
|
bottomMargin: 0
|
||||||
|
}
|
||||||
spacing: 20
|
spacing: 20
|
||||||
|
|
||||||
TabletEntityStatisticsItem {
|
TabletEntityStatisticsItem {
|
||||||
|
|
|
@ -24,6 +24,8 @@ Item {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
|
property string title: "Controls"
|
||||||
|
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
TabBar {
|
TabBar {
|
||||||
|
|
|
@ -79,7 +79,7 @@ StackView {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
location.text = targetString;
|
location.text = targetString;
|
||||||
toggleOrGo(true, targetString);
|
toggleOrGo(targetString, true);
|
||||||
clearAddressLineTimer.start();
|
clearAddressLineTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,6 @@ StackView {
|
||||||
propagateComposedEvents: true
|
propagateComposedEvents: true
|
||||||
onPressed: {
|
onPressed: {
|
||||||
parent.forceActiveFocus();
|
parent.forceActiveFocus();
|
||||||
addressBarDialog.keyboardEnabled = false;
|
|
||||||
mouse.accepted = false;
|
mouse.accepted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +222,6 @@ StackView {
|
||||||
updateLocationText(text.length > 0);
|
updateLocationText(text.length > 0);
|
||||||
}
|
}
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
addressBarDialog.keyboardEnabled = false;
|
|
||||||
toggleOrGo();
|
toggleOrGo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +376,7 @@ StackView {
|
||||||
|
|
||||||
HifiControls.Keyboard {
|
HifiControls.Keyboard {
|
||||||
id: keyboard
|
id: keyboard
|
||||||
raised: parent.keyboardEnabled
|
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||||
numeric: parent.punctuationMode
|
numeric: parent.punctuationMode
|
||||||
anchors {
|
anchors {
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
|
@ -401,7 +399,7 @@ StackView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleOrGo(fromSuggestions, address) {
|
function toggleOrGo(address, fromSuggestions) {
|
||||||
if (address !== undefined && address !== "") {
|
if (address !== undefined && address !== "") {
|
||||||
addressBarDialog.loadAddress(address, fromSuggestions);
|
addressBarDialog.loadAddress(address, fromSuggestions);
|
||||||
clearAddressLineTimer.start();
|
clearAddressLineTimer.start();
|
||||||
|
|
|
@ -23,6 +23,8 @@ FocusScope {
|
||||||
property string subMenu: ""
|
property string subMenu: ""
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: bgNavBar
|
id: bgNavBar
|
||||||
height: 90
|
height: 90
|
||||||
|
@ -45,24 +47,22 @@ FocusScope {
|
||||||
anchors.topMargin: 0
|
anchors.topMargin: 0
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|
||||||
Image {
|
HiFiGlyphs {
|
||||||
id: menuRootIcon
|
id: menuRootIcon
|
||||||
width: 40
|
text: breadcrumbText.text !== "Menu" ? hifi.glyphs.backward : ""
|
||||||
height: 40
|
size: 72
|
||||||
source: "../../../icons/tablet-icons/menu-i.svg"
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 15
|
width: breadcrumbText.text === "Menu" ? 32 : 50
|
||||||
|
visible: breadcrumbText.text !== "Menu"
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onEntered: iconColorOverlay.color = "#1fc6a6";
|
onEntered: iconColorOverlay.color = "#1fc6a6";
|
||||||
onExited: iconColorOverlay.color = "#34a2c7";
|
onExited: iconColorOverlay.color = "#34a2c7";
|
||||||
// navigate back to root level menu
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
buildMenu();
|
menuPopperUpper.closeLastMenu();
|
||||||
breadcrumbText.text = "Menu";
|
|
||||||
tabletRoot.playButtonClickSound();
|
tabletRoot.playButtonClickSound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,23 +79,10 @@ FocusScope {
|
||||||
id: breadcrumbText
|
id: breadcrumbText
|
||||||
text: "Menu"
|
text: "Menu"
|
||||||
size: 26
|
size: 26
|
||||||
color: "#34a2c7"
|
color: "#e3e3e3"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: menuRootIcon.right
|
anchors.left: menuRootIcon.right
|
||||||
anchors.leftMargin: 15
|
anchors.leftMargin: 15
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onEntered: breadcrumbText.color = "#1fc6a6";
|
|
||||||
onExited: breadcrumbText.color = "#34a2c7";
|
|
||||||
// navigate back to parent level menu if there is one
|
|
||||||
onClicked: {
|
|
||||||
if (breadcrumbText.text !== "Menu") {
|
|
||||||
menuPopperUpper.closeLastMenu();
|
|
||||||
}
|
|
||||||
tabletRoot.playButtonClickSound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +90,6 @@ FocusScope {
|
||||||
menuPopperUpper.closeLastMenu();
|
menuPopperUpper.closeLastMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setRootMenu(rootMenu, subMenu) {
|
function setRootMenu(rootMenu, subMenu) {
|
||||||
tabletMenu.subMenu = subMenu;
|
tabletMenu.subMenu = subMenu;
|
||||||
tabletMenu.rootMenu = rootMenu;
|
tabletMenu.rootMenu = rootMenu;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// MessageDialog.qml
|
// TabletMenuStack.qml
|
||||||
//
|
//
|
||||||
// Created by Dante Ruiz on 13 Feb 2017
|
// Created by Dante Ruiz on 13 Feb 2017
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
@ -66,7 +66,7 @@ Item {
|
||||||
|
|
||||||
function popSource() {
|
function popSource() {
|
||||||
console.log("trying to pop page");
|
console.log("trying to pop page");
|
||||||
d.pop();
|
closeLastMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toModel(items, newMenu) {
|
function toModel(items, newMenu) {
|
||||||
|
|
|
@ -41,7 +41,15 @@ Item {
|
||||||
section.saveAll();
|
section.saveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog();
|
if (HMD.active) {
|
||||||
|
if (gotoPreviousApp) {
|
||||||
|
tablet.returnToPreviousApp();
|
||||||
|
} else {
|
||||||
|
tablet.popFromStack();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
closeDialog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreAll() {
|
function restoreAll() {
|
||||||
|
@ -50,7 +58,15 @@ Item {
|
||||||
section.restoreAll();
|
section.restoreAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog();
|
if (HMD.active) {
|
||||||
|
if (gotoPreviousApp) {
|
||||||
|
tablet.returnToPreviousApp();
|
||||||
|
} else {
|
||||||
|
tablet.popFromStack();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
closeDialog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
|
|
|
@ -94,5 +94,25 @@ Frame {
|
||||||
color: hifi.colors.lightGray
|
color: hifi.colors.lightGray
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GlyphButton {
|
||||||
|
id: closeButton
|
||||||
|
visible: window.closeButtonVisible
|
||||||
|
width: 30
|
||||||
|
y: -hifi.dimensions.modalDialogTitleHeight
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: parent.right
|
||||||
|
topMargin: 10
|
||||||
|
rightMargin: 10
|
||||||
|
}
|
||||||
|
glyph: hifi.glyphs.close
|
||||||
|
size: 23
|
||||||
|
onClicked: {
|
||||||
|
window.clickedCloseButton = true;
|
||||||
|
window.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ ScrollingWindow {
|
||||||
destroyOnHidden: true
|
destroyOnHidden: true
|
||||||
frame: ModalFrame { }
|
frame: ModalFrame { }
|
||||||
|
|
||||||
|
property bool closeButtonVisible: false
|
||||||
|
// only applicable for if close button is visible.
|
||||||
|
property bool clickedCloseButton: false
|
||||||
property int colorScheme: hifi.colorSchemes.light
|
property int colorScheme: hifi.colorSchemes.light
|
||||||
property bool draggable: false
|
property bool draggable: false
|
||||||
|
|
||||||
|
|
934
interface/resources/serverless/redirect.json
Normal file
|
@ -0,0 +1,934 @@
|
||||||
|
{
|
||||||
|
"DataVersion": 0,
|
||||||
|
"Paths":
|
||||||
|
{
|
||||||
|
"/": "/4,1.4,4/0,0.49544,0,0.868645"
|
||||||
|
},
|
||||||
|
"Entities": [
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"collidesWith": "static,dynamic,kinematic,otherAvatar,",
|
||||||
|
"collisionMask": 23,
|
||||||
|
"created": "2018-09-05T18:13:00Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 1.159199833869934,
|
||||||
|
"green": 2.8062009811401367,
|
||||||
|
"red": 1.6216505765914917,
|
||||||
|
"x": 1.6216505765914917,
|
||||||
|
"y": 2.8062009811401367,
|
||||||
|
"z": 1.159199833869934
|
||||||
|
},
|
||||||
|
"id": "{d0ed60b8-9174-4c56-8e78-2c5399329ae0}",
|
||||||
|
"lastEdited": 1536171372916208,
|
||||||
|
"lastEditedBy": "{151cb20e-715a-4c80-aa0d-5b58b1c8a0c9}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "Try Again Zone",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue":4.015342712402344,
|
||||||
|
"green":1.649999976158142,
|
||||||
|
"red":2.00921893119812,
|
||||||
|
"x":2.00921893119812,
|
||||||
|
"y":1.649999976158142,
|
||||||
|
"z":4.015342712402344
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 3.4421300888061523,
|
||||||
|
"x": 1.6001315116882324,
|
||||||
|
"y": -0.07100248336791992,
|
||||||
|
"z": 0.14220571517944336
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9914448857307434,
|
||||||
|
"x": 0,
|
||||||
|
"y": -0.13052619993686676,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/zoneTryAgainEntityScript.js",
|
||||||
|
"shapeType": "box",
|
||||||
|
"type": "Zone",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 255
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 8.645400047302246,
|
||||||
|
"green": 0.20000000298023224,
|
||||||
|
"red": 20.025121688842773,
|
||||||
|
"x": 20.025121688842773,
|
||||||
|
"y": 0.20000000298023224,
|
||||||
|
"z": 8.645400047302246
|
||||||
|
},
|
||||||
|
"id": "{e44fb546-b34a-4966-9b11-73556f800d21}",
|
||||||
|
"lastEdited": 1536107948776951,
|
||||||
|
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "ceiling",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 4.846520900726318,
|
||||||
|
"green": 2.912982940673828,
|
||||||
|
"red": 5.739595890045166,
|
||||||
|
"x": 5.739595890045166,
|
||||||
|
"y": 2.912982940673828,
|
||||||
|
"z": 4.846520900726318
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 21.812576293945312,
|
||||||
|
"x": -5.16669225692749,
|
||||||
|
"y": -7.993305206298828,
|
||||||
|
"z": -6.059767246246338
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.970295786857605,
|
||||||
|
"x": 0,
|
||||||
|
"y": -0.24192190170288086,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"shape": "Cube",
|
||||||
|
"type": "Box",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 6.9401350021362305,
|
||||||
|
"green": 0.04553089290857315,
|
||||||
|
"red": 7.004304885864258,
|
||||||
|
"x": 7.004304885864258,
|
||||||
|
"y": 0.04553089290857315,
|
||||||
|
"z": 6.9401350021362305
|
||||||
|
},
|
||||||
|
"id": "{8cd93fe5-16c0-44b7-b1e9-e7e06c4e9228}",
|
||||||
|
"lastEdited": 1536107948774796,
|
||||||
|
"lastEditedBy": "{4eecd88f-ef9b-4a83-bb9a-7f7496209c6b}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "floor",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 3.6175529956817627,
|
||||||
|
"green": 0,
|
||||||
|
"red": 4.102385997772217,
|
||||||
|
"x": 4.102385997772217,
|
||||||
|
"y": 0,
|
||||||
|
"z": 3.6175529956817627
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 9.860417366027832,
|
||||||
|
"x": -0.8278226852416992,
|
||||||
|
"y": -4.930208683013916,
|
||||||
|
"z": -1.3126556873321533
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.8660253882408142,
|
||||||
|
"x": -1.5922749298624694e-05,
|
||||||
|
"y": 0.5,
|
||||||
|
"z": -4.572480611386709e-05
|
||||||
|
},
|
||||||
|
"shape": "Cube",
|
||||||
|
"type": "Box",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 11.117486953735352,
|
||||||
|
"green": 3.580313205718994,
|
||||||
|
"red": 0.20000000298023224,
|
||||||
|
"x": 0.20000000298023224,
|
||||||
|
"y": 3.580313205718994,
|
||||||
|
"z": 11.117486953735352
|
||||||
|
},
|
||||||
|
"id": "{147272dc-a344-4171-9621-efc1c2095997}",
|
||||||
|
"lastEdited": 1536107948776823,
|
||||||
|
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "leftWall",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 6.1806135177612305,
|
||||||
|
"green": 1.0066027641296387,
|
||||||
|
"red": 1.4690406322479248,
|
||||||
|
"x": 1.4690406322479248,
|
||||||
|
"y": 1.0066027641296387,
|
||||||
|
"z": 6.1806135177612305
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 11.681488037109375,
|
||||||
|
"x": -4.371703147888184,
|
||||||
|
"y": -4.834141254425049,
|
||||||
|
"z": 0.33986949920654297
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.8637980222702026,
|
||||||
|
"x": -4.57763671875e-05,
|
||||||
|
"y": 0.5038070678710938,
|
||||||
|
"z": -1.52587890625e-05
|
||||||
|
},
|
||||||
|
"shape": "Cube",
|
||||||
|
"type": "Box",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 11.117486953735352,
|
||||||
|
"green": 3.580313205718994,
|
||||||
|
"red": 0.20000000298023224,
|
||||||
|
"x": 0.20000000298023224,
|
||||||
|
"y": 3.580313205718994,
|
||||||
|
"z": 11.117486953735352
|
||||||
|
},
|
||||||
|
"id": "{5f2b89b8-47e3-4915-a966-d46307a40f06}",
|
||||||
|
"lastEdited": 1536107948774605,
|
||||||
|
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "backWall",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 5.268576622009277,
|
||||||
|
"green": 1.0066027641296387,
|
||||||
|
"red": 6.093774318695068,
|
||||||
|
"x": 6.093774318695068,
|
||||||
|
"y": 1.0066027641296387,
|
||||||
|
"z": 5.268576622009277
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 11.681488037109375,
|
||||||
|
"x": 0.25303030014038086,
|
||||||
|
"y": -4.834141254425049,
|
||||||
|
"z": -0.5721673965454102
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9662165641784668,
|
||||||
|
"x": -4.57763671875e-05,
|
||||||
|
"y": -0.2576791048049927,
|
||||||
|
"z": 1.52587890625e-05
|
||||||
|
},
|
||||||
|
"shape": "Cube",
|
||||||
|
"type": "Box",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 14.40000057220459,
|
||||||
|
"green": 14.40000057220459,
|
||||||
|
"red": 14.40000057220459,
|
||||||
|
"x": 14.40000057220459,
|
||||||
|
"y": 14.40000057220459,
|
||||||
|
"z": 14.40000057220459
|
||||||
|
},
|
||||||
|
"id": "{baf96345-8f68-4068-af4c-3c690035852a}",
|
||||||
|
"lastEdited": 1536107948775591,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"locked": true,
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 2.3440732955932617,
|
||||||
|
"green": 1.6162219047546387,
|
||||||
|
"red": 1.8748211860656738,
|
||||||
|
"x": 1.8748211860656738,
|
||||||
|
"y": 1.6162219047546387,
|
||||||
|
"z": 2.3440732955932617
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 24.9415340423584,
|
||||||
|
"x": -10.595945358276367,
|
||||||
|
"y": -10.854545593261719,
|
||||||
|
"z": -10.126693725585938
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.8697794675827026,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": 0.4933699369430542,
|
||||||
|
"z": -4.57763671875e-05
|
||||||
|
},
|
||||||
|
"shapeType": "box",
|
||||||
|
"skyboxMode": "enabled",
|
||||||
|
"type": "Zone",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alpha": 0,
|
||||||
|
"alphaFinish": 0,
|
||||||
|
"alphaStart": 1,
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 211,
|
||||||
|
"green": 227,
|
||||||
|
"red": 104
|
||||||
|
},
|
||||||
|
"colorFinish": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"colorStart": {
|
||||||
|
"blue": 211,
|
||||||
|
"green": 227,
|
||||||
|
"red": 104,
|
||||||
|
"x": 104,
|
||||||
|
"y": 227,
|
||||||
|
"z": 211
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 2.5,
|
||||||
|
"green": 2.5,
|
||||||
|
"red": 2.5,
|
||||||
|
"x": 2.5,
|
||||||
|
"y": 2.5,
|
||||||
|
"z": 2.5
|
||||||
|
},
|
||||||
|
"emitAcceleration": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"emitDimensions": {
|
||||||
|
"blue": 1,
|
||||||
|
"green": 1,
|
||||||
|
"red": 1,
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"emitOrientation": {
|
||||||
|
"w": 0.9993909597396851,
|
||||||
|
"x": 0.034897372126579285,
|
||||||
|
"y": -1.525880907138344e-05,
|
||||||
|
"z": -1.525880907138344e-05
|
||||||
|
},
|
||||||
|
"emitRate": 2,
|
||||||
|
"emitSpeed": 0,
|
||||||
|
"id": "{639a51f0-8613-4e46-bc7e-fef24597df73}",
|
||||||
|
"lastEdited": 1536107948776693,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"lifespan": 10,
|
||||||
|
"locked": true,
|
||||||
|
"maxParticles": 40,
|
||||||
|
"name": "Rays",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"particleRadius": 0.75,
|
||||||
|
"polarFinish": 3.1415927410125732,
|
||||||
|
"position": {
|
||||||
|
"blue": 1.3553659915924072,
|
||||||
|
"green": 1.2890124320983887,
|
||||||
|
"red": 2.5663273334503174,
|
||||||
|
"x": 2.5663273334503174,
|
||||||
|
"y": 1.2890124320983887,
|
||||||
|
"z": 1.3553659915924072
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 4.330127239227295,
|
||||||
|
"x": 0.4012637138366699,
|
||||||
|
"y": -0.8760511875152588,
|
||||||
|
"z": -0.8096976280212402
|
||||||
|
},
|
||||||
|
"radiusFinish": 0.10000000149011612,
|
||||||
|
"radiusStart": 0,
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9803768396377563,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": 0.19707024097442627,
|
||||||
|
"z": -7.62939453125e-05
|
||||||
|
},
|
||||||
|
"speedSpread": 0,
|
||||||
|
"spinFinish": null,
|
||||||
|
"spinStart": null,
|
||||||
|
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/stripe.png",
|
||||||
|
"type": "ParticleEffect",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alpha": 0,
|
||||||
|
"alphaFinish": 0,
|
||||||
|
"alphaStart": 1,
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 205,
|
||||||
|
"red": 3
|
||||||
|
},
|
||||||
|
"colorFinish": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"colorStart": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 204,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 204,
|
||||||
|
"z": 255
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 2.5,
|
||||||
|
"green": 2.5,
|
||||||
|
"red": 2.5,
|
||||||
|
"x": 2.5,
|
||||||
|
"y": 2.5,
|
||||||
|
"z": 2.5
|
||||||
|
},
|
||||||
|
"emitAcceleration": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"emitDimensions": {
|
||||||
|
"blue": 1,
|
||||||
|
"green": 1,
|
||||||
|
"red": 1,
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"emitOrientation": {
|
||||||
|
"w": 0.9993909597396851,
|
||||||
|
"x": 0.034897372126579285,
|
||||||
|
"y": -1.525880907138344e-05,
|
||||||
|
"z": -1.525880907138344e-05
|
||||||
|
},
|
||||||
|
"emitRate": 2,
|
||||||
|
"emitSpeed": 0,
|
||||||
|
"emitterShouldTrail": true,
|
||||||
|
"id": "{e62ced49-fa18-4ae1-977f-abef5bc0f3ba}",
|
||||||
|
"lastEdited": 1536107948775366,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"lifespan": 10,
|
||||||
|
"locked": true,
|
||||||
|
"maxParticles": 40,
|
||||||
|
"name": "Rays",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"particleRadius": 0.75,
|
||||||
|
"polarFinish": 3.1415927410125732,
|
||||||
|
"position": {
|
||||||
|
"blue": 3.814434051513672,
|
||||||
|
"green": 1.2890124320983887,
|
||||||
|
"red": 1.2254328727722168,
|
||||||
|
"x": 1.2254328727722168,
|
||||||
|
"y": 1.2890124320983887,
|
||||||
|
"z": 3.814434051513672
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 4.330127239227295,
|
||||||
|
"x": -0.9396307468414307,
|
||||||
|
"y": -0.8760511875152588,
|
||||||
|
"z": 1.6493704319000244
|
||||||
|
},
|
||||||
|
"radiusFinish": 0.10000000149011612,
|
||||||
|
"radiusStart": 0,
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9594720602035522,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": 0.28178834915161133,
|
||||||
|
"z": -4.57763671875e-05
|
||||||
|
},
|
||||||
|
"speedSpread": 0,
|
||||||
|
"spinFinish": null,
|
||||||
|
"spinStart": null,
|
||||||
|
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/stripe.png",
|
||||||
|
"type": "ParticleEffect",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alpha": 0,
|
||||||
|
"alphaFinish": 0,
|
||||||
|
"alphaStart": 0.25,
|
||||||
|
"clientOnly": false,
|
||||||
|
"colorFinish": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"colorStart": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 255,
|
||||||
|
"red": 255,
|
||||||
|
"x": 255,
|
||||||
|
"y": 255,
|
||||||
|
"z": 255
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 13.24000072479248,
|
||||||
|
"green": 13.24000072479248,
|
||||||
|
"red": 13.24000072479248,
|
||||||
|
"x": 13.24000072479248,
|
||||||
|
"y": 13.24000072479248,
|
||||||
|
"z": 13.24000072479248
|
||||||
|
},
|
||||||
|
"emitAcceleration": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0.10000000149011612,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.10000000149011612,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"emitDimensions": {
|
||||||
|
"blue": 1,
|
||||||
|
"green": 1,
|
||||||
|
"red": 1,
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"emitOrientation": {
|
||||||
|
"w": 1,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": -1.52587890625e-05,
|
||||||
|
"z": -1.52587890625e-05
|
||||||
|
},
|
||||||
|
"emitRate": 6,
|
||||||
|
"emitSpeed": 0,
|
||||||
|
"id": "{298c0571-cbd8-487b-8640-64037d6a8414}",
|
||||||
|
"lastEdited": 1536107948776382,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"lifespan": 10,
|
||||||
|
"locked": true,
|
||||||
|
"maxParticles": 10,
|
||||||
|
"name": "Stars",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"particleRadius": 0.07000000029802322,
|
||||||
|
"polarFinish": 3.1415927410125732,
|
||||||
|
"position": {
|
||||||
|
"blue": 1.3712034225463867,
|
||||||
|
"green": 0.3698839843273163,
|
||||||
|
"red": 2.6216418743133545,
|
||||||
|
"x": 2.6216418743133545,
|
||||||
|
"y": 0.3698839843273163,
|
||||||
|
"z": 1.3712034225463867
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 22.932353973388672,
|
||||||
|
"x": -8.844534873962402,
|
||||||
|
"y": -11.096293449401855,
|
||||||
|
"z": -10.09497356414795
|
||||||
|
},
|
||||||
|
"radiusFinish": 0,
|
||||||
|
"radiusStart": 0,
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9852597713470459,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": -0.17106890678405762,
|
||||||
|
"z": -7.62939453125e-05
|
||||||
|
},
|
||||||
|
"speedSpread": 0,
|
||||||
|
"spinFinish": null,
|
||||||
|
"spinStart": null,
|
||||||
|
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/star.png",
|
||||||
|
"type": "ParticleEffect",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 2.1097896099090576,
|
||||||
|
"green": 0.04847164824604988,
|
||||||
|
"red": 1.458284616470337,
|
||||||
|
"x": 1.458284616470337,
|
||||||
|
"y": 0.04847164824604988,
|
||||||
|
"z": 2.1097896099090576
|
||||||
|
},
|
||||||
|
"id": "{6625dbb8-ff25-458d-a92e-644b58460604}",
|
||||||
|
"lastEdited": 1536107948776195,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"locked": true,
|
||||||
|
"modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal1.fbx",
|
||||||
|
"name": "Try Again",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 3.946338653564453,
|
||||||
|
"green": 0.09449335932731628,
|
||||||
|
"red": 1.594836711883545,
|
||||||
|
"x": 1.594836711883545,
|
||||||
|
"y": 0.09449335932731628,
|
||||||
|
"z": 3.946338653564453
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 2.5651814937591553,
|
||||||
|
"x": 0.3122459650039673,
|
||||||
|
"y": -1.188097357749939,
|
||||||
|
"z": 2.663747787475586
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.8220492601394653,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": 0.5693598985671997,
|
||||||
|
"z": -0.0001068115234375
|
||||||
|
},
|
||||||
|
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/tryAgainEntityScript.js",
|
||||||
|
"shapeType": "static-mesh",
|
||||||
|
"type": "Model",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 0.06014331430196762,
|
||||||
|
"green": 2.582186460494995,
|
||||||
|
"red": 2.582186698913574,
|
||||||
|
"x": 2.582186698913574,
|
||||||
|
"y": 2.582186460494995,
|
||||||
|
"z": 0.06014331430196762
|
||||||
|
},
|
||||||
|
"id": "{dfe92dce-f09d-4e9e-b3ed-c68ecd4d476f}",
|
||||||
|
"lastEdited": 1536108160862286,
|
||||||
|
"lastEditedBy": "{4656d4a8-5e61-4230-ab34-2888d7945bd6}",
|
||||||
|
"modelURL": "",
|
||||||
|
"name": "Oops Dialog",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 1.45927095413208,
|
||||||
|
"green": 1.6763916015625,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 1.6763916015625,
|
||||||
|
"z": 1.45927095413208
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 3.6522583961486816,
|
||||||
|
"x": -1.8261291980743408,
|
||||||
|
"y": -0.14973759651184082,
|
||||||
|
"z": -0.36685824394226074
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.8684672117233276,
|
||||||
|
"x": -4.57763671875e-05,
|
||||||
|
"y": 0.4957197904586792,
|
||||||
|
"z": -7.62939453125e-05
|
||||||
|
},
|
||||||
|
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/oopsEntityScript.js",
|
||||||
|
"scriptTimestamp": 1536102551825,
|
||||||
|
"type": "Model",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 11.117486953735352,
|
||||||
|
"green": 3.580313205718994,
|
||||||
|
"red": 0.20000000298023224,
|
||||||
|
"x": 0.20000000298023224,
|
||||||
|
"y": 3.580313205718994,
|
||||||
|
"z": 11.117486953735352
|
||||||
|
},
|
||||||
|
"id": "{144a8cf4-b0e8-489a-9403-d74d4dc4cb3e}",
|
||||||
|
"lastEdited": 1536107948775774,
|
||||||
|
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "rightWall",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 1.0061144828796387,
|
||||||
|
"red": 4.965089321136475,
|
||||||
|
"x": 4.965089321136475,
|
||||||
|
"y": 1.0061144828796387,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 11.681488037109375,
|
||||||
|
"x": -0.8756546974182129,
|
||||||
|
"y": -4.834629535675049,
|
||||||
|
"z": -5.8407440185546875
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.8637980222702026,
|
||||||
|
"x": -4.57763671875e-05,
|
||||||
|
"y": 0.5038070678710938,
|
||||||
|
"z": -1.52587890625e-05
|
||||||
|
},
|
||||||
|
"shape": "Cube",
|
||||||
|
"type": "Box",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"collidesWith": "static,dynamic,kinematic,otherAvatar,",
|
||||||
|
"collisionMask": 23,
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 1.159199833869934,
|
||||||
|
"green": 2.8062009811401367,
|
||||||
|
"red": 1.6216505765914917,
|
||||||
|
"x": 1.6216505765914917,
|
||||||
|
"y": 2.8062009811401367,
|
||||||
|
"z": 1.159199833869934
|
||||||
|
},
|
||||||
|
"id": "{37f53408-3d0c-42a5-9891-e6c40a227349}",
|
||||||
|
"lastEdited": 1536107948775010,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "Back Zone",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 1.8632707595825195,
|
||||||
|
"green": 1.6500625610351562,
|
||||||
|
"red": 3.3211965560913086,
|
||||||
|
"x": 3.3211965560913086,
|
||||||
|
"y": 1.6500625610351562,
|
||||||
|
"z": 1.8632707595825195
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 3.4421300888061523,
|
||||||
|
"x": 1.6001315116882324,
|
||||||
|
"y": -0.07100248336791992,
|
||||||
|
"z": 0.14220571517944336
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9304176568984985,
|
||||||
|
"x": 0,
|
||||||
|
"y": -0.36650121212005615,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/zoneBackEntityScript.js",
|
||||||
|
"shapeType": "box",
|
||||||
|
"type": "Zone",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"color": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 11.117486953735352,
|
||||||
|
"green": 3.580313205718994,
|
||||||
|
"red": 0.20000000298023224,
|
||||||
|
"x": 0.20000000298023224,
|
||||||
|
"y": 3.580313205718994,
|
||||||
|
"z": 11.117486953735352
|
||||||
|
},
|
||||||
|
"id": "{aa6e680c-6750-4776-95bc-ef3118cace5c}",
|
||||||
|
"lastEdited": 1536107948775945,
|
||||||
|
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||||
|
"locked": true,
|
||||||
|
"name": "frontWall",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 2.662257671356201,
|
||||||
|
"green": 1.0063786506652832,
|
||||||
|
"red": 1.4868733882904053,
|
||||||
|
"x": 1.4868733882904053,
|
||||||
|
"y": 1.0063786506652832,
|
||||||
|
"z": 2.662257671356201
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 11.681488037109375,
|
||||||
|
"x": -4.353870391845703,
|
||||||
|
"y": -4.834365367889404,
|
||||||
|
"z": -3.1784863471984863
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9666743278503418,
|
||||||
|
"x": -4.57763671875e-05,
|
||||||
|
"y": -0.2560006380081177,
|
||||||
|
"z": 1.52587890625e-05
|
||||||
|
},
|
||||||
|
"shape": "Cube",
|
||||||
|
"type": "Box",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientOnly": false,
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 2.1097896099090576,
|
||||||
|
"green": 0.04847164824604988,
|
||||||
|
"red": 1.458284616470337,
|
||||||
|
"x": 1.458284616470337,
|
||||||
|
"y": 0.04847164824604988,
|
||||||
|
"z": 2.1097896099090576
|
||||||
|
},
|
||||||
|
"id": "{303631f1-04f3-42a6-b8a8-8dd4b65d1231}",
|
||||||
|
"lastEdited": 1536107948776513,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"locked": true,
|
||||||
|
"modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal2.fbx",
|
||||||
|
"name": "Back",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"position": {
|
||||||
|
"blue": 1.5835940837860107,
|
||||||
|
"green": 0.09449335932731628,
|
||||||
|
"red": 3.028078079223633,
|
||||||
|
"x": 3.028078079223633,
|
||||||
|
"y": 0.09449335932731628,
|
||||||
|
"z": 1.5835940837860107
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 2.5651814937591553,
|
||||||
|
"x": 1.7454873323440552,
|
||||||
|
"y": -1.188097357749939,
|
||||||
|
"z": 0.3010033369064331
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9084458351135254,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": 0.4179598093032837,
|
||||||
|
"z": -0.0001068115234375
|
||||||
|
},
|
||||||
|
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/backEntityScript.js",
|
||||||
|
"scriptTimestamp": 1535751754379,
|
||||||
|
"shapeType": "static-mesh",
|
||||||
|
"type": "Model",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alpha": 0,
|
||||||
|
"alphaFinish": 0,
|
||||||
|
"alphaStart": 0.25,
|
||||||
|
"clientOnly": false,
|
||||||
|
"colorFinish": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"colorStart": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 255,
|
||||||
|
"red": 255,
|
||||||
|
"x": 255,
|
||||||
|
"y": 255,
|
||||||
|
"z": 255
|
||||||
|
},
|
||||||
|
"created": "2018-09-05T00:40:03Z",
|
||||||
|
"dimensions": {
|
||||||
|
"blue": 13.24000072479248,
|
||||||
|
"green": 13.24000072479248,
|
||||||
|
"red": 13.24000072479248,
|
||||||
|
"x": 13.24000072479248,
|
||||||
|
"y": 13.24000072479248,
|
||||||
|
"z": 13.24000072479248
|
||||||
|
},
|
||||||
|
"emitAcceleration": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0.10000000149011612,
|
||||||
|
"red": 0,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.10000000149011612,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"emitDimensions": {
|
||||||
|
"blue": 1,
|
||||||
|
"green": 1,
|
||||||
|
"red": 1,
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"emitOrientation": {
|
||||||
|
"w": 1,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": -1.52587890625e-05,
|
||||||
|
"z": -1.52587890625e-05
|
||||||
|
},
|
||||||
|
"emitRate": 6,
|
||||||
|
"emitSpeed": 0,
|
||||||
|
"emitterShouldTrail": true,
|
||||||
|
"id": "{8ded39e6-303c-48f2-be79-81b715cca9f7}",
|
||||||
|
"lastEdited": 1536107948777127,
|
||||||
|
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||||
|
"lifespan": 10,
|
||||||
|
"locked": true,
|
||||||
|
"maxParticles": 10,
|
||||||
|
"name": "Stars",
|
||||||
|
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||||
|
"particleRadius": 0.07000000029802322,
|
||||||
|
"polarFinish": 3.1415927410125732,
|
||||||
|
"position": {
|
||||||
|
"blue": 3.78922963142395,
|
||||||
|
"green": 0.3698839843273163,
|
||||||
|
"red": 1.1863799095153809,
|
||||||
|
"x": 1.1863799095153809,
|
||||||
|
"y": 0.3698839843273163,
|
||||||
|
"z": 3.78922963142395
|
||||||
|
},
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 22.932353973388672,
|
||||||
|
"x": -10.279796600341797,
|
||||||
|
"y": -11.096293449401855,
|
||||||
|
"z": -7.676947593688965
|
||||||
|
},
|
||||||
|
"radiusFinish": 0,
|
||||||
|
"radiusStart": 0,
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.996429443359375,
|
||||||
|
"x": -1.52587890625e-05,
|
||||||
|
"y": -0.08442819118499756,
|
||||||
|
"z": -4.57763671875e-05
|
||||||
|
},
|
||||||
|
"speedSpread": 0,
|
||||||
|
"spinFinish": null,
|
||||||
|
"spinStart": null,
|
||||||
|
"textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/star.png",
|
||||||
|
"type": "ParticleEffect",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Id": "{18abccad-2d57-4176-9d89-24dc424916f5}",
|
||||||
|
"Version": 93
|
||||||
|
}
|
|
@ -1186,13 +1186,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||||
|
|
||||||
connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl)));
|
connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl)));
|
||||||
|
connect(&domainHandler, SIGNAL(redirectToErrorDomainURL(QUrl)), SLOT(goToErrorDomainURL(QUrl)));
|
||||||
connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){
|
connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){
|
||||||
setCrashAnnotation("domain", domainURL.toString().toStdString());
|
setCrashAnnotation("domain", domainURL.toString().toStdString());
|
||||||
});
|
});
|
||||||
connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
|
connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
|
||||||
connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle()));
|
connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle()));
|
||||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
||||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &Application::clearDomainAvatars);
|
|
||||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() {
|
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() {
|
||||||
getOverlays().deleteOverlay(getTabletScreenID());
|
getOverlays().deleteOverlay(getTabletScreenID());
|
||||||
getOverlays().deleteOverlay(getTabletHomeButtonID());
|
getOverlays().deleteOverlay(getTabletHomeButtonID());
|
||||||
|
@ -1200,6 +1200,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
});
|
});
|
||||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused);
|
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused);
|
||||||
|
|
||||||
|
nodeList->getDomainHandler().setErrorDomainURL(QUrl(REDIRECT_HIFI_ADDRESS));
|
||||||
|
|
||||||
// We could clear ATP assets only when changing domains, but it's possible that the domain you are connected
|
// We could clear ATP assets only when changing domains, but it's possible that the domain you are connected
|
||||||
// to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid.
|
// to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid.
|
||||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get<ScriptCache>().data(), &ScriptCache::clearATPScriptsFromCache);
|
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get<ScriptCache>().data(), &ScriptCache::clearATPScriptsFromCache);
|
||||||
|
@ -1641,7 +1643,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
audioClient->setMuted(!audioClient->isMuted());
|
audioClient->setMuted(!audioClient->isMuted());
|
||||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||||
cycleCamera();
|
cycleCamera();
|
||||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU) && !isInterstitialMode()) {
|
||||||
toggleTabletUI();
|
toggleTabletUI();
|
||||||
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
||||||
auto oldPos = getApplicationCompositor().getReticlePosition();
|
auto oldPos = getApplicationCompositor().getReticlePosition();
|
||||||
|
@ -2250,6 +2252,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
|
connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
|
||||||
connect(&domainHandler, &DomainHandler::domainURLChanged, this, &Application::addAssetToWorldMessageClose);
|
connect(&domainHandler, &DomainHandler::domainURLChanged, this, &Application::addAssetToWorldMessageClose);
|
||||||
|
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &Application::addAssetToWorldMessageClose);
|
||||||
|
|
||||||
updateSystemTabletMode();
|
updateSystemTabletMode();
|
||||||
|
|
||||||
|
@ -2299,6 +2302,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground);
|
connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground);
|
||||||
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
|
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
|
||||||
AndroidHelper::instance().notifyLoadComplete();
|
AndroidHelper::instance().notifyLoadComplete();
|
||||||
|
#else
|
||||||
|
static int CHECK_LOGIN_TIMER = 3000;
|
||||||
|
QTimer* checkLoginTimer = new QTimer(this);
|
||||||
|
checkLoginTimer->setInterval(CHECK_LOGIN_TIMER);
|
||||||
|
checkLoginTimer->setSingleShot(true);
|
||||||
|
connect(checkLoginTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||||
|
if (!accountManager->isLoggedIn()) {
|
||||||
|
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(true);
|
||||||
|
dialogsManager->showLoginDialog();
|
||||||
|
QJsonObject loginData = {};
|
||||||
|
loginData["action"] = "login dialog shown";
|
||||||
|
UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(false);
|
||||||
|
checkLoginTimer->start();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2433,6 +2454,8 @@ void Application::onAboutToQuit() {
|
||||||
// so its persisted explicitly here
|
// so its persisted explicitly here
|
||||||
Setting::Handle<QString>{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName());
|
Setting::Handle<QString>{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName());
|
||||||
|
|
||||||
|
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(false);
|
||||||
|
|
||||||
getActiveDisplayPlugin()->deactivate();
|
getActiveDisplayPlugin()->deactivate();
|
||||||
if (_autoSwitchDisplayModeSupportedHMDPlugin
|
if (_autoSwitchDisplayModeSupportedHMDPlugin
|
||||||
&& _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
|
&& _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
|
||||||
|
@ -2664,6 +2687,10 @@ Application::~Application() {
|
||||||
void Application::initializeGL() {
|
void Application::initializeGL() {
|
||||||
qCDebug(interfaceapp) << "Created Display Window.";
|
qCDebug(interfaceapp) << "Created Display Window.";
|
||||||
|
|
||||||
|
#ifdef DISABLE_QML
|
||||||
|
setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
||||||
|
#endif
|
||||||
|
|
||||||
// initialize glut for shape drawing; Qt apparently initializes it on OS X
|
// initialize glut for shape drawing; Qt apparently initializes it on OS X
|
||||||
if (_isGLInitialized) {
|
if (_isGLInitialized) {
|
||||||
return;
|
return;
|
||||||
|
@ -2989,6 +3016,9 @@ void Application::initializeUi() {
|
||||||
if (_window && _window->isFullScreen()) {
|
if (_window && _window->isFullScreen()) {
|
||||||
setFullscreen(nullptr, true);
|
setFullscreen(nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setIsInterstitialMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3467,6 +3497,17 @@ bool Application::isServerlessMode() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::setIsInterstitialMode(bool interstitialMode) {
|
||||||
|
Settings settings;
|
||||||
|
bool enableInterstitial = settings.value("enableIntersitialMode", false).toBool();
|
||||||
|
if (_interstitialMode != interstitialMode && enableInterstitial) {
|
||||||
|
_interstitialMode = interstitialMode;
|
||||||
|
|
||||||
|
DependencyManager::get<AudioClient>()->setAudioPaused(_interstitialMode);
|
||||||
|
DependencyManager::get<AvatarManager>()->setMyAvatarDataPacketsPaused(_interstitialMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setIsServerlessMode(bool serverlessDomain) {
|
void Application::setIsServerlessMode(bool serverlessDomain) {
|
||||||
auto tree = getEntities()->getTree();
|
auto tree = getEntities()->getTree();
|
||||||
if (tree) {
|
if (tree) {
|
||||||
|
@ -3474,9 +3515,9 @@ void Application::setIsServerlessMode(bool serverlessDomain) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadServerlessDomain(QUrl domainURL) {
|
void Application::loadServerlessDomain(QUrl domainURL, bool errorDomain) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL));
|
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL), Q_ARG(bool, errorDomain));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3508,8 +3549,11 @@ void Application::loadServerlessDomain(QUrl domainURL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
|
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
|
||||||
nodeList->getDomainHandler().connectedToServerless(namedPaths);
|
if (errorDomain) {
|
||||||
|
nodeList->getDomainHandler().loadedErrorDomain(namedPaths);
|
||||||
|
} else {
|
||||||
|
nodeList->getDomainHandler().connectedToServerless(namedPaths);
|
||||||
|
}
|
||||||
|
|
||||||
_fullSceneReceivedCounter++;
|
_fullSceneReceivedCounter++;
|
||||||
}
|
}
|
||||||
|
@ -3744,7 +3788,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
|
||||||
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
if (_controllerScriptingInterface->isKeyCaptured(event) || isInterstitialMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5531,6 +5575,7 @@ void Application::update(float deltaTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!_physicsEnabled) {
|
if (!_physicsEnabled) {
|
||||||
if (!domainLoadingInProgress) {
|
if (!domainLoadingInProgress) {
|
||||||
PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
|
PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
|
||||||
|
@ -5551,6 +5596,7 @@ void Application::update(float deltaTime) {
|
||||||
// scene is ready to compute its collision shape.
|
// scene is ready to compute its collision shape.
|
||||||
if (getMyAvatar()->isReadyForPhysics()) {
|
if (getMyAvatar()->isReadyForPhysics()) {
|
||||||
_physicsEnabled = true;
|
_physicsEnabled = true;
|
||||||
|
setIsInterstitialMode(false);
|
||||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5630,7 +5676,7 @@ void Application::update(float deltaTime) {
|
||||||
// Transfer the user inputs to the driveKeys
|
// Transfer the user inputs to the driveKeys
|
||||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||||
myAvatar->clearDriveKeys();
|
myAvatar->clearDriveKeys();
|
||||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT && !isInterstitialMode()) {
|
||||||
if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
||||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
||||||
|
@ -5946,7 +5992,7 @@ void Application::update(float deltaTime) {
|
||||||
// send packet containing downstream audio stats to the AudioMixer
|
// send packet containing downstream audio stats to the AudioMixer
|
||||||
{
|
{
|
||||||
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
|
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
|
||||||
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) {
|
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS && !isInterstitialMode()) {
|
||||||
_lastSendDownstreamAudioStats = now;
|
_lastSendDownstreamAudioStats = now;
|
||||||
|
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);
|
||||||
|
@ -6109,21 +6155,23 @@ void Application::updateRenderArgs(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::queryAvatars() {
|
void Application::queryAvatars() {
|
||||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
if (!isInterstitialMode()) {
|
||||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||||
unsigned char* bufferStart = destinationBuffer;
|
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||||
|
unsigned char* bufferStart = destinationBuffer;
|
||||||
|
|
||||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||||
destinationBuffer += sizeof(numFrustums);
|
destinationBuffer += sizeof(numFrustums);
|
||||||
|
|
||||||
for (const auto& view : _conicalViews) {
|
for (const auto& view : _conicalViews) {
|
||||||
destinationBuffer += view.serialize(destinationBuffer);
|
destinationBuffer += view.serialize(destinationBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||||
|
|
||||||
|
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
|
||||||
|
|
||||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6300,6 +6348,7 @@ void Application::updateWindowTitle() const {
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
auto isInErrorState = nodeList->getDomainHandler().isInErrorState();
|
||||||
|
|
||||||
QString buildVersion = " - "
|
QString buildVersion = " - "
|
||||||
+ (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build"))
|
+ (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build"))
|
||||||
|
@ -6307,14 +6356,19 @@ void Application::updateWindowTitle() const {
|
||||||
|
|
||||||
QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)";
|
QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)";
|
||||||
|
|
||||||
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED)";
|
QString connectionStatus = isInErrorState ? " (ERROR CONNECTING)" :
|
||||||
|
nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED)";
|
||||||
QString username = accountManager->getAccountInfo().getUsername();
|
QString username = accountManager->getAccountInfo().getUsername();
|
||||||
|
|
||||||
setCrashAnnotation("username", username.toStdString());
|
setCrashAnnotation("username", username.toStdString());
|
||||||
|
|
||||||
QString currentPlaceName;
|
QString currentPlaceName;
|
||||||
if (isServerlessMode()) {
|
if (isServerlessMode()) {
|
||||||
currentPlaceName = "serverless: " + DependencyManager::get<AddressManager>()->getDomainURL().toString();
|
if (isInErrorState) {
|
||||||
|
currentPlaceName = "serverless: " + nodeList->getDomainHandler().getErrorDomainURL().toString();
|
||||||
|
} else {
|
||||||
|
currentPlaceName = "serverless: " + DependencyManager::get<AddressManager>()->getDomainURL().toString();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
currentPlaceName = DependencyManager::get<AddressManager>()->getDomainURL().host();
|
currentPlaceName = DependencyManager::get<AddressManager>()->getDomainURL().host();
|
||||||
if (currentPlaceName.isEmpty()) {
|
if (currentPlaceName.isEmpty()) {
|
||||||
|
@ -6346,6 +6400,7 @@ void Application::clearDomainOctreeDetails() {
|
||||||
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
||||||
|
|
||||||
resetPhysicsReadyInformation();
|
resetPhysicsReadyInformation();
|
||||||
|
setIsInterstitialMode(true);
|
||||||
|
|
||||||
_octreeServerSceneStats.withWriteLock([&] {
|
_octreeServerSceneStats.withWriteLock([&] {
|
||||||
_octreeServerSceneStats.clear();
|
_octreeServerSceneStats.clear();
|
||||||
|
@ -6366,10 +6421,6 @@ void Application::clearDomainOctreeDetails() {
|
||||||
getMyAvatar()->setAvatarEntityDataChanged(true);
|
getMyAvatar()->setAvatarEntityDataChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::clearDomainAvatars() {
|
|
||||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::domainURLChanged(QUrl domainURL) {
|
void Application::domainURLChanged(QUrl domainURL) {
|
||||||
// disable physics until we have enough information about our new location to not cause craziness.
|
// disable physics until we have enough information about our new location to not cause craziness.
|
||||||
resetPhysicsReadyInformation();
|
resetPhysicsReadyInformation();
|
||||||
|
@ -6380,6 +6431,16 @@ void Application::domainURLChanged(QUrl domainURL) {
|
||||||
updateWindowTitle();
|
updateWindowTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::goToErrorDomainURL(QUrl errorDomainURL) {
|
||||||
|
// disable physics until we have enough information about our new location to not cause craziness.
|
||||||
|
resetPhysicsReadyInformation();
|
||||||
|
setIsServerlessMode(errorDomainURL.scheme() != URL_SCHEME_HIFI);
|
||||||
|
if (isServerlessMode()) {
|
||||||
|
loadServerlessDomain(errorDomainURL, true);
|
||||||
|
}
|
||||||
|
updateWindowTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Application::resettingDomain() {
|
void Application::resettingDomain() {
|
||||||
_notifiedPacketVersionMismatchThisDomain = false;
|
_notifiedPacketVersionMismatchThisDomain = false;
|
||||||
|
@ -6418,7 +6479,7 @@ void Application::nodeActivated(SharedNodePointer node) {
|
||||||
_octreeQuery.incrementConnectionID();
|
_octreeQuery.incrementConnectionID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->getType() == NodeType::AudioMixer) {
|
if (node->getType() == NodeType::AudioMixer && !isInterstitialMode()) {
|
||||||
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6438,8 +6499,10 @@ void Application::nodeActivated(SharedNodePointer node) {
|
||||||
getMyAvatar()->markIdentityDataChanged();
|
getMyAvatar()->markIdentityDataChanged();
|
||||||
getMyAvatar()->resetLastSent();
|
getMyAvatar()->resetLastSent();
|
||||||
|
|
||||||
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
if (!isInterstitialMode()) {
|
||||||
getMyAvatar()->sendAvatarDataPacket(true);
|
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
||||||
|
getMyAvatar()->sendAvatarDataPacket(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6457,9 +6520,6 @@ void Application::nodeKilled(SharedNodePointer node) {
|
||||||
} else if (node->getType() == NodeType::EntityServer) {
|
} else if (node->getType() == NodeType::EntityServer) {
|
||||||
// we lost an entity server, clear all of the domain octree details
|
// we lost an entity server, clear all of the domain octree details
|
||||||
clearDomainOctreeDetails();
|
clearDomainOctreeDetails();
|
||||||
} else if (node->getType() == NodeType::AvatarMixer) {
|
|
||||||
// our avatar mixer has gone away - clear the hash of avatars
|
|
||||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
|
||||||
} else if (node->getType() == NodeType::AssetServer) {
|
} else if (node->getType() == NodeType::AssetServer) {
|
||||||
// asset server going away - check if we have the asset browser showing
|
// asset server going away - check if we have the asset browser showing
|
||||||
|
|
||||||
|
@ -6872,6 +6932,9 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
||||||
shortName = shortName.mid(startIndex, endIndex - startIndex);
|
shortName = shortName.mid(startIndex, endIndex - startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DISABLE_QML
|
||||||
|
DependencyManager::get<ScriptEngines>()->loadScript(scriptFilenameOrURL);
|
||||||
|
#else
|
||||||
QString message = "Would you like to run this script:\n" + shortName;
|
QString message = "Would you like to run this script:\n" + shortName;
|
||||||
ModalDialogListener* dlg = OffscreenUi::asyncQuestion(getWindow(), "Run Script", message,
|
ModalDialogListener* dlg = OffscreenUi::asyncQuestion(getWindow(), "Run Script", message,
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
@ -6886,7 +6949,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
||||||
}
|
}
|
||||||
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7790,7 +7853,7 @@ float Application::getRenderResolutionScale() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::notifyPacketVersionMismatch() {
|
void Application::notifyPacketVersionMismatch() {
|
||||||
if (!_notifiedPacketVersionMismatchThisDomain) {
|
if (!_notifiedPacketVersionMismatchThisDomain && !isInterstitialMode()) {
|
||||||
_notifiedPacketVersionMismatchThisDomain = true;
|
_notifiedPacketVersionMismatchThisDomain = true;
|
||||||
|
|
||||||
QString message = "The location you are visiting is running an incompatible server version.\n";
|
QString message = "The location you are visiting is running an incompatible server version.\n";
|
||||||
|
|
|
@ -224,6 +224,7 @@ public:
|
||||||
void setHmdTabletBecomesToolbarSetting(bool value);
|
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||||
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
||||||
void setPreferStylusOverLaser(bool value);
|
void setPreferStylusOverLaser(bool value);
|
||||||
|
|
||||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||||
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||||
bool getPreferAvatarFingerOverStylus() { return false; }
|
bool getPreferAvatarFingerOverStylus() { return false; }
|
||||||
|
@ -304,6 +305,7 @@ public:
|
||||||
void saveNextPhysicsStats(QString filename);
|
void saveNextPhysicsStats(QString filename);
|
||||||
|
|
||||||
bool isServerlessMode() const;
|
bool isServerlessMode() const;
|
||||||
|
bool isInterstitialMode() const { return _interstitialMode; }
|
||||||
|
|
||||||
void replaceDomainContent(const QString& url);
|
void replaceDomainContent(const QString& url);
|
||||||
|
|
||||||
|
@ -331,6 +333,8 @@ signals:
|
||||||
|
|
||||||
void uploadRequest(QString path);
|
void uploadRequest(QString path);
|
||||||
|
|
||||||
|
void loginDialogPoppedUp();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
||||||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
||||||
|
@ -338,6 +342,7 @@ public slots:
|
||||||
bool importEntities(const QString& url);
|
bool importEntities(const QString& url);
|
||||||
void updateThreadPoolCount() const;
|
void updateThreadPoolCount() const;
|
||||||
void updateSystemTabletMode();
|
void updateSystemTabletMode();
|
||||||
|
void goToErrorDomainURL(QUrl errorDomainURL);
|
||||||
|
|
||||||
Q_INVOKABLE void loadDialog();
|
Q_INVOKABLE void loadDialog();
|
||||||
Q_INVOKABLE void loadScriptURLDialog() const;
|
Q_INVOKABLE void loadScriptURLDialog() const;
|
||||||
|
@ -426,7 +431,8 @@ public slots:
|
||||||
void setPreferredCursor(const QString& cursor);
|
void setPreferredCursor(const QString& cursor);
|
||||||
|
|
||||||
void setIsServerlessMode(bool serverlessDomain);
|
void setIsServerlessMode(bool serverlessDomain);
|
||||||
void loadServerlessDomain(QUrl domainURL);
|
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
|
||||||
|
void setIsInterstitialMode(bool interstialMode);
|
||||||
|
|
||||||
void updateVerboseLogging();
|
void updateVerboseLogging();
|
||||||
|
|
||||||
|
@ -437,7 +443,6 @@ private slots:
|
||||||
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
||||||
void showDesktop();
|
void showDesktop();
|
||||||
void clearDomainOctreeDetails();
|
void clearDomainOctreeDetails();
|
||||||
void clearDomainAvatars();
|
|
||||||
void onAboutToQuit();
|
void onAboutToQuit();
|
||||||
void onPresent(quint32 frameCount);
|
void onPresent(quint32 frameCount);
|
||||||
|
|
||||||
|
@ -626,6 +631,7 @@ private:
|
||||||
QHash<int, QKeyEvent> _keysPressed;
|
QHash<int, QKeyEvent> _keysPressed;
|
||||||
|
|
||||||
bool _enableProcessOctreeThread;
|
bool _enableProcessOctreeThread;
|
||||||
|
bool _interstitialMode { false };
|
||||||
|
|
||||||
OctreePacketProcessor _octreeProcessor;
|
OctreePacketProcessor _octreeProcessor;
|
||||||
EntityEditPacketSender _entityEditSender;
|
EntityEditPacketSender _entityEditSender;
|
||||||
|
|
|
@ -11,16 +11,18 @@
|
||||||
|
|
||||||
#include "ConnectionMonitor.h"
|
#include "ConnectionMonitor.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "ui/DialogsManager.h"
|
#include "ui/DialogsManager.h"
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <DomainHandler.h>
|
#include <DomainHandler.h>
|
||||||
|
#include <AddressManager.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
|
|
||||||
// Because the connection monitor is created at startup, the time we wait on initial load
|
// Because the connection monitor is created at startup, the time we wait on initial load
|
||||||
// should be longer to allow the application to initialize.
|
// should be longer to allow the application to initialize.
|
||||||
static const int ON_INITIAL_LOAD_DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 10000;
|
static const int ON_INITIAL_LOAD_REDIRECT_AFTER_DISCONNECTED_FOR_X_MS = 10000;
|
||||||
static const int DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
static const int REDIRECT_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
||||||
|
|
||||||
void ConnectionMonitor::init() {
|
void ConnectionMonitor::init() {
|
||||||
// Connect to domain disconnected message
|
// Connect to domain disconnected message
|
||||||
|
@ -30,23 +32,25 @@ void ConnectionMonitor::init() {
|
||||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::startTimer);
|
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::startTimer);
|
||||||
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::stopTimer);
|
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::stopTimer);
|
||||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ConnectionMonitor::stopTimer);
|
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ConnectionMonitor::stopTimer);
|
||||||
|
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &ConnectionMonitor::stopTimer);
|
||||||
|
connect(this, &ConnectionMonitor::setRedirectErrorState, &domainHandler, &DomainHandler::setRedirectErrorState);
|
||||||
|
|
||||||
_timer.setSingleShot(true);
|
_timer.setSingleShot(true);
|
||||||
if (!domainHandler.isConnected()) {
|
if (!domainHandler.isConnected()) {
|
||||||
_timer.start(ON_INITIAL_LOAD_DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
_timer.start(ON_INITIAL_LOAD_REDIRECT_AFTER_DISCONNECTED_FOR_X_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(&_timer, &QTimer::timeout, this, []() {
|
connect(&_timer, &QTimer::timeout, this, [this]() {
|
||||||
qDebug() << "ConnectionMonitor: Showing connection failure window";
|
qDebug() << "ConnectionMonitor: Redirecting to 404 error domain";
|
||||||
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(true);
|
// set in a timeout error
|
||||||
|
emit setRedirectErrorState(REDIRECT_HIFI_ADDRESS, 5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionMonitor::startTimer() {
|
void ConnectionMonitor::startTimer() {
|
||||||
_timer.start(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
_timer.start(REDIRECT_AFTER_DISCONNECTED_FOR_X_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionMonitor::stopTimer() {
|
void ConnectionMonitor::stopTimer() {
|
||||||
_timer.stop();
|
_timer.stop();
|
||||||
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(false);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
class QUrl;
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
class ConnectionMonitor : public QObject {
|
class ConnectionMonitor : public QObject {
|
||||||
|
@ -22,6 +23,9 @@ class ConnectionMonitor : public QObject {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void setRedirectErrorState(QUrl errorURL, int reasonCode);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void startTimer();
|
void startTimer();
|
||||||
void stopTimer();
|
void stopTimer();
|
||||||
|
|
|
@ -45,10 +45,11 @@ const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.08f; // sec
|
||||||
const float LOD_BATCH_TO_PRESENT_CUSHION_TIME = 3.0f; // msec
|
const float LOD_BATCH_TO_PRESENT_CUSHION_TIME = 3.0f; // msec
|
||||||
|
|
||||||
void LODManager::setRenderTimes(float presentTime, float engineRunTime, float batchTime, float gpuTime) {
|
void LODManager::setRenderTimes(float presentTime, float engineRunTime, float batchTime, float gpuTime) {
|
||||||
_presentTime = presentTime;
|
// Make sure the sampled time are positive values
|
||||||
_engineRunTime = engineRunTime;
|
_presentTime = std::max(0.0f, presentTime);
|
||||||
_batchTime = batchTime;
|
_engineRunTime = std::max(0.0f, engineRunTime);
|
||||||
_gpuTime = gpuTime;
|
_batchTime = std::max(0.0f, batchTime);
|
||||||
|
_gpuTime = std::max(0.0f, gpuTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LODManager::autoAdjustLOD(float realTimeDelta) {
|
void LODManager::autoAdjustLOD(float realTimeDelta) {
|
||||||
|
@ -64,16 +65,29 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
|
||||||
auto presentTime = (_presentTime > _batchTime + LOD_BATCH_TO_PRESENT_CUSHION_TIME ? _batchTime + LOD_BATCH_TO_PRESENT_CUSHION_TIME : _presentTime);
|
auto presentTime = (_presentTime > _batchTime + LOD_BATCH_TO_PRESENT_CUSHION_TIME ? _batchTime + LOD_BATCH_TO_PRESENT_CUSHION_TIME : _presentTime);
|
||||||
float maxRenderTime = glm::max(glm::max(presentTime, _engineRunTime), _gpuTime);
|
float maxRenderTime = glm::max(glm::max(presentTime, _engineRunTime), _gpuTime);
|
||||||
|
|
||||||
// compute time-weighted running average maxRenderTime
|
// maxRenderTime must be a realistic valid duration in order for the regulation to work correctly.
|
||||||
// Note: we MUST clamp the blend to 1.0 for stability
|
// We make sure it s a non zero positive value (1.0ms) under 1 sec
|
||||||
|
maxRenderTime = std::max(1.0f, std::min(maxRenderTime, (float)MSECS_PER_SECOND));
|
||||||
|
|
||||||
|
// realTimeDelta must be a realistic valid duration in order for the regulation to work correctly.
|
||||||
|
// We make sure it a positive value under 1 sec
|
||||||
|
// note that if real time delta is very small we will early exit to avoid division by zero
|
||||||
|
realTimeDelta = std::max(0.0f, std::min(realTimeDelta, 1.0f));
|
||||||
|
|
||||||
|
// compute time-weighted running average render time (now and smooth)
|
||||||
|
// We MUST clamp the blend between 0.0 and 1.0 for stability
|
||||||
float nowBlend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
|
float nowBlend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
|
||||||
_nowRenderTime = (1.0f - nowBlend) * _nowRenderTime + nowBlend * maxRenderTime; // msec
|
|
||||||
|
|
||||||
float smoothBlend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE * _smoothScale) ? realTimeDelta / (LOD_ADJUST_RUNNING_AVG_TIMESCALE * _smoothScale) : 1.0f;
|
float smoothBlend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE * _smoothScale) ? realTimeDelta / (LOD_ADJUST_RUNNING_AVG_TIMESCALE * _smoothScale) : 1.0f;
|
||||||
_smoothRenderTime = (1.0f - smoothBlend) * _smoothRenderTime + smoothBlend * maxRenderTime; // msec
|
|
||||||
|
|
||||||
if (!_automaticLODAdjust || _nowRenderTime == 0.0f || _smoothRenderTime == 0.0f) {
|
//Evaluate the running averages for the render time
|
||||||
// early exit
|
// We must sanity check for the output average evaluated to be in a valid range to avoid issues
|
||||||
|
_nowRenderTime = (1.0f - nowBlend) * _nowRenderTime + nowBlend * maxRenderTime; // msec
|
||||||
|
_nowRenderTime = std::max(0.0f, std::min(_nowRenderTime, (float)MSECS_PER_SECOND));
|
||||||
|
_smoothRenderTime = (1.0f - smoothBlend) * _smoothRenderTime + smoothBlend * maxRenderTime; // msec
|
||||||
|
_smoothRenderTime = std::max(0.0f, std::min(_smoothRenderTime, (float)MSECS_PER_SECOND));
|
||||||
|
|
||||||
|
// Early exit if not regulating or if the simulation or render times don't matter
|
||||||
|
if (!_automaticLODAdjust || realTimeDelta <= 0.0f || _nowRenderTime <= 0.0f || _smoothRenderTime <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +144,8 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
|
||||||
glm::clamp(integral, -1.0f, 1.0f);
|
glm::clamp(integral, -1.0f, 1.0f);
|
||||||
|
|
||||||
// Compute derivative
|
// Compute derivative
|
||||||
auto derivative = (error - previous_error) / dt;
|
// dt is never zero because realTimeDelta would have early exit above, but if it ever was let's zero the derivative term
|
||||||
|
auto derivative = (dt <= 0.0f ? 0.0f : (error - previous_error) / dt);
|
||||||
|
|
||||||
// remember history
|
// remember history
|
||||||
_pidHistory.x = error;
|
_pidHistory.x = error;
|
||||||
|
|
|
@ -255,7 +255,7 @@ Menu::Menu() {
|
||||||
connect(action, &QAction::triggered, [] {
|
connect(action, &QAction::triggered, [] {
|
||||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||||
tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml");
|
tablet->pushOntoStack("hifi/tablet/ControllerSettings.qml");
|
||||||
|
|
||||||
if (!hmd->getShouldShowTablet()) {
|
if (!hmd->getShouldShowTablet()) {
|
||||||
hmd->toggleShouldShowTablet();
|
hmd->toggleShouldShowTablet();
|
||||||
|
|
|
@ -196,7 +196,7 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
quint64 dt = now - _lastSendAvatarDataTime;
|
quint64 dt = now - _lastSendAvatarDataTime;
|
||||||
|
|
||||||
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS) {
|
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused) {
|
||||||
// send head/hand data to the avatar mixer and voxel server
|
// send head/hand data to the avatar mixer and voxel server
|
||||||
PerformanceTimer perfTimer("send");
|
PerformanceTimer perfTimer("send");
|
||||||
_myAvatar->sendAvatarDataPacket();
|
_myAvatar->sendAvatarDataPacket();
|
||||||
|
@ -214,6 +214,16 @@ float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& ra
|
||||||
return avatar ? avatar->getDataRate(rateName) : 0.0f;
|
return avatar ? avatar->getDataRate(rateName) : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarManager::setMyAvatarDataPacketsPaused(bool pause) {
|
||||||
|
if (_myAvatarDataPacketsPaused != pause) {
|
||||||
|
_myAvatarDataPacketsPaused = pause;
|
||||||
|
|
||||||
|
if (!_myAvatarDataPacketsPaused) {
|
||||||
|
_myAvatar->sendAvatarDataPacket(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) const {
|
float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) const {
|
||||||
auto avatar = getAvatarBySessionID(sessionID);
|
auto avatar = getAvatarBySessionID(sessionID);
|
||||||
return avatar ? avatar->getUpdateRate(rateName) : 0.0f;
|
return avatar ? avatar->getUpdateRate(rateName) : 0.0f;
|
||||||
|
@ -225,29 +235,29 @@ float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QStri
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarManager::updateOtherAvatars(float deltaTime) {
|
void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
// lock the hash for read to check the size
|
{
|
||||||
QReadLocker lock(&_hashLock);
|
// lock the hash for read to check the size
|
||||||
if (_avatarHash.size() < 2 && _avatarsToFade.isEmpty()) {
|
QReadLocker lock(&_hashLock);
|
||||||
return;
|
if (_avatarHash.size() < 2 && _avatarsToFade.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
PerformanceTimer perfTimer("otherAvatars");
|
PerformanceTimer perfTimer("otherAvatars");
|
||||||
|
|
||||||
class SortableAvatar: public PrioritySortUtil::Sortable {
|
class SortableAvatar: public PrioritySortUtil::Sortable {
|
||||||
public:
|
public:
|
||||||
SortableAvatar() = delete;
|
SortableAvatar() = delete;
|
||||||
SortableAvatar(const AvatarSharedPointer& avatar) : _avatar(avatar) {}
|
SortableAvatar(const std::shared_ptr<Avatar>& avatar) : _avatar(avatar) {}
|
||||||
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
||||||
float getRadius() const override { return std::static_pointer_cast<Avatar>(_avatar)->getBoundingRadius(); }
|
float getRadius() const override { return _avatar->getBoundingRadius(); }
|
||||||
uint64_t getTimestamp() const override { return std::static_pointer_cast<Avatar>(_avatar)->getLastRenderUpdateTime(); }
|
uint64_t getTimestamp() const override { return _avatar->getLastRenderUpdateTime(); }
|
||||||
AvatarSharedPointer getAvatar() const { return _avatar; }
|
std::shared_ptr<Avatar> getAvatar() const { return _avatar; }
|
||||||
private:
|
private:
|
||||||
AvatarSharedPointer _avatar;
|
std::shared_ptr<Avatar> _avatar;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto avatarMap = getHashCopy();
|
auto avatarMap = getHashCopy();
|
||||||
AvatarHash::iterator itr = avatarMap.begin();
|
|
||||||
|
|
||||||
const auto& views = qApp->getConicalViews();
|
const auto& views = qApp->getConicalViews();
|
||||||
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(views,
|
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(views,
|
||||||
|
@ -256,22 +266,24 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
AvatarData::_avatarSortCoefficientAge);
|
AvatarData::_avatarSortCoefficientAge);
|
||||||
sortedAvatars.reserve(avatarMap.size() - 1); // don't include MyAvatar
|
sortedAvatars.reserve(avatarMap.size() - 1); // don't include MyAvatar
|
||||||
|
|
||||||
// sort
|
// Build vector and compute priorities
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
AvatarHash::iterator itr = avatarMap.begin();
|
||||||
while (itr != avatarMap.end()) {
|
while (itr != avatarMap.end()) {
|
||||||
const auto& avatar = std::static_pointer_cast<Avatar>(*itr);
|
const auto& avatar = std::static_pointer_cast<Avatar>(*itr);
|
||||||
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
||||||
// DO NOT update or fade out uninitialized Avatars
|
// DO NOT update or fade out uninitialized Avatars
|
||||||
if (avatar != _myAvatar && avatar->isInitialized()) {
|
if (avatar != _myAvatar && avatar->isInitialized() && !nodeList->isPersonalMutingNode(avatar->getID())) {
|
||||||
sortedAvatars.push(SortableAvatar(avatar));
|
sortedAvatars.push(SortableAvatar(avatar));
|
||||||
}
|
}
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
|
// Sort
|
||||||
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
||||||
|
|
||||||
// process in sorted order
|
// process in sorted order
|
||||||
uint64_t startTime = usecTimestampNow();
|
uint64_t startTime = usecTimestampNow();
|
||||||
const uint64_t UPDATE_BUDGET = 2000; // usec
|
uint64_t updateExpiry = startTime + MAX_UPDATE_AVATARS_TIME_BUDGET;
|
||||||
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
|
|
||||||
int numAvatarsUpdated = 0;
|
int numAvatarsUpdated = 0;
|
||||||
int numAVatarsNotUpdated = 0;
|
int numAVatarsNotUpdated = 0;
|
||||||
|
|
||||||
|
@ -290,18 +302,12 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
avatar->updateOrbPosition();
|
avatar->updateOrbPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
|
||||||
if (ignoring) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for ALL avatars...
|
// for ALL avatars...
|
||||||
if (_shouldRender) {
|
if (_shouldRender) {
|
||||||
avatar->ensureInScene(avatar, qApp->getMain3DScene());
|
avatar->ensureInScene(avatar, qApp->getMain3DScene());
|
||||||
}
|
}
|
||||||
avatar->animateScaleChanges(deltaTime);
|
avatar->animateScaleChanges(deltaTime);
|
||||||
|
|
||||||
const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY;
|
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
if (now < updateExpiry) {
|
if (now < updateExpiry) {
|
||||||
// we're within budget
|
// we're within budget
|
||||||
|
@ -332,7 +338,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
// no time to simulate, but we take the time to count how many were tragically missed
|
// no time to simulate, but we take the time to count how many were tragically missed
|
||||||
while (it != sortedAvatarVector.end()) {
|
while (it != sortedAvatarVector.end()) {
|
||||||
const SortableAvatar& newSortData = *it;
|
const SortableAvatar& newSortData = *it;
|
||||||
const auto newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
|
const auto& newAvatar = newSortData.getAvatar();
|
||||||
bool inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
bool inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||||
// Once we reach an avatar that's not in view, all avatars after it will also be out of view
|
// Once we reach an avatar that's not in view, all avatars after it will also be out of view
|
||||||
if (!inView) {
|
if (!inView) {
|
||||||
|
@ -502,6 +508,11 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
|
||||||
avatar->die();
|
avatar->die();
|
||||||
queuePhysicsChange(avatar);
|
queuePhysicsChange(avatar);
|
||||||
|
|
||||||
|
// remove this avatar's entities from the tree now, if we wait (as we did previously) for this Avatar's destructor
|
||||||
|
// it might not fire until after we create a new instance for the same remote avatar, which creates a race
|
||||||
|
// on the creation of entities for that avatar instance and the deletion of entities for this instance
|
||||||
|
avatar->removeAvatarEntitiesFromTree();
|
||||||
|
|
||||||
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
||||||
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
|
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
|
||||||
} else if (removalReason == KillAvatarReason::AvatarDisconnected) {
|
} else if (removalReason == KillAvatarReason::AvatarDisconnected) {
|
||||||
|
@ -871,13 +882,13 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
|
||||||
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
||||||
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
||||||
QJsonObject thisAvatarPalData;
|
QJsonObject thisAvatarPalData;
|
||||||
|
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
|
||||||
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
||||||
currentSessionUUID = "";
|
currentSessionUUID = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
||||||
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
||||||
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
||||||
|
|
|
@ -91,9 +91,11 @@ public:
|
||||||
void updateOtherAvatars(float deltaTime);
|
void updateOtherAvatars(float deltaTime);
|
||||||
void sendIdentityRequest(const QUuid& avatarID) const;
|
void sendIdentityRequest(const QUuid& avatarID) const;
|
||||||
|
|
||||||
|
void setMyAvatarDataPacketsPaused(bool puase);
|
||||||
|
|
||||||
void postUpdate(float deltaTime, const render::ScenePointer& scene);
|
void postUpdate(float deltaTime, const render::ScenePointer& scene);
|
||||||
|
|
||||||
void clearOtherAvatars();
|
void clearOtherAvatars() override;
|
||||||
void deleteAllAvatars();
|
void deleteAllAvatars();
|
||||||
|
|
||||||
void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates);
|
void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates);
|
||||||
|
@ -229,6 +231,7 @@ private:
|
||||||
int _numAvatarsNotUpdated { 0 };
|
int _numAvatarsNotUpdated { 0 };
|
||||||
float _avatarSimulationTime { 0.0f };
|
float _avatarSimulationTime { 0.0f };
|
||||||
bool _shouldRender { true };
|
bool _shouldRender { true };
|
||||||
|
bool _myAvatarDataPacketsPaused { false };
|
||||||
mutable int _identityRequestsSent { 0 };
|
mutable int _identityRequestsSent { 0 };
|
||||||
|
|
||||||
mutable std::mutex _spaceLock;
|
mutable std::mutex _spaceLock;
|
||||||
|
|
|
@ -113,6 +113,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
_recentModeReadings(MODE_READINGS_RING_BUFFER_SIZE),
|
_recentModeReadings(MODE_READINGS_RING_BUFFER_SIZE),
|
||||||
_bodySensorMatrix(),
|
_bodySensorMatrix(),
|
||||||
_goToPending(false),
|
_goToPending(false),
|
||||||
|
_goToSafe(true),
|
||||||
_goToPosition(),
|
_goToPosition(),
|
||||||
_goToOrientation(),
|
_goToOrientation(),
|
||||||
_prevShouldDrawHead(true),
|
_prevShouldDrawHead(true),
|
||||||
|
@ -148,7 +149,8 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
});
|
});
|
||||||
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
|
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
|
||||||
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
|
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
|
||||||
|
connect(&_skeletonModel->getRig(), &Rig::onLoadComplete, this, &MyAvatar::updateCollisionCapsuleCache);
|
||||||
|
connect(this, &MyAvatar::sensorToWorldScaleChanged, this, &MyAvatar::updateCollisionCapsuleCache);
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
_skeletonModel->flagAsCauterized();
|
_skeletonModel->flagAsCauterized();
|
||||||
|
|
||||||
|
@ -254,6 +256,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete()));
|
connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete()));
|
||||||
|
|
||||||
_characterController.setDensity(_density);
|
_characterController.setDensity(_density);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,7 +512,9 @@ void MyAvatar::update(float deltaTime) {
|
||||||
if (_physicsSafetyPending && qApp->isPhysicsEnabled() && _characterController.isEnabledAndReady()) {
|
if (_physicsSafetyPending && qApp->isPhysicsEnabled() && _characterController.isEnabledAndReady()) {
|
||||||
// When needed and ready, arrange to check and fix.
|
// When needed and ready, arrange to check and fix.
|
||||||
_physicsSafetyPending = false;
|
_physicsSafetyPending = false;
|
||||||
safeLanding(_goToPosition); // no-op if already safe
|
if (_goToSafe) {
|
||||||
|
safeLanding(_goToPosition); // no-op if already safe
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Head* head = getHead();
|
Head* head = getHead();
|
||||||
|
@ -3019,7 +3024,7 @@ void MyAvatar::goToFeetLocation(const glm::vec3& newPosition,
|
||||||
|
|
||||||
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||||
bool hasOrientation, const glm::quat& newOrientation,
|
bool hasOrientation, const glm::quat& newOrientation,
|
||||||
bool shouldFaceLocation) {
|
bool shouldFaceLocation, bool withSafeLanding) {
|
||||||
|
|
||||||
// Most cases of going to a place or user go through this now. Some possible improvements to think about in the future:
|
// Most cases of going to a place or user go through this now. Some possible improvements to think about in the future:
|
||||||
// - It would be nice if this used the same teleport steps and smoothing as in the teleport.js script, as long as it
|
// - It would be nice if this used the same teleport steps and smoothing as in the teleport.js script, as long as it
|
||||||
|
@ -3039,6 +3044,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||||
|
|
||||||
_goToPending = true;
|
_goToPending = true;
|
||||||
_goToPosition = newPosition;
|
_goToPosition = newPosition;
|
||||||
|
_goToSafe = withSafeLanding;
|
||||||
_goToOrientation = getWorldOrientation();
|
_goToOrientation = getWorldOrientation();
|
||||||
if (hasOrientation) {
|
if (hasOrientation) {
|
||||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "
|
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "
|
||||||
|
@ -3311,6 +3317,22 @@ bool MyAvatar::getCollisionsEnabled() {
|
||||||
return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS;
|
return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::updateCollisionCapsuleCache() {
|
||||||
|
glm::vec3 start, end;
|
||||||
|
float radius;
|
||||||
|
getCapsule(start, end, radius);
|
||||||
|
QVariantMap capsule;
|
||||||
|
capsule["start"] = vec3toVariant(start);
|
||||||
|
capsule["end"] = vec3toVariant(end);
|
||||||
|
capsule["radius"] = QVariant(radius);
|
||||||
|
_collisionCapsuleCache.set(capsule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// thread safe
|
||||||
|
QVariantMap MyAvatar::getCollisionCapsule() const {
|
||||||
|
return _collisionCapsuleCache.get();
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::setCharacterControllerEnabled(bool enabled) {
|
void MyAvatar::setCharacterControllerEnabled(bool enabled) {
|
||||||
qCDebug(interfaceapp) << "MyAvatar.characterControllerEnabled is deprecated. Use MyAvatar.collisionsEnabled instead.";
|
qCDebug(interfaceapp) << "MyAvatar.characterControllerEnabled is deprecated. Use MyAvatar.collisionsEnabled instead.";
|
||||||
setCollisionsEnabled(enabled);
|
setCollisionsEnabled(enabled);
|
||||||
|
|
|
@ -1017,6 +1017,12 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE bool getCollisionsEnabled();
|
Q_INVOKABLE bool getCollisionsEnabled();
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @function MyAvatar.getCollisionCapsule
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE QVariantMap getCollisionCapsule() const;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function MyAvatar.setCharacterControllerEnabled
|
* @function MyAvatar.setCharacterControllerEnabled
|
||||||
* @param {boolean} enabled
|
* @param {boolean} enabled
|
||||||
|
@ -1182,11 +1188,12 @@ public slots:
|
||||||
* @param {boolean} [hasOrientation=false] - Set to <code>true</code> to set the orientation of the avatar.
|
* @param {boolean} [hasOrientation=false] - Set to <code>true</code> to set the orientation of the avatar.
|
||||||
* @param {Quat} [orientation=Quat.IDENTITY] - The new orientation for the avatar.
|
* @param {Quat} [orientation=Quat.IDENTITY] - The new orientation for the avatar.
|
||||||
* @param {boolean} [shouldFaceLocation=false] - Set to <code>true</code> to position the avatar a short distance away from
|
* @param {boolean} [shouldFaceLocation=false] - Set to <code>true</code> to position the avatar a short distance away from
|
||||||
|
* @param {boolean} [withSafeLanding=true] - Set to <code>false</code> MyAvatar::safeLanding will not be called (used when teleporting).
|
||||||
* the new position and orientate the avatar to face the position.
|
* the new position and orientate the avatar to face the position.
|
||||||
*/
|
*/
|
||||||
void goToLocation(const glm::vec3& newPosition,
|
void goToLocation(const glm::vec3& newPosition,
|
||||||
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
|
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
|
||||||
bool shouldFaceLocation = false);
|
bool shouldFaceLocation = false, bool withSafeLanding = true);
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function MyAvatar.goToLocation
|
* @function MyAvatar.goToLocation
|
||||||
* @param {object} properties
|
* @param {object} properties
|
||||||
|
@ -1500,6 +1507,7 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void leaveDomain();
|
void leaveDomain();
|
||||||
|
void updateCollisionCapsuleCache();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
|
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
|
||||||
|
@ -1724,6 +1732,7 @@ private:
|
||||||
|
|
||||||
bool _goToPending { false };
|
bool _goToPending { false };
|
||||||
bool _physicsSafetyPending { false };
|
bool _physicsSafetyPending { false };
|
||||||
|
bool _goToSafe { true };
|
||||||
glm::vec3 _goToPosition;
|
glm::vec3 _goToPosition;
|
||||||
glm::quat _goToOrientation;
|
glm::quat _goToOrientation;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,25 @@
|
||||||
|
|
||||||
#include "AvatarMotionState.h"
|
#include "AvatarMotionState.h"
|
||||||
|
|
||||||
|
static xColor getLoadingOrbColor(Avatar::LoadingStatus loadingStatus) {
|
||||||
|
|
||||||
|
const xColor NO_MODEL_COLOR(0xe3, 0xe3, 0xe3);
|
||||||
|
const xColor LOAD_MODEL_COLOR(0xef, 0x93, 0xd1);
|
||||||
|
const xColor LOAD_SUCCESS_COLOR(0x1f, 0xc6, 0xa6);
|
||||||
|
const xColor LOAD_FAILURE_COLOR(0xc6, 0x21, 0x47);
|
||||||
|
switch (loadingStatus) {
|
||||||
|
case Avatar::LoadingStatus::NoModel:
|
||||||
|
return NO_MODEL_COLOR;
|
||||||
|
case Avatar::LoadingStatus::LoadModel:
|
||||||
|
return LOAD_MODEL_COLOR;
|
||||||
|
case Avatar::LoadingStatus::LoadSuccess:
|
||||||
|
return LOAD_SUCCESS_COLOR;
|
||||||
|
case Avatar::LoadingStatus::LoadFailure:
|
||||||
|
default:
|
||||||
|
return LOAD_FAILURE_COLOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
||||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||||
_headData = new Head(this);
|
_headData = new Head(this);
|
||||||
|
@ -48,7 +67,7 @@ void OtherAvatar::createOrb() {
|
||||||
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
|
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
|
||||||
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
|
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
|
||||||
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
|
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
|
||||||
_otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF });
|
_otherAvatarOrbMeshPlaceholder->setColor(getLoadingOrbColor(_loadingStatus));
|
||||||
_otherAvatarOrbMeshPlaceholder->setIsSolid(false);
|
_otherAvatarOrbMeshPlaceholder->setIsSolid(false);
|
||||||
_otherAvatarOrbMeshPlaceholder->setPulseMin(0.5);
|
_otherAvatarOrbMeshPlaceholder->setPulseMin(0.5);
|
||||||
_otherAvatarOrbMeshPlaceholder->setPulseMax(1.0);
|
_otherAvatarOrbMeshPlaceholder->setPulseMax(1.0);
|
||||||
|
@ -64,6 +83,13 @@ void OtherAvatar::createOrb() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OtherAvatar::indicateLoadingStatus(LoadingStatus loadingStatus) {
|
||||||
|
Avatar::indicateLoadingStatus(loadingStatus);
|
||||||
|
if (_otherAvatarOrbMeshPlaceholder) {
|
||||||
|
_otherAvatarOrbMeshPlaceholder->setColor(getLoadingOrbColor(_loadingStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OtherAvatar::setSpaceIndex(int32_t index) {
|
void OtherAvatar::setSpaceIndex(int32_t index) {
|
||||||
assert(_spaceIndex == -1);
|
assert(_spaceIndex == -1);
|
||||||
_spaceIndex = index;
|
_spaceIndex = index;
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
|
|
||||||
virtual void instantiableAvatar() override { };
|
virtual void instantiableAvatar() override { };
|
||||||
virtual void createOrb() override;
|
virtual void createOrb() override;
|
||||||
|
virtual void indicateLoadingStatus(LoadingStatus loadingStatus) override;
|
||||||
void updateOrbPosition();
|
void updateOrbPosition();
|
||||||
void removeOrb();
|
void removeOrb();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "SceneScriptingInterface.h"
|
#include "SceneScriptingInterface.h"
|
||||||
#include "SafeLanding.h"
|
|
||||||
|
|
||||||
OctreePacketProcessor::OctreePacketProcessor():
|
OctreePacketProcessor::OctreePacketProcessor():
|
||||||
_safeLanding(new SafeLanding())
|
_safeLanding(new SafeLanding())
|
||||||
|
@ -133,7 +132,3 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
|
||||||
void OctreePacketProcessor::startEntitySequence() {
|
void OctreePacketProcessor::startEntitySequence() {
|
||||||
_safeLanding->startEntitySequence(qApp->getEntities());
|
_safeLanding->startEntitySequence(qApp->getEntities());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OctreePacketProcessor::isLoadSequenceComplete() const {
|
|
||||||
return _safeLanding->isLoadSequenceComplete();
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <ReceivedPacketProcessor.h>
|
#include <ReceivedPacketProcessor.h>
|
||||||
#include <ReceivedMessage.h>
|
#include <ReceivedMessage.h>
|
||||||
|
|
||||||
class SafeLanding;
|
#include "SafeLanding.h"
|
||||||
|
|
||||||
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
|
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
|
||||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||||
|
@ -26,7 +26,8 @@ public:
|
||||||
~OctreePacketProcessor();
|
~OctreePacketProcessor();
|
||||||
|
|
||||||
void startEntitySequence();
|
void startEntitySequence();
|
||||||
bool isLoadSequenceComplete() const;
|
bool isLoadSequenceComplete() const { return _safeLanding->isLoadSequenceComplete(); }
|
||||||
|
float domainLoadingProgress() const { return _safeLanding->loadingProgressPercentage(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void packetVersionMismatch();
|
void packetVersionMismatch();
|
||||||
|
@ -40,4 +41,4 @@ private slots:
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<SafeLanding> _safeLanding;
|
std::unique_ptr<SafeLanding> _safeLanding;
|
||||||
};
|
};
|
||||||
#endif // hifi_OctreePacketProcessor_h
|
#endif // hifi_OctreePacketProcessor_h
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
#include "ModelEntityItem.h"
|
#include "ModelEntityItem.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
||||||
|
|
||||||
|
@ -53,6 +54,7 @@ void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityT
|
||||||
void SafeLanding::stopEntitySequence() {
|
void SafeLanding::stopEntitySequence() {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
_trackingEntities = false;
|
_trackingEntities = false;
|
||||||
|
_maxTrackedEntityCount = 0;
|
||||||
_initialStart = INVALID_SEQUENCE;
|
_initialStart = INVALID_SEQUENCE;
|
||||||
_initialEnd = INVALID_SEQUENCE;
|
_initialEnd = INVALID_SEQUENCE;
|
||||||
_trackedEntities.clear();
|
_trackedEntities.clear();
|
||||||
|
@ -64,20 +66,18 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
EntityItemPointer entity = _entityTree->findEntityByID(entityID);
|
EntityItemPointer entity = _entityTree->findEntityByID(entityID);
|
||||||
|
|
||||||
if (entity && !entity->getCollisionless()) {
|
if (entity) {
|
||||||
const auto& entityType = entity->getType();
|
|
||||||
if (entityType == EntityTypes::Model) {
|
_trackedEntities.emplace(entityID, entity);
|
||||||
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
|
int trackedEntityCount = (int)_trackedEntities.size();
|
||||||
static const std::set<ShapeType> downloadedCollisionTypes
|
|
||||||
{ SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, SHAPE_TYPE_SIMPLE_HULL };
|
if (trackedEntityCount > _maxTrackedEntityCount) {
|
||||||
bool hasAABox;
|
_maxTrackedEntityCount = trackedEntityCount;
|
||||||
entity->getAABox(hasAABox);
|
|
||||||
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
|
|
||||||
// Only track entities with downloaded collision bodies.
|
|
||||||
_trackedEntities.emplace(entityID, entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "Safe Landing: Null Entity: " << entityID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafeLanding::isLoadSequenceComplete() {
|
bool SafeLanding::isLoadSequenceComplete() {
|
||||||
if (isEntityPhysicsComplete() && isSequenceNumbersComplete()) {
|
if (isEntityLoadingComplete() && isSequenceNumbersComplete()) {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
_trackedEntities.clear();
|
_trackedEntities.clear();
|
||||||
_initialStart = INVALID_SEQUENCE;
|
_initialStart = INVALID_SEQUENCE;
|
||||||
|
@ -114,6 +114,15 @@ bool SafeLanding::isLoadSequenceComplete() {
|
||||||
return !_trackingEntities;
|
return !_trackingEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SafeLanding::loadingProgressPercentage() {
|
||||||
|
Locker lock(_lock);
|
||||||
|
if (_maxTrackedEntityCount > 0) {
|
||||||
|
return ((_maxTrackedEntityCount - _trackedEntities.size()) / (float)_maxTrackedEntityCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
bool SafeLanding::isSequenceNumbersComplete() {
|
bool SafeLanding::isSequenceNumbersComplete() {
|
||||||
if (_initialStart != INVALID_SEQUENCE) {
|
if (_initialStart != INVALID_SEQUENCE) {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
|
@ -132,17 +141,53 @@ bool SafeLanding::isSequenceNumbersComplete() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafeLanding::isEntityPhysicsComplete() {
|
bool isEntityPhysicsReady(const EntityItemPointer& entity) {
|
||||||
Locker lock(_lock);
|
if (entity && !entity->getCollisionless()) {
|
||||||
for (auto entityMapIter = _trackedEntities.begin(); entityMapIter != _trackedEntities.end(); ++entityMapIter) {
|
const auto& entityType = entity->getType();
|
||||||
auto entity = entityMapIter->second;
|
if (entityType == EntityTypes::Model) {
|
||||||
if (!entity->shouldBePhysical() || entity->isReadyToComputeShape()) {
|
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
|
||||||
entityMapIter = _trackedEntities.erase(entityMapIter);
|
static const std::set<ShapeType> downloadedCollisionTypes
|
||||||
if (entityMapIter == _trackedEntities.end()) {
|
{ SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, SHAPE_TYPE_SIMPLE_HULL };
|
||||||
break;
|
bool hasAABox;
|
||||||
|
entity->getAABox(hasAABox);
|
||||||
|
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
|
||||||
|
return (!entity->shouldBePhysical() || entity->isReadyToComputeShape());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SafeLanding::isEntityLoadingComplete() {
|
||||||
|
Locker lock(_lock);
|
||||||
|
|
||||||
|
|
||||||
|
auto entityTree = qApp->getEntities();
|
||||||
|
auto entityMapIter = _trackedEntities.begin();
|
||||||
|
|
||||||
|
while (entityMapIter != _trackedEntities.end()) {
|
||||||
|
auto entity = entityMapIter->second;
|
||||||
|
|
||||||
|
bool isVisuallyReady = true;
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
bool enableInterstitial = settings.value("enableIntersitialMode", false).toBool();
|
||||||
|
|
||||||
|
if (enableInterstitial) {
|
||||||
|
isVisuallyReady = (entity->isVisuallyReady() || !entityTree->renderableForEntityId(entityMapIter->first));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEntityPhysicsReady(entity) && isVisuallyReady) {
|
||||||
|
entityMapIter = _trackedEntities.erase(entityMapIter);
|
||||||
|
} else {
|
||||||
|
if (!isVisuallyReady) {
|
||||||
|
entity->requestRenderUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
entityMapIter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
return _trackedEntities.empty();
|
return _trackedEntities.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
|
|
||||||
#include "EntityItem.h"
|
#include "EntityItem.h"
|
||||||
|
#include "EntityDynamicInterface.h"
|
||||||
|
|
||||||
class EntityTreeRenderer;
|
class EntityTreeRenderer;
|
||||||
class EntityItemID;
|
class EntityItemID;
|
||||||
|
@ -29,6 +30,7 @@ public:
|
||||||
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
||||||
void noteReceivedsequenceNumber(int sequenceNumber);
|
void noteReceivedsequenceNumber(int sequenceNumber);
|
||||||
bool isLoadSequenceComplete();
|
bool isLoadSequenceComplete();
|
||||||
|
float loadingProgressPercentage();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addTrackedEntity(const EntityItemID& entityID);
|
void addTrackedEntity(const EntityItemID& entityID);
|
||||||
|
@ -37,7 +39,7 @@ private slots:
|
||||||
private:
|
private:
|
||||||
bool isSequenceNumbersComplete();
|
bool isSequenceNumbersComplete();
|
||||||
void debugDumpSequenceIDs() const;
|
void debugDumpSequenceIDs() const;
|
||||||
bool isEntityPhysicsComplete();
|
bool isEntityLoadingComplete();
|
||||||
|
|
||||||
std::mutex _lock;
|
std::mutex _lock;
|
||||||
using Locker = std::lock_guard<std::mutex>;
|
using Locker = std::lock_guard<std::mutex>;
|
||||||
|
@ -49,6 +51,7 @@ private:
|
||||||
static constexpr int INVALID_SEQUENCE = -1;
|
static constexpr int INVALID_SEQUENCE = -1;
|
||||||
int _initialStart { INVALID_SEQUENCE };
|
int _initialStart { INVALID_SEQUENCE };
|
||||||
int _initialEnd { INVALID_SEQUENCE };
|
int _initialEnd { INVALID_SEQUENCE };
|
||||||
|
int _maxTrackedEntityCount { 0 };
|
||||||
|
|
||||||
struct SequenceLessThan {
|
struct SequenceLessThan {
|
||||||
bool operator()(const int& a, const int& b) const;
|
bool operator()(const int& a, const int& b) const;
|
||||||
|
|
|
@ -51,6 +51,7 @@ void buildObjectIntersectionsMap(IntersectionType intersectionType, const std::v
|
||||||
QVariantMap collisionPointPair;
|
QVariantMap collisionPointPair;
|
||||||
collisionPointPair["pointOnPick"] = vec3toVariant(objectIntersection.testCollisionPoint);
|
collisionPointPair["pointOnPick"] = vec3toVariant(objectIntersection.testCollisionPoint);
|
||||||
collisionPointPair["pointOnObject"] = vec3toVariant(objectIntersection.foundCollisionPoint);
|
collisionPointPair["pointOnObject"] = vec3toVariant(objectIntersection.foundCollisionPoint);
|
||||||
|
collisionPointPair["normalOnPick"] = vec3toVariant(objectIntersection.collisionNormal);
|
||||||
|
|
||||||
collisionPointPairs[objectIntersection.foundID].append(collisionPointPair);
|
collisionPointPairs[objectIntersection.foundID].append(collisionPointPair);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +398,7 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi
|
||||||
}
|
}
|
||||||
getShapeInfoReady(pick);
|
getShapeInfoReady(pick);
|
||||||
|
|
||||||
auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold);
|
auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *_mathPick.shapeInfo, pick.transform, pick.collisionGroup, pick.threshold);
|
||||||
filterIntersections(entityIntersections);
|
filterIntersections(entityIntersections);
|
||||||
return std::make_shared<CollisionPickResult>(pick, entityIntersections, std::vector<ContactTestResult>());
|
return std::make_shared<CollisionPickResult>(pick, entityIntersections, std::vector<ContactTestResult>());
|
||||||
}
|
}
|
||||||
|
@ -413,13 +414,13 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi
|
||||||
}
|
}
|
||||||
getShapeInfoReady(pick);
|
getShapeInfoReady(pick);
|
||||||
|
|
||||||
auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold);
|
auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *_mathPick.shapeInfo, pick.transform, pick.collisionGroup, pick.threshold);
|
||||||
filterIntersections(avatarIntersections);
|
filterIntersections(avatarIntersections);
|
||||||
return std::make_shared<CollisionPickResult>(pick, std::vector<ContactTestResult>(), avatarIntersections);
|
return std::make_shared<CollisionPickResult>(pick, std::vector<ContactTestResult>(), avatarIntersections);
|
||||||
}
|
}
|
||||||
|
|
||||||
PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) {
|
PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) {
|
||||||
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
return std::make_shared<CollisionPickResult>(pick, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform CollisionPick::getResultTransform() const {
|
Transform CollisionPick::getResultTransform() const {
|
||||||
|
|
|
@ -70,6 +70,9 @@ protected:
|
||||||
CollisionRegion _mathPick;
|
CollisionRegion _mathPick;
|
||||||
PhysicsEnginePointer _physicsEngine;
|
PhysicsEnginePointer _physicsEngine;
|
||||||
QSharedPointer<GeometryResource> _cachedResource;
|
QSharedPointer<GeometryResource> _cachedResource;
|
||||||
|
|
||||||
|
// Options for what information to get from collision results
|
||||||
|
bool _includeNormals;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_CollisionPick_h
|
#endif // hifi_CollisionPick_h
|
|
@ -382,9 +382,8 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
|
||||||
|
|
||||||
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
|
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
|
||||||
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
|
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
state->setBlendFunction(false,
|
state->setBlendFunction(false,
|
||||||
|
@ -396,6 +395,7 @@ const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::get
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola_translucent);
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
state->setBlendFunction(true,
|
state->setBlendFunction(true,
|
||||||
|
|
|
@ -270,6 +270,8 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti
|
||||||
* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined.
|
* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined.
|
||||||
* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region.
|
* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region.
|
||||||
* The depth is measured in world space, but will scale with the parent if defined.
|
* The depth is measured in world space, but will scale with the parent if defined.
|
||||||
|
* @property {CollisionMask} [collisionGroup=8] - The type of object this collision pick collides as. Objects whose collision masks overlap with the pick's collision group
|
||||||
|
* will be considered colliding with the pick.
|
||||||
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay.
|
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay.
|
||||||
* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
|
* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
|
||||||
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
|
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
|
||||||
|
|
|
@ -167,6 +167,7 @@ public:
|
||||||
* @typedef {object} CollisionContact
|
* @typedef {object} CollisionContact
|
||||||
* @property {Vec3} pointOnPick A point representing a penetration of the object's surface into the volume of the pick, in world space.
|
* @property {Vec3} pointOnPick A point representing a penetration of the object's surface into the volume of the pick, in world space.
|
||||||
* @property {Vec3} pointOnObject A point representing a penetration of the pick's surface into the volume of the found object, in world space.
|
* @property {Vec3} pointOnObject A point representing a penetration of the pick's surface into the volume of the found object, in world space.
|
||||||
|
* @property {Vec3} normalOnPick The normalized vector pointing away from the pick, representing the direction of collision.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
|
|
@ -409,6 +409,10 @@ glm::vec2 WindowScriptingInterface::getDeviceSize() const {
|
||||||
return qApp->getDeviceSize();
|
return qApp->getDeviceSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WindowScriptingInterface::getLastDomainConnectionError() const {
|
||||||
|
return DependencyManager::get<NodeList>()->getDomainHandler().getLastDomainConnectionError();
|
||||||
|
}
|
||||||
|
|
||||||
int WindowScriptingInterface::getX() {
|
int WindowScriptingInterface::getX() {
|
||||||
return qApp->getWindow()->geometry().x();
|
return qApp->getWindow()->geometry().x();
|
||||||
}
|
}
|
||||||
|
@ -584,3 +588,8 @@ void WindowScriptingInterface::onMessageBoxSelected(int button) {
|
||||||
_messageBoxes.remove(id);
|
_messageBoxes.remove(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float WindowScriptingInterface::domainLoadingProgress() {
|
||||||
|
return qApp->getOctreePacketProcessor().domainLoadingProgress();
|
||||||
|
}
|
||||||
|
|
|
@ -491,6 +491,13 @@ public slots:
|
||||||
*/
|
*/
|
||||||
glm::vec2 getDeviceSize() const;
|
glm::vec2 getDeviceSize() const;
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Gets the last domain connection error when a connection is refused.
|
||||||
|
* @function Window.getLastDomainConnectionError
|
||||||
|
* @returns {Window.ConnectionRefusedReason} Integer number that enumerates the last domain connection refused.
|
||||||
|
*/
|
||||||
|
int getLastDomainConnectionError() const;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Open a non-modal message box that can have a variety of button combinations. See also,
|
* Open a non-modal message box that can have a variety of button combinations. See also,
|
||||||
* {@link Window.updateMessageBox|updateMessageBox} and {@link Window.closeMessageBox|closeMessageBox}.
|
* {@link Window.updateMessageBox|updateMessageBox} and {@link Window.closeMessageBox|closeMessageBox}.
|
||||||
|
@ -561,6 +568,8 @@ public slots:
|
||||||
*/
|
*/
|
||||||
void closeMessageBox(int id);
|
void closeMessageBox(int id);
|
||||||
|
|
||||||
|
float domainLoadingProgress();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onWindowGeometryChanged(const QRect& geometry);
|
void onWindowGeometryChanged(const QRect& geometry);
|
||||||
void onMessageBoxSelected(int button);
|
void onMessageBoxSelected(int button);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <plugins/PluginManager.h>
|
#include <plugins/PluginManager.h>
|
||||||
#include <plugins/SteamClientPlugin.h>
|
#include <plugins/SteamClientPlugin.h>
|
||||||
#include <ui/TabletScriptingInterface.h>
|
#include <ui/TabletScriptingInterface.h>
|
||||||
|
#include <UserActivityLogger.h>
|
||||||
|
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
#include "DependencyManager.h"
|
#include "DependencyManager.h"
|
||||||
|
@ -37,11 +38,19 @@ LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
|
||||||
connect(accountManager.data(), &AccountManager::loginFailed,
|
connect(accountManager.data(), &AccountManager::loginFailed,
|
||||||
this, &LoginDialog::handleLoginFailed);
|
this, &LoginDialog::handleLoginFailed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoginDialog::showWithSelection()
|
LoginDialog::~LoginDialog() {
|
||||||
{
|
Setting::Handle<bool> loginDialogPoppedUp{ "loginDialogPoppedUp", false };
|
||||||
|
if (loginDialogPoppedUp.get()) {
|
||||||
|
QJsonObject data;
|
||||||
|
data["action"] = "user opted out";
|
||||||
|
UserActivityLogger::getInstance().logAction("encourageLoginDialog", data);
|
||||||
|
}
|
||||||
|
loginDialogPoppedUp.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoginDialog::showWithSelection() {
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
@ -73,9 +82,7 @@ void LoginDialog::toggleAction() {
|
||||||
} else {
|
} else {
|
||||||
// change the menu item to login
|
// change the menu item to login
|
||||||
loginAction->setText("Login / Sign Up");
|
loginAction->setText("Login / Sign Up");
|
||||||
connection = connect(loginAction, &QAction::triggered, [] {
|
connection = connect(loginAction, &QAction::triggered, [] { LoginDialog::showWithSelection(); });
|
||||||
LoginDialog::showWithSelection();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +165,6 @@ void LoginDialog::createAccountFromStream(QString username) {
|
||||||
QJsonDocument(payload).toJson());
|
QJsonDocument(payload).toJson());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoginDialog::openUrl(const QString& url) const {
|
void LoginDialog::openUrl(const QString& url) const {
|
||||||
|
@ -200,25 +206,24 @@ void LoginDialog::createFailed(QNetworkReply* reply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoginDialog::signup(const QString& email, const QString& username, const QString& password) {
|
void LoginDialog::signup(const QString& email, const QString& username, const QString& password) {
|
||||||
|
|
||||||
JSONCallbackParameters callbackParams;
|
JSONCallbackParameters callbackParams;
|
||||||
callbackParams.callbackReceiver = this;
|
callbackParams.callbackReceiver = this;
|
||||||
callbackParams.jsonCallbackMethod = "signupCompleted";
|
callbackParams.jsonCallbackMethod = "signupCompleted";
|
||||||
callbackParams.errorCallbackMethod = "signupFailed";
|
callbackParams.errorCallbackMethod = "signupFailed";
|
||||||
|
|
||||||
QJsonObject payload;
|
QJsonObject payload;
|
||||||
|
|
||||||
QJsonObject userObject;
|
QJsonObject userObject;
|
||||||
userObject.insert("email", email);
|
userObject.insert("email", email);
|
||||||
userObject.insert("username", username);
|
userObject.insert("username", username);
|
||||||
userObject.insert("password", password);
|
userObject.insert("password", password);
|
||||||
|
|
||||||
payload.insert("user", userObject);
|
payload.insert("user", userObject);
|
||||||
|
|
||||||
static const QString API_SIGNUP_PATH = "api/v1/users";
|
static const QString API_SIGNUP_PATH = "api/v1/users";
|
||||||
|
|
||||||
qDebug() << "Sending a request to create an account for" << username;
|
qDebug() << "Sending a request to create an account for" << username;
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
accountManager->sendRequest(API_SIGNUP_PATH, AccountManagerAuth::None,
|
accountManager->sendRequest(API_SIGNUP_PATH, AccountManagerAuth::None,
|
||||||
QNetworkAccessManager::PostOperation, callbackParams,
|
QNetworkAccessManager::PostOperation, callbackParams,
|
||||||
|
@ -240,41 +245,37 @@ QString errorStringFromAPIObject(const QJsonValue& apiObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoginDialog::signupFailed(QNetworkReply* reply) {
|
void LoginDialog::signupFailed(QNetworkReply* reply) {
|
||||||
|
|
||||||
// parse the returned JSON to see what the problem was
|
// parse the returned JSON to see what the problem was
|
||||||
auto jsonResponse = QJsonDocument::fromJson(reply->readAll());
|
auto jsonResponse = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
|
||||||
static const QString RESPONSE_DATA_KEY = "data";
|
static const QString RESPONSE_DATA_KEY = "data";
|
||||||
|
|
||||||
auto dataJsonValue = jsonResponse.object()[RESPONSE_DATA_KEY];
|
auto dataJsonValue = jsonResponse.object()[RESPONSE_DATA_KEY];
|
||||||
|
|
||||||
if (dataJsonValue.isObject()) {
|
if (dataJsonValue.isObject()) {
|
||||||
auto dataObject = dataJsonValue.toObject();
|
auto dataObject = dataJsonValue.toObject();
|
||||||
|
|
||||||
static const QString EMAIL_DATA_KEY = "email";
|
static const QString EMAIL_DATA_KEY = "email";
|
||||||
static const QString USERNAME_DATA_KEY = "username";
|
static const QString USERNAME_DATA_KEY = "username";
|
||||||
static const QString PASSWORD_DATA_KEY = "password";
|
static const QString PASSWORD_DATA_KEY = "password";
|
||||||
|
|
||||||
QStringList errorStringList;
|
QStringList errorStringList;
|
||||||
|
|
||||||
if (dataObject.contains(EMAIL_DATA_KEY)) {
|
if (dataObject.contains(EMAIL_DATA_KEY)) {
|
||||||
errorStringList.append(QString("Email %1.").arg(errorStringFromAPIObject(dataObject[EMAIL_DATA_KEY])));
|
errorStringList.append(QString("Email %1.").arg(errorStringFromAPIObject(dataObject[EMAIL_DATA_KEY])));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataObject.contains(USERNAME_DATA_KEY)) {
|
if (dataObject.contains(USERNAME_DATA_KEY)) {
|
||||||
errorStringList.append(QString("Username %1.").arg(errorStringFromAPIObject(dataObject[USERNAME_DATA_KEY])));
|
errorStringList.append(QString("Username %1.").arg(errorStringFromAPIObject(dataObject[USERNAME_DATA_KEY])));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataObject.contains(PASSWORD_DATA_KEY)) {
|
if (dataObject.contains(PASSWORD_DATA_KEY)) {
|
||||||
errorStringList.append(QString("Password %1.").arg(errorStringFromAPIObject(dataObject[PASSWORD_DATA_KEY])));
|
errorStringList.append(QString("Password %1.").arg(errorStringFromAPIObject(dataObject[PASSWORD_DATA_KEY])));
|
||||||
}
|
}
|
||||||
|
|
||||||
emit handleSignupFailed(errorStringList.join('\n'));
|
emit handleSignupFailed(errorStringList.join('\n'));
|
||||||
} else {
|
} else {
|
||||||
static const QString DEFAULT_SIGN_UP_FAILURE_MESSAGE = "There was an unknown error while creating your account. Please try again later.";
|
static const QString DEFAULT_SIGN_UP_FAILURE_MESSAGE = "There was an unknown error while creating your account. Please try again later.";
|
||||||
emit handleSignupFailed(DEFAULT_SIGN_UP_FAILURE_MESSAGE);
|
emit handleSignupFailed(DEFAULT_SIGN_UP_FAILURE_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,10 @@ public:
|
||||||
|
|
||||||
LoginDialog(QQuickItem* parent = nullptr);
|
LoginDialog(QQuickItem* parent = nullptr);
|
||||||
|
|
||||||
|
~LoginDialog();
|
||||||
|
|
||||||
static void showWithSelection();
|
static void showWithSelection();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void handleLoginCompleted();
|
void handleLoginCompleted();
|
||||||
void handleLoginFailed();
|
void handleLoginFailed();
|
||||||
|
@ -62,7 +65,6 @@ protected slots:
|
||||||
Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
|
Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
|
||||||
|
|
||||||
Q_INVOKABLE void openUrl(const QString& url) const;
|
Q_INVOKABLE void openUrl(const QString& url) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_LoginDialog_h
|
#endif // hifi_LoginDialog_h
|
||||||
|
|
|
@ -106,6 +106,10 @@ extern std::atomic<size_t> DECIMATED_TEXTURE_COUNT;
|
||||||
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
|
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
|
||||||
|
|
||||||
void Stats::updateStats(bool force) {
|
void Stats::updateStats(bool force) {
|
||||||
|
|
||||||
|
if (qApp->isInterstitialMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QQuickItem* parent = parentItem();
|
QQuickItem* parent = parentItem();
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||||
|
|
|
@ -252,12 +252,6 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt
|
||||||
void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
if (overlayID == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
|
if (overlayID == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
|
||||||
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "Overlay ID:" << overlayID;
|
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "Overlay ID:" << overlayID;
|
||||||
Setting::Handle<bool> _settingSwitch{ "commerce", true };
|
|
||||||
if (_settingSwitch.get()) {
|
|
||||||
openInspectionCertificate();
|
|
||||||
} else {
|
|
||||||
openMarketplace();
|
|
||||||
}
|
|
||||||
emit contextOverlayClicked(_currentEntityWithContextOverlay);
|
emit contextOverlayClicked(_currentEntityWithContextOverlay);
|
||||||
_contextOverlayJustClicked = true;
|
_contextOverlayJustClicked = true;
|
||||||
}
|
}
|
||||||
|
@ -390,34 +384,6 @@ void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
|
||||||
void ContextOverlayInterface::openInspectionCertificate() {
|
|
||||||
// lets open the tablet to the inspection certificate QML
|
|
||||||
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
|
|
||||||
setLastInspectedEntity(_currentEntityWithContextOverlay);
|
|
||||||
auto tablet = dynamic_cast<TabletProxy*>(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
|
||||||
tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH);
|
|
||||||
_hmdScriptingInterface->openTablet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
|
||||||
|
|
||||||
void ContextOverlayInterface::openMarketplace() {
|
|
||||||
// lets open the tablet and go to the current item in
|
|
||||||
// the marketplace (if the current entity has a
|
|
||||||
// marketplaceID)
|
|
||||||
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
|
|
||||||
auto tablet = dynamic_cast<TabletProxy*>(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
|
||||||
// construct the url to the marketplace item
|
|
||||||
QString url = MARKETPLACE_BASE_URL + _entityMarketplaceID;
|
|
||||||
QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js";
|
|
||||||
tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH);
|
|
||||||
_hmdScriptingInterface->openTablet();
|
|
||||||
_isInMarketplaceInspectionMode = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
|
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
|
||||||
_selectionScriptingInterface->addToSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID);
|
_selectionScriptingInterface->addToSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,6 @@ private:
|
||||||
|
|
||||||
bool _isInMarketplaceInspectionMode { false };
|
bool _isInMarketplaceInspectionMode { false };
|
||||||
|
|
||||||
void openInspectionCertificate();
|
|
||||||
void openMarketplace();
|
|
||||||
void enableEntityHighlight(const EntityItemID& entityItemID);
|
void enableEntityHighlight(const EntityItemID& entityItemID);
|
||||||
void disableEntityHighlight(const EntityItemID& entityItemID);
|
void disableEntityHighlight(const EntityItemID& entityItemID);
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,9 @@ void Web3DOverlay::destroyWebSurface() {
|
||||||
|
|
||||||
if (rootItem && rootItem->objectName() == "tabletRoot") {
|
if (rootItem && rootItem->objectName() == "tabletRoot") {
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", nullptr);
|
if (tabletScriptingInterface) {
|
||||||
|
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix for crash in QtWebEngineCore when rapidly switching domains
|
// Fix for crash in QtWebEngineCore when rapidly switching domains
|
||||||
|
|
|
@ -305,6 +305,16 @@ void AudioClient::audioMixerKilled() {
|
||||||
emit disconnected();
|
emit disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioClient::setAudioPaused(bool pause) {
|
||||||
|
if (_audioPaused != pause) {
|
||||||
|
_audioPaused = pause;
|
||||||
|
|
||||||
|
if (!_audioPaused) {
|
||||||
|
negotiateAudioFormat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||||
QAudioDeviceInfo result;
|
QAudioDeviceInfo result;
|
||||||
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
||||||
|
@ -651,7 +661,6 @@ void AudioClient::stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
char bitset;
|
char bitset;
|
||||||
message->readPrimitive(&bitset);
|
message->readPrimitive(&bitset);
|
||||||
|
|
||||||
|
@ -664,11 +673,10 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessag
|
||||||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||||
} else {
|
} else {
|
||||||
_receivedAudioStream.clearReverb();
|
_receivedAudioStream.clearReverb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
if (message->getType() == PacketType::SilentAudioFrame) {
|
if (message->getType() == PacketType::SilentAudioFrame) {
|
||||||
_silentInbound.increment();
|
_silentInbound.increment();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1026,80 +1034,82 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||||
if (_muted) {
|
if (!_audioPaused) {
|
||||||
_lastInputLoudness = 0.0f;
|
if (_muted) {
|
||||||
_timeSinceLastClip = 0.0f;
|
_lastInputLoudness = 0.0f;
|
||||||
} else {
|
|
||||||
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
|
||||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
|
||||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
|
||||||
|
|
||||||
if (_isNoiseGateEnabled) {
|
|
||||||
// The audio gate includes DC removal
|
|
||||||
_audioGate->render(samples, samples, numFrames);
|
|
||||||
} else {
|
|
||||||
_audioGate->removeDC(samples, samples, numFrames);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t loudness = 0;
|
|
||||||
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
|
||||||
bool didClip = false;
|
|
||||||
for (int i = 0; i < numSamples; ++i) {
|
|
||||||
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
|
||||||
int32_t sample = std::abs((int32_t)samples[i]);
|
|
||||||
loudness += sample;
|
|
||||||
didClip |= (sample > CLIPPING_THRESHOLD);
|
|
||||||
}
|
|
||||||
_lastInputLoudness = (float)loudness / numSamples;
|
|
||||||
|
|
||||||
if (didClip) {
|
|
||||||
_timeSinceLastClip = 0.0f;
|
_timeSinceLastClip = 0.0f;
|
||||||
} else if (_timeSinceLastClip >= 0.0f) {
|
} else {
|
||||||
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
||||||
|
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||||
|
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
|
|
||||||
|
if (_isNoiseGateEnabled) {
|
||||||
|
// The audio gate includes DC removal
|
||||||
|
_audioGate->render(samples, samples, numFrames);
|
||||||
|
} else {
|
||||||
|
_audioGate->removeDC(samples, samples, numFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t loudness = 0;
|
||||||
|
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
||||||
|
bool didClip = false;
|
||||||
|
for (int i = 0; i < numSamples; ++i) {
|
||||||
|
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
||||||
|
int32_t sample = std::abs((int32_t)samples[i]);
|
||||||
|
loudness += sample;
|
||||||
|
didClip |= (sample > CLIPPING_THRESHOLD);
|
||||||
|
}
|
||||||
|
_lastInputLoudness = (float)loudness / numSamples;
|
||||||
|
|
||||||
|
if (didClip) {
|
||||||
|
_timeSinceLastClip = 0.0f;
|
||||||
|
} else if (_timeSinceLastClip >= 0.0f) {
|
||||||
|
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit inputReceived(audioBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit inputReceived(audioBuffer);
|
emit inputLoudnessChanged(_lastInputLoudness);
|
||||||
|
|
||||||
|
// state machine to detect gate opening and closing
|
||||||
|
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||||
|
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||||
|
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||||
|
_audioGateOpen = audioGateOpen;
|
||||||
|
|
||||||
|
if (openedInLastBlock) {
|
||||||
|
emit noiseGateOpened();
|
||||||
|
} else if (closedInLastBlock) {
|
||||||
|
emit noiseGateClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the codec must be flushed to silence before sending silent packets,
|
||||||
|
// so delay the transition to silent packets by one packet after becoming silent.
|
||||||
|
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
||||||
|
if (!audioGateOpen && !closedInLastBlock) {
|
||||||
|
packetType = PacketType::SilentAudioFrame;
|
||||||
|
_silentOutbound.increment();
|
||||||
|
} else {
|
||||||
|
_audioOutbound.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform audioTransform;
|
||||||
|
audioTransform.setTranslation(_positionGetter());
|
||||||
|
audioTransform.setRotation(_orientationGetter());
|
||||||
|
|
||||||
|
QByteArray encodedBuffer;
|
||||||
|
if (_encoder) {
|
||||||
|
_encoder->encode(audioBuffer, encodedBuffer);
|
||||||
|
} else {
|
||||||
|
encodedBuffer = audioBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||||
|
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||||
|
packetType, _selectedCodecName);
|
||||||
|
_stats.sentPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit inputLoudnessChanged(_lastInputLoudness);
|
|
||||||
|
|
||||||
// state machine to detect gate opening and closing
|
|
||||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
|
||||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
|
||||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
|
||||||
_audioGateOpen = audioGateOpen;
|
|
||||||
|
|
||||||
if (openedInLastBlock) {
|
|
||||||
emit noiseGateOpened();
|
|
||||||
} else if (closedInLastBlock) {
|
|
||||||
emit noiseGateClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the codec must be flushed to silence before sending silent packets,
|
|
||||||
// so delay the transition to silent packets by one packet after becoming silent.
|
|
||||||
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
|
||||||
if (!audioGateOpen && !closedInLastBlock) {
|
|
||||||
packetType = PacketType::SilentAudioFrame;
|
|
||||||
_silentOutbound.increment();
|
|
||||||
} else {
|
|
||||||
_audioOutbound.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform audioTransform;
|
|
||||||
audioTransform.setTranslation(_positionGetter());
|
|
||||||
audioTransform.setRotation(_orientationGetter());
|
|
||||||
|
|
||||||
QByteArray encodedBuffer;
|
|
||||||
if (_encoder) {
|
|
||||||
_encoder->encode(audioBuffer, encodedBuffer);
|
|
||||||
} else {
|
|
||||||
encodedBuffer = audioBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
|
||||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
|
||||||
packetType, _selectedCodecName);
|
|
||||||
_stats.sentPacket();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleMicAudioInput() {
|
void AudioClient::handleMicAudioInput() {
|
||||||
|
|
|
@ -162,6 +162,7 @@ public:
|
||||||
|
|
||||||
bool startRecording(const QString& filename);
|
bool startRecording(const QString& filename);
|
||||||
void stopRecording();
|
void stopRecording();
|
||||||
|
void setAudioPaused(bool pause);
|
||||||
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
@ -416,6 +417,7 @@ private:
|
||||||
QVector<AudioInjectorPointer> _activeLocalAudioInjectors;
|
QVector<AudioInjectorPointer> _activeLocalAudioInjectors;
|
||||||
|
|
||||||
bool _isPlayingBackRecording { false };
|
bool _isPlayingBackRecording { false };
|
||||||
|
bool _audioPaused { false };
|
||||||
|
|
||||||
CodecPluginPointer _codec;
|
CodecPluginPointer _codec;
|
||||||
QString _selectedCodecName;
|
QString _selectedCodecName;
|
||||||
|
|
|
@ -214,19 +214,11 @@ Avatar::Avatar(QThread* thread) :
|
||||||
_leftPointerGeometryID = geometryCache->allocateID();
|
_leftPointerGeometryID = geometryCache->allocateID();
|
||||||
_rightPointerGeometryID = geometryCache->allocateID();
|
_rightPointerGeometryID = geometryCache->allocateID();
|
||||||
_lastRenderUpdateTime = usecTimestampNow();
|
_lastRenderUpdateTime = usecTimestampNow();
|
||||||
|
|
||||||
|
indicateLoadingStatus(LoadingStatus::NoModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar::~Avatar() {
|
Avatar::~Avatar() {
|
||||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
|
||||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
|
||||||
if (entityTree) {
|
|
||||||
entityTree->withWriteLock([&] {
|
|
||||||
AvatarEntityMap avatarEntities = getAvatarEntityData();
|
|
||||||
for (auto entityID : avatarEntities.keys()) {
|
|
||||||
entityTree->deleteEntity(entityID, true, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
if (geometryCache) {
|
if (geometryCache) {
|
||||||
geometryCache->releaseID(_nameRectGeometryID);
|
geometryCache->releaseID(_nameRectGeometryID);
|
||||||
|
@ -471,6 +463,19 @@ void Avatar::updateAvatarEntities() {
|
||||||
setAvatarEntityDataChanged(false);
|
setAvatarEntityDataChanged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Avatar::removeAvatarEntitiesFromTree() {
|
||||||
|
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||||
|
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||||
|
if (entityTree) {
|
||||||
|
entityTree->withWriteLock([&] {
|
||||||
|
AvatarEntityMap avatarEntities = getAvatarEntityData();
|
||||||
|
for (auto entityID : avatarEntities.keys()) {
|
||||||
|
entityTree->deleteEntity(entityID, true, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Avatar::relayJointDataToChildren() {
|
void Avatar::relayJointDataToChildren() {
|
||||||
forEachChild([&](SpatiallyNestablePointer child) {
|
forEachChild([&](SpatiallyNestablePointer child) {
|
||||||
if (child->getNestableType() == NestableType::Entity) {
|
if (child->getNestableType() == NestableType::Entity) {
|
||||||
|
@ -1469,12 +1474,15 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
if (!isMyAvatar()) {
|
|
||||||
createOrb();
|
|
||||||
}
|
|
||||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||||
if (QThread::currentThread() == thread()) {
|
if (QThread::currentThread() == thread()) {
|
||||||
|
|
||||||
|
if (!isMyAvatar()) {
|
||||||
|
createOrb();
|
||||||
|
}
|
||||||
|
|
||||||
_skeletonModel->setURL(_skeletonModelURL);
|
_skeletonModel->setURL(_skeletonModelURL);
|
||||||
|
indicateLoadingStatus(LoadingStatus::LoadModel);
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, _skeletonModelURL));
|
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, _skeletonModelURL));
|
||||||
}
|
}
|
||||||
|
@ -1487,11 +1495,12 @@ void Avatar::setModelURLFinished(bool success) {
|
||||||
_reconstructSoftEntitiesJointMap = true;
|
_reconstructSoftEntitiesJointMap = true;
|
||||||
|
|
||||||
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
|
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
|
||||||
|
indicateLoadingStatus(LoadingStatus::LoadFailure);
|
||||||
const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts
|
const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts
|
||||||
if (_skeletonModel->getResourceDownloadAttemptsRemaining() <= 0 ||
|
if (_skeletonModel->getResourceDownloadAttemptsRemaining() <= 0 ||
|
||||||
_skeletonModel->getResourceDownloadAttempts() > MAX_SKELETON_DOWNLOAD_ATTEMPTS) {
|
_skeletonModel->getResourceDownloadAttempts() > MAX_SKELETON_DOWNLOAD_ATTEMPTS) {
|
||||||
qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL
|
qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL
|
||||||
<< "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts.";
|
<< "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts.";
|
||||||
// call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that
|
// call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that
|
||||||
// we don't redo this every time we receive an identity packet from the avatar with the bad url.
|
// we don't redo this every time we receive an identity packet from the avatar with the bad url.
|
||||||
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL",
|
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL",
|
||||||
|
@ -1502,6 +1511,9 @@ void Avatar::setModelURLFinished(bool success) {
|
||||||
<< "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS;
|
<< "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (success) {
|
||||||
|
indicateLoadingStatus(LoadingStatus::LoadSuccess);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rig is ready
|
// rig is ready
|
||||||
|
|
|
@ -143,6 +143,7 @@ public:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void updateAvatarEntities();
|
void updateAvatarEntities();
|
||||||
|
void removeAvatarEntitiesFromTree();
|
||||||
void simulate(float deltaTime, bool inView);
|
void simulate(float deltaTime, bool inView);
|
||||||
virtual void simulateAttachments(float deltaTime);
|
virtual void simulateAttachments(float deltaTime);
|
||||||
|
|
||||||
|
@ -177,6 +178,14 @@ public:
|
||||||
virtual bool isMyAvatar() const override { return false; }
|
virtual bool isMyAvatar() const override { return false; }
|
||||||
virtual void createOrb() { }
|
virtual void createOrb() { }
|
||||||
|
|
||||||
|
enum class LoadingStatus {
|
||||||
|
NoModel,
|
||||||
|
LoadModel,
|
||||||
|
LoadSuccess,
|
||||||
|
LoadFailure
|
||||||
|
};
|
||||||
|
virtual void indicateLoadingStatus(LoadingStatus loadingStatus) { _loadingStatus = loadingStatus; }
|
||||||
|
|
||||||
virtual QVector<glm::quat> getJointRotations() const override;
|
virtual QVector<glm::quat> getJointRotations() const override;
|
||||||
using AvatarData::getJointRotation;
|
using AvatarData::getJointRotation;
|
||||||
virtual glm::quat getJointRotation(int index) const override;
|
virtual glm::quat getJointRotation(int index) const override;
|
||||||
|
@ -621,6 +630,7 @@ protected:
|
||||||
static const float ATTACHMENT_LOADING_PRIORITY;
|
static const float ATTACHMENT_LOADING_PRIORITY;
|
||||||
|
|
||||||
QUuid _transitEffectID{ QUuid::createUuid() };
|
QUuid _transitEffectID{ QUuid::createUuid() };
|
||||||
|
LoadingStatus _loadingStatus { LoadingStatus::NoModel };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Avatar_h
|
#endif // hifi_Avatar_h
|
||||||
|
|
|
@ -363,13 +363,13 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
|
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
|
||||||
destinationBuffer += sizeof(packetStateFlags);
|
destinationBuffer += sizeof(packetStateFlags);
|
||||||
|
|
||||||
|
#define AVATAR_MEMCPY(src) \
|
||||||
|
memcpy(destinationBuffer, &(src), sizeof(src)); \
|
||||||
|
destinationBuffer += sizeof(src);
|
||||||
|
|
||||||
if (hasAvatarGlobalPosition) {
|
if (hasAvatarGlobalPosition) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
auto data = reinterpret_cast<AvatarDataPacket::AvatarGlobalPosition*>(destinationBuffer);
|
AVATAR_MEMCPY(_globalPosition);
|
||||||
data->globalPosition[0] = _globalPosition.x;
|
|
||||||
data->globalPosition[1] = _globalPosition.y;
|
|
||||||
data->globalPosition[2] = _globalPosition.z;
|
|
||||||
destinationBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
|
|
||||||
|
|
||||||
int numBytes = destinationBuffer - startSection;
|
int numBytes = destinationBuffer - startSection;
|
||||||
|
|
||||||
|
@ -380,17 +380,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
if (hasAvatarBoundingBox) {
|
if (hasAvatarBoundingBox) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
auto data = reinterpret_cast<AvatarDataPacket::AvatarBoundingBox*>(destinationBuffer);
|
AVATAR_MEMCPY(_globalBoundingBoxDimensions);
|
||||||
|
AVATAR_MEMCPY(_globalBoundingBoxOffset);
|
||||||
data->avatarDimensions[0] = _globalBoundingBoxDimensions.x;
|
|
||||||
data->avatarDimensions[1] = _globalBoundingBoxDimensions.y;
|
|
||||||
data->avatarDimensions[2] = _globalBoundingBoxDimensions.z;
|
|
||||||
|
|
||||||
data->boundOriginOffset[0] = _globalBoundingBoxOffset.x;
|
|
||||||
data->boundOriginOffset[1] = _globalBoundingBoxOffset.y;
|
|
||||||
data->boundOriginOffset[2] = _globalBoundingBoxOffset.z;
|
|
||||||
|
|
||||||
destinationBuffer += sizeof(AvatarDataPacket::AvatarBoundingBox);
|
|
||||||
|
|
||||||
int numBytes = destinationBuffer - startSection;
|
int numBytes = destinationBuffer - startSection;
|
||||||
if (outboundDataRateOut) {
|
if (outboundDataRateOut) {
|
||||||
|
@ -424,13 +415,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
if (hasLookAtPosition) {
|
if (hasLookAtPosition) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
auto data = reinterpret_cast<AvatarDataPacket::LookAtPosition*>(destinationBuffer);
|
AVATAR_MEMCPY(_headData->getLookAtPosition());
|
||||||
auto lookAt = _headData->getLookAtPosition();
|
|
||||||
data->lookAtPosition[0] = lookAt.x;
|
|
||||||
data->lookAtPosition[1] = lookAt.y;
|
|
||||||
data->lookAtPosition[2] = lookAt.z;
|
|
||||||
destinationBuffer += sizeof(AvatarDataPacket::LookAtPosition);
|
|
||||||
|
|
||||||
int numBytes = destinationBuffer - startSection;
|
int numBytes = destinationBuffer - startSection;
|
||||||
if (outboundDataRateOut) {
|
if (outboundDataRateOut) {
|
||||||
outboundDataRateOut->lookAtPositionRate.increment(numBytes);
|
outboundDataRateOut->lookAtPositionRate.increment(numBytes);
|
||||||
|
@ -531,12 +516,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
if (hasAvatarLocalPosition) {
|
if (hasAvatarLocalPosition) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
auto data = reinterpret_cast<AvatarDataPacket::AvatarLocalPosition*>(destinationBuffer);
|
const auto localPosition = getLocalPosition();
|
||||||
auto localPosition = getLocalPosition();
|
AVATAR_MEMCPY(localPosition);
|
||||||
data->localPosition[0] = localPosition.x;
|
|
||||||
data->localPosition[1] = localPosition.y;
|
|
||||||
data->localPosition[2] = localPosition.z;
|
|
||||||
destinationBuffer += sizeof(AvatarDataPacket::AvatarLocalPosition);
|
|
||||||
|
|
||||||
int numBytes = destinationBuffer - startSection;
|
int numBytes = destinationBuffer - startSection;
|
||||||
if (outboundDataRateOut) {
|
if (outboundDataRateOut) {
|
||||||
|
@ -567,19 +548,24 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<JointData> jointData;
|
||||||
|
if (hasJointData || hasJointDefaultPoseFlags) {
|
||||||
|
QReadLocker readLock(&_jointDataLock);
|
||||||
|
jointData = _jointData;
|
||||||
|
}
|
||||||
|
|
||||||
// If it is connected, pack up the data
|
// If it is connected, pack up the data
|
||||||
if (hasJointData) {
|
if (hasJointData) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
QReadLocker readLock(&_jointDataLock);
|
|
||||||
|
|
||||||
// joint rotation data
|
// joint rotation data
|
||||||
int numJoints = _jointData.size();
|
int numJoints = jointData.size();
|
||||||
*destinationBuffer++ = (uint8_t)numJoints;
|
*destinationBuffer++ = (uint8_t)numJoints;
|
||||||
|
|
||||||
unsigned char* validityPosition = destinationBuffer;
|
unsigned char* validityPosition = destinationBuffer;
|
||||||
unsigned char validity = 0;
|
unsigned char validity = 0;
|
||||||
int validityBit = 0;
|
int validityBit = 0;
|
||||||
int numValidityBytes = (int)std::ceil(numJoints / (float)BITS_IN_BYTE);
|
int numValidityBytes = calcBitVectorSize(numJoints);
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
int rotationSentCount = 0;
|
int rotationSentCount = 0;
|
||||||
|
@ -589,43 +575,37 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
|
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
|
||||||
|
|
||||||
// sentJointDataOut and lastSentJointData might be the same vector
|
// sentJointDataOut and lastSentJointData might be the same vector
|
||||||
// build sentJointDataOut locally and then swap it at the end.
|
|
||||||
QVector<JointData> localSentJointDataOut;
|
|
||||||
if (sentJointDataOut) {
|
if (sentJointDataOut) {
|
||||||
localSentJointDataOut.resize(numJoints); // Make sure the destination is resized before using it
|
sentJointDataOut->resize(numJoints); // Make sure the destination is resized before using it
|
||||||
}
|
}
|
||||||
|
|
||||||
float minRotationDOT = !distanceAdjust ? AVATAR_MIN_ROTATION_DOT : getDistanceBasedMinRotationDOT(viewerPosition);
|
float minRotationDOT = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinRotationDOT(viewerPosition) : AVATAR_MIN_ROTATION_DOT;
|
||||||
|
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
for (int i = 0; i < jointData.size(); i++) {
|
||||||
const JointData& data = _jointData[i];
|
const JointData& data = jointData[i];
|
||||||
const JointData& last = lastSentJointData[i];
|
const JointData& last = lastSentJointData[i];
|
||||||
|
|
||||||
if (!data.rotationIsDefaultPose) {
|
if (!data.rotationIsDefaultPose) {
|
||||||
bool mustSend = sendAll || last.rotationIsDefaultPose;
|
// The dot product for larger rotations is a lower number.
|
||||||
if (mustSend || last.rotation != data.rotation) {
|
// So if the dot() is less than the value, then the rotation is a larger angle of rotation
|
||||||
|
if (sendAll || last.rotationIsDefaultPose || (!cullSmallChanges && last.rotation != data.rotation)
|
||||||
bool largeEnoughRotation = true;
|
|| (cullSmallChanges && glm::dot(last.rotation, data.rotation) < minRotationDOT) ) {
|
||||||
if (cullSmallChanges) {
|
validity |= (1 << validityBit);
|
||||||
// The dot product for smaller rotations is a smaller number.
|
|
||||||
// So if the dot() is less than the value, then the rotation is a larger angle of rotation
|
|
||||||
largeEnoughRotation = fabsf(glm::dot(last.rotation, data.rotation)) < minRotationDOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mustSend || !cullSmallChanges || largeEnoughRotation) {
|
|
||||||
validity |= (1 << validityBit);
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
rotationSentCount++;
|
rotationSentCount++;
|
||||||
#endif
|
#endif
|
||||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
|
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
|
||||||
|
|
||||||
if (sentJointDataOut) {
|
if (sentJointDataOut) {
|
||||||
localSentJointDataOut[i].rotation = data.rotation;
|
(*sentJointDataOut)[i].rotation = data.rotation;
|
||||||
localSentJointDataOut[i].rotationIsDefaultPose = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sentJointDataOut) {
|
||||||
|
(*sentJointDataOut)[i].rotationIsDefaultPose = data.rotationIsDefaultPose;
|
||||||
|
}
|
||||||
|
|
||||||
if (++validityBit == BITS_IN_BYTE) {
|
if (++validityBit == BITS_IN_BYTE) {
|
||||||
*validityPosition++ = validity;
|
*validityPosition++ = validity;
|
||||||
validityBit = validity = 0;
|
validityBit = validity = 0;
|
||||||
|
@ -647,35 +627,38 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
|
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
|
||||||
|
|
||||||
float minTranslation = !distanceAdjust ? AVATAR_MIN_TRANSLATION : getDistanceBasedMinTranslationDistance(viewerPosition);
|
float minTranslation = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinTranslationDistance(viewerPosition) : AVATAR_MIN_TRANSLATION;
|
||||||
|
|
||||||
float maxTranslationDimension = 0.0;
|
float maxTranslationDimension = 0.0;
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
for (int i = 0; i < jointData.size(); i++) {
|
||||||
const JointData& data = _jointData[i];
|
const JointData& data = jointData[i];
|
||||||
const JointData& last = lastSentJointData[i];
|
const JointData& last = lastSentJointData[i];
|
||||||
|
|
||||||
if (!data.translationIsDefaultPose) {
|
if (!data.translationIsDefaultPose) {
|
||||||
bool mustSend = sendAll || last.translationIsDefaultPose;
|
if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation)
|
||||||
if (mustSend || last.translation != data.translation) {
|
|| (cullSmallChanges && glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation)) {
|
||||||
if (mustSend || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
|
|
||||||
validity |= (1 << validityBit);
|
validity |= (1 << validityBit);
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
translationSentCount++;
|
translationSentCount++;
|
||||||
#endif
|
#endif
|
||||||
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
|
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
|
||||||
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
|
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
|
||||||
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
|
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
|
||||||
|
|
||||||
destinationBuffer +=
|
destinationBuffer +=
|
||||||
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||||
|
|
||||||
if (sentJointDataOut) {
|
if (sentJointDataOut) {
|
||||||
localSentJointDataOut[i].translation = data.translation;
|
(*sentJointDataOut)[i].translation = data.translation;
|
||||||
localSentJointDataOut[i].translationIsDefaultPose = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sentJointDataOut) {
|
||||||
|
(*sentJointDataOut)[i].translationIsDefaultPose = data.translationIsDefaultPose;
|
||||||
|
}
|
||||||
|
|
||||||
if (++validityBit == BITS_IN_BYTE) {
|
if (++validityBit == BITS_IN_BYTE) {
|
||||||
*validityPosition++ = validity;
|
*validityPosition++ = validity;
|
||||||
validityBit = validity = 0;
|
validityBit = validity = 0;
|
||||||
|
@ -691,6 +674,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
|
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
|
||||||
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
|
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
|
||||||
TRANSLATION_COMPRESSION_RADIX);
|
TRANSLATION_COMPRESSION_RADIX);
|
||||||
|
|
||||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
|
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
|
||||||
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
|
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
|
||||||
|
@ -707,34 +691,27 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
glm::vec3 mouseFarGrabPosition = extractTranslation(mouseFarGrabMatrix);
|
glm::vec3 mouseFarGrabPosition = extractTranslation(mouseFarGrabMatrix);
|
||||||
glm::quat mouseFarGrabRotation = extractRotation(mouseFarGrabMatrix);
|
glm::quat mouseFarGrabRotation = extractRotation(mouseFarGrabMatrix);
|
||||||
|
|
||||||
data->leftFarGrabPosition[0] = leftFarGrabPosition.x;
|
AVATAR_MEMCPY(leftFarGrabPosition);
|
||||||
data->leftFarGrabPosition[1] = leftFarGrabPosition.y;
|
// Can't do block copy as struct order is x, y, z, w.
|
||||||
data->leftFarGrabPosition[2] = leftFarGrabPosition.z;
|
|
||||||
|
|
||||||
data->leftFarGrabRotation[0] = leftFarGrabRotation.w;
|
data->leftFarGrabRotation[0] = leftFarGrabRotation.w;
|
||||||
data->leftFarGrabRotation[1] = leftFarGrabRotation.x;
|
data->leftFarGrabRotation[1] = leftFarGrabRotation.x;
|
||||||
data->leftFarGrabRotation[2] = leftFarGrabRotation.y;
|
data->leftFarGrabRotation[2] = leftFarGrabRotation.y;
|
||||||
data->leftFarGrabRotation[3] = leftFarGrabRotation.z;
|
data->leftFarGrabRotation[3] = leftFarGrabRotation.z;
|
||||||
|
destinationBuffer += sizeof(data->leftFarGrabPosition);
|
||||||
|
|
||||||
data->rightFarGrabPosition[0] = rightFarGrabPosition.x;
|
AVATAR_MEMCPY(rightFarGrabPosition);
|
||||||
data->rightFarGrabPosition[1] = rightFarGrabPosition.y;
|
|
||||||
data->rightFarGrabPosition[2] = rightFarGrabPosition.z;
|
|
||||||
|
|
||||||
data->rightFarGrabRotation[0] = rightFarGrabRotation.w;
|
data->rightFarGrabRotation[0] = rightFarGrabRotation.w;
|
||||||
data->rightFarGrabRotation[1] = rightFarGrabRotation.x;
|
data->rightFarGrabRotation[1] = rightFarGrabRotation.x;
|
||||||
data->rightFarGrabRotation[2] = rightFarGrabRotation.y;
|
data->rightFarGrabRotation[2] = rightFarGrabRotation.y;
|
||||||
data->rightFarGrabRotation[3] = rightFarGrabRotation.z;
|
data->rightFarGrabRotation[3] = rightFarGrabRotation.z;
|
||||||
|
destinationBuffer += sizeof(data->rightFarGrabRotation);
|
||||||
|
|
||||||
data->mouseFarGrabPosition[0] = mouseFarGrabPosition.x;
|
AVATAR_MEMCPY(mouseFarGrabPosition);
|
||||||
data->mouseFarGrabPosition[1] = mouseFarGrabPosition.y;
|
|
||||||
data->mouseFarGrabPosition[2] = mouseFarGrabPosition.z;
|
|
||||||
|
|
||||||
data->mouseFarGrabRotation[0] = mouseFarGrabRotation.w;
|
data->mouseFarGrabRotation[0] = mouseFarGrabRotation.w;
|
||||||
data->mouseFarGrabRotation[1] = mouseFarGrabRotation.x;
|
data->mouseFarGrabRotation[1] = mouseFarGrabRotation.x;
|
||||||
data->mouseFarGrabRotation[2] = mouseFarGrabRotation.y;
|
data->mouseFarGrabRotation[2] = mouseFarGrabRotation.y;
|
||||||
data->mouseFarGrabRotation[3] = mouseFarGrabRotation.z;
|
data->mouseFarGrabRotation[3] = mouseFarGrabRotation.z;
|
||||||
|
destinationBuffer += sizeof(data->mouseFarGrabRotation);
|
||||||
destinationBuffer += sizeof(AvatarDataPacket::FarGrabJoints);
|
|
||||||
|
|
||||||
int numBytes = destinationBuffer - startSection;
|
int numBytes = destinationBuffer - startSection;
|
||||||
|
|
||||||
|
@ -761,41 +738,23 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
outboundDataRateOut->jointDataRate.increment(numBytes);
|
outboundDataRateOut->jointDataRate.increment(numBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sentJointDataOut) {
|
|
||||||
|
|
||||||
// Mark default poses in lastSentJointData, so when they become non-default we send them.
|
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
|
||||||
const JointData& data = _jointData[i];
|
|
||||||
JointData& local = localSentJointDataOut[i];
|
|
||||||
if (data.rotationIsDefaultPose) {
|
|
||||||
local.rotationIsDefaultPose = true;
|
|
||||||
}
|
|
||||||
if (data.translationIsDefaultPose) {
|
|
||||||
local.translationIsDefaultPose = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push new sent joint data to sentJointDataOut
|
|
||||||
sentJointDataOut->swap(localSentJointDataOut);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasJointDefaultPoseFlags) {
|
if (hasJointDefaultPoseFlags) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
QReadLocker readLock(&_jointDataLock);
|
|
||||||
|
|
||||||
// write numJoints
|
// write numJoints
|
||||||
int numJoints = _jointData.size();
|
int numJoints = jointData.size();
|
||||||
*destinationBuffer++ = (uint8_t)numJoints;
|
*destinationBuffer++ = (uint8_t)numJoints;
|
||||||
|
|
||||||
// write rotationIsDefaultPose bits
|
// write rotationIsDefaultPose bits
|
||||||
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
|
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
|
||||||
return _jointData[i].rotationIsDefaultPose;
|
return jointData[i].rotationIsDefaultPose;
|
||||||
});
|
});
|
||||||
|
|
||||||
// write translationIsDefaultPose bits
|
// write translationIsDefaultPose bits
|
||||||
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
|
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
|
||||||
return _jointData[i].translationIsDefaultPose;
|
return jointData[i].translationIsDefaultPose;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (outboundDataRateOut) {
|
if (outboundDataRateOut) {
|
||||||
|
@ -880,7 +839,6 @@ const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSa
|
||||||
|
|
||||||
// read data in packet starting at byte offset and return number of bytes parsed
|
// read data in packet starting at byte offset and return number of bytes parsed
|
||||||
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
|
|
||||||
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
||||||
lazyInitHeadData();
|
lazyInitHeadData();
|
||||||
|
|
||||||
|
@ -932,7 +890,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
|
auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
|
||||||
if (_globalPosition != newValue) {
|
if (_globalPosition != newValue) {
|
||||||
_globalPosition = newValue;
|
_globalPosition = newValue;
|
||||||
_globalPositionChanged = usecTimestampNow();
|
_globalPositionChanged = now;
|
||||||
}
|
}
|
||||||
sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
|
sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
|
||||||
int numBytesRead = sourceBuffer - startSection;
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
|
@ -956,11 +914,11 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
|
|
||||||
if (_globalBoundingBoxDimensions != newDimensions) {
|
if (_globalBoundingBoxDimensions != newDimensions) {
|
||||||
_globalBoundingBoxDimensions = newDimensions;
|
_globalBoundingBoxDimensions = newDimensions;
|
||||||
_avatarBoundingBoxChanged = usecTimestampNow();
|
_avatarBoundingBoxChanged = now;
|
||||||
}
|
}
|
||||||
if (_globalBoundingBoxOffset != newOffset) {
|
if (_globalBoundingBoxOffset != newOffset) {
|
||||||
_globalBoundingBoxOffset = newOffset;
|
_globalBoundingBoxOffset = newOffset;
|
||||||
_avatarBoundingBoxChanged = usecTimestampNow();
|
_avatarBoundingBoxChanged = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceBuffer += sizeof(AvatarDataPacket::AvatarBoundingBox);
|
sourceBuffer += sizeof(AvatarDataPacket::AvatarBoundingBox);
|
||||||
|
@ -1061,7 +1019,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
glm::mat4 sensorToWorldMatrix = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), sensorToWorldQuat, sensorToWorldTrans);
|
glm::mat4 sensorToWorldMatrix = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), sensorToWorldQuat, sensorToWorldTrans);
|
||||||
if (_sensorToWorldMatrixCache.get() != sensorToWorldMatrix) {
|
if (_sensorToWorldMatrixCache.get() != sensorToWorldMatrix) {
|
||||||
_sensorToWorldMatrixCache.set(sensorToWorldMatrix);
|
_sensorToWorldMatrixCache.set(sensorToWorldMatrix);
|
||||||
_sensorToWorldMatrixChanged = usecTimestampNow();
|
_sensorToWorldMatrixChanged = now;
|
||||||
}
|
}
|
||||||
sourceBuffer += sizeof(AvatarDataPacket::SensorToWorldMatrix);
|
sourceBuffer += sizeof(AvatarDataPacket::SensorToWorldMatrix);
|
||||||
int numBytesRead = sourceBuffer - startSection;
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
|
@ -1118,7 +1076,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
sourceBuffer += sizeof(AvatarDataPacket::AdditionalFlags);
|
sourceBuffer += sizeof(AvatarDataPacket::AdditionalFlags);
|
||||||
|
|
||||||
if (somethingChanged) {
|
if (somethingChanged) {
|
||||||
_additionalFlagsChanged = usecTimestampNow();
|
_additionalFlagsChanged = now;
|
||||||
}
|
}
|
||||||
int numBytesRead = sourceBuffer - startSection;
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
_additionalFlagsRate.increment(numBytesRead);
|
_additionalFlagsRate.increment(numBytesRead);
|
||||||
|
@ -1138,7 +1096,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
if ((getParentID() != newParentID) || (getParentJointIndex() != parentInfo->parentJointIndex)) {
|
if ((getParentID() != newParentID) || (getParentJointIndex() != parentInfo->parentJointIndex)) {
|
||||||
SpatiallyNestable::setParentID(newParentID);
|
SpatiallyNestable::setParentID(newParentID);
|
||||||
SpatiallyNestable::setParentJointIndex(parentInfo->parentJointIndex);
|
SpatiallyNestable::setParentJointIndex(parentInfo->parentJointIndex);
|
||||||
_parentChanged = usecTimestampNow();
|
_parentChanged = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numBytesRead = sourceBuffer - startSection;
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
|
@ -1187,8 +1145,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
int numBytesRead = sourceBuffer - startSection;
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
_faceTrackerRate.increment(numBytesRead);
|
_faceTrackerRate.increment(numBytesRead);
|
||||||
_faceTrackerUpdateRate.increment();
|
_faceTrackerUpdateRate.increment();
|
||||||
} else {
|
|
||||||
_headData->_blendshapeCoefficients.fill(0, _headData->_blendshapeCoefficients.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasJointData) {
|
if (hasJointData) {
|
||||||
|
@ -1861,9 +1817,7 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID traitInstanceID,
|
qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID traitInstanceID,
|
||||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion,
|
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion) {
|
||||||
AvatarTraits::TraitInstanceID wireInstanceID) {
|
|
||||||
|
|
||||||
qint64 bytesWritten = 0;
|
qint64 bytesWritten = 0;
|
||||||
|
|
||||||
bytesWritten += destination.writePrimitive(traitType);
|
bytesWritten += destination.writePrimitive(traitType);
|
||||||
|
@ -1872,11 +1826,7 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr
|
||||||
bytesWritten += destination.writePrimitive(traitVersion);
|
bytesWritten += destination.writePrimitive(traitVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wireInstanceID.isNull()) {
|
bytesWritten += destination.write(traitInstanceID.toRfc4122());
|
||||||
bytesWritten += destination.write(wireInstanceID.toRfc4122());
|
|
||||||
} else {
|
|
||||||
bytesWritten += destination.write(traitInstanceID.toRfc4122());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (traitType == AvatarTraits::AvatarEntity) {
|
if (traitType == AvatarTraits::AvatarEntity) {
|
||||||
// grab a read lock on the avatar entities and check for entity data for the given ID
|
// grab a read lock on the avatar entities and check for entity data for the given ID
|
||||||
|
@ -2879,10 +2829,10 @@ void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, Ra
|
||||||
value.extraInfo = object.property("extraInfo").toVariant().toMap();
|
value.extraInfo = object.property("extraInfo").toVariant().toMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const float AvatarData::OUT_OF_VIEW_PENALTY = -10.0f;
|
// these coefficients can be changed via JS for experimental tuning
|
||||||
|
// use AvatatManager.setAvatarSortCoefficient("name", value) by a user with domain kick-rights
|
||||||
float AvatarData::_avatarSortCoefficientSize { 1.0f };
|
float AvatarData::_avatarSortCoefficientSize { 8.0f };
|
||||||
float AvatarData::_avatarSortCoefficientCenter { 0.25 };
|
float AvatarData::_avatarSortCoefficientCenter { 0.25f };
|
||||||
float AvatarData::_avatarSortCoefficientAge { 1.0f };
|
float AvatarData::_avatarSortCoefficientAge { 1.0f };
|
||||||
|
|
||||||
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
|
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
|
||||||
|
|
|
@ -962,8 +962,7 @@ public:
|
||||||
qint64 packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination,
|
qint64 packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination,
|
||||||
AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
||||||
qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID,
|
qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID,
|
||||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION,
|
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
||||||
AvatarTraits::TraitInstanceID wireInstanceID = AvatarTraits::TraitInstanceID());
|
|
||||||
|
|
||||||
void prepareResetTraitInstances();
|
void prepareResetTraitInstances();
|
||||||
|
|
||||||
|
@ -1098,7 +1097,7 @@ public:
|
||||||
void fromJson(const QJsonObject& json, bool useFrameSkeleton = true);
|
void fromJson(const QJsonObject& json, bool useFrameSkeleton = true);
|
||||||
|
|
||||||
glm::vec3 getClientGlobalPosition() const { return _globalPosition; }
|
glm::vec3 getClientGlobalPosition() const { return _globalPosition; }
|
||||||
glm::vec3 getGlobalBoundingBoxCorner() const { return _globalPosition + _globalBoundingBoxOffset - _globalBoundingBoxDimensions; }
|
AABox getGlobalBoundingBox() const { return AABox(_globalPosition + _globalBoundingBoxOffset - _globalBoundingBoxDimensions, _globalBoundingBoxDimensions); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function MyAvatar.getAvatarEntityData
|
* @function MyAvatar.getAvatarEntityData
|
||||||
|
@ -1170,8 +1169,6 @@ public:
|
||||||
// A method intended to be overriden by MyAvatar for polling orientation for network transmission.
|
// A method intended to be overriden by MyAvatar for polling orientation for network transmission.
|
||||||
virtual glm::quat getOrientationOutbound() const;
|
virtual glm::quat getOrientationOutbound() const;
|
||||||
|
|
||||||
static const float OUT_OF_VIEW_PENALTY;
|
|
||||||
|
|
||||||
// TODO: remove this HACK once we settle on optimal sort coefficients
|
// TODO: remove this HACK once we settle on optimal sort coefficients
|
||||||
// These coefficients exposed for fine tuning the sort priority for transfering new _jointData to the render pipeline.
|
// These coefficients exposed for fine tuning the sort priority for transfering new _jointData to the render pipeline.
|
||||||
static float _avatarSortCoefficientSize;
|
static float _avatarSortCoefficientSize;
|
||||||
|
@ -1193,9 +1190,6 @@ public:
|
||||||
void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; }
|
void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; }
|
||||||
int getReplicaIndex() { return _replicaIndex; }
|
int getReplicaIndex() { return _replicaIndex; }
|
||||||
|
|
||||||
const AvatarTraits::TraitInstanceID getTraitInstanceXORID() const { return _traitInstanceXORID; }
|
|
||||||
void cycleTraitInstanceXORID() { _traitInstanceXORID = QUuid::createUuid(); }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -1444,6 +1438,8 @@ protected:
|
||||||
ThreadSafeValueCache<glm::mat4> _farGrabLeftMatrixCache { glm::mat4() };
|
ThreadSafeValueCache<glm::mat4> _farGrabLeftMatrixCache { glm::mat4() };
|
||||||
ThreadSafeValueCache<glm::mat4> _farGrabMouseMatrixCache { glm::mat4() };
|
ThreadSafeValueCache<glm::mat4> _farGrabMouseMatrixCache { glm::mat4() };
|
||||||
|
|
||||||
|
ThreadSafeValueCache<QVariantMap> _collisionCapsuleCache{ QVariantMap() };
|
||||||
|
|
||||||
int getFauxJointIndex(const QString& name) const;
|
int getFauxJointIndex(const QString& name) const;
|
||||||
|
|
||||||
float _audioLoudness { 0.0f };
|
float _audioLoudness { 0.0f };
|
||||||
|
@ -1502,8 +1498,6 @@ private:
|
||||||
// privatize the copy constructor and assignment operator so they cannot be called
|
// privatize the copy constructor and assignment operator so they cannot be called
|
||||||
AvatarData(const AvatarData&);
|
AvatarData(const AvatarData&);
|
||||||
AvatarData& operator= (const AvatarData&);
|
AvatarData& operator= (const AvatarData&);
|
||||||
|
|
||||||
AvatarTraits::TraitInstanceID _traitInstanceXORID { QUuid::createUuid() };
|
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(AvatarData*)
|
Q_DECLARE_METATYPE(AvatarData*)
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,7 @@ void AvatarReplicas::processDeletedTraitInstance(const QUuid& parentID, AvatarTr
|
||||||
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
||||||
auto &replicas = _replicasMap[parentID];
|
auto &replicas = _replicasMap[parentID];
|
||||||
for (auto avatar : replicas) {
|
for (auto avatar : replicas) {
|
||||||
avatar->processDeletedTraitInstance(traitType,
|
avatar->processDeletedTraitInstance(traitType, instanceID);
|
||||||
AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,9 +95,7 @@ void AvatarReplicas::processTraitInstance(const QUuid& parentID, AvatarTraits::T
|
||||||
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
||||||
auto &replicas = _replicasMap[parentID];
|
auto &replicas = _replicasMap[parentID];
|
||||||
for (auto avatar : replicas) {
|
for (auto avatar : replicas) {
|
||||||
avatar->processTraitInstance(traitType,
|
avatar->processTraitInstance(traitType, instanceID, traitBinaryData);
|
||||||
AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()),
|
|
||||||
traitBinaryData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +110,12 @@ AvatarHashMap::AvatarHashMap() {
|
||||||
packetReceiver.registerListener(PacketType::BulkAvatarTraits, this, "processBulkAvatarTraits");
|
packetReceiver.registerListener(PacketType::BulkAvatarTraits, this, "processBulkAvatarTraits");
|
||||||
|
|
||||||
connect(nodeList.data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
|
connect(nodeList.data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
|
||||||
|
|
||||||
|
connect(nodeList.data(), &NodeList::nodeKilled, this, [this](SharedNodePointer killedNode){
|
||||||
|
if (killedNode->getType() == NodeType::AvatarMixer) {
|
||||||
|
clearOtherAvatars();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QUuid> AvatarHashMap::getAvatarIdentifiers() {
|
QVector<QUuid> AvatarHashMap::getAvatarIdentifiers() {
|
||||||
|
@ -341,28 +344,16 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> mess
|
||||||
AvatarTraits::TraitInstanceID traitInstanceID =
|
AvatarTraits::TraitInstanceID traitInstanceID =
|
||||||
QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
// XOR the incoming trait instance ID with this avatar object's personal XOR ID
|
|
||||||
|
|
||||||
// this ensures that we have separate entity instances in the local tree
|
|
||||||
// if we briefly end up with two Avatar objects for this node
|
|
||||||
|
|
||||||
// (which can occur if the shared pointer for the
|
|
||||||
// previous instance of an avatar hasn't yet gone out of scope before the
|
|
||||||
// new instance is created)
|
|
||||||
|
|
||||||
auto xoredInstanceID = AvatarTraits::xoredInstanceID(traitInstanceID, avatar->getTraitInstanceXORID());
|
|
||||||
|
|
||||||
message->readPrimitive(&traitBinarySize);
|
message->readPrimitive(&traitBinarySize);
|
||||||
|
|
||||||
auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID);
|
auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID);
|
||||||
if (packetTraitVersion > processedInstanceVersion) {
|
if (packetTraitVersion > processedInstanceVersion) {
|
||||||
// in order to handle re-connections to the avatar mixer when the other
|
|
||||||
if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) {
|
if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) {
|
||||||
avatar->processDeletedTraitInstance(traitType, xoredInstanceID);
|
avatar->processDeletedTraitInstance(traitType, traitInstanceID);
|
||||||
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
|
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
|
||||||
} else {
|
} else {
|
||||||
auto traitData = message->read(traitBinarySize);
|
auto traitData = message->read(traitBinarySize);
|
||||||
avatar->processTraitInstance(traitType, xoredInstanceID, traitData);
|
avatar->processTraitInstance(traitType, traitInstanceID, traitData);
|
||||||
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
|
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
|
||||||
}
|
}
|
||||||
processedInstanceVersion = packetTraitVersion;
|
processedInstanceVersion = packetTraitVersion;
|
||||||
|
@ -430,3 +421,12 @@ void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& ol
|
||||||
emit avatarSessionChangedEvent(sessionUUID, oldUUID);
|
emit avatarSessionChangedEvent(sessionUUID, oldUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarHashMap::clearOtherAvatars() {
|
||||||
|
QWriteLocker locker(&_hashLock);
|
||||||
|
|
||||||
|
for (auto& av : _avatarHash) {
|
||||||
|
handleRemovedAvatar(av);
|
||||||
|
}
|
||||||
|
|
||||||
|
_avatarHash.clear();
|
||||||
|
}
|
||||||
|
|
|
@ -101,6 +101,8 @@ public:
|
||||||
void setReplicaCount(int count);
|
void setReplicaCount(int count);
|
||||||
int getReplicaCount() { return _replicas.getReplicaCount(); };
|
int getReplicaCount() { return _replicas.getReplicaCount(); };
|
||||||
|
|
||||||
|
virtual void clearOtherAvatars();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
|
|
@ -41,8 +41,7 @@ namespace AvatarTraits {
|
||||||
const TraitWireSize DELETED_TRAIT_SIZE = -1;
|
const TraitWireSize DELETED_TRAIT_SIZE = -1;
|
||||||
|
|
||||||
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
|
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
|
||||||
TraitVersion traitVersion = NULL_TRAIT_VERSION,
|
TraitVersion traitVersion = NULL_TRAIT_VERSION) {
|
||||||
TraitInstanceID xoredInstanceID = TraitInstanceID()) {
|
|
||||||
qint64 bytesWritten = 0;
|
qint64 bytesWritten = 0;
|
||||||
|
|
||||||
bytesWritten += destination.writePrimitive(traitType);
|
bytesWritten += destination.writePrimitive(traitType);
|
||||||
|
@ -51,28 +50,12 @@ namespace AvatarTraits {
|
||||||
bytesWritten += destination.writePrimitive(traitVersion);
|
bytesWritten += destination.writePrimitive(traitVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xoredInstanceID.isNull()) {
|
bytesWritten += destination.write(instanceID.toRfc4122());
|
||||||
bytesWritten += destination.write(instanceID.toRfc4122());
|
|
||||||
} else {
|
|
||||||
bytesWritten += destination.write(xoredInstanceID.toRfc4122());
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesWritten += destination.writePrimitive(DELETED_TRAIT_SIZE);
|
bytesWritten += destination.writePrimitive(DELETED_TRAIT_SIZE);
|
||||||
|
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TraitInstanceID xoredInstanceID(TraitInstanceID localInstanceID, TraitInstanceID xorKeyID) {
|
|
||||||
QByteArray xoredInstanceID { NUM_BYTES_RFC4122_UUID, 0 };
|
|
||||||
auto xorKeyIDBytes = xorKeyID.toRfc4122();
|
|
||||||
auto localInstanceIDBytes = localInstanceID.toRfc4122();
|
|
||||||
|
|
||||||
for (auto i = 0; i < localInstanceIDBytes.size(); ++i) {
|
|
||||||
xoredInstanceID[i] = localInstanceIDBytes[i] ^ xorKeyIDBytes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return QUuid::fromRfc4122(xoredInstanceID);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AvatarTraits_h
|
#endif // hifi_AvatarTraits_h
|
||||||
|
|
|
@ -43,9 +43,6 @@ void ClientTraitsHandler::resetForNewMixer() {
|
||||||
|
|
||||||
// pre-fill the instanced statuses that we will need to send next frame
|
// pre-fill the instanced statuses that we will need to send next frame
|
||||||
_owningAvatar->prepareResetTraitInstances();
|
_owningAvatar->prepareResetTraitInstances();
|
||||||
|
|
||||||
// reset the trait XOR ID since we're resetting for a new avatar mixer
|
|
||||||
_owningAvatar->cycleTraitInstanceXORID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
||||||
|
@ -96,19 +93,11 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
||||||
|| instanceIDValuePair.value == Updated) {
|
|| instanceIDValuePair.value == Updated) {
|
||||||
// this is a changed trait we need to send or we haven't send out trait information yet
|
// this is a changed trait we need to send or we haven't send out trait information yet
|
||||||
// ask the owning avatar to pack it
|
// ask the owning avatar to pack it
|
||||||
|
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList);
|
||||||
// since this is going to the mixer, use the XORed instance ID (to anonymize trait instance IDs
|
|
||||||
// that would typically persist across sessions)
|
|
||||||
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList,
|
|
||||||
AvatarTraits::NULL_TRAIT_VERSION,
|
|
||||||
AvatarTraits::xoredInstanceID(instanceIDValuePair.id,
|
|
||||||
_owningAvatar->getTraitInstanceXORID()));
|
|
||||||
} else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) {
|
} else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) {
|
||||||
// pack delete for this trait instance
|
// pack delete for this trait instance
|
||||||
AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id,
|
AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id,
|
||||||
*traitsPacketList, AvatarTraits::NULL_TRAIT_VERSION,
|
*traitsPacketList);
|
||||||
AvatarTraits::xoredInstanceID(instanceIDValuePair.id,
|
|
||||||
_owningAvatar->getTraitInstanceXORID()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|