mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 07:27:04 +02:00
Merge branch 'replicants' of https://github.com/highfidelity/hifi into feat/downstream-in-nodelist
This commit is contained in:
commit
1ed0b693da
108 changed files with 2356 additions and 1395 deletions
|
@ -143,6 +143,8 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> mess
|
||||||
rewrittenType = PacketType::InjectAudio;
|
rewrittenType = PacketType::InjectAudio;
|
||||||
} else if (message->getType() == PacketType::ReplicatedSilentAudioFrame) {
|
} else if (message->getType() == PacketType::ReplicatedSilentAudioFrame) {
|
||||||
rewrittenType = PacketType::SilentAudioFrame;
|
rewrittenType = PacketType::SilentAudioFrame;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto replicatedMessage = QSharedPointer<ReceivedMessage>::create(audioData, rewrittenType,
|
auto replicatedMessage = QSharedPointer<ReceivedMessage>::create(audioData, rewrittenType,
|
||||||
|
|
|
@ -691,9 +691,10 @@ bool AudioMixerClientData::shouldIgnore(const SharedNodePointer self, const Shar
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointer<ReceivedMessage> message) {
|
void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointer<ReceivedMessage> message) {
|
||||||
// pull the codec string from the packet
|
// hop past the sequence number that leads the packet
|
||||||
message->seek(sizeof(quint16));
|
message->seek(sizeof(quint16));
|
||||||
|
|
||||||
|
// pull the codec string from the packet
|
||||||
auto codecString = message->readString();
|
auto codecString = message->readString();
|
||||||
|
|
||||||
qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID())
|
qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID())
|
||||||
|
|
|
@ -85,7 +85,7 @@ SharedNodePointer addOrUpdateReplicatedNode(const QUuid& nodeID, const HifiSockA
|
||||||
|
|
||||||
void AvatarMixer::handleReplicatedPackets(QSharedPointer<ReceivedMessage> message) {
|
void AvatarMixer::handleReplicatedPackets(QSharedPointer<ReceivedMessage> message) {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
auto nodeID = QUuid::fromRfc4122(message->peek(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
auto replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr());
|
auto replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr());
|
||||||
|
|
||||||
|
@ -516,12 +516,9 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
|
||||||
AvatarData& avatar = nodeData->getAvatar();
|
AvatarData& avatar = nodeData->getAvatar();
|
||||||
|
|
||||||
// parse the identity packet and update the change timestamp if appropriate
|
// parse the identity packet and update the change timestamp if appropriate
|
||||||
AvatarData::Identity identity;
|
|
||||||
AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity);
|
|
||||||
|
|
||||||
bool identityChanged = false;
|
bool identityChanged = false;
|
||||||
bool displayNameChanged = false;
|
bool displayNameChanged = false;
|
||||||
avatar.processAvatarIdentity(identity, identityChanged, displayNameChanged);
|
avatar.processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged);
|
||||||
if (identityChanged) {
|
if (identityChanged) {
|
||||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||||
nodeData->flagIdentityChange();
|
nodeData->flagIdentityChange();
|
||||||
|
|
|
@ -67,7 +67,7 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) {
|
||||||
|
|
||||||
int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
||||||
if (destinationNode->getType() == NodeType::Agent && !destinationNode->isUpstream()) {
|
if (destinationNode->getType() == NodeType::Agent && !destinationNode->isUpstream()) {
|
||||||
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
|
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(true);
|
||||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
||||||
auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||||
identityPackets->write(individualData);
|
identityPackets->write(individualData);
|
||||||
|
@ -81,7 +81,7 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData,
|
||||||
|
|
||||||
int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
||||||
if (destinationNode->getType() == NodeType::DownstreamAvatarMixer) {
|
if (destinationNode->getType() == NodeType::DownstreamAvatarMixer) {
|
||||||
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
|
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(true);
|
||||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
||||||
auto identityPacket = NLPacket::create(PacketType::ReplicatedAvatarIdentity);
|
auto identityPacket = NLPacket::create(PacketType::ReplicatedAvatarIdentity);
|
||||||
identityPacket->write(individualData);
|
identityPacket->write(individualData);
|
||||||
|
@ -204,216 +204,212 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
ViewFrustum cameraView = nodeData->getViewFrustom();
|
ViewFrustum cameraView = nodeData->getViewFrustom();
|
||||||
std::priority_queue<AvatarPriority> sortedAvatars;
|
std::priority_queue<AvatarPriority> sortedAvatars;
|
||||||
AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars,
|
AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars,
|
||||||
[&](AvatarSharedPointer avatar)->uint64_t{
|
[&](AvatarSharedPointer avatar)->uint64_t {
|
||||||
auto avatarNode = avatarDataToNodes[avatar];
|
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
|
||||||
return nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
return nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
||||||
},
|
}, [&](AvatarSharedPointer avatar)->float{
|
||||||
|
glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner());
|
||||||
|
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
||||||
|
}, [&](AvatarSharedPointer avatar)->bool {
|
||||||
|
if (avatar == thisAvatar) {
|
||||||
|
return true; // ignore ourselves...
|
||||||
|
}
|
||||||
|
|
||||||
[&](AvatarSharedPointer avatar)->float{
|
bool shouldIgnore = false;
|
||||||
glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner());
|
|
||||||
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
|
||||||
},
|
|
||||||
|
|
||||||
[&](AvatarSharedPointer avatar)->bool{
|
// We will also ignore other nodes for a couple of different reasons:
|
||||||
if (avatar == thisAvatar) {
|
// 1) ignore bubbles and ignore specific node
|
||||||
return true; // ignore ourselves...
|
// 2) the node hasn't really updated it's frame data recently, this can
|
||||||
}
|
// happen if for example the avatar is connected on a desktop and sending
|
||||||
|
// updates at ~30hz. So every 3 frames we skip a frame.
|
||||||
|
auto avatarNode = avatarDataToNodes[avatar];
|
||||||
|
|
||||||
bool shouldIgnore = false;
|
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
|
|
||||||
// We will also ignore other nodes for a couple of different reasons:
|
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||||
// 1) ignore bubbles and ignore specific node
|
assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data
|
||||||
// 2) the node hasn't really updated it's frame data recently, this can
|
quint64 startIgnoreCalculation = usecTimestampNow();
|
||||||
// happen if for example the avatar is connected on a desktop and sending
|
|
||||||
// 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
|
// 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
|
||||||
|
// or that has ignored the viewing node
|
||||||
|
if (!avatarNode->getLinkedData()
|
||||||
|
|| avatarNode->getUUID() == node->getUUID()
|
||||||
|
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
||||||
|
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
||||||
|
shouldIgnore = true;
|
||||||
|
} else {
|
||||||
|
|
||||||
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
// Check to see if the space bubble is enabled
|
||||||
assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data
|
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
||||||
quint64 startIgnoreCalculation = usecTimestampNow();
|
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||||
|
|
||||||
// make sure we have data for this avatar, that it isn't the same node,
|
// Define the scale of the box for the current other node
|
||||||
// and isn't an avatar that the viewing node has ignored
|
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
||||||
// or that has ignored the viewing node
|
// Set up the bounding box for the current other node
|
||||||
if (!avatarNode->getLinkedData()
|
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
|| avatarNode->getUUID() == node->getUUID()
|
// Clamp the size of the bounding box to a minimum scale
|
||||||
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) {
|
||||||
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
otherNodeBox.setScaleStayCentered(minBubbleSize);
|
||||||
shouldIgnore = true;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// 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
|
|
||||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
|
||||||
|
|
||||||
// Define the scale of the box for the current other node
|
|
||||||
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
// Quadruple the scale of both bounding boxes
|
|
||||||
otherNodeBox.embiggen(4.0f);
|
|
||||||
|
|
||||||
// Perform the collision check between the two bounding boxes
|
|
||||||
if (nodeBox.touches(otherNodeBox)) {
|
|
||||||
nodeData->ignoreOther(node, avatarNode);
|
|
||||||
shouldIgnore = !getsAnyIgnored;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Not close enough to ignore
|
// Quadruple the scale of both bounding boxes
|
||||||
if (!shouldIgnore) {
|
otherNodeBox.embiggen(4.0f);
|
||||||
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
|
||||||
|
// Perform the collision check between the two bounding boxes
|
||||||
|
if (nodeBox.touches(otherNodeBox)) {
|
||||||
|
nodeData->ignoreOther(node, avatarNode);
|
||||||
|
shouldIgnore = !getsAnyIgnored;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
quint64 endIgnoreCalculation = usecTimestampNow();
|
// Not close enough to ignore
|
||||||
_stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation);
|
|
||||||
|
|
||||||
if (!shouldIgnore) {
|
if (!shouldIgnore) {
|
||||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
||||||
AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber();
|
|
||||||
|
|
||||||
// FIXME - This code does appear to be working. But it seems brittle.
|
|
||||||
// It supports determining if the frame of data for this "other"
|
|
||||||
// avatar has already been sent to the reciever. This has been
|
|
||||||
// verified to work on a desktop display that renders at 60hz and
|
|
||||||
// therefore sends to mixer at 30hz. Each second you'd expect to
|
|
||||||
// have 15 (45hz-30hz) duplicate frames. In this case, the stat
|
|
||||||
// avg_other_av_skips_per_second does report 15.
|
|
||||||
//
|
|
||||||
// make sure we haven't already sent this data from this sender to this receiver
|
|
||||||
// or that somehow we haven't sent
|
|
||||||
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
|
||||||
++numAvatarsHeldBack;
|
|
||||||
shouldIgnore = true;
|
|
||||||
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
|
||||||
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
|
||||||
++numAvatarsWithSkippedFrames;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return shouldIgnore;
|
}
|
||||||
});
|
quint64 endIgnoreCalculation = usecTimestampNow();
|
||||||
|
_stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation);
|
||||||
|
|
||||||
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
if (!shouldIgnore) {
|
||||||
int avatarRank = 0;
|
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
||||||
|
AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber();
|
||||||
|
|
||||||
// this is overly conservative, because it includes some avatars we might not consider
|
// FIXME - This code does appear to be working. But it seems brittle.
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
// It supports determining if the frame of data for this "other"
|
||||||
|
// avatar has already been sent to the reciever. This has been
|
||||||
while (!sortedAvatars.empty()) {
|
// verified to work on a desktop display that renders at 60hz and
|
||||||
AvatarPriority sortData = sortedAvatars.top();
|
// therefore sends to mixer at 30hz. Each second you'd expect to
|
||||||
sortedAvatars.pop();
|
// have 15 (45hz-30hz) duplicate frames. In this case, the stat
|
||||||
const auto& avatarData = sortData.avatar;
|
// avg_other_av_skips_per_second does report 15.
|
||||||
avatarRank++;
|
//
|
||||||
remainingAvatars--;
|
// make sure we haven't already sent this data from this sender to this receiver
|
||||||
|
// or that somehow we haven't sent
|
||||||
auto otherNode = avatarDataToNodes[avatarData];
|
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
||||||
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
++numAvatarsHeldBack;
|
||||||
|
shouldIgnore = true;
|
||||||
// NOTE: Here's where we determine if we are over budget and drop to bare minimum data
|
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
||||||
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
||||||
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
++numAvatarsWithSkippedFrames;
|
||||||
|
|
||||||
quint64 startAvatarDataPacking = usecTimestampNow();
|
|
||||||
|
|
||||||
++numOtherAvatars;
|
|
||||||
|
|
||||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
|
||||||
|
|
||||||
// If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO
|
|
||||||
// the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A.
|
|
||||||
if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) {
|
|
||||||
identityBytesSent += sendIdentityPacket(otherNodeData, node);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return shouldIgnore;
|
||||||
|
});
|
||||||
|
|
||||||
const AvatarData* otherAvatar = otherNodeData->getConstAvatarData();
|
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
||||||
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
int avatarRank = 0;
|
||||||
|
|
||||||
// determine if avatar is in view, to determine how much data to include...
|
// this is overly conservative, because it includes some avatars we might not consider
|
||||||
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
|
||||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
|
||||||
|
|
||||||
// start a new segment in the PacketList for this avatar
|
while (!sortedAvatars.empty()) {
|
||||||
avatarPacketList->startSegment();
|
AvatarPriority sortData = sortedAvatars.top();
|
||||||
|
sortedAvatars.pop();
|
||||||
|
const auto& avatarData = sortData.avatar;
|
||||||
|
avatarRank++;
|
||||||
|
remainingAvatars--;
|
||||||
|
|
||||||
AvatarData::AvatarDataDetail detail;
|
auto otherNode = avatarDataToNodes[avatarData];
|
||||||
|
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
|
|
||||||
if (overBudget) {
|
// NOTE: Here's where we determine if we are over budget and drop to bare minimum data
|
||||||
overBudgetAvatars++;
|
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
||||||
_stats.overBudgetAvatars++;
|
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
||||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
|
||||||
} else if (!isInView) {
|
|
||||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData;
|
|
||||||
nodeData->incrementAvatarOutOfView();
|
|
||||||
} else {
|
|
||||||
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
|
||||||
? AvatarData::SendAllData : AvatarData::CullSmallData;
|
|
||||||
nodeData->incrementAvatarInView();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool includeThisAvatar = true;
|
quint64 startAvatarDataPacking = usecTimestampNow();
|
||||||
auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID());
|
|
||||||
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
|
||||||
bool distanceAdjust = true;
|
|
||||||
glm::vec3 viewerPosition = myPosition;
|
|
||||||
AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray
|
|
||||||
bool dropFaceTracking = false;
|
|
||||||
|
|
||||||
quint64 start = usecTimestampNow();
|
++numOtherAvatars;
|
||||||
QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
|
||||||
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||||
quint64 end = usecTimestampNow();
|
|
||||||
_stats.toByteArrayElapsedTime += (end - start);
|
// If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO
|
||||||
|
// the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A.
|
||||||
|
if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) {
|
||||||
|
identityBytesSent += sendIdentityPacket(otherNodeData, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AvatarData* otherAvatar = otherNodeData->getConstAvatarData();
|
||||||
|
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
||||||
|
|
||||||
|
// determine if avatar is in view, to determine how much data to include...
|
||||||
|
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
||||||
|
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
|
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
||||||
|
|
||||||
|
// start a new segment in the PacketList for this avatar
|
||||||
|
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;
|
||||||
|
nodeData->incrementAvatarOutOfView();
|
||||||
|
} else {
|
||||||
|
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
||||||
|
? AvatarData::SendAllData : AvatarData::CullSmallData;
|
||||||
|
nodeData->incrementAvatarInView();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool includeThisAvatar = true;
|
||||||
|
auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID());
|
||||||
|
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
||||||
|
bool distanceAdjust = true;
|
||||||
|
glm::vec3 viewerPosition = myPosition;
|
||||||
|
AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray
|
||||||
|
bool dropFaceTracking = false;
|
||||||
|
|
||||||
|
quint64 start = usecTimestampNow();
|
||||||
|
QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
||||||
|
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
||||||
|
quint64 end = usecTimestampNow();
|
||||||
|
_stats.toByteArrayElapsedTime += (end - start);
|
||||||
|
|
||||||
|
static const int MAX_ALLOWED_AVATAR_DATA = (1400 - NUM_BYTES_RFC4122_UUID);
|
||||||
|
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
||||||
|
qCWarning(avatars) << "otherAvatar.toByteArray() resulted in very large buffer:" << bytes.size() << "... attempt to drop facial data";
|
||||||
|
|
||||||
|
dropFaceTracking = true; // first try dropping the facial data
|
||||||
|
bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
||||||
|
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
||||||
|
|
||||||
static const int MAX_ALLOWED_AVATAR_DATA = (1400 - NUM_BYTES_RFC4122_UUID);
|
|
||||||
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
||||||
qCWarning(avatars) << "otherAvatar.toByteArray() resulted in very large buffer:" << bytes.size() << "... attempt to drop facial data";
|
qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData";
|
||||||
|
bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther,
|
||||||
dropFaceTracking = true; // first try dropping the facial data
|
|
||||||
bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
|
||||||
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
||||||
|
|
||||||
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
|
||||||
qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData";
|
|
||||||
bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther,
|
|
||||||
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
|
||||||
qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!";
|
|
||||||
includeThisAvatar = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeThisAvatar) {
|
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
||||||
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!";
|
||||||
numAvatarDataBytes += avatarPacketList->write(bytes);
|
includeThisAvatar = false;
|
||||||
|
|
||||||
if (detail != AvatarData::NoData) {
|
|
||||||
_stats.numOthersIncluded++;
|
|
||||||
|
|
||||||
// increment the number of avatars sent to this reciever
|
|
||||||
nodeData->incrementNumAvatarsSentLastFrame();
|
|
||||||
|
|
||||||
// set the last sent sequence number for this sender on the receiver
|
|
||||||
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
|
|
||||||
otherNodeData->getLastReceivedSequenceNumber());
|
|
||||||
|
|
||||||
// remember the last time we sent details about this other node to the receiver
|
|
||||||
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
avatarPacketList->endSegment();
|
if (includeThisAvatar) {
|
||||||
|
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
||||||
|
numAvatarDataBytes += avatarPacketList->write(bytes);
|
||||||
|
|
||||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
if (detail != AvatarData::NoData) {
|
||||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
_stats.numOthersIncluded++;
|
||||||
|
|
||||||
|
// increment the number of avatars sent to this reciever
|
||||||
|
nodeData->incrementNumAvatarsSentLastFrame();
|
||||||
|
|
||||||
|
// set the last sent sequence number for this sender on the receiver
|
||||||
|
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
|
||||||
|
otherNodeData->getLastReceivedSequenceNumber());
|
||||||
|
|
||||||
|
// remember the last time we sent details about this other node to the receiver
|
||||||
|
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarPacketList->endSegment();
|
||||||
|
|
||||||
|
quint64 endAvatarDataPacking = usecTimestampNow();
|
||||||
|
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
||||||
};
|
};
|
||||||
|
|
||||||
quint64 startPacketSending = usecTimestampNow();
|
quint64 startPacketSending = usecTimestampNow();
|
||||||
|
|
|
@ -76,8 +76,8 @@ void AvatarMixerSlavePool::processIncomingPackets(ConstIter begin, ConstIter end
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixerSlavePool::broadcastAvatarData(ConstIter begin, ConstIter end,
|
void AvatarMixerSlavePool::broadcastAvatarData(ConstIter begin, ConstIter end,
|
||||||
p_high_resolution_clock::time_point lastFrameTimestamp,
|
p_high_resolution_clock::time_point lastFrameTimestamp,
|
||||||
float maxKbpsPerNode, float throttlingRatio) {
|
float maxKbpsPerNode, float throttlingRatio) {
|
||||||
_function = &AvatarMixerSlave::broadcastAvatarData;
|
_function = &AvatarMixerSlave::broadcastAvatarData;
|
||||||
_configure = [&](AvatarMixerSlave& slave) {
|
_configure = [&](AvatarMixerSlave& slave) {
|
||||||
slave.configureBroadcast(begin, end, lastFrameTimestamp, maxKbpsPerNode, throttlingRatio);
|
slave.configureBroadcast(begin, end, lastFrameTimestamp, maxKbpsPerNode, throttlingRatio);
|
||||||
|
|
|
@ -47,7 +47,7 @@ void OctreeInboundPacketProcessor::resetStats() {
|
||||||
_singleSenderStats.clear();
|
_singleSenderStats.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long OctreeInboundPacketProcessor::getMaxWait() const {
|
uint32_t OctreeInboundPacketProcessor::getMaxWait() const {
|
||||||
// calculate time until next sendNackPackets()
|
// calculate time until next sendNackPackets()
|
||||||
quint64 nextNackTime = _lastNackTime + TOO_LONG_SINCE_LAST_NACK;
|
quint64 nextNackTime = _lastNackTime + TOO_LONG_SINCE_LAST_NACK;
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
|
@ -80,7 +80,7 @@ protected:
|
||||||
|
|
||||||
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
|
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
|
||||||
|
|
||||||
virtual unsigned long getMaxWait() const override;
|
virtual uint32_t getMaxWait() const override;
|
||||||
virtual void preProcess() override;
|
virtual void preProcess() override;
|
||||||
virtual void midProcess() override;
|
virtual void midProcess() override;
|
||||||
|
|
||||||
|
|
|
@ -1360,8 +1360,19 @@
|
||||||
{
|
{
|
||||||
"name": "server_type",
|
"name": "server_type",
|
||||||
"label": "Server Type",
|
"label": "Server Type",
|
||||||
|
"type": "select",
|
||||||
"placeholder": "Audio Mixer",
|
"placeholder": "Audio Mixer",
|
||||||
"can_set": true
|
"can_set": true,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"value": "Audio Mixer",
|
||||||
|
"label": "Audio Mixer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Avatar Mixer",
|
||||||
|
"label": "Avatar Mixer"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,14 @@ $(document).ready(function(){
|
||||||
// set focus to the first input in the new row
|
// set focus to the first input in the new row
|
||||||
$target.closest('table').find('tr.inputs input:first').focus();
|
$target.closest('table').find('tr.inputs input:first').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tableRows = sibling.parent();
|
||||||
|
var tableBody = tableRows.parent();
|
||||||
|
|
||||||
|
// if theres no more siblings, we should jump to a new row
|
||||||
|
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
|
||||||
|
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ($target.is('input')) {
|
} else if ($target.is('input')) {
|
||||||
|
@ -1281,6 +1289,17 @@ function makeTableHiddenInputs(setting, initialValues, categoryValue) {
|
||||||
"<input type='checkbox' style='display: none;' class='form-control table-checkbox' " +
|
"<input type='checkbox' style='display: none;' class='form-control table-checkbox' " +
|
||||||
"name='" + col.name + "'" + (defaultValue ? " checked" : "") + "/>" +
|
"name='" + col.name + "'" + (defaultValue ? " checked" : "") + "/>" +
|
||||||
"</td>";
|
"</td>";
|
||||||
|
} else if (col.type === "select") {
|
||||||
|
html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>"
|
||||||
|
html += "<select style='display: none;' class='form-control' data-hidden-input='" + col.name + "'>'"
|
||||||
|
|
||||||
|
for (var i in col.options) {
|
||||||
|
var option = col.options[i];
|
||||||
|
html += "<option value='" + option.value + "' " + (option.value == defaultValue ? 'selected' : '') + ">" + option.label + "</option>";
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "</select>";
|
||||||
|
html += "<input type='hidden' class='table-dropdown form-control trigger-change' name='" + col.name + "' value='" + option.value + "'></td>";
|
||||||
} else {
|
} else {
|
||||||
html +=
|
html +=
|
||||||
"<td " + (col.hidden ? "style='display: none;'" : "") + " class='" + Settings.DATA_COL_CLASS + "' " +
|
"<td " + (col.hidden ? "style='display: none;'" : "") + " class='" + Settings.DATA_COL_CLASS + "' " +
|
||||||
|
@ -1408,6 +1427,7 @@ function addTableRow(row) {
|
||||||
input.show();
|
input.show();
|
||||||
|
|
||||||
var isCheckbox = input.hasClass("table-checkbox");
|
var isCheckbox = input.hasClass("table-checkbox");
|
||||||
|
var isDropdown = input.hasClass("table-dropdown");
|
||||||
|
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
var row_index = row.siblings('.' + Settings.DATA_ROW_CLASS).length
|
var row_index = row.siblings('.' + Settings.DATA_ROW_CLASS).length
|
||||||
|
@ -1416,11 +1436,15 @@ function addTableRow(row) {
|
||||||
// are there multiple columns or just one?
|
// are there multiple columns or just one?
|
||||||
// with multiple we have an array of Objects, with one we have an array of whatever the value type is
|
// with multiple we have an array of Objects, with one we have an array of whatever the value type is
|
||||||
var num_columns = row.children('.' + Settings.DATA_COL_CLASS).length
|
var num_columns = row.children('.' + Settings.DATA_COL_CLASS).length
|
||||||
|
var newName = setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : "");
|
||||||
|
|
||||||
if (isCheckbox) {
|
if (isCheckbox) {
|
||||||
input.attr("name", setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : ""))
|
input.attr("name", newName)
|
||||||
} else {
|
} else {
|
||||||
input.attr("name", setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : ""))
|
if (isDropdown) {
|
||||||
|
$(element).children("select").attr("data-hidden-input", newName);
|
||||||
|
}
|
||||||
|
input.attr("name", newName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// because the name of the setting in question requires the key
|
// because the name of the setting in question requires the key
|
||||||
|
@ -1435,6 +1459,12 @@ function addTableRow(row) {
|
||||||
input.focus();
|
input.focus();
|
||||||
focusChanged = true;
|
focusChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we are adding a dropdown, we should go ahead and make its select
|
||||||
|
// element is visible
|
||||||
|
if (isDropdown) {
|
||||||
|
$(element).children("select").attr("style", "");
|
||||||
|
}
|
||||||
|
|
||||||
if (isCheckbox) {
|
if (isCheckbox) {
|
||||||
$(input).find("input").attr("data-changed", "true");
|
$(input).find("input").attr("data-changed", "true");
|
||||||
|
|
|
@ -2322,6 +2322,11 @@ void DomainServer::updateReplicatedNodes() {
|
||||||
qDebug() << "Setting node to NOT be replicated:" << otherNode->getUUID();
|
qDebug() << "Setting node to NOT be replicated:" << otherNode->getUUID();
|
||||||
} else if (!isReplicated && shouldReplicate) {
|
} else if (!isReplicated && shouldReplicate) {
|
||||||
qDebug() << "Setting node to replicated:" << otherNode->getUUID();
|
qDebug() << "Setting node to replicated:" << otherNode->getUUID();
|
||||||
|
qDebug() << "Setting node to NOT be replicated:"
|
||||||
|
<< otherNode->getPermissions().getVerifiedUserName() << otherNode->getUUID();
|
||||||
|
} else if (!isReplicated && shouldReplicate) {
|
||||||
|
qDebug() << "Setting node to replicated:"
|
||||||
|
<< otherNode->getPermissions().getVerifiedUserName() << otherNode->getUUID();
|
||||||
}
|
}
|
||||||
otherNode->setIsReplicated(shouldReplicate);
|
otherNode->setIsReplicated(shouldReplicate);
|
||||||
}
|
}
|
||||||
|
@ -2330,7 +2335,7 @@ void DomainServer::updateReplicatedNodes() {
|
||||||
|
|
||||||
bool DomainServer::shouldReplicateNode(const Node& node) {
|
bool DomainServer::shouldReplicateNode(const Node& node) {
|
||||||
QString verifiedUsername = node.getPermissions().getVerifiedUserName();
|
QString verifiedUsername = node.getPermissions().getVerifiedUserName();
|
||||||
// Both he verified username and usernames in _replicatedUsernames are lowercase, so
|
// Both the verified username and usernames in _replicatedUsernames are lowercase, so
|
||||||
// comparisons here are case-insensitive.
|
// comparisons here are case-insensitive.
|
||||||
auto it = find(_replicatedUsernames.cbegin(), _replicatedUsernames.cend(), verifiedUsername);
|
auto it = find(_replicatedUsernames.cbegin(), _replicatedUsernames.cend(), verifiedUsername);
|
||||||
return it != _replicatedUsernames.end() && node.getType() == NodeType::Agent;
|
return it != _replicatedUsernames.end() && node.getType() == NodeType::Agent;
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
{
|
{
|
||||||
"RenderShadowTask": {
|
"RenderMainView": {
|
||||||
"Enabled": {
|
"RenderShadowTask": {
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RenderDeferredTask": {
|
|
||||||
"AmbientOcclusion": {
|
|
||||||
"Enabled": {
|
"Enabled": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"RenderDeferredTask": {
|
||||||
|
"AmbientOcclusion": {
|
||||||
|
"Enabled": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ var EventBridge;
|
||||||
var webChannel = new QWebChannel(qt.webChannelTransport, function (channel) {
|
var webChannel = new QWebChannel(qt.webChannelTransport, function (channel) {
|
||||||
// replace the TempEventBridge with the real one.
|
// replace the TempEventBridge with the real one.
|
||||||
var tempEventBridge = EventBridge;
|
var tempEventBridge = EventBridge;
|
||||||
EventBridge = channel.objects.eventBridgeWrapper.eventBridge;
|
EventBridge = channel.objects.eventBridge;
|
||||||
tempEventBridge._callbacks.forEach(function (callback) {
|
tempEventBridge._callbacks.forEach(function (callback) {
|
||||||
EventBridge.scriptEventReceived.connect(callback);
|
EventBridge.scriptEventReceived.connect(callback);
|
||||||
});
|
});
|
||||||
|
|
Binary file not shown.
|
@ -1,85 +1,89 @@
|
||||||
name = Jointy3
|
name = mannequin
|
||||||
type = body+head
|
type = body+head
|
||||||
scale = 1
|
scale = 1
|
||||||
filename = Jointy3/Jointy3.fbx
|
filename = mannequin/mannequin.baked.fbx
|
||||||
texdir = Jointy3/textures
|
joint = jointEyeLeft = LeftEye
|
||||||
|
joint = jointRightHand = RightHand
|
||||||
|
joint = jointHead = Head
|
||||||
|
joint = jointEyeRight = RightEye
|
||||||
|
joint = jointLean = Spine
|
||||||
joint = jointNeck = Neck
|
joint = jointNeck = Neck
|
||||||
joint = jointLeftHand = LeftHand
|
joint = jointLeftHand = LeftHand
|
||||||
joint = jointEyeRight = RightEye
|
|
||||||
joint = jointHead = Head
|
|
||||||
joint = jointRightHand = RightHand
|
|
||||||
joint = jointRoot = Hips
|
joint = jointRoot = Hips
|
||||||
joint = jointLean = Spine
|
|
||||||
joint = jointEyeLeft = LeftEye
|
|
||||||
freeJoint = LeftArm
|
freeJoint = LeftArm
|
||||||
freeJoint = LeftForeArm
|
freeJoint = LeftForeArm
|
||||||
freeJoint = RightArm
|
freeJoint = RightArm
|
||||||
freeJoint = RightForeArm
|
freeJoint = RightForeArm
|
||||||
jointIndex = RightHand = 17
|
bs = EyeBlink_L = blink = 1
|
||||||
jointIndex = LeftHandIndex3 = 56
|
bs = JawOpen = mouth_Open = 1
|
||||||
jointIndex = Hips = 0
|
bs = LipsFunnel = Oo = 1
|
||||||
jointIndex = LeftHandRing2 = 47
|
bs = BrowsU_L = brow_Up = 1
|
||||||
jointIndex = LeftHandThumb3 = 60
|
jointIndex = RightHandIndex2 = 27
|
||||||
jointIndex = RightShoulder = 14
|
jointIndex = LeftHandIndex2 = 51
|
||||||
jointIndex = RightHandRing1 = 30
|
jointIndex = RightUpLeg = 6
|
||||||
jointIndex = RightHandRing3 = 32
|
jointIndex = RightToe_End = 10
|
||||||
jointIndex = LeftHandPinky4 = 45
|
jointIndex = RightEye = 65
|
||||||
jointIndex = LeftHandRing1 = 46
|
|
||||||
jointIndex = LeftFoot = 8
|
|
||||||
jointIndex = RightHandIndex2 = 23
|
|
||||||
jointIndex = RightToeBase = 4
|
|
||||||
jointIndex = RightHandMiddle4 = 29
|
|
||||||
jointIndex = RightHandPinky4 = 37
|
|
||||||
jointIndex = LeftToe_End = 10
|
|
||||||
jointIndex = RightEye = 66
|
|
||||||
jointIndex = RightHandPinky2 = 35
|
|
||||||
jointIndex = RightHandRing2 = 31
|
|
||||||
jointIndex = LeftHand = 41
|
|
||||||
jointIndex = RightToe_End = 5
|
|
||||||
jointIndex = LeftEye = 65
|
|
||||||
jointIndex = LeftHandThumb2 = 59
|
|
||||||
jointIndex = pCylinder73Shape1 = 67
|
|
||||||
jointIndex = LeftShoulder = 38
|
|
||||||
jointIndex = LeftHandIndex2 = 55
|
|
||||||
jointIndex = RightForeArm = 16
|
|
||||||
jointIndex = LeftHandMiddle2 = 51
|
|
||||||
jointIndex = RightHandRing4 = 33
|
|
||||||
jointIndex = LeftLeg = 7
|
|
||||||
jointIndex = LeftHandThumb4 = 61
|
|
||||||
jointIndex = LeftForeArm = 40
|
|
||||||
jointIndex = HeadTop_End = 64
|
|
||||||
jointIndex = RightHandPinky1 = 34
|
|
||||||
jointIndex = RightHandIndex1 = 22
|
|
||||||
jointIndex = LeftHandIndex1 = 54
|
|
||||||
jointIndex = RightLeg = 2
|
|
||||||
jointIndex = RightHandIndex4 = 25
|
|
||||||
jointIndex = Neck = 62
|
|
||||||
jointIndex = LeftHandMiddle1 = 50
|
|
||||||
jointIndex = RightHandPinky3 = 36
|
|
||||||
jointIndex = LeftHandPinky2 = 43
|
|
||||||
jointIndex = RightHandMiddle3 = 28
|
|
||||||
jointIndex = RightHandThumb4 = 21
|
|
||||||
jointIndex = LeftUpLeg = 6
|
|
||||||
jointIndex = RightFoot = 3
|
|
||||||
jointIndex = LeftHandThumb1 = 58
|
|
||||||
jointIndex = LeftArm = 39
|
|
||||||
jointIndex = RightHandMiddle1 = 26
|
|
||||||
jointIndex = LeftHandRing3 = 48
|
|
||||||
jointIndex = LeftHandMiddle4 = 53
|
|
||||||
jointIndex = RightUpLeg = 1
|
|
||||||
jointIndex = RightHandMiddle2 = 27
|
|
||||||
jointIndex = LeftToeBase = 9
|
|
||||||
jointIndex = RightHandThumb2 = 19
|
|
||||||
jointIndex = Spine2 = 13
|
|
||||||
jointIndex = Spine = 11
|
|
||||||
jointIndex = LeftHandRing4 = 49
|
|
||||||
jointIndex = Head = 63
|
|
||||||
jointIndex = LeftHandPinky3 = 44
|
|
||||||
jointIndex = LeftHandPinky1 = 42
|
jointIndex = LeftHandPinky1 = 42
|
||||||
jointIndex = RightHandThumb1 = 18
|
jointIndex = RightHandRing1 = 22
|
||||||
jointIndex = LeftHandIndex4 = 57
|
jointIndex = face = 67
|
||||||
jointIndex = LeftHandMiddle3 = 52
|
jointIndex = LeftUpLeg = 1
|
||||||
jointIndex = RightHandIndex3 = 24
|
jointIndex = LeftHand = 41
|
||||||
jointIndex = Spine1 = 12
|
jointIndex = LeftHandMiddle1 = 58
|
||||||
|
jointIndex = LeftHandIndex1 = 50
|
||||||
|
jointIndex = LeftEye = 64
|
||||||
|
jointIndex = RightHandIndex1 = 26
|
||||||
|
jointIndex = LeftHandPinky4 = 45
|
||||||
jointIndex = RightArm = 15
|
jointIndex = RightArm = 15
|
||||||
jointIndex = RightHandThumb3 = 20
|
jointIndex = LeftShoulder = 38
|
||||||
|
jointIndex = RightHandPinky2 = 19
|
||||||
|
jointIndex = RightHandThumb1 = 30
|
||||||
|
jointIndex = RightForeArm = 16
|
||||||
|
jointIndex = LeftHandMiddle3 = 60
|
||||||
|
jointIndex = Neck = 62
|
||||||
|
jointIndex = LeftHandThumb1 = 54
|
||||||
|
jointIndex = RightHandMiddle2 = 35
|
||||||
|
jointIndex = LeftHandMiddle4 = 61
|
||||||
|
jointIndex = mannequin = 68
|
||||||
|
jointIndex = Spine1 = 12
|
||||||
|
jointIndex = RightFoot = 8
|
||||||
|
jointIndex = RightHand = 17
|
||||||
|
jointIndex = LeftHandIndex3 = 52
|
||||||
|
jointIndex = RightHandIndex3 = 28
|
||||||
|
jointIndex = RightHandMiddle4 = 37
|
||||||
|
jointIndex = LeftLeg = 2
|
||||||
|
jointIndex = RightHandMiddle1 = 34
|
||||||
|
jointIndex = Spine2 = 13
|
||||||
|
jointIndex = LeftHandMiddle2 = 59
|
||||||
|
jointIndex = LeftHandPinky3 = 44
|
||||||
|
jointIndex = LeftHandThumb3 = 56
|
||||||
|
jointIndex = LeftHandRing4 = 49
|
||||||
|
jointIndex = RightHandThumb2 = 31
|
||||||
|
jointIndex = LeftHandRing3 = 48
|
||||||
|
jointIndex = HeadTop_End = 66
|
||||||
|
jointIndex = LeftHandThumb4 = 57
|
||||||
|
jointIndex = RightHandThumb3 = 32
|
||||||
|
jointIndex = RightHandPinky1 = 18
|
||||||
|
jointIndex = RightLeg = 7
|
||||||
|
jointIndex = RightHandMiddle3 = 36
|
||||||
|
jointIndex = RightHandPinky3 = 20
|
||||||
|
jointIndex = LeftToeBase = 4
|
||||||
|
jointIndex = LeftForeArm = 40
|
||||||
|
jointIndex = RightShoulder = 14
|
||||||
|
jointIndex = LeftHandRing2 = 47
|
||||||
|
jointIndex = LeftHandThumb2 = 55
|
||||||
|
jointIndex = Head = 63
|
||||||
|
jointIndex = RightHandRing4 = 25
|
||||||
|
jointIndex = LeftHandRing1 = 46
|
||||||
|
jointIndex = LeftFoot = 3
|
||||||
|
jointIndex = RightHandRing3 = 24
|
||||||
|
jointIndex = RightHandThumb4 = 33
|
||||||
|
jointIndex = LeftArm = 39
|
||||||
|
jointIndex = LeftToe_End = 5
|
||||||
|
jointIndex = RightToeBase = 9
|
||||||
|
jointIndex = RightHandPinky4 = 21
|
||||||
|
jointIndex = Spine = 11
|
||||||
|
jointIndex = LeftHandIndex4 = 53
|
||||||
|
jointIndex = LeftHandPinky2 = 43
|
||||||
|
jointIndex = RightHandIndex4 = 29
|
||||||
|
jointIndex = Hips = 0
|
||||||
|
jointIndex = RightHandRing2 = 23
|
||||||
|
|
BIN
interface/resources/meshes/mannequin/Eyes.ktx
Executable file
BIN
interface/resources/meshes/mannequin/Eyes.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Base_Color.ktx
Executable file
BIN
interface/resources/meshes/mannequin/lambert1_Base_Color.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Normal_OpenGL.ktx
Executable file
BIN
interface/resources/meshes/mannequin/lambert1_Normal_OpenGL.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.ktx
Executable file
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/mannequin.baked.fbx
Executable file
BIN
interface/resources/meshes/mannequin/mannequin.baked.fbx
Executable file
Binary file not shown.
|
@ -21,8 +21,6 @@ ScrollingWindow {
|
||||||
property alias url: webview.url
|
property alias url: webview.url
|
||||||
property alias webView: webview
|
property alias webView: webview
|
||||||
|
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
|
|
||||||
signal loadingChanged(int status)
|
signal loadingChanged(int status)
|
||||||
|
|
||||||
x: 100
|
x: 100
|
||||||
|
@ -210,17 +208,6 @@ ScrollingWindow {
|
||||||
url: "https://highfidelity.com/"
|
url: "https://highfidelity.com/"
|
||||||
profile: FileTypeProfile;
|
profile: FileTypeProfile;
|
||||||
|
|
||||||
property alias eventBridgeWrapper: eventBridgeWrapper
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
||||||
WebEngineScript {
|
WebEngineScript {
|
||||||
id: createGlobalEventBridge
|
id: createGlobalEventBridge
|
||||||
|
@ -267,6 +254,8 @@ ScrollingWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
desktop.initWebviewProfileHandlers(webview.profile);
|
desktop.initWebviewProfileHandlers(webview.profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,8 @@ Windows.ScrollingWindow {
|
||||||
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
||||||
destroyOnCloseButton: false
|
destroyOnCloseButton: false
|
||||||
property alias source: webview.url
|
property alias source: webview.url
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge;
|
|
||||||
property alias scriptUrl: webview.userScriptUrl
|
property alias scriptUrl: webview.userScriptUrl
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is for JS/QML communication, which is unused in a WebWindow,
|
// This is for JS/QML communication, which is unused in a WebWindow,
|
||||||
// but not having this here results in spurious warnings about a
|
// but not having this here results in spurious warnings about a
|
||||||
// missing signal
|
// missing signal
|
||||||
|
@ -70,7 +63,6 @@ Windows.ScrollingWindow {
|
||||||
url: "about:blank"
|
url: "about:blank"
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
property string userScriptUrl: ""
|
property string userScriptUrl: ""
|
||||||
|
|
||||||
|
@ -107,6 +99,8 @@ Windows.ScrollingWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
eventBridge.webEventReceived.connect(onWebEventReceived);
|
eventBridge.webEventReceived.connect(onWebEventReceived);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,15 +30,6 @@ Windows.Window {
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
||||||
// JavaScript event bridge object in case QML content includes Web content.
|
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge;
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
if (dynamicContent) {
|
if (dynamicContent) {
|
||||||
dynamicContent.destroy();
|
dynamicContent.destroy();
|
||||||
|
|
|
@ -18,7 +18,6 @@ Item {
|
||||||
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
|
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
|
||||||
property alias url: webview.url
|
property alias url: webview.url
|
||||||
property WebEngineView webView: webview
|
property WebEngineView webView: webview
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
property bool canGoBack: webview.canGoBack
|
property bool canGoBack: webview.canGoBack
|
||||||
property bool canGoForward: webview.canGoForward
|
property bool canGoForward: webview.canGoForward
|
||||||
|
|
||||||
|
@ -32,12 +31,6 @@ Item {
|
||||||
webview.profile = profile;
|
webview.profile = profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebEngineView {
|
WebEngineView {
|
||||||
id: webview
|
id: webview
|
||||||
objectName: "webEngineView"
|
objectName: "webEngineView"
|
||||||
|
@ -78,9 +71,10 @@ Item {
|
||||||
|
|
||||||
property string newUrl: ""
|
property string newUrl: ""
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
|
|
||||||
// Ensure the JS from the web-engine makes it to our logging
|
// Ensure the JS from the web-engine makes it to our logging
|
||||||
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||||
|
|
|
@ -79,15 +79,11 @@ ScrollingWindow {
|
||||||
id: webView
|
id: webView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: false
|
enabled: false
|
||||||
property alias eventBridgeWrapper: eventBridgeWrapper
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
QtObject {
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge
|
|
||||||
}
|
}
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
onEnabledChanged: toolWindow.updateVisiblity()
|
onEnabledChanged: toolWindow.updateVisiblity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,12 +247,9 @@ ScrollingWindow {
|
||||||
tab.enabled = true;
|
tab.enabled = true;
|
||||||
tab.originalUrl = properties.source;
|
tab.originalUrl = properties.source;
|
||||||
|
|
||||||
var eventBridge = properties.eventBridge;
|
|
||||||
|
|
||||||
var result = tab.item;
|
var result = tab.item;
|
||||||
result.enabled = true;
|
result.enabled = true;
|
||||||
tabView.tabCount++;
|
tabView.tabCount++;
|
||||||
result.eventBridgeWrapper.eventBridge = eventBridge;
|
|
||||||
result.url = properties.source;
|
result.url = properties.source;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import "../controls-uit" as HiFiControls
|
||||||
Item {
|
Item {
|
||||||
property alias url: root.url
|
property alias url: root.url
|
||||||
property alias scriptURL: root.userScriptUrl
|
property alias scriptURL: root.userScriptUrl
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
property alias canGoBack: root.canGoBack;
|
property alias canGoBack: root.canGoBack;
|
||||||
property var goBack: root.goBack;
|
property var goBack: root.goBack;
|
||||||
property alias urlTag: root.urlTag
|
property alias urlTag: root.urlTag
|
||||||
|
@ -22,12 +21,6 @@ Item {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
property alias viewProfile: root.profile
|
property alias viewProfile: root.profile
|
||||||
|
|
||||||
WebEngineView {
|
WebEngineView {
|
||||||
|
@ -71,10 +64,11 @@ Item {
|
||||||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
|
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
|
||||||
|
|
||||||
property string newUrl: ""
|
property string newUrl: ""
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
// Ensure the JS from the web-engine makes it to our logging
|
// Ensure the JS from the web-engine makes it to our logging
|
||||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||||
|
|
|
@ -17,7 +17,6 @@ Item {
|
||||||
property int headerHeight: 70
|
property int headerHeight: 70
|
||||||
property string url
|
property string url
|
||||||
property string scriptURL
|
property string scriptURL
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
property bool keyboardEnabled: false
|
property bool keyboardEnabled: false
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
@ -135,12 +134,6 @@ Item {
|
||||||
loadUrl(url);
|
loadUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebEngineView {
|
WebEngineView {
|
||||||
id: webview
|
id: webview
|
||||||
objectName: "webEngineView"
|
objectName: "webEngineView"
|
||||||
|
@ -182,9 +175,9 @@ Item {
|
||||||
|
|
||||||
property string newUrl: ""
|
property string newUrl: ""
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
// Ensure the JS from the web-engine makes it to our logging
|
// Ensure the JS from the web-engine makes it to our logging
|
||||||
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||||
|
|
|
@ -6,7 +6,6 @@ import "../controls-uit" as HiFiControls
|
||||||
Item {
|
Item {
|
||||||
property alias url: root.url
|
property alias url: root.url
|
||||||
property alias scriptURL: root.userScriptUrl
|
property alias scriptURL: root.userScriptUrl
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
property alias canGoBack: root.canGoBack;
|
property alias canGoBack: root.canGoBack;
|
||||||
property var goBack: root.goBack;
|
property var goBack: root.goBack;
|
||||||
property alias urlTag: root.urlTag
|
property alias urlTag: root.urlTag
|
||||||
|
@ -22,12 +21,6 @@ Item {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
property alias viewProfile: root.profile
|
property alias viewProfile: root.profile
|
||||||
|
|
||||||
WebEngineView {
|
WebEngineView {
|
||||||
|
@ -72,9 +65,9 @@ Item {
|
||||||
|
|
||||||
property string newUrl: ""
|
property string newUrl: ""
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
// Ensure the JS from the web-engine makes it to our logging
|
// Ensure the JS from the web-engine makes it to our logging
|
||||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||||
|
|
|
@ -20,7 +20,6 @@ TabletModalWindow {
|
||||||
id: loginDialogRoot
|
id: loginDialogRoot
|
||||||
objectName: "LoginDialog"
|
objectName: "LoginDialog"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
property bool gotoPreviousApp: false;
|
property bool gotoPreviousApp: false;
|
||||||
|
|
|
@ -24,8 +24,6 @@ Window {
|
||||||
resizable: true
|
resizable: true
|
||||||
modality: Qt.ApplicationModal
|
modality: Qt.ApplicationModal
|
||||||
|
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
@ -45,16 +43,6 @@ Window {
|
||||||
bottom: keyboard.top
|
bottom: keyboard.top
|
||||||
}
|
}
|
||||||
|
|
||||||
property alias eventBridgeWrapper: eventBridgeWrapper
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
||||||
WebEngineScript {
|
WebEngineScript {
|
||||||
id: createGlobalEventBridge
|
id: createGlobalEventBridge
|
||||||
|
@ -73,6 +61,10 @@ Window {
|
||||||
|
|
||||||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Keyboard {
|
Keyboard {
|
||||||
|
|
|
@ -116,9 +116,7 @@ Preference {
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: tabletAvatarBrowserBuilder;
|
id: tabletAvatarBrowserBuilder;
|
||||||
TabletAvatarBrowser {
|
TabletAvatarBrowser { }
|
||||||
eventBridge: tabletRoot.eventBridge
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ Rectangle {
|
||||||
HifiConstants { id: hifi; }
|
HifiConstants { id: hifi; }
|
||||||
objectName: "AudioWindow"
|
objectName: "AudioWindow"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
property string title: "Audio Options"
|
property string title: "Audio Options"
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ Rectangle {
|
||||||
property var activeTab: "nearbyTab";
|
property var activeTab: "nearbyTab";
|
||||||
property bool currentlyEditingDisplayName: false
|
property bool currentlyEditingDisplayName: false
|
||||||
property bool punctuationMode: false;
|
property bool punctuationMode: false;
|
||||||
property var eventBridge;
|
|
||||||
|
|
||||||
HifiConstants { id: hifi; }
|
HifiConstants { id: hifi; }
|
||||||
|
|
||||||
|
@ -129,7 +128,7 @@ Rectangle {
|
||||||
pal.sendToScript({method: 'refreshNearby', params: params});
|
pal.sendToScript({method: 'refreshNearby', params: params});
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
id: palTabContainer;
|
id: palTabContainer;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -138,6 +137,7 @@ Rectangle {
|
||||||
left: parent.left;
|
left: parent.left;
|
||||||
right: parent.right;
|
right: parent.right;
|
||||||
}
|
}
|
||||||
|
color: "white";
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: tabSelectorContainer;
|
id: tabSelectorContainer;
|
||||||
// Anchors
|
// Anchors
|
||||||
|
@ -1043,7 +1043,6 @@ Rectangle {
|
||||||
} // Keyboard
|
} // Keyboard
|
||||||
|
|
||||||
HifiControls.TabletWebView {
|
HifiControls.TabletWebView {
|
||||||
eventBridge: pal.eventBridge;
|
|
||||||
id: userInfoViewer;
|
id: userInfoViewer;
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top;
|
top: parent.top;
|
||||||
|
|
|
@ -24,7 +24,6 @@ Rectangle {
|
||||||
property string title: "Asset Browser"
|
property string title: "Asset Browser"
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
||||||
id: root
|
id: root
|
||||||
objectName: "DCConectionTiming"
|
objectName: "DCConectionTiming"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
objectName: "DebugWindow"
|
objectName: "DebugWindow"
|
||||||
property var eventBridge;
|
|
||||||
|
|
||||||
property var title: "Debug Window"
|
property var title: "Debug Window"
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
||||||
id: root
|
id: root
|
||||||
objectName: "EntityStatistics"
|
objectName: "EntityStatistics"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
||||||
id: root
|
id: root
|
||||||
objectName: "LODTools"
|
objectName: "LODTools"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ Rectangle {
|
||||||
property string title: "Running Scripts"
|
property string title: "Running Scripts"
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property var eventBridge;
|
|
||||||
property var scripts: ScriptDiscoveryService;
|
property var scripts: ScriptDiscoveryService;
|
||||||
property var scriptsModel: scripts.scriptsModelFilter
|
property var scriptsModel: scripts.scriptsModelFilter
|
||||||
property var runningScriptsModel: ListModel { }
|
property var runningScriptsModel: ListModel { }
|
||||||
|
|
|
@ -7,14 +7,12 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
initialItem: Qt.resolvedUrl('EditTabView.qml')
|
initialItem: Qt.resolvedUrl('EditTabView.qml')
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
editRoot.push(Qt.resolvedUrl(path));
|
editRoot.push(Qt.resolvedUrl(path));
|
||||||
editRoot.currentItem.eventBridge = editRoot.eventBridge;
|
|
||||||
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
|
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,6 @@ TabView {
|
||||||
WebView {
|
WebView {
|
||||||
id: entityListToolWebView
|
id: entityListToolWebView
|
||||||
url: "../../../../../scripts/system/html/entityList.html"
|
url: "../../../../../scripts/system/html/entityList.html"
|
||||||
eventBridge: editRoot.eventBridge
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
|
@ -196,7 +195,6 @@ TabView {
|
||||||
WebView {
|
WebView {
|
||||||
id: entityPropertiesWebView
|
id: entityPropertiesWebView
|
||||||
url: "../../../../../scripts/system/html/entityProperties.html"
|
url: "../../../../../scripts/system/html/entityProperties.html"
|
||||||
eventBridge: editRoot.eventBridge
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
|
@ -211,7 +209,6 @@ TabView {
|
||||||
WebView {
|
WebView {
|
||||||
id: gridControlsWebView
|
id: gridControlsWebView
|
||||||
url: "../../../../../scripts/system/html/gridControls.html"
|
url: "../../../../../scripts/system/html/gridControls.html"
|
||||||
eventBridge: editRoot.eventBridge
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
|
@ -226,7 +223,6 @@ TabView {
|
||||||
WebView {
|
WebView {
|
||||||
id: particleExplorerWebView
|
id: particleExplorerWebView
|
||||||
url: "../../../../../scripts/system/particle_explorer/particleExplorer.html"
|
url: "../../../../../scripts/system/particle_explorer/particleExplorer.html"
|
||||||
eventBridge: editRoot.eventBridge
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
|
@ -289,7 +285,7 @@ TabView {
|
||||||
editTabView.currentIndex = id;
|
editTabView.currentIndex = id;
|
||||||
} else {
|
} else {
|
||||||
console.warn('Attempt to switch to invalid tab:', id);
|
console.warn('Attempt to switch to invalid tab:', id);
|
||||||
}
|
}
|
||||||
} else if (typeof id === 'string'){
|
} else if (typeof id === 'string'){
|
||||||
switch (id.toLowerCase()) {
|
switch (id.toLowerCase()) {
|
||||||
case 'create':
|
case 'create':
|
||||||
|
|
|
@ -18,7 +18,6 @@ import "../../dialogs"
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: inputRecorder
|
id: inputRecorder
|
||||||
property var eventBridge;
|
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
color: hifi.colors.baseGray;
|
color: hifi.colors.baseGray;
|
||||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
||||||
// height: parent.height
|
// height: parent.height
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
color: hifi.colors.baseGray;
|
color: hifi.colors.baseGray;
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool keyboardEnabled: false
|
property bool keyboardEnabled: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
|
@ -29,7 +29,6 @@ StackView {
|
||||||
initialItem: addressBarDialog
|
initialItem: addressBarDialog
|
||||||
width: parent !== null ? parent.width : undefined
|
width: parent !== null ? parent.width : undefined
|
||||||
height: parent !== null ? parent.height : undefined
|
height: parent !== null ? parent.height : undefined
|
||||||
property var eventBridge;
|
|
||||||
property int cardWidth: 212;
|
property int cardWidth: 212;
|
||||||
property int cardHeight: 152;
|
property int cardHeight: 152;
|
||||||
property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/";
|
property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/";
|
||||||
|
@ -80,7 +79,6 @@ StackView {
|
||||||
var card = tabletWebView.createObject();
|
var card = tabletWebView.createObject();
|
||||||
card.url = addressBarDialog.metaverseServerUrl + targetString;
|
card.url = addressBarDialog.metaverseServerUrl + targetString;
|
||||||
card.parentStackItem = root;
|
card.parentStackItem = root;
|
||||||
card.eventBridge = root.eventBridge;
|
|
||||||
root.push(card);
|
root.push(card);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ Item {
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
property string title: "Audio Settings"
|
property string title: "Audio Settings"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
property string title: "Avatar Settings"
|
property string title: "Avatar Settings"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
property string title: "General Settings"
|
property string title: "General Settings"
|
||||||
property alias gotoPreviousApp: root.gotoPreviousApp;
|
property alias gotoPreviousApp: root.gotoPreviousApp;
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
property string title: "Graphics Settings"
|
property string title: "Graphics Settings"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
property string title: "LOD Settings"
|
property string title: "LOD Settings"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
|
|
|
@ -21,7 +21,6 @@ FocusScope {
|
||||||
property var point: Qt.point(50, 50);
|
property var point: Qt.point(50, 50);
|
||||||
TabletMenuStack { id: menuPopperUpper }
|
TabletMenuStack { id: menuPopperUpper }
|
||||||
property string subMenu: ""
|
property string subMenu: ""
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
|
@ -49,7 +49,6 @@ Item {
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
d.push(Qt.resolvedUrl(path));
|
d.push(Qt.resolvedUrl(path));
|
||||||
d.currentItem.eventBridge = tabletMenu.eventBridge
|
|
||||||
d.currentItem.sendToScript.connect(tabletMenu.sendToScript);
|
d.currentItem.sendToScript.connect(tabletMenu.sendToScript);
|
||||||
d.currentItem.focus = true;
|
d.currentItem.focus = true;
|
||||||
d.currentItem.forceActiveFocus();
|
d.currentItem.forceActiveFocus();
|
||||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
||||||
objectName: "stack"
|
objectName: "stack"
|
||||||
property var title: "Networking Settings"
|
property var title: "Networking Settings"
|
||||||
|
|
||||||
property var eventBridge;
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
|
|
|
@ -8,7 +8,6 @@ Item {
|
||||||
id: tabletRoot
|
id: tabletRoot
|
||||||
objectName: "tabletRoot"
|
objectName: "tabletRoot"
|
||||||
property string username: "Unknown user"
|
property string username: "Unknown user"
|
||||||
property var eventBridge;
|
|
||||||
property var rootMenu;
|
property var rootMenu;
|
||||||
property var openModal: null;
|
property var openModal: null;
|
||||||
property var openMessage: null;
|
property var openMessage: null;
|
||||||
|
@ -111,7 +110,6 @@ Item {
|
||||||
function openBrowserWindow(request, profile) {
|
function openBrowserWindow(request, profile) {
|
||||||
var component = Qt.createComponent("../../controls/TabletWebView.qml");
|
var component = Qt.createComponent("../../controls/TabletWebView.qml");
|
||||||
var newWindow = component.createObject(tabletRoot);
|
var newWindow = component.createObject(tabletRoot);
|
||||||
newWindow.eventBridge = tabletRoot.eventBridge;
|
|
||||||
newWindow.remove = true;
|
newWindow.remove = true;
|
||||||
newWindow.profile = profile;
|
newWindow.profile = profile;
|
||||||
request.openIn(newWindow.webView);
|
request.openIn(newWindow.webView);
|
||||||
|
@ -175,7 +173,7 @@ Item {
|
||||||
// Hook up callback for clara.io download from the marketplace.
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
Connections {
|
Connections {
|
||||||
id: eventBridgeConnection
|
id: eventBridgeConnection
|
||||||
target: null
|
target: eventBridge
|
||||||
onWebEventReceived: {
|
onWebEventReceived: {
|
||||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||||
|
@ -184,10 +182,6 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (loader.item.hasOwnProperty("eventBridge")) {
|
|
||||||
loader.item.eventBridge = eventBridge;
|
|
||||||
eventBridgeConnection.target = eventBridge
|
|
||||||
}
|
|
||||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ Windows.ScrollingWindow {
|
||||||
id: tabletRoot
|
id: tabletRoot
|
||||||
objectName: "tabletRoot"
|
objectName: "tabletRoot"
|
||||||
property string username: "Unknown user"
|
property string username: "Unknown user"
|
||||||
property var eventBridge;
|
|
||||||
|
|
||||||
property var rootMenu;
|
property var rootMenu;
|
||||||
property string subMenu: ""
|
property string subMenu: ""
|
||||||
|
@ -93,7 +92,7 @@ Windows.ScrollingWindow {
|
||||||
// Hook up callback for clara.io download from the marketplace.
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
Connections {
|
Connections {
|
||||||
id: eventBridgeConnection
|
id: eventBridgeConnection
|
||||||
target: null
|
target: eventBridge
|
||||||
onWebEventReceived: {
|
onWebEventReceived: {
|
||||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||||
|
@ -102,10 +101,6 @@ Windows.ScrollingWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (loader.item.hasOwnProperty("eventBridge")) {
|
|
||||||
loader.item.eventBridge = eventBridge;
|
|
||||||
eventBridgeConnection.target = eventBridge
|
|
||||||
}
|
|
||||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ Item {
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
||||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
BaseWebView {
|
BaseWebView {
|
||||||
|
@ -43,14 +41,6 @@ Item {
|
||||||
bottom: footer.top
|
bottom: footer.top
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: eventBridgeWrapper
|
|
||||||
WebChannel.id: "eventBridgeWrapper"
|
|
||||||
property var eventBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
|
||||||
|
|
||||||
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
||||||
WebEngineScript {
|
WebEngineScript {
|
||||||
id: createGlobalEventBridge
|
id: createGlobalEventBridge
|
||||||
|
@ -68,6 +58,11 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
webChannel.registerObject("eventBridge", eventBridge);
|
||||||
|
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
|
@ -114,6 +114,7 @@
|
||||||
#include <render/RenderFetchCullSortTask.h>
|
#include <render/RenderFetchCullSortTask.h>
|
||||||
#include <RenderDeferredTask.h>
|
#include <RenderDeferredTask.h>
|
||||||
#include <RenderForwardTask.h>
|
#include <RenderForwardTask.h>
|
||||||
|
#include <RenderViewTask.h>
|
||||||
#include <ResourceCache.h>
|
#include <ResourceCache.h>
|
||||||
#include <ResourceRequest.h>
|
#include <ResourceRequest.h>
|
||||||
#include <SandboxUtils.h>
|
#include <SandboxUtils.h>
|
||||||
|
@ -1866,15 +1867,9 @@ void Application::initializeGL() {
|
||||||
|
|
||||||
// Set up the render engine
|
// Set up the render engine
|
||||||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||||
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
|
||||||
const auto items = _renderEngine->addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
|
||||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
|
||||||
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
||||||
if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
|
bool isDeferred = !QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
|
||||||
_renderEngine->addJob<RenderForwardTask>("Forward", items);
|
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
|
||||||
} else {
|
|
||||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
|
||||||
}
|
|
||||||
_renderEngine->load();
|
_renderEngine->load();
|
||||||
_renderEngine->registerScene(_main3DScene);
|
_renderEngine->registerScene(_main3DScene);
|
||||||
|
|
||||||
|
@ -5076,7 +5071,7 @@ namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
||||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||||
if (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||||
PerformanceTimer perfTimer("worldBox");
|
PerformanceTimer perfTimer("worldBox");
|
||||||
|
|
||||||
auto& batch = *args->_batch;
|
auto& batch = *args->_batch;
|
||||||
|
|
|
@ -73,7 +73,7 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
||||||
layout->addWidget(label);
|
layout->addWidget(label);
|
||||||
|
|
||||||
QRadioButton* option1 = new QRadioButton("Reset all my settings");
|
QRadioButton* option1 = new QRadioButton("Reset all my settings");
|
||||||
QRadioButton* option2 = new QRadioButton("Reset my settings but retain avatar info.");
|
QRadioButton* option2 = new QRadioButton("Reset my settings but keep essential info");
|
||||||
QRadioButton* option3 = new QRadioButton("Continue with my current settings");
|
QRadioButton* option3 = new QRadioButton("Continue with my current settings");
|
||||||
option3->setChecked(true);
|
option3->setChecked(true);
|
||||||
layout->addWidget(option1);
|
layout->addWidget(option1);
|
||||||
|
@ -95,7 +95,7 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
||||||
return CrashHandler::DELETE_INTERFACE_INI;
|
return CrashHandler::DELETE_INTERFACE_INI;
|
||||||
}
|
}
|
||||||
if (option2->isChecked()) {
|
if (option2->isChecked()) {
|
||||||
return CrashHandler::RETAIN_AVATAR_INFO;
|
return CrashHandler::RETAIN_IMPORTANT_INFO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashHandler::handleCrash(CrashHandler::Action action) {
|
void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||||
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_AVATAR_INFO) {
|
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||||
// CrashHandler::DO_NOTHING or unexpected value
|
// CrashHandler::DO_NOTHING or unexpected value
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -116,12 +116,15 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||||
const QString DISPLAY_NAME_KEY = "displayName";
|
const QString DISPLAY_NAME_KEY = "displayName";
|
||||||
const QString FULL_AVATAR_URL_KEY = "fullAvatarURL";
|
const QString FULL_AVATAR_URL_KEY = "fullAvatarURL";
|
||||||
const QString FULL_AVATAR_MODEL_NAME_KEY = "fullAvatarModelName";
|
const QString FULL_AVATAR_MODEL_NAME_KEY = "fullAvatarModelName";
|
||||||
|
const QString TUTORIAL_COMPLETE_FLAG_KEY = "tutorialComplete";
|
||||||
|
|
||||||
QString displayName;
|
QString displayName;
|
||||||
QUrl fullAvatarURL;
|
QUrl fullAvatarURL;
|
||||||
QString fullAvatarModelName;
|
QString fullAvatarModelName;
|
||||||
QUrl address;
|
QUrl address;
|
||||||
|
bool tutorialComplete = false;
|
||||||
|
|
||||||
if (action == CrashHandler::RETAIN_AVATAR_INFO) {
|
if (action == CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||||
// Read avatar info
|
// Read avatar info
|
||||||
|
|
||||||
// Location and orientation
|
// Location and orientation
|
||||||
|
@ -135,6 +138,9 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||||
fullAvatarURL = settings.value(FULL_AVATAR_URL_KEY).toUrl();
|
fullAvatarURL = settings.value(FULL_AVATAR_URL_KEY).toUrl();
|
||||||
fullAvatarModelName = settings.value(FULL_AVATAR_MODEL_NAME_KEY).toString();
|
fullAvatarModelName = settings.value(FULL_AVATAR_MODEL_NAME_KEY).toString();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
// Tutorial complete
|
||||||
|
tutorialComplete = settings.value(TUTORIAL_COMPLETE_FLAG_KEY).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Interface.ini
|
// Delete Interface.ini
|
||||||
|
@ -143,7 +149,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||||
settingsFile.remove();
|
settingsFile.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == CrashHandler::RETAIN_AVATAR_INFO) {
|
if (action == CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||||
// Write avatar info
|
// Write avatar info
|
||||||
|
|
||||||
// Location and orientation
|
// Location and orientation
|
||||||
|
@ -157,6 +163,9 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||||
settings.setValue(FULL_AVATAR_URL_KEY, fullAvatarURL);
|
settings.setValue(FULL_AVATAR_URL_KEY, fullAvatarURL);
|
||||||
settings.setValue(FULL_AVATAR_MODEL_NAME_KEY, fullAvatarModelName);
|
settings.setValue(FULL_AVATAR_MODEL_NAME_KEY, fullAvatarModelName);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
// Tutorial complete
|
||||||
|
settings.setValue(TUTORIAL_COMPLETE_FLAG_KEY, tutorialComplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
private:
|
private:
|
||||||
enum Action {
|
enum Action {
|
||||||
DELETE_INTERFACE_INI,
|
DELETE_INTERFACE_INI,
|
||||||
RETAIN_AVATAR_INFO,
|
RETAIN_IMPORTANT_INFO,
|
||||||
DO_NOTHING
|
DO_NOTHING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -794,6 +794,77 @@ controller::Pose MyAvatar::getRightHandTipPose() const {
|
||||||
return pose;
|
return pose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const {
|
||||||
|
glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified
|
||||||
|
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||||
|
if (jointIndex != -1) {
|
||||||
|
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) {
|
||||||
|
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glm::vec3 modelOffset = position - jointPos;
|
||||||
|
glm::vec3 jointSpacePosition = glm::inverse(jointRot) * modelOffset;
|
||||||
|
|
||||||
|
return jointSpacePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 MyAvatar::worldToJointDirection(const glm::vec3& worldDir, const int jointIndex) const {
|
||||||
|
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||||
|
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||||
|
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 jointSpaceDir = glm::inverse(jointRot) * worldDir;
|
||||||
|
return jointSpaceDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jointIndex) const {
|
||||||
|
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||||
|
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||||
|
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||||
|
}
|
||||||
|
glm::quat jointSpaceRot = glm::inverse(jointRot) * worldRot;
|
||||||
|
return jointSpaceRot;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const {
|
||||||
|
glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified
|
||||||
|
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||||
|
|
||||||
|
if (jointIndex != -1) {
|
||||||
|
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) {
|
||||||
|
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 worldOffset = jointRot * jointSpacePos;
|
||||||
|
glm::vec3 worldPos = jointPos + worldOffset;
|
||||||
|
|
||||||
|
return worldPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 MyAvatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const int jointIndex) const {
|
||||||
|
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||||
|
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||||
|
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||||
|
}
|
||||||
|
glm::vec3 worldDir = jointRot * jointSpaceDir;
|
||||||
|
return worldDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat MyAvatar::jointToWorldRotation(const glm::quat& jointSpaceRot, const int jointIndex) const {
|
||||||
|
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||||
|
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||||
|
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||||
|
}
|
||||||
|
glm::quat worldRot = jointRot * jointSpaceRot;
|
||||||
|
return worldRot;
|
||||||
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void MyAvatar::render(RenderArgs* renderArgs) {
|
void MyAvatar::render(RenderArgs* renderArgs) {
|
||||||
// don't render if we've been asked to disable local rendering
|
// don't render if we've been asked to disable local rendering
|
||||||
|
|
|
@ -378,6 +378,15 @@ public:
|
||||||
Q_INVOKABLE controller::Pose getLeftHandTipPose() const;
|
Q_INVOKABLE controller::Pose getLeftHandTipPose() const;
|
||||||
Q_INVOKABLE controller::Pose getRightHandTipPose() const;
|
Q_INVOKABLE controller::Pose getRightHandTipPose() const;
|
||||||
|
|
||||||
|
// world-space to avatar-space rigconversion functions
|
||||||
|
Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const;
|
||||||
|
Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const;
|
||||||
|
Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const;
|
||||||
|
Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const;
|
||||||
|
Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const;
|
||||||
|
|
||||||
AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
|
AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
|
||||||
void updateLookAtTargetAvatar();
|
void updateLookAtTargetAvatar();
|
||||||
void clearLookAtTargetAvatar();
|
void clearLookAtTargetAvatar();
|
||||||
|
|
|
@ -184,6 +184,8 @@ AudioClient::AudioClient() :
|
||||||
checkDevices();
|
checkDevices();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
||||||
|
_checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
|
||||||
|
|
||||||
|
|
||||||
configureReverb();
|
configureReverb();
|
||||||
|
|
|
@ -1473,27 +1473,6 @@ QStringList AvatarData::getJointNames() const {
|
||||||
return _jointNames;
|
return _jointNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) {
|
|
||||||
QDataStream packetStream(data);
|
|
||||||
|
|
||||||
packetStream >> identityOut.uuid
|
|
||||||
>> identityOut.skeletonModelURL
|
|
||||||
>> identityOut.attachmentData
|
|
||||||
>> identityOut.displayName
|
|
||||||
>> identityOut.sessionDisplayName
|
|
||||||
>> identityOut.avatarEntityData
|
|
||||||
>> identityOut.sequenceId;
|
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
|
||||||
qCDebug(avatars) << __FUNCTION__
|
|
||||||
<< "identityOut.uuid:" << identityOut.uuid
|
|
||||||
<< "identityOut.skeletonModelURL:" << identityOut.skeletonModelURL
|
|
||||||
<< "identityOut.displayName:" << identityOut.displayName
|
|
||||||
<< "identityOut.sessionDisplayName:" << identityOut.sessionDisplayName;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::quat AvatarData::getOrientationOutbound() const {
|
glm::quat AvatarData::getOrientationOutbound() const {
|
||||||
return (getLocalOrientation());
|
return (getLocalOrientation());
|
||||||
}
|
}
|
||||||
|
@ -1504,61 +1483,106 @@ QUrl AvatarData::cannonicalSkeletonModelURL(const QUrl& emptyURL) const {
|
||||||
return _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL;
|
return _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged) {
|
void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged) {
|
||||||
|
|
||||||
if (identity.sequenceId < _identitySequenceId) {
|
QDataStream packetStream(identityData);
|
||||||
qCDebug(avatars) << "Ignoring older identity packet for avatar" << getSessionUUID()
|
|
||||||
<< "_identitySequenceId (" << _identitySequenceId << ") is greater than" << identity.sequenceId;
|
QUuid avatarSessionID;
|
||||||
return;
|
|
||||||
|
// peek the sequence number, this will tell us if we should be processing this identity packet at all
|
||||||
|
udt::SequenceNumber::Type incomingSequenceNumberType;
|
||||||
|
packetStream >> avatarSessionID >> incomingSequenceNumberType;
|
||||||
|
udt::SequenceNumber incomingSequenceNumber(incomingSequenceNumberType);
|
||||||
|
|
||||||
|
if (!_hasProcessedFirstIdentity) {
|
||||||
|
_lastIncomingSequenceNumber = incomingSequenceNumber - 1;
|
||||||
|
_hasProcessedFirstIdentity = true;
|
||||||
|
qCDebug(avatars) << "Processing first identity packet for" << avatarSessionID << "-"
|
||||||
|
<< (udt::SequenceNumber::Type) incomingSequenceNumber;
|
||||||
}
|
}
|
||||||
// otherwise, set the identitySequenceId to match the incoming identity
|
|
||||||
_identitySequenceId = identity.sequenceId;
|
|
||||||
|
|
||||||
if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) {
|
if (incomingSequenceNumber > _lastIncomingSequenceNumber) {
|
||||||
setSkeletonModelURL(identity.skeletonModelURL);
|
Identity identity;
|
||||||
identityChanged = true;
|
|
||||||
if (_firstSkeletonCheck) {
|
packetStream >> identity.skeletonModelURL
|
||||||
|
>> identity.attachmentData
|
||||||
|
>> identity.displayName
|
||||||
|
>> identity.sessionDisplayName
|
||||||
|
>> identity.avatarEntityData;
|
||||||
|
|
||||||
|
// set the store identity sequence number to match the incoming identity
|
||||||
|
_lastIncomingSequenceNumber = incomingSequenceNumber;
|
||||||
|
|
||||||
|
if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) {
|
||||||
|
setSkeletonModelURL(identity.skeletonModelURL);
|
||||||
|
identityChanged = true;
|
||||||
|
if (_firstSkeletonCheck) {
|
||||||
|
displayNameChanged = true;
|
||||||
|
}
|
||||||
|
_firstSkeletonCheck = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identity.displayName != _displayName) {
|
||||||
|
_displayName = identity.displayName;
|
||||||
|
identityChanged = true;
|
||||||
displayNameChanged = true;
|
displayNameChanged = true;
|
||||||
}
|
}
|
||||||
_firstSkeletonCheck = false;
|
maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName);
|
||||||
}
|
|
||||||
|
|
||||||
if (identity.displayName != _displayName) {
|
if (identity.attachmentData != _attachmentData) {
|
||||||
_displayName = identity.displayName;
|
setAttachmentData(identity.attachmentData);
|
||||||
identityChanged = true;
|
identityChanged = true;
|
||||||
displayNameChanged = true;
|
}
|
||||||
}
|
|
||||||
maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName);
|
|
||||||
|
|
||||||
if (identity.attachmentData != _attachmentData) {
|
bool avatarEntityDataChanged = false;
|
||||||
setAttachmentData(identity.attachmentData);
|
_avatarEntitiesLock.withReadLock([&] {
|
||||||
identityChanged = true;
|
avatarEntityDataChanged = (identity.avatarEntityData != _avatarEntityData);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
if (avatarEntityDataChanged) {
|
||||||
|
setAvatarEntityData(identity.avatarEntityData);
|
||||||
|
identityChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool avatarEntityDataChanged = false;
|
#ifdef WANT_DEBUG
|
||||||
_avatarEntitiesLock.withReadLock([&] {
|
qCDebug(avatars) << __FUNCTION__
|
||||||
avatarEntityDataChanged = (identity.avatarEntityData != _avatarEntityData);
|
<< "identity.uuid:" << identity.uuid
|
||||||
});
|
<< "identity.skeletonModelURL:" << identity.skeletonModelURL
|
||||||
if (avatarEntityDataChanged) {
|
<< "identity.displayName:" << identity.displayName
|
||||||
setAvatarEntityData(identity.avatarEntityData);
|
<< "identity.sessionDisplayName:" << identity.sessionDisplayName;
|
||||||
identityChanged = true;
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qCDebug(avatars) << "Refusing to process identity for" << uuidStringWithoutCurlyBraces(avatarSessionID) << "since"
|
||||||
|
<< (udt::SequenceNumber::Type) _lastIncomingSequenceNumber
|
||||||
|
<< "is >=" << (udt::SequenceNumber::Type) incomingSequenceNumber;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AvatarData::identityByteArray() const {
|
QByteArray AvatarData::identityByteArray(bool shouldForwardIncomingSequenceNumber) const {
|
||||||
QByteArray identityData;
|
QByteArray identityData;
|
||||||
QDataStream identityStream(&identityData, QIODevice::Append);
|
QDataStream identityStream(&identityData, QIODevice::Append);
|
||||||
const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL); // depends on _skeletonModelURL
|
const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL); // depends on _skeletonModelURL
|
||||||
|
|
||||||
|
// we use the boolean flag to determine if this is an identity byte array for a mixer to send to an agent
|
||||||
|
// or an agent to send to a mixer
|
||||||
|
|
||||||
|
// when mixers send identity packets to agents, they simply forward along the last incoming sequence number they received
|
||||||
|
// whereas agents send a fresh outgoing sequence number when identity data has changed
|
||||||
|
|
||||||
|
udt::SequenceNumber identitySequenceNumber =
|
||||||
|
shouldForwardIncomingSequenceNumber ? _lastIncomingSequenceNumber : _lastOutgoingSequenceNumber;
|
||||||
|
|
||||||
_avatarEntitiesLock.withReadLock([&] {
|
_avatarEntitiesLock.withReadLock([&] {
|
||||||
identityStream << getSessionUUID()
|
identityStream << getSessionUUID()
|
||||||
<< urlToSend
|
<< (udt::SequenceNumber::Type) identitySequenceNumber
|
||||||
<< _attachmentData
|
<< urlToSend
|
||||||
<< _displayName
|
<< _attachmentData
|
||||||
<< getSessionDisplayNameForTransport() // depends on _sessionDisplayName
|
<< _displayName
|
||||||
<< _avatarEntityData
|
<< getSessionDisplayNameForTransport() // depends on _sessionDisplayName
|
||||||
<< _identitySequenceId;
|
<< _avatarEntityData;
|
||||||
});
|
});
|
||||||
|
|
||||||
return identityData;
|
return identityData;
|
||||||
|
@ -1734,6 +1758,12 @@ void AvatarData::sendAvatarDataPacket() {
|
||||||
|
|
||||||
void AvatarData::sendIdentityPacket() {
|
void AvatarData::sendIdentityPacket() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
if (_identityDataChanged) {
|
||||||
|
// if the identity data has changed, push the sequence number forwards
|
||||||
|
++_lastOutgoingSequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray identityData = identityByteArray();
|
QByteArray identityData = identityByteArray();
|
||||||
|
|
||||||
auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||||
|
@ -1744,7 +1774,7 @@ void AvatarData::sendIdentityPacket() {
|
||||||
},
|
},
|
||||||
[&](const SharedNodePointer& node) {
|
[&](const SharedNodePointer& node) {
|
||||||
nodeList->sendPacketList(std::move(packetList), *node);
|
nodeList->sendPacketList(std::move(packetList), *node);
|
||||||
});
|
});
|
||||||
|
|
||||||
_avatarEntityDataLocallyEdited = false;
|
_avatarEntityDataLocallyEdited = false;
|
||||||
_identityDataChanged = false;
|
_identityDataChanged = false;
|
||||||
|
|
|
@ -52,15 +52,16 @@ typedef unsigned long long quint64;
|
||||||
#include <JointData.h>
|
#include <JointData.h>
|
||||||
#include <NLPacket.h>
|
#include <NLPacket.h>
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
|
||||||
#include <SimpleMovingAverage.h>
|
|
||||||
#include <SpatiallyNestable.h>
|
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
#include <Packed.h>
|
#include <Packed.h>
|
||||||
#include <ThreadSafeValueCache.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <shared/RateCounter.h>
|
#include <SimpleMovingAverage.h>
|
||||||
|
#include <SpatiallyNestable.h>
|
||||||
|
#include <ThreadSafeValueCache.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
#include <shared/RateCounter.h>
|
||||||
|
#include <udt/SequenceNumber.h>
|
||||||
|
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
#include "HeadData.h"
|
#include "HeadData.h"
|
||||||
|
@ -525,22 +526,18 @@ public:
|
||||||
const HeadData* getHeadData() const { return _headData; }
|
const HeadData* getHeadData() const { return _headData; }
|
||||||
|
|
||||||
struct Identity {
|
struct Identity {
|
||||||
QUuid uuid;
|
|
||||||
QUrl skeletonModelURL;
|
QUrl skeletonModelURL;
|
||||||
QVector<AttachmentData> attachmentData;
|
QVector<AttachmentData> attachmentData;
|
||||||
QString displayName;
|
QString displayName;
|
||||||
QString sessionDisplayName;
|
QString sessionDisplayName;
|
||||||
AvatarEntityMap avatarEntityData;
|
AvatarEntityMap avatarEntityData;
|
||||||
quint64 sequenceId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut);
|
|
||||||
|
|
||||||
// identityChanged returns true if identity has changed, false otherwise.
|
// identityChanged returns true if identity has changed, false otherwise.
|
||||||
// displayNameChanged returns true if displayName has changed, false otherwise.
|
// displayNameChanged returns true if displayName has changed, false otherwise.
|
||||||
void processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged);
|
void processAvatarIdentity(const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged);
|
||||||
|
|
||||||
QByteArray identityByteArray() const;
|
QByteArray identityByteArray(bool shouldForwardIncomingSequenceNumber = false) const;
|
||||||
|
|
||||||
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
||||||
const QString& getDisplayName() const { return _displayName; }
|
const QString& getDisplayName() const { return _displayName; }
|
||||||
|
@ -624,10 +621,7 @@ public:
|
||||||
static float _avatarSortCoefficientAge;
|
static float _avatarSortCoefficientAge;
|
||||||
|
|
||||||
bool getIdentityDataChanged() const { return _identityDataChanged; } // has the identity data changed since the last time sendIdentityPacket() was called
|
bool getIdentityDataChanged() const { return _identityDataChanged; } // has the identity data changed since the last time sendIdentityPacket() was called
|
||||||
void markIdentityDataChanged() {
|
void markIdentityDataChanged() { _identityDataChanged = true; }
|
||||||
_identityDataChanged = true;
|
|
||||||
_identitySequenceId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getDensity() const { return _density; }
|
float getDensity() const { return _density; }
|
||||||
|
|
||||||
|
@ -786,7 +780,9 @@ protected:
|
||||||
float _audioAverageLoudness { 0.0f };
|
float _audioAverageLoudness { 0.0f };
|
||||||
|
|
||||||
bool _identityDataChanged { false };
|
bool _identityDataChanged { false };
|
||||||
quint64 _identitySequenceId { 0 };
|
udt::SequenceNumber _lastIncomingSequenceNumber { 0 };
|
||||||
|
udt::SequenceNumber _lastOutgoingSequenceNumber { 0 };
|
||||||
|
bool _hasProcessedFirstIdentity { false };
|
||||||
float _density;
|
float _density;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -126,8 +126,9 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer<ReceivedMessag
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
AvatarData::Identity identity;
|
|
||||||
AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity);
|
// peek the avatar UUID from the incoming packet
|
||||||
|
QUuid identityUUID = message->peek(NUM_BYTES_RFC4122_UUID);
|
||||||
|
|
||||||
// make sure this isn't for an ignored avatar
|
// make sure this isn't for an ignored avatar
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
@ -136,20 +137,21 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
|
||||||
{
|
{
|
||||||
QReadLocker locker(&_hashLock);
|
QReadLocker locker(&_hashLock);
|
||||||
auto me = _avatarHash.find(EMPTY);
|
auto me = _avatarHash.find(EMPTY);
|
||||||
if ((me != _avatarHash.end()) && (identity.uuid == me.value()->getSessionUUID())) {
|
if ((me != _avatarHash.end()) && (identityUUID == me.value()->getSessionUUID())) {
|
||||||
// We add MyAvatar to _avatarHash with an empty UUID. Code relies on this. In order to correctly handle an
|
// We add MyAvatar to _avatarHash with an empty UUID. Code relies on this. In order to correctly handle an
|
||||||
// identity packet for ourself (such as when we are assigned a sessionDisplayName by the mixer upon joining),
|
// identity packet for ourself (such as when we are assigned a sessionDisplayName by the mixer upon joining),
|
||||||
// we make things match here.
|
// we make things match here.
|
||||||
identity.uuid = EMPTY;
|
identityUUID = EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!nodeList->isIgnoringNode(identity.uuid) || nodeList->getRequestsDomainListData()) {
|
|
||||||
|
if (!nodeList->isIgnoringNode(identityUUID) || nodeList->getRequestsDomainListData()) {
|
||||||
// mesh URL for a UUID, find avatar in our list
|
// mesh URL for a UUID, find avatar in our list
|
||||||
auto avatar = newOrExistingAvatar(identity.uuid, sendingNode);
|
auto avatar = newOrExistingAvatar(identityUUID, sendingNode);
|
||||||
bool identityChanged = false;
|
bool identityChanged = false;
|
||||||
bool displayNameChanged = false;
|
bool displayNameChanged = false;
|
||||||
// In this case, the "sendingNode" is the Avatar Mixer.
|
// In this case, the "sendingNode" is the Avatar Mixer.
|
||||||
avatar->processAvatarIdentity(identity, identityChanged, displayNameChanged);
|
avatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -605,7 +605,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
||||||
|
|
||||||
QString extraInfo;
|
QString extraInfo;
|
||||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||||
face, surfaceNormal, extraInfo, precisionPicking, precisionPicking);
|
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderableModelEntityItem::getCollisionGeometryResource() {
|
void RenderableModelEntityItem::getCollisionGeometryResource() {
|
||||||
|
|
|
@ -460,17 +460,11 @@ FBXLight extractLight(const FBXNode& object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
|
QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
|
||||||
QString path = QFileInfo(url).path();
|
// in order to match the behaviour when loading models from remote URLs
|
||||||
QByteArray filename = filepath;
|
// we assume that all external textures are right beside the loaded model
|
||||||
QFileInfo checkFile(path + "/" + filepath);
|
// ignoring any relative paths or absolute paths inside of models
|
||||||
|
|
||||||
// check if the file exists at the RelativeFilename
|
return filepath.mid(filepath.lastIndexOf('/') + 1);
|
||||||
if (!(checkFile.exists() && checkFile.isFile())) {
|
|
||||||
// if not, assume it is in the fbx directory
|
|
||||||
filename = filename.mid(filename.lastIndexOf('/') + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
|
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
|
||||||
|
|
|
@ -277,6 +277,23 @@ QString getEventBridgeJavascript() {
|
||||||
return javaScriptToInject;
|
return javaScriptToInject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EventBridgeWrapper : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT);
|
||||||
|
|
||||||
|
public:
|
||||||
|
EventBridgeWrapper(QObject* eventBridge, QObject* parent = nullptr) : QObject(parent), _eventBridge(eventBridge) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject* getEventBridge() {
|
||||||
|
return _eventBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QObject* _eventBridge;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QQmlEngine* acquireEngine(QQuickWindow* window) {
|
QQmlEngine* acquireEngine(QQuickWindow* window) {
|
||||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||||
|
@ -430,7 +447,6 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
||||||
|
|
||||||
_canvas->deleteLater();
|
_canvas->deleteLater();
|
||||||
_rootItem->deleteLater();
|
_rootItem->deleteLater();
|
||||||
_qmlComponent->deleteLater();
|
|
||||||
_quickWindow->deleteLater();
|
_quickWindow->deleteLater();
|
||||||
releaseEngine();
|
releaseEngine();
|
||||||
}
|
}
|
||||||
|
@ -473,11 +489,12 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
||||||
_qmlContext = new QQmlContext(qmlEngine->rootContext());
|
_qmlContext = new QQmlContext(qmlEngine->rootContext());
|
||||||
|
|
||||||
_qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
_qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
||||||
_qmlContext->setContextProperty("globalEventBridge", this);
|
_qmlContext->setContextProperty("eventBridge", this);
|
||||||
_qmlContext->setContextProperty("webEntity", this);
|
_qmlContext->setContextProperty("webEntity", this);
|
||||||
|
|
||||||
_qmlComponent = new QQmlComponent(qmlEngine);
|
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||||
|
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||||
|
_qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, _qmlContext));
|
||||||
|
|
||||||
if (!_canvas->makeCurrent()) {
|
if (!_canvas->makeCurrent()) {
|
||||||
qWarning("Failed to make context current for QML Renderer");
|
qWarning("Failed to make context current for QML Renderer");
|
||||||
|
@ -577,71 +594,79 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
|
||||||
_qmlContext->setBaseUrl(baseUrl);
|
_qmlContext->setBaseUrl(baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f) {
|
||||||
// Synchronous loading may take a while; restart the deadlock timer
|
// Synchronous loading may take a while; restart the deadlock timer
|
||||||
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
|
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
|
||||||
|
|
||||||
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
|
QQmlContext* targetContext = _qmlContext;
|
||||||
_qmlComponent->loadUrl(_qmlContext->resolvedUrl(qmlSource), QQmlComponent::PreferSynchronous);
|
if (_rootItem && createNewContext) {
|
||||||
} else {
|
targetContext = new QQmlContext(targetContext);
|
||||||
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl finalQmlSource = qmlSource;
|
||||||
|
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
|
||||||
|
finalQmlSource = _qmlContext->resolvedUrl(qmlSource);
|
||||||
|
}
|
||||||
|
|
||||||
if (_qmlComponent->isLoading()) {
|
auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous);
|
||||||
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
|
if (qmlComponent->isLoading()) {
|
||||||
[this, f](QQmlComponent::Status){
|
connect(qmlComponent, &QQmlComponent::statusChanged, this,
|
||||||
finishQmlLoad(f);
|
[this, qmlComponent, targetContext, f](QQmlComponent::Status) {
|
||||||
});
|
finishQmlLoad(qmlComponent, targetContext, f);
|
||||||
|
});
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return finishQmlLoad(f);
|
return finishQmlLoad(qmlComponent, targetContext, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject* OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
||||||
|
return load(qmlSource, true, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
||||||
|
return load(qmlSource, false, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::clearCache() {
|
void OffscreenQmlSurface::clearCache() {
|
||||||
_qmlContext->engine()->clearComponentCache();
|
_qmlContext->engine()->clearComponentCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f) {
|
QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f) {
|
||||||
#if 0
|
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
|
||||||
if (!_rootItem) {
|
if (qmlComponent->isError()) {
|
||||||
QQmlComponent component(_qmlContext->engine());
|
for (const auto& error : qmlComponent->errors()) {
|
||||||
component.setData(R"QML(
|
qCWarning(glLogging) << error.url() << error.line() << error;
|
||||||
import QtQuick 2.0
|
|
||||||
import QtWebChannel 1.0
|
|
||||||
Item { Component.onCompleted: globalEventBridge.WebChannel.id = "globalEventBridge"; }
|
|
||||||
)QML", QUrl());
|
|
||||||
QObject *helper = component.create(_qmlContext);
|
|
||||||
qDebug() << "Created helper";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0);
|
|
||||||
if (_qmlComponent->isError()) {
|
|
||||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
|
||||||
foreach(const QQmlError& error, errorList) {
|
|
||||||
qWarning() << error.url() << error.line() << error;
|
|
||||||
}
|
}
|
||||||
|
qmlComponent->deleteLater();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QObject* newObject = _qmlComponent->beginCreate(_qmlContext);
|
QObject* newObject = qmlComponent->beginCreate(qmlContext);
|
||||||
if (_qmlComponent->isError()) {
|
if (qmlComponent->isError()) {
|
||||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
for (const auto& error : qmlComponent->errors()) {
|
||||||
foreach(const QQmlError& error, errorList)
|
|
||||||
qCWarning(glLogging) << error.url() << error.line() << error;
|
qCWarning(glLogging) << error.url() << error.line() << error;
|
||||||
|
}
|
||||||
if (!_rootItem) {
|
if (!_rootItem) {
|
||||||
qFatal("Unable to finish loading QML root");
|
qFatal("Unable to finish loading QML root");
|
||||||
}
|
}
|
||||||
|
qmlComponent->deleteLater();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
newObject->setProperty("eventBridge", QVariant::fromValue(this));
|
f(qmlContext, newObject);
|
||||||
|
|
||||||
f(_qmlContext, newObject);
|
QObject* eventBridge = qmlContext->contextProperty("eventBridge").value<QObject*>();
|
||||||
_qmlComponent->completeCreate();
|
if (qmlContext != _qmlContext && eventBridge && eventBridge != this) {
|
||||||
|
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||||
|
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||||
|
qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
qmlComponent->completeCreate();
|
||||||
|
qmlComponent->deleteLater();
|
||||||
|
|
||||||
|
|
||||||
// All quick items should be focusable
|
// All quick items should be focusable
|
||||||
|
|
|
@ -48,6 +48,8 @@ public:
|
||||||
void resize(const QSize& size, bool forceResize = false);
|
void resize(const QSize& size, bool forceResize = false);
|
||||||
QSize size() const;
|
QSize size() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QObject* load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
||||||
|
Q_INVOKABLE QObject* loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
||||||
Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
||||||
Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) {
|
Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) {
|
||||||
return load(QUrl(qmlSourceFile), f);
|
return load(QUrl(qmlSourceFile), f);
|
||||||
|
@ -118,7 +120,7 @@ protected:
|
||||||
void setFocusText(bool newFocusText);
|
void setFocusText(bool newFocusText);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);
|
QObject* finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f);
|
||||||
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
|
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
|
||||||
void setupFbo();
|
void setupFbo();
|
||||||
bool allowNewFrame(uint8_t fps);
|
bool allowNewFrame(uint8_t fps);
|
||||||
|
@ -134,7 +136,6 @@ private:
|
||||||
QQuickWindow* _quickWindow { nullptr };
|
QQuickWindow* _quickWindow { nullptr };
|
||||||
QMyQuickRenderControl* _renderControl{ nullptr };
|
QMyQuickRenderControl* _renderControl{ nullptr };
|
||||||
QQmlContext* _qmlContext { nullptr };
|
QQmlContext* _qmlContext { nullptr };
|
||||||
QQmlComponent* _qmlComponent { nullptr };
|
|
||||||
QQuickItem* _rootItem { nullptr };
|
QQuickItem* _rootItem { nullptr };
|
||||||
OffscreenGLCanvas* _canvas { nullptr };
|
OffscreenGLCanvas* _canvas { nullptr };
|
||||||
|
|
||||||
|
|
|
@ -63,11 +63,17 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||||
int useScissor = batch._params[paramOffset + 0]._int;
|
int useScissor = batch._params[paramOffset + 0]._int;
|
||||||
|
|
||||||
GLuint glmask = 0;
|
GLuint glmask = 0;
|
||||||
|
bool restoreStencilMask = false;
|
||||||
|
uint8_t cacheStencilMask = 0xFF;
|
||||||
if (masks & Framebuffer::BUFFER_STENCIL) {
|
if (masks & Framebuffer::BUFFER_STENCIL) {
|
||||||
glClearStencil(stencil);
|
glClearStencil(stencil);
|
||||||
glmask |= GL_STENCIL_BUFFER_BIT;
|
glmask |= GL_STENCIL_BUFFER_BIT;
|
||||||
// TODO: we will probably need to also check the write mask of stencil like we do
|
|
||||||
// for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it"
|
cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront();
|
||||||
|
if (cacheStencilMask != 0xFF) {
|
||||||
|
restoreStencilMask = true;
|
||||||
|
glStencilMask( 0xFF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restoreDepthMask = false;
|
bool restoreDepthMask = false;
|
||||||
|
@ -121,6 +127,11 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore Stencil write mask
|
||||||
|
if (restoreStencilMask) {
|
||||||
|
glStencilMask(cacheStencilMask);
|
||||||
|
}
|
||||||
|
|
||||||
// Restore write mask meaning turn back off
|
// Restore write mask meaning turn back off
|
||||||
if (restoreDepthMask) {
|
if (restoreDepthMask) {
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
class ReceivedPacketProcessor : public GenericThread {
|
class ReceivedPacketProcessor : public GenericThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static const unsigned long MAX_WAIT_TIME { 100 };
|
static const uint64_t MAX_WAIT_TIME { 100 }; // Max wait time in ms
|
||||||
|
|
||||||
ReceivedPacketProcessor();
|
ReceivedPacketProcessor();
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ protected:
|
||||||
virtual bool process() override;
|
virtual bool process() override;
|
||||||
|
|
||||||
/// Determines the timeout of the wait when there are no packets to process. Default value is 100ms to allow for regular event processing.
|
/// Determines the timeout of the wait when there are no packets to process. Default value is 100ms to allow for regular event processing.
|
||||||
virtual unsigned long getMaxWait() const { return MAX_WAIT_TIME; }
|
virtual uint32_t getMaxWait() const { return MAX_WAIT_TIME; }
|
||||||
|
|
||||||
/// Override to do work before the packets processing loop. Default does nothing.
|
/// Override to do work before the packets processing loop. Default does nothing.
|
||||||
virtual void preProcess() { }
|
virtual void preProcess() { }
|
||||||
|
|
|
@ -59,7 +59,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::AvatarData:
|
case PacketType::AvatarData:
|
||||||
case PacketType::BulkAvatarData:
|
case PacketType::BulkAvatarData:
|
||||||
case PacketType::KillAvatar:
|
case PacketType::KillAvatar:
|
||||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarIdentitySequenceId);
|
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarIdentitySequenceFront);
|
||||||
case PacketType::MessagesData:
|
case PacketType::MessagesData:
|
||||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||||
case PacketType::ICEServerHeartbeat:
|
case PacketType::ICEServerHeartbeat:
|
||||||
|
|
|
@ -243,7 +243,9 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
AvatarAsChildFixes,
|
AvatarAsChildFixes,
|
||||||
StickAndBallDefaultAvatar,
|
StickAndBallDefaultAvatar,
|
||||||
IdentityPacketsIncludeUpdateTime,
|
IdentityPacketsIncludeUpdateTime,
|
||||||
AvatarIdentitySequenceId
|
AvatarIdentitySequenceId,
|
||||||
|
MannequinDefaultAvatar,
|
||||||
|
AvatarIdentitySequenceFront
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DomainConnectRequestVersion : PacketVersion {
|
enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
|
|
|
@ -35,8 +35,8 @@ public:
|
||||||
explicit SequenceNumber(char* value) { _value = (*reinterpret_cast<int32_t*>(value)) & MAX; }
|
explicit SequenceNumber(char* value) { _value = (*reinterpret_cast<int32_t*>(value)) & MAX; }
|
||||||
explicit SequenceNumber(Type value) { _value = (value <= MAX) ? ((value >= 0) ? value : 0) : MAX; }
|
explicit SequenceNumber(Type value) { _value = (value <= MAX) ? ((value >= 0) ? value : 0) : MAX; }
|
||||||
explicit SequenceNumber(UType value) { _value = (value <= MAX) ? value : MAX; }
|
explicit SequenceNumber(UType value) { _value = (value <= MAX) ? value : MAX; }
|
||||||
explicit operator Type() { return _value; }
|
explicit operator Type() const { return _value; }
|
||||||
explicit operator UType() { return static_cast<UType>(_value); }
|
explicit operator UType() const { return static_cast<UType>(_value); }
|
||||||
|
|
||||||
inline SequenceNumber& operator++() {
|
inline SequenceNumber& operator++() {
|
||||||
_value = (_value + 1) % (MAX + 1);
|
_value = (_value + 1) % (MAX + 1);
|
||||||
|
|
|
@ -35,14 +35,13 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JurisdictionListener::queueJurisdictionRequest() {
|
bool JurisdictionListener::queueJurisdictionRequest() {
|
||||||
auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0);
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
int nodeCount = 0;
|
int nodeCount = 0;
|
||||||
|
|
||||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||||
if (node->getType() == getNodeType() && node->getActiveSocket()) {
|
if (node->getType() == getNodeType() && node->getActiveSocket()) {
|
||||||
|
auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0);
|
||||||
_packetSender.queuePacketForSending(node, std::move(packet));
|
_packetSender.queuePacketForSending(node, std::move(packet));
|
||||||
nodeCount++;
|
nodeCount++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,6 @@ bool JurisdictionSender::process() {
|
||||||
|
|
||||||
// call our ReceivedPacketProcessor base class process so we'll get any pending packets
|
// call our ReceivedPacketProcessor base class process so we'll get any pending packets
|
||||||
if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) {
|
if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) {
|
||||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
|
||||||
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
|
||||||
int nodeCount = 0;
|
int nodeCount = 0;
|
||||||
|
|
||||||
lockRequestingNodes();
|
lockRequestingNodes();
|
||||||
|
@ -53,6 +51,8 @@ bool JurisdictionSender::process() {
|
||||||
SharedNodePointer node = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
|
SharedNodePointer node = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
|
||||||
|
|
||||||
if (node && node->getActiveSocket()) {
|
if (node && node->getActiveSocket()) {
|
||||||
|
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
||||||
|
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
||||||
_packetSender.queuePacketForSending(node, std::move(packet));
|
_packetSender.queuePacketForSending(node, std::move(packet));
|
||||||
nodeCount++;
|
nodeCount++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "AntialiasingEffect.h"
|
#include "AntialiasingEffect.h"
|
||||||
#include "StencilMaskPass.h"
|
#include "StencilMaskPass.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
#include "FramebufferCache.h"
|
|
||||||
#include "DependencyManager.h"
|
#include "DependencyManager.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "GeometryCache.h"
|
#include "GeometryCache.h"
|
||||||
|
@ -40,9 +39,9 @@ Antialiasing::~Antialiasing() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* args) {
|
||||||
int width = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width();
|
int width = args->_viewport.z;
|
||||||
int height = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height();
|
int height = args->_viewport.w;
|
||||||
|
|
||||||
if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) {
|
if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) {
|
||||||
_antialiasingBuffer.reset();
|
_antialiasingBuffer.reset();
|
||||||
|
@ -51,7 +50,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
||||||
if (!_antialiasingBuffer) {
|
if (!_antialiasingBuffer) {
|
||||||
// Link the antialiasing FBO to texture
|
// Link the antialiasing FBO to texture
|
||||||
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing"));
|
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing"));
|
||||||
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
|
auto format = gpu::Element::COLOR_SRGBA_32;
|
||||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||||
_antialiasingTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler);
|
_antialiasingTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler);
|
||||||
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
|
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
|
||||||
|
@ -110,19 +109,13 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
||||||
|
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
batch.enableStereo(false);
|
batch.enableStereo(false);
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
|
||||||
// FIXME: NEED to simplify that code to avoid all the GeometryCahce call, this is purely pixel manipulation
|
// FIXME: NEED to simplify that code to avoid all the GeometryCahce call, this is purely pixel manipulation
|
||||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
float fbWidth = renderContext->args->_viewport.z;
|
||||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
float fbHeight = renderContext->args->_viewport.w;
|
||||||
float fbWidth = framebufferSize.width();
|
|
||||||
float fbHeight = framebufferSize.height();
|
|
||||||
// float sMin = args->_viewport.x / fbWidth;
|
// float sMin = args->_viewport.x / fbWidth;
|
||||||
// float sWidth = args->_viewport.z / fbWidth;
|
// float sWidth = args->_viewport.z / fbWidth;
|
||||||
// float tMin = args->_viewport.y / fbHeight;
|
// float tMin = args->_viewport.y / fbHeight;
|
||||||
|
@ -137,10 +130,10 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
||||||
batch.setModelTransform(Transform());
|
batch.setModelTransform(Transform());
|
||||||
|
|
||||||
// FXAA step
|
// FXAA step
|
||||||
getAntialiasingPipeline();
|
auto pipeline = getAntialiasingPipeline(renderContext->args);
|
||||||
batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0));
|
batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0));
|
||||||
batch.setFramebuffer(_antialiasingBuffer);
|
batch.setFramebuffer(_antialiasingBuffer);
|
||||||
batch.setPipeline(getAntialiasingPipeline());
|
batch.setPipeline(pipeline);
|
||||||
|
|
||||||
// initialize the view-space unpacking uniforms using frustum data
|
// initialize the view-space unpacking uniforms using frustum data
|
||||||
float left, right, bottom, top, nearVal, farVal;
|
float left, right, bottom, top, nearVal, farVal;
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
void configure(const Config& config) {}
|
void configure(const Config& config) {}
|
||||||
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceBuffer);
|
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceBuffer);
|
||||||
|
|
||||||
const gpu::PipelinePointer& getAntialiasingPipeline();
|
const gpu::PipelinePointer& getAntialiasingPipeline(RenderArgs* args);
|
||||||
const gpu::PipelinePointer& getBlendPipeline();
|
const gpu::PipelinePointer& getBlendPipeline();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
#include "GeometryCache.h"
|
#include "GeometryCache.h"
|
||||||
#include "FramebufferCache.h"
|
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
|
|
||||||
|
@ -410,7 +409,6 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
|
||||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||||
const auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
|
||||||
const auto textureCache = DependencyManager::get<TextureCache>();
|
const auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
|
||||||
glm::mat4 projMat;
|
glm::mat4 projMat;
|
||||||
|
|
|
@ -418,10 +418,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {
|
void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {
|
||||||
|
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
|
||||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
|
||||||
auto framebufferSize = framebufferCache->getFrameBufferSize();
|
|
||||||
glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height());
|
|
||||||
|
|
||||||
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
|
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
|
||||||
// rendering
|
// rendering
|
||||||
|
@ -504,10 +501,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
||||||
{
|
{
|
||||||
// Framebuffer copy operations cannot function as multipass stereo operations.
|
// Framebuffer copy operations cannot function as multipass stereo operations.
|
||||||
batch.enableStereo(false);
|
batch.enableStereo(false);
|
||||||
|
|
||||||
// perform deferred lighting, rendering to free fbo
|
|
||||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
|
||||||
|
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||||
|
|
||||||
|
|
|
@ -152,9 +152,9 @@ public:
|
||||||
int numInputLights { 0 };
|
int numInputLights { 0 };
|
||||||
int numClusteredLights { 0 };
|
int numClusteredLights { 0 };
|
||||||
|
|
||||||
void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; emit dirty(); }
|
void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; }
|
||||||
void setNumInputLights(int numLights) { numInputLights = numLights; emit dirty(); }
|
void setNumInputLights(int numLights) { numInputLights = numLights; }
|
||||||
void setNumClusteredLights(int numLights) { numClusteredLights = numLights; emit dirty(); }
|
void setNumClusteredLights(int numLights) { numClusteredLights = numLights; }
|
||||||
|
|
||||||
int numSceneLights { 0 };
|
int numSceneLights { 0 };
|
||||||
int numFreeSceneLights { 0 };
|
int numFreeSceneLights { 0 };
|
||||||
|
|
|
@ -48,6 +48,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
|
batch.enableStereo(false);
|
||||||
|
|
||||||
glm::ivec4 viewport{0, 0, fbo->getWidth(), fbo->getHeight()};
|
glm::ivec4 viewport{0, 0, fbo->getWidth(), fbo->getHeight()};
|
||||||
batch.setViewportTransform(viewport);
|
batch.setViewportTransform(viewport);
|
||||||
|
@ -114,7 +115,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
||||||
skinProgram, state);
|
skinProgram, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto cachedMode = task.addJob<RenderShadowSetup>("Setup");
|
const auto cachedMode = task.addJob<RenderShadowSetup>("ShadowSetup");
|
||||||
|
|
||||||
// CPU jobs:
|
// CPU jobs:
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
|
@ -129,7 +130,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
||||||
// GPU jobs: Render to shadow map
|
// GPU jobs: Render to shadow map
|
||||||
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
||||||
|
|
||||||
task.addJob<RenderShadowTeardown>("Teardown", cachedMode);
|
task.addJob<RenderShadowTeardown>("ShadowTeardown", cachedMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowTask::configure(const Config& configuration) {
|
void RenderShadowTask::configure(const Config& configuration) {
|
||||||
|
|
33
libraries/render-utils/src/RenderViewTask.cpp
Normal file
33
libraries/render-utils/src/RenderViewTask.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// RenderViewTask.cpp
|
||||||
|
// render-utils/src/
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 5/25/2017.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#include "RenderViewTask.h"
|
||||||
|
|
||||||
|
#include "RenderShadowTask.h"
|
||||||
|
#include "RenderDeferredTask.h"
|
||||||
|
#include "RenderForwardTask.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||||
|
// auto items = input.get<Input>();
|
||||||
|
|
||||||
|
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||||
|
|
||||||
|
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||||
|
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||||
|
|
||||||
|
if (isDeferred) {
|
||||||
|
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||||
|
} else {
|
||||||
|
task.addJob<RenderForwardTask>("Forward", items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
31
libraries/render-utils/src/RenderViewTask.h
Normal file
31
libraries/render-utils/src/RenderViewTask.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// RenderViewTask.h
|
||||||
|
// render-utils/src/
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 5/25/2017.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_RenderViewTask_h
|
||||||
|
#define hifi_RenderViewTask_h
|
||||||
|
|
||||||
|
#include <render/Engine.h>
|
||||||
|
#include <render/RenderFetchCullSortTask.h>
|
||||||
|
|
||||||
|
|
||||||
|
class RenderViewTask {
|
||||||
|
public:
|
||||||
|
using Input = RenderFetchCullSortTask::Output;
|
||||||
|
using JobModel = render::Task::ModelI<RenderViewTask, Input>;
|
||||||
|
|
||||||
|
RenderViewTask() {}
|
||||||
|
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_RenderViewTask_h
|
|
@ -14,6 +14,8 @@
|
||||||
#include "../RenderUtilsLogging.h"
|
#include "../RenderUtilsLogging.h"
|
||||||
#include "FontFamilies.h"
|
#include "FontFamilies.h"
|
||||||
|
|
||||||
|
static std::mutex fontMutex;
|
||||||
|
|
||||||
struct TextureVertex {
|
struct TextureVertex {
|
||||||
glm::vec2 pos;
|
glm::vec2 pos;
|
||||||
glm::vec2 tex;
|
glm::vec2 tex;
|
||||||
|
@ -56,6 +58,7 @@ Font::Pointer Font::load(QIODevice& fontFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Pointer Font::load(const QString& family) {
|
Font::Pointer Font::load(const QString& family) {
|
||||||
|
std::lock_guard<std::mutex> lock(fontMutex);
|
||||||
if (!LOADED_FONTS.contains(family)) {
|
if (!LOADED_FONTS.contains(family)) {
|
||||||
|
|
||||||
static const QString SDFF_COURIER_PRIME_FILENAME{ ":/CourierPrime.sdff" };
|
static const QString SDFF_COURIER_PRIME_FILENAME{ ":/CourierPrime.sdff" };
|
||||||
|
|
|
@ -31,10 +31,10 @@ public:
|
||||||
const glm::vec4* color, EffectType effectType,
|
const glm::vec4* color, EffectType effectType,
|
||||||
const glm::vec2& bound, bool layered = false);
|
const glm::vec2& bound, bool layered = false);
|
||||||
|
|
||||||
static Pointer load(QIODevice& fontFile);
|
|
||||||
static Pointer load(const QString& family);
|
static Pointer load(const QString& family);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static Pointer load(QIODevice& fontFile);
|
||||||
QStringList tokenizeForWrapping(const QString& str) const;
|
QStringList tokenizeForWrapping(const QString& str) const;
|
||||||
QStringList splitLines(const QString& str) const;
|
QStringList splitLines(const QString& str) const;
|
||||||
glm::vec2 computeTokenExtent(const QString& str) const;
|
glm::vec2 computeTokenExtent(const QString& str) const;
|
||||||
|
|
|
@ -63,6 +63,4 @@ void EngineStats::run(const RenderContextPointer& renderContext) {
|
||||||
|
|
||||||
config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines;
|
config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines;
|
||||||
config->frameSetInputFormatCount = _gpuStats._ISNumFormatChanges;
|
config->frameSetInputFormatCount = _gpuStats._ISNumFormatChanges;
|
||||||
|
|
||||||
config->emitDirty();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::strin
|
||||||
if (childConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
if (childConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||||
// Connect dirty->refresh if defined
|
// Connect dirty->refresh if defined
|
||||||
QObject::connect(childConfig.get(), SIGNAL(dirty()), this, SLOT(refresh()));
|
QObject::connect(childConfig.get(), SIGNAL(dirty()), this, SLOT(refresh()));
|
||||||
|
QObject::connect(childConfig.get(), SIGNAL(dirtyEnabled()), this, SLOT(refresh()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ void TaskConfig::transferChildrenConfigs(QConfigPointer source) {
|
||||||
if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||||
// Connect dirty->refresh if defined
|
// Connect dirty->refresh if defined
|
||||||
QObject::connect(child, SIGNAL(dirty()), this, SLOT(refresh()));
|
QObject::connect(child, SIGNAL(dirty()), this, SLOT(refresh()));
|
||||||
|
QObject::connect(child, SIGNAL(dirtyEnabled()), this, SLOT(refresh()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ protected:
|
||||||
class JobConfig : public QObject {
|
class JobConfig : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms
|
Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms
|
||||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY dirtyEnabled())
|
||||||
|
|
||||||
double _msCPURunTime{ 0.0 };
|
double _msCPURunTime{ 0.0 };
|
||||||
public:
|
public:
|
||||||
|
@ -99,7 +99,7 @@ public:
|
||||||
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
||||||
|
|
||||||
bool isEnabled() { return alwaysEnabled || enabled; }
|
bool isEnabled() { return alwaysEnabled || enabled; }
|
||||||
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; }
|
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; emit dirtyEnabled(); }
|
||||||
|
|
||||||
bool alwaysEnabled{ true };
|
bool alwaysEnabled{ true };
|
||||||
bool enabled{ true };
|
bool enabled{ true };
|
||||||
|
@ -121,6 +121,7 @@ public slots:
|
||||||
signals:
|
signals:
|
||||||
void loaded();
|
void loaded();
|
||||||
void newStats();
|
void newStats();
|
||||||
|
void dirtyEnabled();
|
||||||
};
|
};
|
||||||
|
|
||||||
class TaskConfig : public JobConfig {
|
class TaskConfig : public JobConfig {
|
||||||
|
|
|
@ -170,6 +170,7 @@ protected:
|
||||||
std::string _name = "";
|
std::string _name = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// A task is a specialized job to run a collection of other jobs
|
// A task is a specialized job to run a collection of other jobs
|
||||||
// It can be created on any type T by aliasing the type JobModel in the class T
|
// It can be created on any type T by aliasing the type JobModel in the class T
|
||||||
// using JobModel = Task::Model<T>
|
// using JobModel = Task::Model<T>
|
||||||
|
|
|
@ -540,7 +540,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS
|
||||||
|
|
||||||
QObject* TabletProxy::addButton(const QVariant& properties) {
|
QObject* TabletProxy::addButton(const QVariant& properties) {
|
||||||
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
||||||
std::lock_guard<std::mutex> guard(_tabletMutex);
|
std::unique_lock<std::mutex> guard(_tabletMutex);
|
||||||
_tabletButtonProxies.push_back(tabletButtonProxy);
|
_tabletButtonProxies.push_back(tabletButtonProxy);
|
||||||
if (!_toolbarMode && _qmlTabletRoot) {
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
auto tablet = getQmlTablet();
|
auto tablet = getQmlTablet();
|
||||||
|
@ -550,7 +550,6 @@ QObject* TabletProxy::addButton(const QVariant& properties) {
|
||||||
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||||
}
|
}
|
||||||
} else if (_toolbarMode) {
|
} else if (_toolbarMode) {
|
||||||
|
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||||
|
|
||||||
|
@ -559,6 +558,8 @@ QObject* TabletProxy::addButton(const QVariant& properties) {
|
||||||
connectionType = Qt::BlockingQueuedConnection;
|
connectionType = Qt::BlockingQueuedConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard.unlock();
|
||||||
|
|
||||||
// copy properties from tablet button proxy to toolbar button proxy.
|
// copy properties from tablet button proxy to toolbar button proxy.
|
||||||
QObject* toolbarButtonProxy = nullptr;
|
QObject* toolbarButtonProxy = nullptr;
|
||||||
bool hasResult = QMetaObject::invokeMethod(toolbarProxy, "addButton", connectionType, Q_RETURN_ARG(QObject*, toolbarButtonProxy), Q_ARG(QVariant, tabletButtonProxy->getProperties()));
|
bool hasResult = QMetaObject::invokeMethod(toolbarProxy, "addButton", connectionType, Q_RETURN_ARG(QObject*, toolbarButtonProxy), Q_ARG(QVariant, tabletButtonProxy->getProperties()));
|
||||||
|
@ -576,31 +577,38 @@ bool TabletProxy::onHomeScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
||||||
std::lock_guard<std::mutex> guard(_tabletMutex);
|
std::unique_lock<std::mutex> guard(_tabletMutex);
|
||||||
|
|
||||||
auto tablet = getQmlTablet();
|
auto tablet = getQmlTablet();
|
||||||
if (!tablet) {
|
if (!tablet) {
|
||||||
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
QSharedPointer<TabletButtonProxy> buttonProxy;
|
||||||
if (iter != _tabletButtonProxies.end()) {
|
{
|
||||||
if (!_toolbarMode && _qmlTabletRoot) {
|
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
||||||
(*iter)->setQmlButton(nullptr);
|
if (iter == _tabletButtonProxies.end()) {
|
||||||
if (tablet) {
|
qCWarning(scriptengine) << "TabletProxy::removeButton() could not find button " << tabletButtonProxy;
|
||||||
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getProperties()));
|
return;
|
||||||
}
|
|
||||||
} else if (_toolbarMode) {
|
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
|
||||||
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
|
||||||
|
|
||||||
// remove button from toolbarProxy
|
|
||||||
QMetaObject::invokeMethod(toolbarProxy, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getUuid().toString()));
|
|
||||||
(*iter)->setToolbarButtonProxy(nullptr);
|
|
||||||
}
|
}
|
||||||
|
buttonProxy = *iter;
|
||||||
_tabletButtonProxies.erase(iter);
|
_tabletButtonProxies.erase(iter);
|
||||||
} else {
|
}
|
||||||
qCWarning(scriptengine) << "TabletProxy::removeButton() could not find button " << tabletButtonProxy;
|
|
||||||
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
|
buttonProxy->setQmlButton(nullptr);
|
||||||
|
if (tablet) {
|
||||||
|
guard.unlock();
|
||||||
|
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||||
|
}
|
||||||
|
} else if (_toolbarMode) {
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||||
|
|
||||||
|
// remove button from toolbarProxy
|
||||||
|
guard.unlock();
|
||||||
|
QMetaObject::invokeMethod(toolbarProxy, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getUuid().toString()));
|
||||||
|
buttonProxy->setToolbarButtonProxy(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,9 +104,9 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
||||||
Q_ASSERT(invokeResult);
|
Q_ASSERT(invokeResult);
|
||||||
} else {
|
} else {
|
||||||
// Build the event bridge and wrapper on the main thread
|
// Build the event bridge and wrapper on the main thread
|
||||||
offscreenUi->load(qmlSource(), [&](QQmlContext* context, QObject* object) {
|
offscreenUi->loadInNewContext(qmlSource(), [&](QQmlContext* context, QObject* object) {
|
||||||
_qmlWindow = object;
|
_qmlWindow = object;
|
||||||
_qmlWindow->setProperty("eventBridge", QVariant::fromValue(this));
|
context->setContextProperty("eventBridge", this);
|
||||||
context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
context->engine()->setObjectOwnership(object, QQmlEngine::CppOwnership);
|
context->engine()->setObjectOwnership(object, QQmlEngine::CppOwnership);
|
||||||
if (properties.contains(TITLE_PROPERTY)) {
|
if (properties.contains(TITLE_PROPERTY)) {
|
||||||
|
|
|
@ -10,10 +10,10 @@ if (WIN32)
|
||||||
# we're using static GLEW, so define GLEW_STATIC
|
# we're using static GLEW, so define GLEW_STATIC
|
||||||
add_definitions(-DGLEW_STATIC)
|
add_definitions(-DGLEW_STATIC)
|
||||||
set(TARGET_NAME openvr)
|
set(TARGET_NAME openvr)
|
||||||
setup_hifi_plugin(OpenGL Script Qml Widgets)
|
setup_hifi_plugin(OpenGL Script Qml Widgets Multimedia)
|
||||||
link_hifi_libraries(shared gl networking controllers ui
|
link_hifi_libraries(shared gl networking controllers ui
|
||||||
plugins display-plugins ui-plugins input-plugins script-engine
|
plugins display-plugins ui-plugins input-plugins script-engine
|
||||||
render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
audio-client render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
||||||
|
|
||||||
include_hifi_library_headers(octree)
|
include_hifi_library_headers(octree)
|
||||||
|
|
||||||
|
@ -21,4 +21,5 @@ if (WIN32)
|
||||||
find_package(OpenVR REQUIRED)
|
find_package(OpenVR REQUIRED)
|
||||||
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
|
||||||
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
|
||||||
|
target_link_libraries(${TARGET_NAME} Winmm.lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
//
|
//
|
||||||
#include "OpenVrDisplayPlugin.h"
|
#include "OpenVrDisplayPlugin.h"
|
||||||
|
|
||||||
|
// Odd ordering of header is required to avoid 'macro redinition warnings'
|
||||||
|
#include <AudioClient.h>
|
||||||
|
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
|
@ -713,3 +716,30 @@ bool OpenVrDisplayPlugin::isKeyboardVisible() {
|
||||||
int OpenVrDisplayPlugin::getRequiredThreadCount() const {
|
int OpenVrDisplayPlugin::getRequiredThreadCount() const {
|
||||||
return Parent::getRequiredThreadCount() + (_threadedSubmit ? 1 : 0);
|
return Parent::getRequiredThreadCount() + (_threadedSubmit ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const {
|
||||||
|
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String);
|
||||||
|
if (!device.isEmpty()) {
|
||||||
|
static const WCHAR INIT = 0;
|
||||||
|
size_t size = device.size() + 1;
|
||||||
|
std::vector<WCHAR> deviceW;
|
||||||
|
deviceW.assign(size, INIT);
|
||||||
|
device.toWCharArray(deviceW.data());
|
||||||
|
device = AudioClient::friendlyNameForAudioDevice(deviceW.data());
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const {
|
||||||
|
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_OnRecordDevice_String);
|
||||||
|
if (!device.isEmpty()) {
|
||||||
|
static const WCHAR INIT = 0;
|
||||||
|
size_t size = device.size() + 1;
|
||||||
|
std::vector<WCHAR> deviceW;
|
||||||
|
deviceW.assign(size, INIT);
|
||||||
|
device.toWCharArray(deviceW.data());
|
||||||
|
device = AudioClient::friendlyNameForAudioDevice(deviceW.data());
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,9 @@ public:
|
||||||
// Possibly needs an additional thread for VR submission
|
// Possibly needs an additional thread for VR submission
|
||||||
int getRequiredThreadCount() const override;
|
int getRequiredThreadCount() const override;
|
||||||
|
|
||||||
|
QString getPreferredAudioInDevice() const override;
|
||||||
|
QString getPreferredAudioOutDevice() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool internalActivate() override;
|
bool internalActivate() override;
|
||||||
void internalDeactivate() override;
|
void internalDeactivate() override;
|
||||||
|
|
|
@ -72,6 +72,21 @@ bool openVrSupported() {
|
||||||
return (enableDebugOpenVR || !isOculusPresent()) && vr::VR_IsHmdPresent();
|
return (enableDebugOpenVR || !isOculusPresent()) && vr::VR_IsHmdPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString getVrSettingString(const char* section, const char* setting) {
|
||||||
|
QString result;
|
||||||
|
static const uint32_t BUFFER_SIZE = 1024;
|
||||||
|
static char BUFFER[BUFFER_SIZE];
|
||||||
|
vr::IVRSettings * vrSettings = vr::VRSettings();
|
||||||
|
if (vrSettings) {
|
||||||
|
vr::EVRSettingsError error = vr::VRSettingsError_None;
|
||||||
|
vrSettings->GetString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String, BUFFER, BUFFER_SIZE, &error);
|
||||||
|
if (error == vr::VRSettingsError_None) {
|
||||||
|
result = BUFFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
vr::IVRSystem* acquireOpenVrSystem() {
|
vr::IVRSystem* acquireOpenVrSystem() {
|
||||||
bool hmdPresent = vr::VR_IsHmdPresent();
|
bool hmdPresent = vr::VR_IsHmdPresent();
|
||||||
if (hmdPresent) {
|
if (hmdPresent) {
|
||||||
|
@ -82,6 +97,7 @@ vr::IVRSystem* acquireOpenVrSystem() {
|
||||||
#endif
|
#endif
|
||||||
vr::EVRInitError eError = vr::VRInitError_None;
|
vr::EVRInitError eError = vr::VRInitError_None;
|
||||||
activeHmd = vr::VR_Init(&eError, vr::VRApplication_Scene);
|
activeHmd = vr::VR_Init(&eError, vr::VRApplication_Scene);
|
||||||
|
|
||||||
#if DEV_BUILD
|
#if DEV_BUILD
|
||||||
qCDebug(displayplugins) << "OpenVR display: HMD is " << activeHmd << " error is " << eError;
|
qCDebug(displayplugins) << "OpenVR display: HMD is " << activeHmd << " error is " << eError;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,7 @@ bool openVrQuitRequested();
|
||||||
void enableOpenVrKeyboard(PluginContainer* container);
|
void enableOpenVrKeyboard(PluginContainer* container);
|
||||||
void disableOpenVrKeyboard();
|
void disableOpenVrKeyboard();
|
||||||
bool isOpenVrKeyboardShown();
|
bool isOpenVrKeyboardShown();
|
||||||
|
QString getVrSettingString(const char* section, const char* setting);
|
||||||
|
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
|
|
|
@ -123,15 +123,18 @@ bool ViveControllerManager::isSupported() const {
|
||||||
bool ViveControllerManager::activate() {
|
bool ViveControllerManager::activate() {
|
||||||
InputPlugin::activate();
|
InputPlugin::activate();
|
||||||
|
|
||||||
_container->addMenu(MENU_PATH);
|
|
||||||
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS,
|
|
||||||
[this] (bool clicked) { this->setRenderControllers(clicked); },
|
|
||||||
true, true);
|
|
||||||
|
|
||||||
if (!_system) {
|
if (!_system) {
|
||||||
_system = acquireOpenVrSystem();
|
_system = acquireOpenVrSystem();
|
||||||
}
|
}
|
||||||
Q_ASSERT(_system);
|
|
||||||
|
if (!_system) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_container->addMenu(MENU_PATH);
|
||||||
|
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS,
|
||||||
|
[this](bool clicked) { this->setRenderControllers(clicked); },
|
||||||
|
true, true);
|
||||||
|
|
||||||
enableOpenVrKeyboard(_container);
|
enableOpenVrKeyboard(_container);
|
||||||
|
|
||||||
|
|
127
scripts/developer/tests/avatarToWorldTests.js
Normal file
127
scripts/developer/tests/avatarToWorldTests.js
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||||
|
|
||||||
|
var debugSphereBaseProperties = {
|
||||||
|
type: "Sphere",
|
||||||
|
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||||
|
dynamic: false,
|
||||||
|
collisionless: true,
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
lifetime: 10.0,
|
||||||
|
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||||
|
};
|
||||||
|
|
||||||
|
var debugBoxBaseProperties = {
|
||||||
|
type: "Box",
|
||||||
|
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||||
|
dynamic: false,
|
||||||
|
collisionless: true,
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
lifetime: 10.0,
|
||||||
|
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||||
|
};
|
||||||
|
|
||||||
|
//jointToWorldPoint
|
||||||
|
// create sphere for finger on left hand
|
||||||
|
// each frame, calculate world position of finger, with some offset
|
||||||
|
// update sphere to match this position
|
||||||
|
var jointToWorldPointTest_sphereEntity;
|
||||||
|
function jointToWorldPointTest() {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
|
||||||
|
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
|
||||||
|
var worldPos = MyAvatar.jointToWorldPoint(jointOffset_WorldSpace, jointIndex);
|
||||||
|
|
||||||
|
var jointSphereProps = Object.create(debugSphereBaseProperties);
|
||||||
|
jointSphereProps.name = "jointToWorldPointTest_Sphere";
|
||||||
|
jointSphereProps.color = { blue: 240, green: 150, red: 150 };
|
||||||
|
jointSphereProps.position = worldPos;
|
||||||
|
jointToWorldPointTest_sphereEntity = Entities.addEntity(jointSphereProps);
|
||||||
|
}
|
||||||
|
function jointToWorldPointTest_update(deltaTime) {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
|
||||||
|
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
|
||||||
|
var worldPos = MyAvatar.jointToWorldPoint(jointOffset_WorldSpace, jointIndex);
|
||||||
|
var newProperties = { position: worldPos };
|
||||||
|
Entities.editEntity(jointToWorldPointTest_sphereEntity, newProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
//jointToWorldDirection
|
||||||
|
// create line in world space
|
||||||
|
// each frame calculate world space direction of players head z axis
|
||||||
|
// update line to match
|
||||||
|
var jointToWorldDirectionTest_lineEntity;
|
||||||
|
function jointToWorldDirectionTest() {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||||
|
var avatarPos = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
|
||||||
|
var jointDir = { x: 1, y: 0, z: 1 };
|
||||||
|
var worldDir = MyAvatar.jointToWorldDirection(jointDir, jointIndex);
|
||||||
|
print(worldDir.x);
|
||||||
|
print(worldDir.y);
|
||||||
|
print(worldDir.z);
|
||||||
|
jointToWorldDirectionTest_lineEntity = Entities.addEntity({
|
||||||
|
type: "Line",
|
||||||
|
color: {red: 250, green: 0, blue: 0},
|
||||||
|
dimensions: {x: 5, y: 5, z: 5},
|
||||||
|
lifetime: 10.0,
|
||||||
|
linePoints: [{
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}, worldDir
|
||||||
|
],
|
||||||
|
position : avatarPos,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function jointToWorldDirection_update(deltaTime) {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||||
|
var avatarPos = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
var jointDir = { x: 1, y: 0, z: 0 };
|
||||||
|
var worldDir = MyAvatar.jointToWorldDirection(jointDir, jointIndex);
|
||||||
|
var newProperties = {
|
||||||
|
linePoints: [{
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}, worldDir
|
||||||
|
],
|
||||||
|
position : avatarPos
|
||||||
|
};
|
||||||
|
|
||||||
|
Entities.editEntity(jointToWorldDirectionTest_lineEntity, newProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
//jointToWorldRotation
|
||||||
|
// create box in world space
|
||||||
|
// each frame calculate world space rotation of players head
|
||||||
|
// update box rotation to match
|
||||||
|
var jointToWorldRotationTest_boxEntity;
|
||||||
|
function jointToWorldRotationTest() {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||||
|
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
var jointRot = MyAvatar.getJointRotation(jointIndex);
|
||||||
|
var jointRot_WorldSpace = MyAvatar.jointToWorldRotation(jointRot, jointIndex);
|
||||||
|
|
||||||
|
var boxProps = Object.create(debugBoxBaseProperties);
|
||||||
|
boxProps.name = "jointToWorldRotationTest_Box";
|
||||||
|
boxProps.color = { blue: 250, green: 250, red: 250 };
|
||||||
|
boxProps.position = jointPosition_WorldSpace;
|
||||||
|
boxProps.rotation = jointRot_WorldSpace;
|
||||||
|
jointToWorldRotationTest_boxEntity = Entities.addEntity(boxProps);
|
||||||
|
}
|
||||||
|
function jointToWorldRotationTest_update(deltaTime) {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||||
|
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
var jointRot = MyAvatar.getJointRotation(jointIndex);
|
||||||
|
var jointRot_WorldSpace = MyAvatar.jointToWorldRotation(jointRot, jointIndex);
|
||||||
|
var newProperties = { position: jointPosition_WorldSpace, rotation: jointRot_WorldSpace };
|
||||||
|
Entities.editEntity(jointToWorldRotationTest_boxEntity, newProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
jointToWorldPointTest();
|
||||||
|
Script.update.connect(jointToWorldPointTest_update);
|
||||||
|
|
||||||
|
jointToWorldDirectionTest();
|
||||||
|
Script.update.connect(jointToWorldDirection_update);
|
||||||
|
|
||||||
|
jointToWorldRotationTest();
|
||||||
|
Script.update.connect(jointToWorldRotationTest_update);
|
134
scripts/developer/tests/worldToAvatarTests.js
Normal file
134
scripts/developer/tests/worldToAvatarTests.js
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||||
|
|
||||||
|
var debugSphereBaseProperties = {
|
||||||
|
type: "Sphere",
|
||||||
|
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||||
|
dynamic: false,
|
||||||
|
collisionless: true,
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
lifetime: 10.0,
|
||||||
|
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||||
|
};
|
||||||
|
|
||||||
|
var debugBoxBaseProperties = {
|
||||||
|
type: "Box",
|
||||||
|
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||||
|
dynamic: false,
|
||||||
|
collisionless: true,
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
lifetime: 10.0,
|
||||||
|
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||||
|
};
|
||||||
|
|
||||||
|
//worldToJointPoint
|
||||||
|
// calculate position offset from joint using getJointPosition
|
||||||
|
// pass through worldToJointPoint to get offset in joint space of players joint
|
||||||
|
// create a blue sphere and attach it to players joint using the joint space offset
|
||||||
|
// The two spheres should appear in the same place, but the blue sphere will follow the avatar
|
||||||
|
function worldToJointPointTest() {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
|
||||||
|
var avatarPos = MyAvatar.position;
|
||||||
|
|
||||||
|
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
|
||||||
|
var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace);
|
||||||
|
var jointPosition_JointSpaceOffset = MyAvatar.worldToJointPoint(jointPosition_WorldSpaceOffset, jointIndex);
|
||||||
|
|
||||||
|
var jointSphereProps = Object.create(debugSphereBaseProperties);
|
||||||
|
jointSphereProps.name = "worldToJointPointTest_Joint";
|
||||||
|
jointSphereProps.color = { blue: 240, green: 150, red: 150 };
|
||||||
|
jointSphereProps.localPosition = jointPosition_JointSpaceOffset;
|
||||||
|
jointSphereProps.parentID = AVATAR_SELF_ID;
|
||||||
|
jointSphereProps.parentJointIndex = jointIndex;
|
||||||
|
Entities.addEntity(jointSphereProps);
|
||||||
|
|
||||||
|
var worldSphereProps = Object.create(debugSphereBaseProperties);
|
||||||
|
worldSphereProps.name = "worldToJointPointTest_World";
|
||||||
|
worldSphereProps.color = { blue: 150, green: 250, red: 150 };
|
||||||
|
worldSphereProps.position = jointPosition_WorldSpaceOffset;
|
||||||
|
Entities.addEntity(worldSphereProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
//worldToJointDirection
|
||||||
|
// create line and attach to avatars head
|
||||||
|
// each frame calculate direction of world x axis in joint space of players head
|
||||||
|
// update arrow orientation to match
|
||||||
|
var worldToJointDirectionTest_lineEntity;
|
||||||
|
function worldToJointDirectionTest() {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||||
|
|
||||||
|
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
var jointOffset_WorldSpace = { x: 0, y: 0, z: 0 };
|
||||||
|
var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace);
|
||||||
|
var jointPosition_JointSpaceOffset = MyAvatar.worldToJointPoint(jointPosition_WorldSpaceOffset, jointIndex);
|
||||||
|
|
||||||
|
var worldDir = { x: 1, y: 0, z: 0 };
|
||||||
|
var avatarDir = MyAvatar.worldToJointDirection(worldDir, jointIndex);
|
||||||
|
|
||||||
|
worldToJointDirectionTest_lineEntity = Entities.addEntity({
|
||||||
|
type: "Line",
|
||||||
|
color: {red: 200, green: 250, blue: 0},
|
||||||
|
dimensions: {x: 5, y: 5, z: 5},
|
||||||
|
lifetime: 10.0,
|
||||||
|
linePoints: [{
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}, avatarDir
|
||||||
|
],
|
||||||
|
localPosition : jointOffset_WorldSpace,
|
||||||
|
parentID : AVATAR_SELF_ID,
|
||||||
|
parentJointIndex : jointIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function worldToJointDirectionTest_update(deltaTime) {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||||
|
var worldDir = { x: 1, y: 0, z: 0 };
|
||||||
|
var avatarDir = MyAvatar.worldToJointDirection(worldDir, jointIndex);
|
||||||
|
var newProperties = { linePoints: [{
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}, avatarDir
|
||||||
|
]};
|
||||||
|
|
||||||
|
Entities.editEntity(worldToJointDirectionTest_lineEntity, newProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
//worldToJointRotation
|
||||||
|
// create box and parent to some player joint
|
||||||
|
// convert world identity rotation to joint space rotation
|
||||||
|
// each frame, update box with new orientation
|
||||||
|
var worldToJointRotationTest_boxEntity;
|
||||||
|
function worldToJointRotationTest() {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("RightHandPinky4");
|
||||||
|
var avatarPos = MyAvatar.position;
|
||||||
|
|
||||||
|
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||||
|
var jointOffset_WorldSpace = { x: 0.0, y: 0, z: 0 };
|
||||||
|
var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace);
|
||||||
|
var jointPosition_JointSpaceOffset = MyAvatar.worldToJointPoint(jointPosition_WorldSpaceOffset, jointIndex);
|
||||||
|
|
||||||
|
var jointBoxProps = Object.create(debugBoxBaseProperties);
|
||||||
|
jointBoxProps.name = "worldToJointRotationTest_Box";
|
||||||
|
jointBoxProps.color = { blue: 0, green: 0, red: 250 };
|
||||||
|
jointBoxProps.localPosition = jointPosition_JointSpaceOffset;
|
||||||
|
jointBoxProps.parentID = AVATAR_SELF_ID;
|
||||||
|
jointBoxProps.parentJointIndex = jointIndex;
|
||||||
|
worldToJointRotationTest_boxEntity = Entities.addEntity(jointBoxProps);
|
||||||
|
}
|
||||||
|
function worldToJointRotationTest_update(deltaTime) {
|
||||||
|
var jointIndex = MyAvatar.getJointIndex("RightHandPinky4");
|
||||||
|
var worldRot = Quat.fromPitchYawRollDegrees(0,0,0);
|
||||||
|
var avatarRot = MyAvatar.worldToJointRotation(worldRot, jointIndex);
|
||||||
|
var newProperties = { localRotation: avatarRot };
|
||||||
|
Entities.editEntity(worldToJointRotationTest_boxEntity, newProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
worldToJointPointTest();
|
||||||
|
worldToJointDirectionTest();
|
||||||
|
worldToJointRotationTest();
|
||||||
|
|
||||||
|
Script.update.connect(worldToJointDirectionTest_update);
|
||||||
|
Script.update.connect(worldToJointRotationTest_update);
|
|
@ -12,7 +12,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger,
|
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger,
|
||||||
Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */
|
Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
@ -80,27 +80,7 @@ selectionManager.addEventListener(function () {
|
||||||
}
|
}
|
||||||
var type = Entities.getEntityProperties(selectedEntityID, "type").type;
|
var type = Entities.getEntityProperties(selectedEntityID, "type").type;
|
||||||
if (type === "ParticleEffect") {
|
if (type === "ParticleEffect") {
|
||||||
// Destroy the old particles web view first
|
selectParticleEntity(selectedEntityID);
|
||||||
particleExplorerTool.destroyWebView();
|
|
||||||
particleExplorerTool.createWebView();
|
|
||||||
var properties = Entities.getEntityProperties(selectedEntityID);
|
|
||||||
var particleData = {
|
|
||||||
messageType: "particle_settings",
|
|
||||||
currentProperties: properties
|
|
||||||
};
|
|
||||||
selectedParticleEntityID = selectedEntityID;
|
|
||||||
particleExplorerTool.setActiveParticleEntity(selectedParticleEntityID);
|
|
||||||
|
|
||||||
particleExplorerTool.webView.webEventReceived.connect(function (data) {
|
|
||||||
data = JSON.parse(data);
|
|
||||||
if (data.messageType === "page_loaded") {
|
|
||||||
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Switch to particle explorer
|
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
tablet.sendToQml({method: 'selectTab', params: {id: 'particle'}});
|
|
||||||
} else {
|
} else {
|
||||||
needToDestroyParticleExplorer = true;
|
needToDestroyParticleExplorer = true;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +198,7 @@ function hideMarketplace() {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
|
function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
|
||||||
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
|
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
|
||||||
// position in the given direction.
|
// position in the given direction.
|
||||||
var CORNERS = [
|
var CORNERS = [
|
||||||
{ x: 0, y: 0, z: 0 },
|
{ x: 0, y: 0, z: 0 },
|
||||||
|
@ -1373,7 +1353,7 @@ function parentSelectedEntities() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(parentCheck) {
|
if (parentCheck) {
|
||||||
Window.notify("Entities parented");
|
Window.notify("Entities parented");
|
||||||
}else {
|
}else {
|
||||||
Window.notify("Entities are already parented to last");
|
Window.notify("Entities are already parented to last");
|
||||||
|
@ -1575,7 +1555,7 @@ function importSVO(importURL) {
|
||||||
var properties = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
|
var properties = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
|
||||||
"registrationPoint"]);
|
"registrationPoint"]);
|
||||||
var position = Vec3.sum(deltaPosition, properties.position);
|
var position = Vec3.sum(deltaPosition, properties.position);
|
||||||
position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions,
|
position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions,
|
||||||
properties.registrationPoint), properties.dimensions, properties.registrationPoint);
|
properties.registrationPoint), properties.dimensions, properties.registrationPoint);
|
||||||
deltaPosition = Vec3.subtract(position, properties.position);
|
deltaPosition = Vec3.subtract(position, properties.position);
|
||||||
}
|
}
|
||||||
|
@ -1907,11 +1887,11 @@ var PropertiesTool = function (opts) {
|
||||||
}
|
}
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update();
|
||||||
} else if(data.type === 'parent') {
|
} else if (data.type === 'parent') {
|
||||||
parentSelectedEntities();
|
parentSelectedEntities();
|
||||||
} else if(data.type === 'unparent') {
|
} else if (data.type === 'unparent') {
|
||||||
unparentSelectedEntities();
|
unparentSelectedEntities();
|
||||||
} else if(data.type === 'saveUserData'){
|
} else if (data.type === 'saveUserData'){
|
||||||
//the event bridge and json parsing handle our avatar id string differently.
|
//the event bridge and json parsing handle our avatar id string differently.
|
||||||
var actualID = data.id.split('"')[1];
|
var actualID = data.id.split('"')[1];
|
||||||
Entities.editEntity(actualID, data.properties);
|
Entities.editEntity(actualID, data.properties);
|
||||||
|
@ -2203,6 +2183,10 @@ var selectedParticleEntityID = null;
|
||||||
|
|
||||||
function selectParticleEntity(entityID) {
|
function selectParticleEntity(entityID) {
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
|
|
||||||
|
if (properties.emitOrientation) {
|
||||||
|
properties.emitOrientation = Quat.safeEulerAngles(properties.emitOrientation);
|
||||||
|
}
|
||||||
var particleData = {
|
var particleData = {
|
||||||
messageType: "particle_settings",
|
messageType: "particle_settings",
|
||||||
currentProperties: properties
|
currentProperties: properties
|
||||||
|
@ -2212,6 +2196,7 @@ function selectParticleEntity(entityID) {
|
||||||
|
|
||||||
selectedParticleEntity = entityID;
|
selectedParticleEntity = entityID;
|
||||||
particleExplorerTool.setActiveParticleEntity(entityID);
|
particleExplorerTool.setActiveParticleEntity(entityID);
|
||||||
|
|
||||||
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
|
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
|
||||||
|
|
||||||
// Switch to particle explorer
|
// Switch to particle explorer
|
||||||
|
@ -2229,7 +2214,7 @@ entityListTool.webView.webEventReceived.connect(function (data) {
|
||||||
|
|
||||||
if (data.type === 'parent') {
|
if (data.type === 'parent') {
|
||||||
parentSelectedEntities();
|
parentSelectedEntities();
|
||||||
} else if(data.type === 'unparent') {
|
} else if (data.type === 'unparent') {
|
||||||
unparentSelectedEntities();
|
unparentSelectedEntities();
|
||||||
} else if (data.type === "selectionUpdate") {
|
} else if (data.type === "selectionUpdate") {
|
||||||
var ids = data.entityIds;
|
var ids = data.entityIds;
|
||||||
|
@ -2250,4 +2235,3 @@ entityListTool.webView.webEventReceived.connect(function (data) {
|
||||||
});
|
});
|
||||||
|
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue