Merge branch 'master' of github.com:highfidelity/hifi into controllerDispatcher-interval
|
@ -25,6 +25,23 @@ AvatarMixerClientData::AvatarMixerClientData(const QUuid& nodeID) :
|
||||||
_avatar->setID(nodeID);
|
_avatar->setID(nodeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t AvatarMixerClientData::getLastOtherAvatarEncodeTime(QUuid otherAvatar) const {
|
||||||
|
std::unordered_map<QUuid, uint64_t>::const_iterator itr = _lastOtherAvatarEncodeTime.find(otherAvatar);
|
||||||
|
if (itr != _lastOtherAvatarEncodeTime.end()) {
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarMixerClientData::setLastOtherAvatarEncodeTime(const QUuid& otherAvatar, const uint64_t& time) {
|
||||||
|
std::unordered_map<QUuid, uint64_t>::iterator itr = _lastOtherAvatarEncodeTime.find(otherAvatar);
|
||||||
|
if (itr != _lastOtherAvatarEncodeTime.end()) {
|
||||||
|
itr->second = time;
|
||||||
|
} else {
|
||||||
|
_lastOtherAvatarEncodeTime.emplace(std::pair<QUuid, uint64_t>(otherAvatar, time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarMixerClientData::queuePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node) {
|
void AvatarMixerClientData::queuePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node) {
|
||||||
if (!_packetQueue.node) {
|
if (!_packetQueue.node) {
|
||||||
_packetQueue.node = node;
|
_packetQueue.node = node;
|
||||||
|
|
|
@ -110,16 +110,10 @@ public:
|
||||||
bool getRequestsDomainListData() { return _requestsDomainListData; }
|
bool getRequestsDomainListData() { return _requestsDomainListData; }
|
||||||
void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; }
|
void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; }
|
||||||
|
|
||||||
ViewFrustum getViewFrustom() const { return _currentViewFrustum; }
|
ViewFrustum getViewFrustum() const { return _currentViewFrustum; }
|
||||||
|
|
||||||
quint64 getLastOtherAvatarEncodeTime(QUuid otherAvatar) {
|
uint64_t getLastOtherAvatarEncodeTime(QUuid otherAvatar) const;
|
||||||
quint64 result = 0;
|
void setLastOtherAvatarEncodeTime(const QUuid& otherAvatar, const uint64_t& time);
|
||||||
if (_lastOtherAvatarEncodeTime.find(otherAvatar) != _lastOtherAvatarEncodeTime.end()) {
|
|
||||||
result = _lastOtherAvatarEncodeTime[otherAvatar];
|
|
||||||
}
|
|
||||||
_lastOtherAvatarEncodeTime[otherAvatar] = usecTimestampNow();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<JointData>& getLastOtherAvatarSentJoints(QUuid otherAvatar) {
|
QVector<JointData>& getLastOtherAvatarSentJoints(QUuid otherAvatar) {
|
||||||
_lastOtherAvatarSentJoints[otherAvatar].resize(_avatar->getJointCount());
|
_lastOtherAvatarSentJoints[otherAvatar].resize(_avatar->getJointCount());
|
||||||
|
@ -143,7 +137,7 @@ private:
|
||||||
|
|
||||||
// this is a map of the last time we encoded an "other" avatar for
|
// this is a map of the last time we encoded an "other" avatar for
|
||||||
// sending to "this" node
|
// sending to "this" node
|
||||||
std::unordered_map<QUuid, quint64> _lastOtherAvatarEncodeTime;
|
std::unordered_map<QUuid, uint64_t> _lastOtherAvatarEncodeTime;
|
||||||
std::unordered_map<QUuid, QVector<JointData>> _lastOtherAvatarSentJoints;
|
std::unordered_map<QUuid, QVector<JointData>> _lastOtherAvatarSentJoints;
|
||||||
|
|
||||||
uint64_t _identityChangeTimestamp;
|
uint64_t _identityChangeTimestamp;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
#include <OctreeConstants.h>
|
#include <OctreeConstants.h>
|
||||||
|
#include <PrioritySortUtil.h>
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <StDev.h>
|
#include <StDev.h>
|
||||||
|
@ -32,6 +33,10 @@
|
||||||
#include "AvatarMixerClientData.h"
|
#include "AvatarMixerClientData.h"
|
||||||
#include "AvatarMixerSlave.h"
|
#include "AvatarMixerSlave.h"
|
||||||
|
|
||||||
|
namespace PrioritySortUtil {
|
||||||
|
// we declare this callback here but override it later
|
||||||
|
std::function<uint64_t(const AvatarSharedPointer&)> getAvatarAgeCallback = [] (const AvatarSharedPointer& avatar) { return 0; };
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) {
|
void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) {
|
||||||
_begin = begin;
|
_begin = begin;
|
||||||
|
@ -184,10 +189,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
|
|
||||||
// setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes
|
// setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes
|
||||||
// for calling the AvatarData::sortAvatars() function and getting our sorted list of client nodes
|
std::vector<AvatarSharedPointer> avatarsToSort;
|
||||||
QList<AvatarSharedPointer> avatarList;
|
|
||||||
std::unordered_map<AvatarSharedPointer, SharedNodePointer> avatarDataToNodes;
|
std::unordered_map<AvatarSharedPointer, SharedNodePointer> avatarDataToNodes;
|
||||||
|
|
||||||
std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) {
|
std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) {
|
||||||
// make sure this is an agent that we have avatar data for before considering it for inclusion
|
// make sure this is an agent that we have avatar data for before considering it for inclusion
|
||||||
if (otherNode->getType() == NodeType::Agent
|
if (otherNode->getType() == NodeType::Agent
|
||||||
|
@ -195,36 +198,61 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||||
|
|
||||||
AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer();
|
AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer();
|
||||||
avatarList << otherAvatar;
|
avatarsToSort.push_back(otherAvatar);
|
||||||
avatarDataToNodes[otherAvatar] = otherNode;
|
avatarDataToNodes[otherAvatar] = otherNode;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer();
|
// now that we've assembled the avatarDataToNodes map we can replace PrioritySortUtil::getAvatarAgeCallback
|
||||||
ViewFrustum cameraView = nodeData->getViewFrustom();
|
// with the true implementation
|
||||||
std::priority_queue<AvatarPriority> sortedAvatars;
|
PrioritySortUtil::getAvatarAgeCallback = [&] (const AvatarSharedPointer& avatar) {
|
||||||
AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars,
|
|
||||||
[&](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->getLastOtherAvatarEncodeTime(avatarNode->getUUID());
|
||||||
}, [&](AvatarSharedPointer avatar)->float{
|
};
|
||||||
glm::vec3 nodeBoxHalfScale = (avatar->getWorldPosition() - avatar->getGlobalBoundingBoxCorner() * avatar->getSensorToWorldScale());
|
|
||||||
|
class SortableAvatar: public PrioritySortUtil::Sortable {
|
||||||
|
public:
|
||||||
|
SortableAvatar() = delete;
|
||||||
|
SortableAvatar(const AvatarSharedPointer& avatar) : _avatar(avatar) {}
|
||||||
|
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
||||||
|
float getRadius() const override {
|
||||||
|
glm::vec3 nodeBoxHalfScale = (_avatar->getWorldPosition() - _avatar->getGlobalBoundingBoxCorner() * _avatar->getSensorToWorldScale());
|
||||||
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
||||||
}, [&](AvatarSharedPointer avatar)->bool {
|
}
|
||||||
|
uint64_t getTimestamp() const override {
|
||||||
|
// use the callback implemented above
|
||||||
|
return PrioritySortUtil::getAvatarAgeCallback(_avatar);
|
||||||
|
}
|
||||||
|
const AvatarSharedPointer& getAvatar() const { return _avatar; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AvatarSharedPointer _avatar;
|
||||||
|
};
|
||||||
|
|
||||||
|
// prepare to sort
|
||||||
|
ViewFrustum cameraView = nodeData->getViewFrustum();
|
||||||
|
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(cameraView,
|
||||||
|
AvatarData::_avatarSortCoefficientSize,
|
||||||
|
AvatarData::_avatarSortCoefficientCenter,
|
||||||
|
AvatarData::_avatarSortCoefficientAge);
|
||||||
|
|
||||||
|
// ignore or sort
|
||||||
|
const AvatarSharedPointer& thisAvatar = nodeData->getAvatarSharedPointer();
|
||||||
|
for (const auto& avatar : avatarsToSort) {
|
||||||
if (avatar == thisAvatar) {
|
if (avatar == thisAvatar) {
|
||||||
return true; // ignore ourselves...
|
// don't echo updates to self
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldIgnore = false;
|
bool shouldIgnore = false;
|
||||||
|
// We ignore other nodes for a couple of reasons:
|
||||||
// We will also ignore other nodes for a couple of different reasons:
|
|
||||||
// 1) ignore bubbles and ignore specific node
|
// 1) ignore bubbles and ignore specific node
|
||||||
// 2) the node hasn't really updated it's frame data recently, this can
|
// 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
|
// happen if for example the avatar is connected on a desktop and sending
|
||||||
// updates at ~30hz. So every 3 frames we skip a frame.
|
// updates at ~30hz. So every 3 frames we skip a frame.
|
||||||
auto avatarNode = avatarDataToNodes[avatar];
|
|
||||||
|
|
||||||
|
auto avatarNode = avatarDataToNodes[avatar];
|
||||||
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
|
|
||||||
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||||
|
@ -240,7 +268,6 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
||||||
shouldIgnore = true;
|
shouldIgnore = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Check to see if the space bubble is enabled
|
// Check to see if the space bubble is enabled
|
||||||
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
||||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||||
|
@ -267,8 +294,6 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
quint64 endIgnoreCalculation = usecTimestampNow();
|
|
||||||
_stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation);
|
|
||||||
|
|
||||||
if (!shouldIgnore) {
|
if (!shouldIgnore) {
|
||||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
||||||
|
@ -292,20 +317,21 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
++numAvatarsWithSkippedFrames;
|
++numAvatarsWithSkippedFrames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shouldIgnore;
|
quint64 endIgnoreCalculation = usecTimestampNow();
|
||||||
});
|
_stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation);
|
||||||
|
|
||||||
|
if (!shouldIgnore) {
|
||||||
|
// sort this one for later
|
||||||
|
sortedAvatars.push(SortableAvatar(avatar));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
||||||
int avatarRank = 0;
|
|
||||||
|
|
||||||
// this is overly conservative, because it includes some avatars we might not consider
|
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
|
|
||||||
while (!sortedAvatars.empty()) {
|
while (!sortedAvatars.empty()) {
|
||||||
AvatarPriority sortData = sortedAvatars.top();
|
const auto& avatarData = sortedAvatars.top().getAvatar();
|
||||||
sortedAvatars.pop();
|
sortedAvatars.pop();
|
||||||
const auto& avatarData = sortData.avatar;
|
|
||||||
avatarRank++;
|
|
||||||
remainingAvatars--;
|
remainingAvatars--;
|
||||||
|
|
||||||
auto otherNode = avatarDataToNodes[avatarData];
|
auto otherNode = avatarDataToNodes[avatarData];
|
||||||
|
@ -332,10 +358,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
nodeData->setLastBroadcastTime(otherNode->getUUID(), usecTimestampNow());
|
nodeData->setLastBroadcastTime(otherNode->getUUID(), usecTimestampNow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// determine if avatar is in view which determines how much data to send
|
||||||
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
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 * otherAvatar->getSensorToWorldScale();
|
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f * otherAvatar->getSensorToWorldScale();
|
||||||
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
||||||
|
@ -405,14 +429,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
// set the last sent sequence number for this sender on the receiver
|
// set the last sent sequence number for this sender on the receiver
|
||||||
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
|
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
|
||||||
otherNodeData->getLastReceivedSequenceNumber());
|
otherNodeData->getLastReceivedSequenceNumber());
|
||||||
|
nodeData->setLastOtherAvatarEncodeTime(otherNode->getUUID(), usecTimestampNow());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// TODO? this avatar is not included now, and will probably not be included next frame.
|
||||||
|
// It would be nice if we could tweak its future sort priority to put it at the back of the list.
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarPacketList->endSegment();
|
avatarPacketList->endSegment();
|
||||||
|
|
||||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
quint64 endAvatarDataPacking = usecTimestampNow();
|
||||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
||||||
};
|
}
|
||||||
|
|
||||||
quint64 startPacketSending = usecTimestampNow();
|
quint64 startPacketSending = usecTimestampNow();
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,6 @@ macro(GENERATE_INSTALLERS)
|
||||||
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# Do not install the Visual Studio C runtime libraries. The installer will do this automatically
|
|
||||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
|
||||||
|
|
||||||
include(InstallRequiredSystemLibraries)
|
|
||||||
set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico")
|
set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico")
|
||||||
|
|
||||||
# install and reference the Add/Remove icon
|
# install and reference the Add/Remove icon
|
||||||
|
@ -49,6 +45,10 @@ macro(GENERATE_INSTALLERS)
|
||||||
set(_UNINSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/uninstaller-header.bmp")
|
set(_UNINSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/uninstaller-header.bmp")
|
||||||
set(UNINSTALLER_HEADER_IMAGE "")
|
set(UNINSTALLER_HEADER_IMAGE "")
|
||||||
fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE)
|
fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE)
|
||||||
|
|
||||||
|
# grab the latest VC redist (2017) and add it to the installer, our NSIS template
|
||||||
|
# will call it during the install
|
||||||
|
install(CODE "file(DOWNLOAD https://go.microsoft.com/fwlink/?LinkId=746572 \"\${CMAKE_INSTALL_PREFIX}/vcredist_x64.exe\")")
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
# produce a drag and drop DMG on OS X
|
# produce a drag and drop DMG on OS X
|
||||||
set(CPACK_GENERATOR "DragNDrop")
|
set(CPACK_GENERATOR "DragNDrop")
|
||||||
|
@ -84,4 +84,3 @@ macro(GENERATE_INSTALLERS)
|
||||||
|
|
||||||
include(CPack)
|
include(CPack)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
|
|
@ -45,5 +45,4 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(GLOB EXTRA_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
file(GLOB EXTRA_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
||||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_PLUGINS}" "@FIXUP_LIBS@")
|
fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_PLUGINS}" "@FIXUP_LIBS@" IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe")
|
||||||
|
|
||||||
|
|
|
@ -65,21 +65,23 @@ var EventBridge;
|
||||||
// we need to listen to events that might precede the addition of this elements.
|
// we need to listen to events that might precede the addition of this elements.
|
||||||
// A more robust hack will be to add a setInterval that look for DOM changes every 100-300 ms (low performance?)
|
// A more robust hack will be to add a setInterval that look for DOM changes every 100-300 ms (low performance?)
|
||||||
|
|
||||||
window.onload = function(){
|
window.addEventListener("load",function(event) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
EventBridge.forceHtmlAudioOutputDeviceUpdate();
|
EventBridge.forceHtmlAudioOutputDeviceUpdate();
|
||||||
}, 1200);
|
}, 1200);
|
||||||
};
|
}, false);
|
||||||
document.onclick = function(){
|
|
||||||
|
document.addEventListener("click",function(){
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
EventBridge.forceHtmlAudioOutputDeviceUpdate();
|
EventBridge.forceHtmlAudioOutputDeviceUpdate();
|
||||||
}, 1200);
|
}, 1200);
|
||||||
};
|
}, false);
|
||||||
document.onchange = function(){
|
|
||||||
|
document.addEventListener("change",function(){
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
EventBridge.forceHtmlAudioOutputDeviceUpdate();
|
EventBridge.forceHtmlAudioOutputDeviceUpdate();
|
||||||
}, 1200);
|
}, 1200);
|
||||||
};
|
}, false);
|
||||||
|
|
||||||
tempEventBridge._callbacks.forEach(function (callback) {
|
tempEventBridge._callbacks.forEach(function (callback) {
|
||||||
EventBridge.scriptEventReceived.connect(callback);
|
EventBridge.scriptEventReceived.connect(callback);
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
<!-- Copyright 2016 High Fidelity, Inc. -->
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<input type="hidden" id="version" value="1"/>
|
|
||||||
<title>Welcome to Interface</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background: black;
|
|
||||||
width: 100%;
|
|
||||||
overflow-x: hidden;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#kbm_button {
|
|
||||||
position: absolute;
|
|
||||||
left: 70;
|
|
||||||
top: 118;
|
|
||||||
width: 297;
|
|
||||||
height: 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
#hand_controllers_button {
|
|
||||||
position: absolute;
|
|
||||||
left: 367;
|
|
||||||
top: 118;
|
|
||||||
width: 267;
|
|
||||||
height: 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
#game_controller_button {
|
|
||||||
position: absolute;
|
|
||||||
left: 634;
|
|
||||||
top: 118;
|
|
||||||
width: 297;
|
|
||||||
height: 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
#image_area {
|
|
||||||
width: 1024;
|
|
||||||
height: 720;
|
|
||||||
margin: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 0; left: 0; bottom: 0; right: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
var handControllerImageURL = null;
|
|
||||||
|
|
||||||
function showKbm() {
|
|
||||||
document.getElementById("main_image").setAttribute("src", "img/controls-help-keyboard.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
function showHandControllers() {
|
|
||||||
document.getElementById("main_image").setAttribute("src", handControllerImageURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showGamepad() {
|
|
||||||
document.getElementById("main_image").setAttribute("src", "img/controls-help-gamepad.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is not meant to be a complete or hardened query string parser - it only
|
|
||||||
// needs to handle the values we send in and have control over.
|
|
||||||
//
|
|
||||||
// queryString is a string of the form "key1=value1&key2=value2&key3&key4=value4"
|
|
||||||
function parseQueryString(queryString) {
|
|
||||||
var params = {};
|
|
||||||
var paramsParts = queryString.split("&");
|
|
||||||
for (var i = 0; i < paramsParts.length; ++i) {
|
|
||||||
var paramKeyValue = paramsParts[i].split("=");
|
|
||||||
if (paramKeyValue.length == 1) {
|
|
||||||
params[paramKeyValue[0]] = undefined;
|
|
||||||
} else if (paramKeyValue.length == 2) {
|
|
||||||
params[paramKeyValue[0]] = paramKeyValue[1];
|
|
||||||
} else {
|
|
||||||
console.error("Error parsing param keyvalue: ", paramParts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
var parts = window.location.href.split("?");
|
|
||||||
var params = {};
|
|
||||||
if (parts.length > 0) {
|
|
||||||
params = parseQueryString(parts[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (params.handControllerName) {
|
|
||||||
case "oculus":
|
|
||||||
handControllerImageURL = "img/controls-help-oculus.png";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "vive":
|
|
||||||
default:
|
|
||||||
handControllerImageURL = "img/controls-help-vive.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (params.defaultTab) {
|
|
||||||
case "gamepad":
|
|
||||||
showGamepad();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "handControllers":
|
|
||||||
showHandControllers();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "kbm":
|
|
||||||
default:
|
|
||||||
showKbm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body onload="load()">
|
|
||||||
<div id="image_area">
|
|
||||||
<img id="main_image" src="img/controls-help-keyboard.png" width="1024px" height="720px"></img>
|
|
||||||
<a href="#" id="kbm_button" onmousedown="showKbm()"></a>
|
|
||||||
<a href="#" id="hand_controllers_button" onmousedown="showHandControllers()"></a>
|
|
||||||
<a href="#" id="game_controller_button" onmousedown="showGamepad()"></a>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 604 KiB After Width: | Height: | Size: 298 KiB |
Before Width: | Height: | Size: 503 KiB After Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 585 KiB After Width: | Height: | Size: 289 KiB |
Before Width: | Height: | Size: 547 KiB After Width: | Height: | Size: 254 KiB |
|
@ -12,9 +12,9 @@
|
||||||
var MAX_WARNINGS = 3;
|
var MAX_WARNINGS = 3;
|
||||||
var numWarnings = 0;
|
var numWarnings = 0;
|
||||||
var isWindowFocused = true;
|
var isWindowFocused = true;
|
||||||
var isKeyboardRaised = false;
|
window.isKeyboardRaised = false;
|
||||||
var isNumericKeyboard = false;
|
window.isNumericKeyboard = false;
|
||||||
var isPasswordField = false;
|
window.isPasswordField = false;
|
||||||
|
|
||||||
function shouldSetPasswordField() {
|
function shouldSetPasswordField() {
|
||||||
var nodeType = document.activeElement.type;
|
var nodeType = document.activeElement.type;
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
var passwordField = shouldSetPasswordField();
|
var passwordField = shouldSetPasswordField();
|
||||||
|
|
||||||
if (isWindowFocused &&
|
if (isWindowFocused &&
|
||||||
(keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard || passwordField !== isPasswordField)) {
|
(keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard || passwordField !== window.isPasswordField)) {
|
||||||
|
|
||||||
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
|
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
|
||||||
EventBridge.emitWebEvent(
|
EventBridge.emitWebEvent(
|
||||||
|
@ -75,20 +75,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isKeyboardRaised) {
|
if (!window.isKeyboardRaised) {
|
||||||
scheduleBringToView(250); // Allow time for keyboard to be raised in QML.
|
scheduleBringToView(250); // Allow time for keyboard to be raised in QML.
|
||||||
// 2DO: should it be rather done from 'client area height changed' event?
|
// 2DO: should it be rather done from 'client area height changed' event?
|
||||||
}
|
}
|
||||||
|
|
||||||
isKeyboardRaised = keyboardRaised;
|
window.isKeyboardRaised = keyboardRaised;
|
||||||
isNumericKeyboard = numericKeyboard;
|
window.isNumericKeyboard = numericKeyboard;
|
||||||
isPasswordField = passwordField;
|
window.isPasswordField = passwordField;
|
||||||
}
|
}
|
||||||
}, POLL_FREQUENCY);
|
}, POLL_FREQUENCY);
|
||||||
|
|
||||||
window.addEventListener("click", function () {
|
window.addEventListener("click", function () {
|
||||||
var keyboardRaised = shouldRaiseKeyboard();
|
var keyboardRaised = shouldRaiseKeyboard();
|
||||||
if(keyboardRaised && isKeyboardRaised) {
|
if (keyboardRaised && window.isKeyboardRaised) {
|
||||||
scheduleBringToView(150);
|
scheduleBringToView(150);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
|
|
||||||
window.addEventListener("blur", function () {
|
window.addEventListener("blur", function () {
|
||||||
isWindowFocused = false;
|
isWindowFocused = false;
|
||||||
isKeyboardRaised = false;
|
window.isKeyboardRaised = false;
|
||||||
isNumericKeyboard = false;
|
window.isNumericKeyboard = false;
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
import QtQuick.Controls 2.2 as QQC2
|
||||||
|
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
|
|
||||||
|
@ -24,6 +25,45 @@ TableView {
|
||||||
|
|
||||||
model: ListModel { }
|
model: ListModel { }
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (flickableItem !== null && flickableItem !== undefined) {
|
||||||
|
tableView.flickableItem.QQC2.ScrollBar.vertical = scrollbar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ScrollBar {
|
||||||
|
id: scrollbar
|
||||||
|
parent: tableView.flickableItem
|
||||||
|
policy: QQC2.ScrollBar.AsNeeded
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
visible: size < 1.0
|
||||||
|
topPadding: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight + 1 : 1
|
||||||
|
anchors.top: tableView.top
|
||||||
|
anchors.left: tableView.right
|
||||||
|
anchors.bottom: tableView.bottom
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
fill: parent;
|
||||||
|
topMargin: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight : 0
|
||||||
|
}
|
||||||
|
color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight
|
||||||
|
: hifi.colors.tableScrollBackgroundDark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
implicitWidth: hifi.dimensions.scrollbarHandleWidth
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: (width - 4)/2
|
||||||
|
color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
headerVisible: false
|
headerVisible: false
|
||||||
headerDelegate: Rectangle {
|
headerDelegate: Rectangle {
|
||||||
height: hifi.dimensions.tableHeaderHeight
|
height: hifi.dimensions.tableHeaderHeight
|
||||||
|
@ -98,74 +138,13 @@ TableView {
|
||||||
backgroundVisible: true
|
backgroundVisible: true
|
||||||
|
|
||||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||||
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
|
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||||
|
|
||||||
style: TableViewStyle {
|
style: TableViewStyle {
|
||||||
// Needed in order for rows to keep displaying rows after end of table entries.
|
// Needed in order for rows to keep displaying rows after end of table entries.
|
||||||
backgroundColor: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
|
backgroundColor: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
|
||||||
alternateBackgroundColor: tableView.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
|
alternateBackgroundColor: tableView.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
|
||||||
|
|
||||||
padding.top: headerVisible ? hifi.dimensions.tableHeaderHeight: 0
|
padding.top: headerVisible ? hifi.dimensions.tableHeaderHeight: 0
|
||||||
|
|
||||||
handle: Item {
|
|
||||||
id: scrollbarHandle
|
|
||||||
implicitWidth: hifi.dimensions.scrollbarHandleWidth
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
topMargin: 3
|
|
||||||
bottomMargin: 3 // ""
|
|
||||||
leftMargin: 1 // Move it right
|
|
||||||
rightMargin: -1 // ""
|
|
||||||
}
|
|
||||||
radius: hifi.dimensions.scrollbarHandleWidth/2
|
|
||||||
color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollBarBackground: Item {
|
|
||||||
implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
margins: -1 // Expand
|
|
||||||
topMargin: -1
|
|
||||||
}
|
|
||||||
color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight : hifi.colors.tableScrollBackgroundDark
|
|
||||||
|
|
||||||
// Extend header color above scrollbar background
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: -hifi.dimensions.tableHeaderHeight
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
height: hifi.dimensions.tableHeaderHeight
|
|
||||||
color: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
|
|
||||||
visible: headerVisible
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
// Extend header bottom border
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
height: 1
|
|
||||||
color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
|
||||||
visible: headerVisible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
incrementControl: Item {
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
decrementControl: Item {
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rowDelegate: Rectangle {
|
rowDelegate: Rectangle {
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import QtQml.Models 2.2
|
import QtQml.Models 2.2
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
import QtQuick.Controls 2.2 as QQC2
|
||||||
|
|
||||||
|
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
|
|
||||||
|
@ -35,6 +37,45 @@ TreeView {
|
||||||
|
|
||||||
headerVisible: false
|
headerVisible: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (flickableItem !== null && flickableItem !== undefined) {
|
||||||
|
treeView.flickableItem.QQC2.ScrollBar.vertical = scrollbar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ScrollBar {
|
||||||
|
id: scrollbar
|
||||||
|
parent: treeView.flickableItem
|
||||||
|
policy: QQC2.ScrollBar.AsNeeded
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
visible: size < 1.0
|
||||||
|
topPadding: treeView.headerVisible ? hifi.dimensions.tableHeaderHeight + 1 : 1
|
||||||
|
anchors.top: treeView.top
|
||||||
|
anchors.left: treeView.right
|
||||||
|
anchors.bottom: treeView.bottom
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
fill: parent;
|
||||||
|
topMargin: treeView.headerVisible ? hifi.dimensions.tableHeaderHeight: 0
|
||||||
|
}
|
||||||
|
color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight
|
||||||
|
: hifi.colors.tableScrollBackgroundDark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
implicitWidth: hifi.dimensions.scrollbarHandleWidth
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: (width - 4)/2
|
||||||
|
color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use rectangle to draw border with rounded corners.
|
// Use rectangle to draw border with rounded corners.
|
||||||
frameVisible: false
|
frameVisible: false
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -50,7 +91,7 @@ TreeView {
|
||||||
backgroundVisible: true
|
backgroundVisible: true
|
||||||
|
|
||||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||||
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
|
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||||
|
|
||||||
style: TreeViewStyle {
|
style: TreeViewStyle {
|
||||||
// Needed in order for rows to keep displaying rows after end of table entries.
|
// Needed in order for rows to keep displaying rows after end of table entries.
|
||||||
|
@ -126,66 +167,6 @@ TreeView {
|
||||||
leftMargin: hifi.dimensions.tablePadding / 2
|
leftMargin: hifi.dimensions.tablePadding / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handle: Item {
|
|
||||||
id: scrollbarHandle
|
|
||||||
implicitWidth: hifi.dimensions.scrollbarHandleWidth
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
topMargin: treeView.headerVisible ? hifi.dimensions.tableHeaderHeight + 3 : 3
|
|
||||||
bottomMargin: 3 // ""
|
|
||||||
leftMargin: 1 // Move it right
|
|
||||||
rightMargin: -1 // ""
|
|
||||||
}
|
|
||||||
radius: hifi.dimensions.scrollbarHandleWidth / 2
|
|
||||||
color: treeView.isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollBarBackground: Item {
|
|
||||||
implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
topMargin: treeView.headerVisible ? hifi.dimensions.tableHeaderHeight - 1 : -1
|
|
||||||
margins: -1 // Expand
|
|
||||||
}
|
|
||||||
color: treeView.isLightColorScheme ? hifi.colors.tableScrollBackgroundLight : hifi.colors.tableScrollBackgroundDark
|
|
||||||
|
|
||||||
// Extend header color above scrollbar background
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: -hifi.dimensions.tableHeaderHeight
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
height: hifi.dimensions.tableHeaderHeight
|
|
||||||
color: treeView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
|
|
||||||
visible: treeView.headerVisible
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
// Extend header bottom border
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
height: 1
|
|
||||||
color: treeView.isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
|
||||||
visible: treeView.headerVisible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
incrementControl: Item {
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
decrementControl: Item {
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rowDelegate: Rectangle {
|
rowDelegate: Rectangle {
|
||||||
|
|
|
@ -79,10 +79,12 @@ Rectangle {
|
||||||
if (result.status !== 'success') {
|
if (result.status !== 'success') {
|
||||||
failureErrorText.text = result.message;
|
failureErrorText.text = result.message;
|
||||||
root.activeView = "checkoutFailure";
|
root.activeView = "checkoutFailure";
|
||||||
|
UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemPrice, !root.alreadyOwned, result.message);
|
||||||
} else {
|
} else {
|
||||||
root.itemHref = result.data.download_url;
|
root.itemHref = result.data.download_url;
|
||||||
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
|
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
|
||||||
root.activeView = "checkoutSuccess";
|
root.activeView = "checkoutSuccess";
|
||||||
|
UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemPrice, !root.alreadyOwned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,6 +601,7 @@ Rectangle {
|
||||||
sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
|
sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
|
||||||
rezzedNotifContainer.visible = true;
|
rezzedNotifContainer.visible = true;
|
||||||
rezzedNotifContainerTimer.start();
|
rezzedNotifContainerTimer.start();
|
||||||
|
UserActivityLogger.commerceEntityRezzed(root.itemId, "checkout", root.isWearable ? "rez" : "wear");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RalewaySemiBold {
|
RalewaySemiBold {
|
||||||
|
|
|
@ -430,7 +430,7 @@ Rectangle {
|
||||||
|
|
||||||
var a = new Date(timestamp);
|
var a = new Date(timestamp);
|
||||||
var year = a.getFullYear();
|
var year = a.getFullYear();
|
||||||
var month = addLeadingZero(a.getMonth());
|
var month = addLeadingZero(a.getMonth() + 1);
|
||||||
var day = addLeadingZero(a.getDate());
|
var day = addLeadingZero(a.getDate());
|
||||||
var hour = a.getHours();
|
var hour = a.getHours();
|
||||||
var drawnHour = hour;
|
var drawnHour = hour;
|
||||||
|
|
|
@ -349,6 +349,7 @@ Item {
|
||||||
sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
|
sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
|
||||||
rezzedNotifContainer.visible = true;
|
rezzedNotifContainer.visible = true;
|
||||||
rezzedNotifContainerTimer.start();
|
rezzedNotifContainerTimer.start();
|
||||||
|
UserActivityLogger.commerceEntityRezzed(root.itemId, "purchases", root.isWearable ? "rez" : "wear");
|
||||||
}
|
}
|
||||||
|
|
||||||
style: ButtonStyle {
|
style: ButtonStyle {
|
||||||
|
|
|
@ -343,6 +343,9 @@ Rectangle {
|
||||||
ListModel {
|
ListModel {
|
||||||
id: previousPurchasesModel;
|
id: previousPurchasesModel;
|
||||||
}
|
}
|
||||||
|
HifiCommerceCommon.SortableListModel {
|
||||||
|
id: tempPurchasesModel;
|
||||||
|
}
|
||||||
HifiCommerceCommon.SortableListModel {
|
HifiCommerceCommon.SortableListModel {
|
||||||
id: filteredPurchasesModel;
|
id: filteredPurchasesModel;
|
||||||
}
|
}
|
||||||
|
@ -635,21 +638,41 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildFilteredPurchasesModel() {
|
function buildFilteredPurchasesModel() {
|
||||||
filteredPurchasesModel.clear();
|
var sameItemCount = 0;
|
||||||
|
|
||||||
|
tempPurchasesModel.clear();
|
||||||
for (var i = 0; i < purchasesModel.count; i++) {
|
for (var i = 0; i < purchasesModel.count; i++) {
|
||||||
if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) {
|
if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) {
|
||||||
if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems) {
|
if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems) {
|
||||||
filteredPurchasesModel.insert(0, purchasesModel.get(i));
|
tempPurchasesModel.insert(0, purchasesModel.get(i));
|
||||||
} else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === "0") ||
|
} else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === "0") ||
|
||||||
(!root.isShowingMyItems && purchasesModel.get(i).edition_number !== "0")) {
|
(!root.isShowingMyItems && purchasesModel.get(i).edition_number !== "0")) {
|
||||||
filteredPurchasesModel.append(purchasesModel.get(i));
|
tempPurchasesModel.append(purchasesModel.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < tempPurchasesModel.count; i++) {
|
||||||
|
if (!filteredPurchasesModel.get(i)) {
|
||||||
|
sameItemCount = -1;
|
||||||
|
break;
|
||||||
|
} else if (tempPurchasesModel.get(i).itemId === filteredPurchasesModel.get(i).itemId &&
|
||||||
|
tempPurchasesModel.get(i).edition_number === filteredPurchasesModel.get(i).edition_number &&
|
||||||
|
tempPurchasesModel.get(i).status === filteredPurchasesModel.get(i).status) {
|
||||||
|
sameItemCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sameItemCount !== tempPurchasesModel.count) {
|
||||||
|
filteredPurchasesModel.clear();
|
||||||
|
for (var i = 0; i < tempPurchasesModel.count; i++) {
|
||||||
|
filteredPurchasesModel.append(tempPurchasesModel.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
populateDisplayedItemCounts();
|
populateDisplayedItemCounts();
|
||||||
sortByDate();
|
sortByDate();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkIfAnyItemStatusChanged() {
|
function checkIfAnyItemStatusChanged() {
|
||||||
var currentPurchasesModelId, currentPurchasesModelEdition, currentPurchasesModelStatus;
|
var currentPurchasesModelId, currentPurchasesModelEdition, currentPurchasesModelStatus;
|
||||||
|
|
|
@ -206,16 +206,6 @@ Item {
|
||||||
root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password);
|
root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password);
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent;
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.keyboardRaised = true;
|
|
||||||
root.isPasswordField = (passphraseField.echoMode === TextInput.Password);
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
submitPassphraseInputButton.enabled = false;
|
submitPassphraseInputButton.enabled = false;
|
||||||
commerce.setPassphrase(passphraseField.text);
|
commerce.setPassphrase(passphraseField.text);
|
||||||
|
@ -362,25 +352,6 @@ Item {
|
||||||
right: parent.right;
|
right: parent.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
|
||||||
id: lowerKeyboardButton;
|
|
||||||
z: 999;
|
|
||||||
source: "images/lowerKeyboard.png";
|
|
||||||
anchors.right: keyboard.right;
|
|
||||||
anchors.top: keyboard.showMirrorText ? keyboard.top : undefined;
|
|
||||||
anchors.bottom: keyboard.showMirrorText ? undefined : keyboard.bottom;
|
|
||||||
height: 50;
|
|
||||||
width: 60;
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent;
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.keyboardRaised = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControlsUit.Keyboard {
|
HifiControlsUit.Keyboard {
|
||||||
id: keyboard;
|
id: keyboard;
|
||||||
raised: HMD.mounted && root.keyboardRaised;
|
raised: HMD.mounted && root.keyboardRaised;
|
||||||
|
|
|
@ -82,17 +82,6 @@ Item {
|
||||||
if (focus) {
|
if (focus) {
|
||||||
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
||||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||||
} else if (!passphraseFieldAgain.focus) {
|
|
||||||
sendSignalToWallet({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent;
|
|
||||||
onPressed: {
|
|
||||||
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
|
|
||||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,21 +104,10 @@ Item {
|
||||||
activeFocusOnPress: true;
|
activeFocusOnPress: true;
|
||||||
activeFocusOnTab: true;
|
activeFocusOnTab: true;
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent;
|
|
||||||
onPressed: {
|
|
||||||
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
|
||||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onFocusChanged: {
|
onFocusChanged: {
|
||||||
if (focus) {
|
if (focus) {
|
||||||
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
var hidePassword = (passphraseField.echoMode === TextInput.Password);
|
||||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||||
} else if (!passphraseFieldAgain.focus) {
|
|
||||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,21 +129,10 @@ Item {
|
||||||
activeFocusOnPress: true;
|
activeFocusOnPress: true;
|
||||||
activeFocusOnTab: true;
|
activeFocusOnTab: true;
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent;
|
|
||||||
onPressed: {
|
|
||||||
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
|
||||||
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onFocusChanged: {
|
onFocusChanged: {
|
||||||
if (focus) {
|
if (focus) {
|
||||||
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
|
||||||
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
|
||||||
} else if (!passphraseField.focus) {
|
|
||||||
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,12 @@ Rectangle {
|
||||||
} else if (walletStatus === 1) {
|
} else if (walletStatus === 1) {
|
||||||
if (root.activeView !== "walletSetup") {
|
if (root.activeView !== "walletSetup") {
|
||||||
root.activeView = "walletSetup";
|
root.activeView = "walletSetup";
|
||||||
|
commerce.resetLocalWalletOnly();
|
||||||
|
var timestamp = new Date();
|
||||||
|
walletSetup.startingTimestamp = timestamp;
|
||||||
|
walletSetup.setupAttemptID = generateUUID();
|
||||||
|
UserActivityLogger.commerceWalletSetupStarted(timestamp, setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app",
|
||||||
|
(AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''));
|
||||||
}
|
}
|
||||||
} else if (walletStatus === 2) {
|
} else if (walletStatus === 2) {
|
||||||
if (root.activeView !== "passphraseModal") {
|
if (root.activeView !== "passphraseModal") {
|
||||||
|
@ -172,7 +178,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToWallet: {
|
onSendSignalToWallet: {
|
||||||
if (msg.method === 'walletSetup_finished') {
|
if (msg.method === 'walletSetup_finished') {
|
||||||
if (msg.referrer === '') {
|
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getWalletStatus();
|
commerce.getWalletStatus();
|
||||||
} else if (msg.referrer === 'purchases') {
|
} else if (msg.referrer === 'purchases') {
|
||||||
|
@ -666,25 +672,6 @@ Rectangle {
|
||||||
right: parent.right;
|
right: parent.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
|
||||||
id: lowerKeyboardButton;
|
|
||||||
z: 999;
|
|
||||||
source: "images/lowerKeyboard.png";
|
|
||||||
anchors.right: keyboard.right;
|
|
||||||
anchors.top: keyboard.showMirrorText ? keyboard.top : undefined;
|
|
||||||
anchors.bottom: keyboard.showMirrorText ? undefined : keyboard.bottom;
|
|
||||||
height: 50;
|
|
||||||
width: 60;
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent;
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.keyboardRaised = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControlsUit.Keyboard {
|
HifiControlsUit.Keyboard {
|
||||||
id: keyboard;
|
id: keyboard;
|
||||||
raised: HMD.mounted && root.keyboardRaised;
|
raised: HMD.mounted && root.keyboardRaised;
|
||||||
|
@ -719,12 +706,28 @@ Rectangle {
|
||||||
case 'updateWalletReferrer':
|
case 'updateWalletReferrer':
|
||||||
walletSetup.referrer = message.referrer;
|
walletSetup.referrer = message.referrer;
|
||||||
break;
|
break;
|
||||||
|
case 'inspectionCertificate_resetCert':
|
||||||
|
// NOP
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
|
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
|
// generateUUID() taken from:
|
||||||
|
// https://stackoverflow.com/a/8809472
|
||||||
|
function generateUUID() { // Public Domain/MIT
|
||||||
|
var d = new Date().getTime();
|
||||||
|
if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
|
||||||
|
d += performance.now(); //use high-precision timer if available
|
||||||
|
}
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
|
var r = (d + Math.random() * 16) % 16 | 0;
|
||||||
|
d = Math.floor(d / 16);
|
||||||
|
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// FUNCTION DEFINITIONS END
|
// FUNCTION DEFINITIONS END
|
||||||
//
|
//
|
||||||
|
|
|
@ -38,11 +38,29 @@ Item {
|
||||||
onHistoryResult : {
|
onHistoryResult : {
|
||||||
historyReceived = true;
|
historyReceived = true;
|
||||||
if (result.status === 'success') {
|
if (result.status === 'success') {
|
||||||
transactionHistoryModel.clear();
|
var sameItemCount = 0;
|
||||||
transactionHistoryModel.append(result.data.history);
|
tempTransactionHistoryModel.clear();
|
||||||
|
|
||||||
|
tempTransactionHistoryModel.append(result.data.history);
|
||||||
|
|
||||||
|
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
||||||
|
if (!transactionHistoryModel.get(i)) {
|
||||||
|
sameItemCount = -1;
|
||||||
|
break;
|
||||||
|
} else if (tempTransactionHistoryModel.get(i).transaction_type === transactionHistoryModel.get(i).transaction_type &&
|
||||||
|
tempTransactionHistoryModel.get(i).text === transactionHistoryModel.get(i).text) {
|
||||||
|
sameItemCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sameItemCount !== tempTransactionHistoryModel.count) {
|
||||||
|
transactionHistoryModel.clear();
|
||||||
|
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
||||||
|
transactionHistoryModel.append(tempTransactionHistoryModel.get(i));
|
||||||
|
}
|
||||||
calculatePendingAndInvalidated();
|
calculatePendingAndInvalidated();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
refreshTimer.start();
|
refreshTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +68,7 @@ Item {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
|
transactionHistoryModel.clear();
|
||||||
usernameText.text = Account.username;
|
usernameText.text = Account.username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,10 +162,9 @@ Item {
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: refreshTimer;
|
id: refreshTimer;
|
||||||
interval: 4000; // Remove this after demo?
|
interval: 4000;
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
console.log("Refreshing Wallet Home...");
|
console.log("Refreshing Wallet Home...");
|
||||||
historyReceived = false;
|
|
||||||
commerce.balance();
|
commerce.balance();
|
||||||
commerce.history();
|
commerce.history();
|
||||||
}
|
}
|
||||||
|
@ -187,6 +205,9 @@ Item {
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.baseGrayHighlight;
|
color: hifi.colors.baseGrayHighlight;
|
||||||
}
|
}
|
||||||
|
ListModel {
|
||||||
|
id: tempTransactionHistoryModel;
|
||||||
|
}
|
||||||
ListModel {
|
ListModel {
|
||||||
id: transactionHistoryModel;
|
id: transactionHistoryModel;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +360,7 @@ Item {
|
||||||
|
|
||||||
var a = new Date(timestamp);
|
var a = new Date(timestamp);
|
||||||
var year = a.getFullYear();
|
var year = a.getFullYear();
|
||||||
var month = addLeadingZero(a.getMonth());
|
var month = addLeadingZero(a.getMonth() + 1);
|
||||||
var day = addLeadingZero(a.getDate());
|
var day = addLeadingZero(a.getDate());
|
||||||
var hour = a.getHours();
|
var hour = a.getHours();
|
||||||
var drawnHour = hour;
|
var drawnHour = hour;
|
||||||
|
|
|
@ -31,6 +31,10 @@ Item {
|
||||||
property bool hasShownSecurityImageTip: false;
|
property bool hasShownSecurityImageTip: false;
|
||||||
property string referrer;
|
property string referrer;
|
||||||
property string keyFilePath;
|
property string keyFilePath;
|
||||||
|
property date startingTimestamp;
|
||||||
|
property string setupAttemptID;
|
||||||
|
readonly property int setupFlowVersion: 1;
|
||||||
|
readonly property var setupStepNames: [ "Setup Prompt", "Security Image Selection", "Passphrase Selection", "Private Keys Ready" ];
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
|
@ -67,6 +71,13 @@ Item {
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onActiveViewChanged: {
|
||||||
|
var timestamp = new Date();
|
||||||
|
var currentStepNumber = root.activeView.substring(5);
|
||||||
|
UserActivityLogger.commerceWalletSetupProgress(timestamp, root.setupAttemptID,
|
||||||
|
Math.round((timestamp - root.startingTimestamp)/1000), currentStepNumber, root.setupStepNames[currentStepNumber - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// TITLE BAR START
|
// TITLE BAR START
|
||||||
//
|
//
|
||||||
|
@ -371,7 +382,7 @@ Item {
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: securityImageTip;
|
id: securityImageTip;
|
||||||
visible: false;
|
visible: !root.hasShownSecurityImageTip && root.activeView === "step_3";
|
||||||
z: 999;
|
z: 999;
|
||||||
anchors.fill: root;
|
anchors.fill: root;
|
||||||
|
|
||||||
|
@ -421,7 +432,6 @@ Item {
|
||||||
text: "Got It";
|
text: "Got It";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.hasShownSecurityImageTip = true;
|
root.hasShownSecurityImageTip = true;
|
||||||
securityImageTip.visible = false;
|
|
||||||
passphraseSelection.focusFirstTextField();
|
passphraseSelection.focusFirstTextField();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -439,9 +449,6 @@ Item {
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getWalletAuthenticatedStatus();
|
commerce.getWalletAuthenticatedStatus();
|
||||||
if (!root.hasShownSecurityImageTip) {
|
|
||||||
securityImageTip.visible = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +739,11 @@ Item {
|
||||||
text: "Finish";
|
text: "Finish";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.visible = false;
|
root.visible = false;
|
||||||
|
root.hasShownSecurityImageTip = false;
|
||||||
sendSignalToWallet({method: 'walletSetup_finished', referrer: root.referrer ? root.referrer : ""});
|
sendSignalToWallet({method: 'walletSetup_finished', referrer: root.referrer ? root.referrer : ""});
|
||||||
|
|
||||||
|
var timestamp = new Date();
|
||||||
|
UserActivityLogger.commerceWalletSetupFinished(timestamp, setupAttemptID, Math.round((timestamp - root.startingTimestamp)/1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,33 +9,30 @@ Overlay {
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: image
|
id: image
|
||||||
property bool scaleFix: true;
|
property bool scaleFix: true
|
||||||
property real xOffset: 0
|
property real xStart: 0
|
||||||
property real yOffset: 0
|
property real yStart: 0
|
||||||
|
property real xSize: 0
|
||||||
|
property real ySize: 0
|
||||||
property real imageScale: 1.0
|
property real imageScale: 1.0
|
||||||
property var resizer: Timer {
|
property var resizer: Timer {
|
||||||
interval: 50
|
interval: 50
|
||||||
repeat: false
|
repeat: false
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var targetAspect = root.width / root.height;
|
if (image.xSize === 0) {
|
||||||
var sourceAspect = image.sourceSize.width / image.sourceSize.height;
|
image.xSize = image.sourceSize.width - image.xStart;
|
||||||
if (sourceAspect <= targetAspect) {
|
|
||||||
if (root.width === image.sourceSize.width) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
image.imageScale = root.width / image.sourceSize.width;
|
if (image.ySize === 0) {
|
||||||
} else if (sourceAspect > targetAspect){
|
image.ySize = image.sourceSize.height - image.yStart;
|
||||||
if (root.height === image.sourceSize.height) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
image.imageScale = root.height / image.sourceSize.height;
|
|
||||||
}
|
image.anchors.leftMargin = -image.xStart * root.width / image.xSize;
|
||||||
image.sourceSize = Qt.size(image.sourceSize.width * image.imageScale, image.sourceSize.height * image.imageScale);
|
image.anchors.topMargin = -image.yStart * root.height / image.ySize;
|
||||||
|
image.anchors.rightMargin = (image.xStart + image.xSize - image.sourceSize.width) * root.width / image.xSize;
|
||||||
|
image.anchors.bottomMargin = (image.yStart + image.ySize - image.sourceSize.height) * root.height / image.ySize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x: -1 * xOffset * imageScale
|
|
||||||
y: -1 * yOffset * imageScale
|
|
||||||
|
|
||||||
onSourceSizeChanged: {
|
onSourceSizeChanged: {
|
||||||
if (sourceSize.width !== 0 && sourceSize.height !== 0 && progress === 1.0 && scaleFix) {
|
if (sourceSize.width !== 0 && sourceSize.height !== 0 && progress === 1.0 && scaleFix) {
|
||||||
|
@ -43,6 +40,8 @@ Overlay {
|
||||||
resizer.start();
|
resizer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorOverlay {
|
ColorOverlay {
|
||||||
|
@ -57,8 +56,10 @@ Overlay {
|
||||||
var key = keys[i];
|
var key = keys[i];
|
||||||
var value = subImage[key];
|
var value = subImage[key];
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "x": image.xOffset = value; break;
|
case "x": image.xStart = value; break;
|
||||||
case "y": image.yOffset = value; break;
|
case "y": image.yStart = value; break;
|
||||||
|
case "width": image.xSize = value; break;
|
||||||
|
case "height": image.ySize = value; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +79,7 @@ Overlay {
|
||||||
case "imageURL": image.source = value; break;
|
case "imageURL": image.source = value; break;
|
||||||
case "subImage": updateSubImage(value); break;
|
case "subImage": updateSubImage(value); break;
|
||||||
case "color": color.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, root.opacity); break;
|
case "color": color.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, root.opacity); break;
|
||||||
|
case "bounds": break; // The bounds property is handled in C++.
|
||||||
default: console.log("OVERLAY Unhandled image property " + key);
|
default: console.log("OVERLAY Unhandled image property " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ Overlay {
|
||||||
case "borderColor": rectangle.border.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, rectangle.border.color.a); break;
|
case "borderColor": rectangle.border.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, rectangle.border.color.a); break;
|
||||||
case "borderWidth": rectangle.border.width = value; break;
|
case "borderWidth": rectangle.border.width = value; break;
|
||||||
case "radius": rectangle.radius = value; break;
|
case "radius": rectangle.radius = value; break;
|
||||||
|
case "bounds": break; // The bounds property is handled in C++.
|
||||||
default: console.warn("OVERLAY Unhandled rectangle property " + key);
|
default: console.warn("OVERLAY Unhandled rectangle property " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ Overlay {
|
||||||
case "backgroundColor": background.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, background.color.a); break;
|
case "backgroundColor": background.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, background.color.a); break;
|
||||||
case "font": textField.font.pixelSize = value.size; break;
|
case "font": textField.font.pixelSize = value.size; break;
|
||||||
case "lineHeight": textField.lineHeight = value; break;
|
case "lineHeight": textField.lineHeight = value; break;
|
||||||
|
case "bounds": break; // The bounds property is handled in C++.
|
||||||
default: console.warn("OVERLAY text unhandled property " + key);
|
default: console.warn("OVERLAY text unhandled property " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@ Item {
|
||||||
readonly property real controlLineHeight: 28 // Height of spinbox control on 1920 x 1080 monitor
|
readonly property real controlLineHeight: 28 // Height of spinbox control on 1920 x 1080 monitor
|
||||||
readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight
|
readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight
|
||||||
readonly property vector2d menuPadding: Qt.vector2d(14, 102)
|
readonly property vector2d menuPadding: Qt.vector2d(14, 102)
|
||||||
readonly property real scrollbarBackgroundWidth: 18
|
readonly property real scrollbarBackgroundWidth: 20
|
||||||
readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2
|
readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2
|
||||||
readonly property real tabletMenuHeader: 90
|
readonly property real tabletMenuHeader: 90
|
||||||
}
|
}
|
||||||
|
|
|
@ -7075,11 +7075,11 @@ QRect Application::getRecommendedHUDRect() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Application::getDeviceSize() const {
|
glm::vec2 Application::getDeviceSize() const {
|
||||||
static const int MIN_SIZE = 1;
|
static const int MIN_SIZE = 1;
|
||||||
QSize result(MIN_SIZE, MIN_SIZE);
|
glm::vec2 result(MIN_SIZE);
|
||||||
if (_displayPlugin) {
|
if (_displayPlugin) {
|
||||||
result = fromGlm(getActiveDisplayPlugin()->getRecommendedRenderSize());
|
result = getActiveDisplayPlugin()->getRecommendedRenderSize();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -7098,10 +7098,6 @@ bool Application::hasFocus() const {
|
||||||
return (QApplication::activeWindow() != nullptr);
|
return (QApplication::activeWindow() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Application::getViewportDimensions() const {
|
|
||||||
return toGlm(getDeviceSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) {
|
void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) {
|
||||||
if (maxOctreePPS != _maxOctreePPS) {
|
if (maxOctreePPS != _maxOctreePPS) {
|
||||||
_maxOctreePPS = maxOctreePPS;
|
_maxOctreePPS = maxOctreePPS;
|
||||||
|
|
|
@ -158,7 +158,7 @@ public:
|
||||||
|
|
||||||
glm::uvec2 getUiSize() const;
|
glm::uvec2 getUiSize() const;
|
||||||
QRect getRecommendedHUDRect() const;
|
QRect getRecommendedHUDRect() const;
|
||||||
QSize getDeviceSize() const;
|
glm::vec2 getDeviceSize() const;
|
||||||
bool hasFocus() const;
|
bool hasFocus() const;
|
||||||
|
|
||||||
void showCursor(const Cursor::Icon& cursor);
|
void showCursor(const Cursor::Icon& cursor);
|
||||||
|
@ -228,8 +228,6 @@ public:
|
||||||
|
|
||||||
FileLogger* getLogger() const { return _logger; }
|
FileLogger* getLogger() const { return _logger; }
|
||||||
|
|
||||||
glm::vec2 getViewportDimensions() const;
|
|
||||||
|
|
||||||
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
||||||
|
|
||||||
float getRenderResolutionScale() const;
|
float getRenderResolutionScale() const;
|
||||||
|
|
|
@ -104,8 +104,7 @@ void Application::paintGL() {
|
||||||
PerformanceTimer perfTimer("renderOverlay");
|
PerformanceTimer perfTimer("renderOverlay");
|
||||||
// NOTE: There is no batch associated with this renderArgs
|
// NOTE: There is no batch associated with this renderArgs
|
||||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||||
QSize size = getDeviceSize();
|
renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize());
|
||||||
renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height());
|
|
||||||
_applicationOverlay.renderOverlay(&renderArgs);
|
_applicationOverlay.renderOverlay(&renderArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <PrioritySortUtil.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <Rig.h>
|
#include <Rig.h>
|
||||||
#include <SettingHandle.h>
|
#include <SettingHandle.h>
|
||||||
|
@ -142,32 +143,39 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
|
|
||||||
PerformanceTimer perfTimer("otherAvatars");
|
PerformanceTimer perfTimer("otherAvatars");
|
||||||
|
|
||||||
auto avatarMap = getHashCopy();
|
class SortableAvatar: public PrioritySortUtil::Sortable {
|
||||||
QList<AvatarSharedPointer> avatarList = avatarMap.values();
|
public:
|
||||||
|
SortableAvatar() = delete;
|
||||||
|
SortableAvatar(const AvatarSharedPointer& avatar) : _avatar(avatar) {}
|
||||||
|
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
||||||
|
float getRadius() const override { return std::static_pointer_cast<Avatar>(_avatar)->getBoundingRadius(); }
|
||||||
|
uint64_t getTimestamp() const override { return std::static_pointer_cast<Avatar>(_avatar)->getLastRenderUpdateTime(); }
|
||||||
|
const AvatarSharedPointer& getAvatar() const { return _avatar; }
|
||||||
|
private:
|
||||||
|
AvatarSharedPointer _avatar;
|
||||||
|
};
|
||||||
|
|
||||||
ViewFrustum cameraView;
|
ViewFrustum cameraView;
|
||||||
qApp->copyDisplayViewFrustum(cameraView);
|
qApp->copyDisplayViewFrustum(cameraView);
|
||||||
|
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(cameraView,
|
||||||
|
AvatarData::_avatarSortCoefficientSize,
|
||||||
|
AvatarData::_avatarSortCoefficientCenter,
|
||||||
|
AvatarData::_avatarSortCoefficientAge);
|
||||||
|
|
||||||
std::priority_queue<AvatarPriority> sortedAvatars;
|
// sort
|
||||||
AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars,
|
auto avatarMap = getHashCopy();
|
||||||
|
AvatarHash::iterator itr = avatarMap.begin();
|
||||||
[](AvatarSharedPointer avatar)->uint64_t{
|
while (itr != avatarMap.end()) {
|
||||||
return std::static_pointer_cast<Avatar>(avatar)->getLastRenderUpdateTime();
|
const auto& avatar = std::static_pointer_cast<Avatar>(*itr);
|
||||||
},
|
|
||||||
|
|
||||||
[](AvatarSharedPointer avatar)->float{
|
|
||||||
return std::static_pointer_cast<Avatar>(avatar)->getBoundingRadius();
|
|
||||||
},
|
|
||||||
|
|
||||||
[this](AvatarSharedPointer avatar)->bool{
|
|
||||||
const auto& castedAvatar = std::static_pointer_cast<Avatar>(avatar);
|
|
||||||
if (castedAvatar == _myAvatar || !castedAvatar->isInitialized()) {
|
|
||||||
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
||||||
// DO NOT update or fade out uninitialized Avatars
|
// DO NOT update or fade out uninitialized Avatars
|
||||||
return true; // ignore it
|
if (avatar != _myAvatar && avatar->isInitialized()) {
|
||||||
|
sortedAvatars.push(SortableAvatar(avatar));
|
||||||
|
}
|
||||||
|
++itr;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// process in sorted order
|
||||||
uint64_t startTime = usecTimestampNow();
|
uint64_t startTime = usecTimestampNow();
|
||||||
const uint64_t UPDATE_BUDGET = 2000; // usec
|
const uint64_t UPDATE_BUDGET = 2000; // usec
|
||||||
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
|
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
|
||||||
|
@ -176,8 +184,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
|
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
while (!sortedAvatars.empty()) {
|
while (!sortedAvatars.empty()) {
|
||||||
const AvatarPriority& sortData = sortedAvatars.top();
|
const SortableAvatar& sortData = sortedAvatars.top();
|
||||||
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.avatar);
|
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
|
||||||
|
|
||||||
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
||||||
if (ignoring) {
|
if (ignoring) {
|
||||||
|
@ -207,7 +215,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
if (now < updateExpiry) {
|
if (now < updateExpiry) {
|
||||||
// we're within budget
|
// we're within budget
|
||||||
bool inView = sortData.priority > OUT_OF_VIEW_THRESHOLD;
|
bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||||
if (inView && avatar->hasNewJointData()) {
|
if (inView && avatar->hasNewJointData()) {
|
||||||
numAvatarsUpdated++;
|
numAvatarsUpdated++;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +229,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
// --> some avatar velocity measurements may be a little off
|
// --> some avatar velocity measurements may be a little off
|
||||||
|
|
||||||
// no time simulate, but we take the time to count how many were tragically missed
|
// no time simulate, but we take the time to count how many were tragically missed
|
||||||
bool inView = sortData.priority > OUT_OF_VIEW_THRESHOLD;
|
bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||||
if (!inView) {
|
if (!inView) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -230,9 +238,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
}
|
}
|
||||||
sortedAvatars.pop();
|
sortedAvatars.pop();
|
||||||
while (inView && !sortedAvatars.empty()) {
|
while (inView && !sortedAvatars.empty()) {
|
||||||
const AvatarPriority& newSortData = sortedAvatars.top();
|
const SortableAvatar& newSortData = sortedAvatars.top();
|
||||||
const auto& newAvatar = std::static_pointer_cast<Avatar>(newSortData.avatar);
|
const auto& newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
|
||||||
inView = newSortData.priority > OUT_OF_VIEW_THRESHOLD;
|
inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||||
if (inView && newAvatar->hasNewJointData()) {
|
if (inView && newAvatar->hasNewJointData()) {
|
||||||
numAVatarsNotUpdated++;
|
numAVatarsNotUpdated++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,19 +83,28 @@ void QmlCommerce::buy(const QString& assetId, int cost, const bool controlledFai
|
||||||
void QmlCommerce::balance() {
|
void QmlCommerce::balance() {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
ledger->balance(wallet->listPublicKeys());
|
QStringList cachedPublicKeys = wallet->listPublicKeys();
|
||||||
|
if (!cachedPublicKeys.isEmpty()) {
|
||||||
|
ledger->balance(cachedPublicKeys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::inventory() {
|
void QmlCommerce::inventory() {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
ledger->inventory(wallet->listPublicKeys());
|
QStringList cachedPublicKeys = wallet->listPublicKeys();
|
||||||
|
if (!cachedPublicKeys.isEmpty()) {
|
||||||
|
ledger->inventory(cachedPublicKeys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::history() {
|
void QmlCommerce::history() {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
ledger->history(wallet->listPublicKeys());
|
QStringList cachedPublicKeys = wallet->listPublicKeys();
|
||||||
|
if (!cachedPublicKeys.isEmpty()) {
|
||||||
|
ledger->history(cachedPublicKeys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString& newPassphrase) {
|
void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString& newPassphrase) {
|
||||||
|
@ -128,6 +137,11 @@ void QmlCommerce::reset() {
|
||||||
wallet->reset();
|
wallet->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlCommerce::resetLocalWalletOnly() {
|
||||||
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
|
wallet->reset();
|
||||||
|
}
|
||||||
|
|
||||||
void QmlCommerce::account() {
|
void QmlCommerce::account() {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
ledger->account();
|
ledger->account();
|
||||||
|
|
|
@ -65,6 +65,7 @@ protected:
|
||||||
Q_INVOKABLE void history();
|
Q_INVOKABLE void history();
|
||||||
Q_INVOKABLE void generateKeyPair();
|
Q_INVOKABLE void generateKeyPair();
|
||||||
Q_INVOKABLE void reset();
|
Q_INVOKABLE void reset();
|
||||||
|
Q_INVOKABLE void resetLocalWalletOnly();
|
||||||
Q_INVOKABLE void account();
|
Q_INVOKABLE void account();
|
||||||
|
|
||||||
Q_INVOKABLE void certificateInfo(const QString& certificateId);
|
Q_INVOKABLE void certificateInfo(const QString& certificateId);
|
||||||
|
|
|
@ -321,6 +321,16 @@ Wallet::Wallet() {
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() {
|
connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() {
|
||||||
getWalletStatus();
|
getWalletStatus();
|
||||||
|
_publicKeys.clear();
|
||||||
|
|
||||||
|
if (_securityImage) {
|
||||||
|
delete _securityImage;
|
||||||
|
}
|
||||||
|
_securityImage = nullptr;
|
||||||
|
|
||||||
|
// tell the provider we got nothing
|
||||||
|
updateImageProvider();
|
||||||
|
_passphrase->clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,18 +84,7 @@ glm::vec2 RayPick::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3
|
||||||
glm::vec2 RayPick::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized) {
|
glm::vec2 RayPick::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized) {
|
||||||
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
|
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
|
||||||
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
|
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
|
||||||
glm::vec3 dimensions;
|
glm::vec3 dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f);
|
||||||
|
|
||||||
float dpi = qApp->getOverlays().getProperty(overlayID, "dpi").value.toFloat();
|
|
||||||
if (dpi > 0) {
|
|
||||||
// Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale.
|
|
||||||
glm::vec3 resolution = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "resolution").value), 1);
|
|
||||||
glm::vec3 scale = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f);
|
|
||||||
const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
|
||||||
dimensions = (resolution * INCHES_TO_METERS / dpi) * scale;
|
|
||||||
} else {
|
|
||||||
dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
return projectOntoXYPlane(worldPos, position, rotation, dimensions, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT, unNormalized);
|
return projectOntoXYPlane(worldPos, position, rotation, dimensions, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT, unNormalized);
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,10 @@ bool WindowScriptingInterface::isPointOnDesktopWindow(QVariant point) {
|
||||||
return offscreenUi->isPointOnDesktopWindow(point);
|
return offscreenUi->isPointOnDesktopWindow(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec2 WindowScriptingInterface::getDeviceSize() const {
|
||||||
|
return qApp->getDeviceSize();
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes sure that the reticle is visible, use this in blocking forms that require a reticle and
|
/// Makes sure that the reticle is visible, use this in blocking forms that require a reticle and
|
||||||
/// might be in same thread as a script that sets the reticle to invisible
|
/// might be in same thread as a script that sets the reticle to invisible
|
||||||
void WindowScriptingInterface::ensureReticleVisible() const {
|
void WindowScriptingInterface::ensureReticleVisible() const {
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef hifi_WindowScriptingInterface_h
|
#ifndef hifi_WindowScriptingInterface_h
|
||||||
#define hifi_WindowScriptingInterface_h
|
#define hifi_WindowScriptingInterface_h
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtQuick/QQuickItem>
|
#include <QtQuick/QQuickItem>
|
||||||
|
@ -73,6 +75,7 @@ public slots:
|
||||||
bool isPhysicsEnabled();
|
bool isPhysicsEnabled();
|
||||||
bool setDisplayTexture(const QString& name);
|
bool setDisplayTexture(const QString& name);
|
||||||
bool isPointOnDesktopWindow(QVariant point);
|
bool isPointOnDesktopWindow(QVariant point);
|
||||||
|
glm::vec2 getDeviceSize() const;
|
||||||
|
|
||||||
int openMessageBox(QString title, QString text, int buttons, int defaultButton);
|
int openMessageBox(QString title, QString text, int buttons, int defaultButton);
|
||||||
void updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton);
|
void updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton);
|
||||||
|
|
|
@ -166,26 +166,36 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
||||||
bool newEndSet { false };
|
bool newEndSet { false };
|
||||||
|
|
||||||
auto start = properties["start"];
|
auto start = properties["start"];
|
||||||
// if "start" property was not there, check to see if they included aliases: startPoint
|
// If "start" property was not there, check to see if they included aliases: startPoint, p1
|
||||||
if (!start.isValid()) {
|
if (!start.isValid()) {
|
||||||
start = properties["startPoint"];
|
start = properties["startPoint"];
|
||||||
}
|
}
|
||||||
|
if (!start.isValid()) {
|
||||||
|
start = properties["p1"];
|
||||||
|
}
|
||||||
if (start.isValid()) {
|
if (start.isValid()) {
|
||||||
newStart = vec3FromVariant(start);
|
newStart = vec3FromVariant(start);
|
||||||
newStartSet = true;
|
newStartSet = true;
|
||||||
}
|
}
|
||||||
properties.remove("start"); // so that Base3DOverlay doesn't respond to it
|
properties.remove("start"); // so that Base3DOverlay doesn't respond to it
|
||||||
|
properties.remove("startPoint");
|
||||||
|
properties.remove("p1");
|
||||||
|
|
||||||
auto end = properties["end"];
|
auto end = properties["end"];
|
||||||
// if "end" property was not there, check to see if they included aliases: endPoint
|
// If "end" property was not there, check to see if they included aliases: endPoint, p2
|
||||||
if (!end.isValid()) {
|
if (!end.isValid()) {
|
||||||
end = properties["endPoint"];
|
end = properties["endPoint"];
|
||||||
}
|
}
|
||||||
|
if (!end.isValid()) {
|
||||||
|
end = properties["p2"];
|
||||||
|
}
|
||||||
if (end.isValid()) {
|
if (end.isValid()) {
|
||||||
newEnd = vec3FromVariant(end);
|
newEnd = vec3FromVariant(end);
|
||||||
newEndSet = true;
|
newEndSet = true;
|
||||||
}
|
}
|
||||||
properties.remove("end"); // so that Base3DOverlay doesn't respond to it
|
properties.remove("end"); // so that Base3DOverlay doesn't respond to it
|
||||||
|
properties.remove("endPoint");
|
||||||
|
properties.remove("p2");
|
||||||
|
|
||||||
auto length = properties["length"];
|
auto length = properties["length"];
|
||||||
if (length.isValid()) {
|
if (length.isValid()) {
|
||||||
|
@ -252,14 +262,23 @@ QVariant Line3DOverlay::getProperty(const QString& property) {
|
||||||
if (property == "end" || property == "endPoint" || property == "p2") {
|
if (property == "end" || property == "endPoint" || property == "p2") {
|
||||||
return vec3toVariant(getEnd());
|
return vec3toVariant(getEnd());
|
||||||
}
|
}
|
||||||
|
if (property == "length") {
|
||||||
|
return QVariant(getLength());
|
||||||
|
}
|
||||||
|
if (property == "endParentID") {
|
||||||
|
return _endParentID;
|
||||||
|
}
|
||||||
|
if (property == "endParentJointIndex") {
|
||||||
|
return _endParentJointIndex;
|
||||||
|
}
|
||||||
if (property == "localStart") {
|
if (property == "localStart") {
|
||||||
return vec3toVariant(getLocalStart());
|
return vec3toVariant(getLocalStart());
|
||||||
}
|
}
|
||||||
if (property == "localEnd") {
|
if (property == "localEnd") {
|
||||||
return vec3toVariant(getLocalEnd());
|
return vec3toVariant(getLocalEnd());
|
||||||
}
|
}
|
||||||
if (property == "length") {
|
if (property == "glow") {
|
||||||
return QVariant(getLength());
|
return getGlow();
|
||||||
}
|
}
|
||||||
if (property == "lineWidth") {
|
if (property == "lineWidth") {
|
||||||
return _lineWidth;
|
return _lineWidth;
|
||||||
|
|
|
@ -35,7 +35,8 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) :
|
||||||
_modelTextures(QVariantMap()),
|
_modelTextures(QVariantMap()),
|
||||||
_url(modelOverlay->_url),
|
_url(modelOverlay->_url),
|
||||||
_updateModel(false),
|
_updateModel(false),
|
||||||
_loadPriority(modelOverlay->getLoadPriority())
|
_scaleToFit(modelOverlay->_scaleToFit),
|
||||||
|
_loadPriority(modelOverlay->_loadPriority)
|
||||||
{
|
{
|
||||||
_model->init();
|
_model->init();
|
||||||
_model->setLoadingPriority(_loadPriority);
|
_model->setLoadingPriority(_loadPriority);
|
||||||
|
@ -134,6 +135,9 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dimensions = properties["dimensions"];
|
auto dimensions = properties["dimensions"];
|
||||||
|
if (!dimensions.isValid()) {
|
||||||
|
dimensions = properties["size"];
|
||||||
|
}
|
||||||
if (dimensions.isValid()) {
|
if (dimensions.isValid()) {
|
||||||
_scaleToFit = true;
|
_scaleToFit = true;
|
||||||
setDimensions(vec3FromVariant(dimensions));
|
setDimensions(vec3FromVariant(dimensions));
|
||||||
|
|
|
@ -75,8 +75,8 @@ private:
|
||||||
QVariantMap _modelTextures;
|
QVariantMap _modelTextures;
|
||||||
|
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
bool _updateModel = { false };
|
bool _updateModel { false };
|
||||||
bool _scaleToFit = { false };
|
bool _scaleToFit { false };
|
||||||
float _loadPriority { 0.0f };
|
float _loadPriority { 0.0f };
|
||||||
|
|
||||||
AnimationPointer _animation;
|
AnimationPointer _animation;
|
||||||
|
@ -87,7 +87,7 @@ private:
|
||||||
bool _animationRunning { false };
|
bool _animationRunning { false };
|
||||||
bool _animationLoop { false };
|
bool _animationLoop { false };
|
||||||
float _animationFirstFrame { 0.0f };
|
float _animationFirstFrame { 0.0f };
|
||||||
float _animationLastFrame = { 0.0f };
|
float _animationLastFrame { 0.0f };
|
||||||
bool _animationHold { false };
|
bool _animationHold { false };
|
||||||
bool _animationAllowTranslation { false };
|
bool _animationAllowTranslation { false };
|
||||||
uint64_t _lastAnimated { 0 };
|
uint64_t _lastAnimated { 0 };
|
||||||
|
|
|
@ -305,13 +305,6 @@ public slots:
|
||||||
OverlayID getKeyboardFocusOverlay();
|
OverlayID getKeyboardFocusOverlay();
|
||||||
void setKeyboardFocusOverlay(const OverlayID& id);
|
void setKeyboardFocusOverlay(const OverlayID& id);
|
||||||
|
|
||||||
void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
|
||||||
void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
|
||||||
void mouseReleasePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
|
||||||
void hoverEnterPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
|
||||||
void hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
|
||||||
void hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Emitted when an overlay is deleted
|
* Emitted when an overlay is deleted
|
||||||
|
@ -358,6 +351,14 @@ private:
|
||||||
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
|
|
||||||
RayToOverlayIntersectionResult findRayIntersectionForMouseEvent(PickRay ray);
|
RayToOverlayIntersectionResult findRayIntersectionForMouseEvent(PickRay ray);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void mouseReleasePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void hoverEnterPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Overlays_h
|
#endif // hifi_Overlays_h
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
|
|
||||||
QString const Shape3DOverlay::TYPE = "shape";
|
QString const Shape3DOverlay::TYPE = "shape";
|
||||||
|
|
||||||
Shape3DOverlay::Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay) :
|
Shape3DOverlay::Shape3DOverlay(const Shape3DOverlay* shape3DOverlay) :
|
||||||
Volume3DOverlay(Shape3DOverlay)
|
Volume3DOverlay(shape3DOverlay),
|
||||||
|
_shape(shape3DOverlay->_shape)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
virtual QString getType() const override { return TYPE; }
|
virtual QString getType() const override { return TYPE; }
|
||||||
|
|
||||||
Shape3DOverlay() {}
|
Shape3DOverlay() {}
|
||||||
Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay);
|
Shape3DOverlay(const Shape3DOverlay* shape3DOverlay);
|
||||||
|
|
||||||
virtual void render(RenderArgs* args) override;
|
virtual void render(RenderArgs* args) override;
|
||||||
virtual const render::ShapeKey getShapeKey() override;
|
virtual const render::ShapeKey getShapeKey() override;
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
|
||||||
Volume3DOverlay::Volume3DOverlay(const Volume3DOverlay* volume3DOverlay) :
|
Volume3DOverlay::Volume3DOverlay(const Volume3DOverlay* volume3DOverlay) :
|
||||||
Base3DOverlay(volume3DOverlay)
|
Base3DOverlay(volume3DOverlay),
|
||||||
|
_localBoundingBox(volume3DOverlay->_localBoundingBox)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,17 +55,15 @@
|
||||||
#include <plugins/InputConfiguration.h>
|
#include <plugins/InputConfiguration.h>
|
||||||
#include "ui/Snapshot.h"
|
#include "ui/Snapshot.h"
|
||||||
#include "SoundCache.h"
|
#include "SoundCache.h"
|
||||||
|
|
||||||
#include "raypick/PointerScriptingInterface.h"
|
#include "raypick/PointerScriptingInterface.h"
|
||||||
|
|
||||||
static const float DPI = 30.47f;
|
static int MAX_WINDOW_SIZE = 4096;
|
||||||
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
|
||||||
static const float METERS_TO_INCHES = 39.3701f;
|
static const float METERS_TO_INCHES = 39.3701f;
|
||||||
static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
|
static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
|
||||||
|
|
||||||
const QString Web3DOverlay::TYPE = "web3d";
|
const QString Web3DOverlay::TYPE = "web3d";
|
||||||
const QString Web3DOverlay::QML = "Web3DOverlay.qml";
|
const QString Web3DOverlay::QML = "Web3DOverlay.qml";
|
||||||
Web3DOverlay::Web3DOverlay() : _dpi(DPI) {
|
Web3DOverlay::Web3DOverlay() {
|
||||||
_touchDevice.setCapabilities(QTouchDevice::Position);
|
_touchDevice.setCapabilities(QTouchDevice::Position);
|
||||||
_touchDevice.setType(QTouchDevice::TouchScreen);
|
_touchDevice.setType(QTouchDevice::TouchScreen);
|
||||||
_touchDevice.setName("Web3DOverlayTouchDevice");
|
_touchDevice.setName("Web3DOverlayTouchDevice");
|
||||||
|
@ -82,7 +80,6 @@ Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
|
||||||
_url(Web3DOverlay->_url),
|
_url(Web3DOverlay->_url),
|
||||||
_scriptURL(Web3DOverlay->_scriptURL),
|
_scriptURL(Web3DOverlay->_scriptURL),
|
||||||
_dpi(Web3DOverlay->_dpi),
|
_dpi(Web3DOverlay->_dpi),
|
||||||
_resolution(Web3DOverlay->_resolution),
|
|
||||||
_showKeyboardFocusHighlight(Web3DOverlay->_showKeyboardFocusHighlight)
|
_showKeyboardFocusHighlight(Web3DOverlay->_showKeyboardFocusHighlight)
|
||||||
{
|
{
|
||||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||||
|
@ -154,7 +151,7 @@ void Web3DOverlay::buildWebSurface() {
|
||||||
setupQmlSurface();
|
setupQmlSurface();
|
||||||
}
|
}
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));
|
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));
|
||||||
_webSurface->resize(QSize(_resolution.x, _resolution.y));
|
onResizeWebSurface();
|
||||||
_webSurface->resume();
|
_webSurface->resume();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -244,8 +241,16 @@ void Web3DOverlay::setMaxFPS(uint8_t maxFPS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Web3DOverlay::onResizeWebSurface() {
|
void Web3DOverlay::onResizeWebSurface() {
|
||||||
_mayNeedResize = false;
|
glm::vec2 dims = glm::vec2(getDimensions());
|
||||||
_webSurface->resize(QSize(_resolution.x, _resolution.y));
|
dims *= METERS_TO_INCHES * _dpi;
|
||||||
|
|
||||||
|
// ensure no side is never larger then MAX_WINDOW_SIZE
|
||||||
|
float max = (dims.x > dims.y) ? dims.x : dims.y;
|
||||||
|
if (max > MAX_WINDOW_SIZE) {
|
||||||
|
dims *= MAX_WINDOW_SIZE / max;
|
||||||
|
}
|
||||||
|
|
||||||
|
_webSurface->resize(QSize(dims.x, dims.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) {
|
unsigned int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) {
|
||||||
|
@ -266,14 +271,14 @@ void Web3DOverlay::render(RenderArgs* args) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentMaxFPS != _desiredMaxFPS) {
|
|
||||||
setMaxFPS(_desiredMaxFPS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mayNeedResize) {
|
if (_mayNeedResize) {
|
||||||
emit resizeWebSurface();
|
emit resizeWebSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_currentMaxFPS != _desiredMaxFPS) {
|
||||||
|
setMaxFPS(_desiredMaxFPS);
|
||||||
|
}
|
||||||
|
|
||||||
vec4 color(toGlm(getColor()), getAlpha());
|
vec4 color(toGlm(getColor()), getAlpha());
|
||||||
|
|
||||||
if (!_texture) {
|
if (!_texture) {
|
||||||
|
@ -310,7 +315,7 @@ void Web3DOverlay::render(RenderArgs* args) {
|
||||||
Transform Web3DOverlay::evalRenderTransform() {
|
Transform Web3DOverlay::evalRenderTransform() {
|
||||||
Transform transform = Parent::evalRenderTransform();
|
Transform transform = Parent::evalRenderTransform();
|
||||||
transform.setScale(1.0f);
|
transform.setScale(1.0f);
|
||||||
transform.postScale(glm::vec3(getSize(), 1.0f));
|
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,18 +439,10 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resolution = properties["resolution"];
|
|
||||||
if (resolution.isValid()) {
|
|
||||||
bool valid;
|
|
||||||
auto res = vec2FromVariant(resolution, valid);
|
|
||||||
if (valid) {
|
|
||||||
_resolution = res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dpi = properties["dpi"];
|
auto dpi = properties["dpi"];
|
||||||
if (dpi.isValid()) {
|
if (dpi.isValid()) {
|
||||||
_dpi = dpi.toFloat();
|
_dpi = dpi.toFloat();
|
||||||
|
_mayNeedResize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto maxFPS = properties["maxFPS"];
|
auto maxFPS = properties["maxFPS"];
|
||||||
|
@ -467,8 +464,6 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
_inputMode = Touch;
|
_inputMode = Touch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_mayNeedResize = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant Web3DOverlay::getProperty(const QString& property) {
|
QVariant Web3DOverlay::getProperty(const QString& property) {
|
||||||
|
@ -478,9 +473,6 @@ QVariant Web3DOverlay::getProperty(const QString& property) {
|
||||||
if (property == "scriptURL") {
|
if (property == "scriptURL") {
|
||||||
return _scriptURL;
|
return _scriptURL;
|
||||||
}
|
}
|
||||||
if (property == "resolution") {
|
|
||||||
return vec2toVariant(_resolution);
|
|
||||||
}
|
|
||||||
if (property == "dpi") {
|
if (property == "dpi") {
|
||||||
return _dpi;
|
return _dpi;
|
||||||
}
|
}
|
||||||
|
@ -536,17 +528,18 @@ void Web3DOverlay::setScriptURL(const QString& scriptURL) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Web3DOverlay::getSize() const {
|
|
||||||
return _resolution / _dpi * INCHES_TO_METERS * getDimensions();
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||||
// FIXME - face and surfaceNormal not being returned
|
glm::vec2 dimensions = getDimensions();
|
||||||
|
glm::quat rotation = getWorldOrientation();
|
||||||
|
glm::vec3 position = getWorldPosition();
|
||||||
|
|
||||||
// Don't call applyTransformTo() or setTransform() here because this code runs too frequently.
|
if (findRayRectangleIntersection(origin, direction, rotation, position, dimensions, distance)) {
|
||||||
|
surfaceNormal = rotation * Vectors::UNIT_Z;
|
||||||
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
|
face = glm::dot(surfaceNormal, direction) > 0 ? MIN_Z_FACE : MAX_Z_FACE;
|
||||||
return findRayRectangleIntersection(origin, direction, getWorldOrientation(), getWorldPosition(), getSize(), distance);
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Web3DOverlay* Web3DOverlay::createClone() const {
|
Web3DOverlay* Web3DOverlay::createClone() const {
|
||||||
|
|
|
@ -52,8 +52,6 @@ public:
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
|
||||||
glm::vec2 getSize() const override;
|
|
||||||
|
|
||||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||||
|
|
||||||
|
@ -93,8 +91,7 @@ private:
|
||||||
gpu::TexturePointer _texture;
|
gpu::TexturePointer _texture;
|
||||||
QString _url;
|
QString _url;
|
||||||
QString _scriptURL;
|
QString _scriptURL;
|
||||||
float _dpi;
|
float _dpi { 30.0f };
|
||||||
vec2 _resolution{ 640, 480 };
|
|
||||||
int _geometryId { 0 };
|
int _geometryId { 0 };
|
||||||
bool _showKeyboardFocusHighlight { true };
|
bool _showKeyboardFocusHighlight { true };
|
||||||
|
|
||||||
|
|
|
@ -2387,63 +2387,10 @@ void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, Ra
|
||||||
|
|
||||||
const float AvatarData::OUT_OF_VIEW_PENALTY = -10.0f;
|
const float AvatarData::OUT_OF_VIEW_PENALTY = -10.0f;
|
||||||
|
|
||||||
float AvatarData::_avatarSortCoefficientSize { 0.5f };
|
float AvatarData::_avatarSortCoefficientSize { 1.0f };
|
||||||
float AvatarData::_avatarSortCoefficientCenter { 0.25 };
|
float AvatarData::_avatarSortCoefficientCenter { 0.25 };
|
||||||
float AvatarData::_avatarSortCoefficientAge { 1.0f };
|
float AvatarData::_avatarSortCoefficientAge { 1.0f };
|
||||||
|
|
||||||
void AvatarData::sortAvatars(
|
|
||||||
QList<AvatarSharedPointer> avatarList,
|
|
||||||
const ViewFrustum& cameraView,
|
|
||||||
std::priority_queue<AvatarPriority>& sortedAvatarsOut,
|
|
||||||
std::function<uint64_t(AvatarSharedPointer)> getLastUpdated,
|
|
||||||
std::function<float(AvatarSharedPointer)> getBoundingRadius,
|
|
||||||
std::function<bool(AvatarSharedPointer)> shouldIgnore) {
|
|
||||||
|
|
||||||
PROFILE_RANGE(simulation, "sort");
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
|
|
||||||
glm::vec3 frustumCenter = cameraView.getPosition();
|
|
||||||
const glm::vec3& forward = cameraView.getDirection();
|
|
||||||
for (int32_t i = 0; i < avatarList.size(); ++i) {
|
|
||||||
const auto& avatar = avatarList.at(i);
|
|
||||||
|
|
||||||
if (shouldIgnore(avatar)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// priority = weighted linear combination of:
|
|
||||||
// (a) apparentSize
|
|
||||||
// (b) proximity to center of view
|
|
||||||
// (c) time since last update
|
|
||||||
glm::vec3 avatarPosition = avatar->getWorldPosition();
|
|
||||||
glm::vec3 offset = avatarPosition - frustumCenter;
|
|
||||||
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
|
||||||
|
|
||||||
// FIXME - AvatarData has something equivolent to this
|
|
||||||
float radius = getBoundingRadius(avatar);
|
|
||||||
|
|
||||||
float apparentSize = 2.0f * radius / distance;
|
|
||||||
float cosineAngle = glm::dot(offset, forward) / distance;
|
|
||||||
float age = (float)(now - getLastUpdated(avatar)) / (float)(USECS_PER_SECOND);
|
|
||||||
|
|
||||||
// NOTE: we are adding values of different units to get a single measure of "priority".
|
|
||||||
// Thus we multiply each component by a conversion "weight" that scales its units relative to the others.
|
|
||||||
// These weights are pure magic tuning and should be hard coded in the relation below,
|
|
||||||
// but are currently exposed for anyone who would like to explore fine tuning:
|
|
||||||
float priority = _avatarSortCoefficientSize * apparentSize
|
|
||||||
+ _avatarSortCoefficientCenter * cosineAngle
|
|
||||||
+ _avatarSortCoefficientAge * age;
|
|
||||||
|
|
||||||
// decrement priority of avatars outside keyhole
|
|
||||||
if (distance > cameraView.getCenterRadius()) {
|
|
||||||
if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) {
|
|
||||||
priority += OUT_OF_VIEW_PENALTY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortedAvatarsOut.push(AvatarPriority(avatar, priority));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
|
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
|
||||||
QScriptValue obj = engine->newObject();
|
QScriptValue obj = engine->newObject();
|
||||||
for (auto entityID : value.keys()) {
|
for (auto entityID : value.keys()) {
|
||||||
|
|
|
@ -629,14 +629,6 @@ public:
|
||||||
|
|
||||||
static const float OUT_OF_VIEW_PENALTY;
|
static const float OUT_OF_VIEW_PENALTY;
|
||||||
|
|
||||||
static void sortAvatars(
|
|
||||||
QList<AvatarSharedPointer> avatarList,
|
|
||||||
const ViewFrustum& cameraView,
|
|
||||||
std::priority_queue<AvatarPriority>& sortedAvatarsOut,
|
|
||||||
std::function<uint64_t(AvatarSharedPointer)> getLastUpdated,
|
|
||||||
std::function<float(AvatarSharedPointer)> getBoundingRadius,
|
|
||||||
std::function<bool(AvatarSharedPointer)> shouldIgnore);
|
|
||||||
|
|
||||||
// TODO: remove this HACK once we settle on optimal sort coefficients
|
// TODO: remove this HACK once we settle on optimal sort coefficients
|
||||||
// These coefficients exposed for fine tuning the sort priority for transfering new _jointData to the render pipeline.
|
// These coefficients exposed for fine tuning the sort priority for transfering new _jointData to the render pipeline.
|
||||||
static float _avatarSortCoefficientSize;
|
static float _avatarSortCoefficientSize;
|
||||||
|
|
|
@ -437,9 +437,11 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const
|
||||||
} else {
|
} else {
|
||||||
d = glm::normalize(overlaySurfacePoint);
|
d = glm::normalize(overlaySurfacePoint);
|
||||||
}
|
}
|
||||||
reticlePosition = headPosition + (d * getReticleDepth());
|
// Our sensor to world matrix always has uniform scale
|
||||||
|
float sensorSpaceReticleDepth = getReticleDepth() / extractScale(_sensorToWorldMatrix).x;
|
||||||
|
reticlePosition = headPosition + (d * sensorSpaceReticleDepth);
|
||||||
quat reticleOrientation = cancelOutRoll(glm::quat_cast(_currentDisplayPlugin->getHeadPose()));
|
quat reticleOrientation = cancelOutRoll(glm::quat_cast(_currentDisplayPlugin->getHeadPose()));
|
||||||
vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize * getReticleDepth());
|
vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize * sensorSpaceReticleDepth);
|
||||||
return glm::inverse(eyePose) * createMatFromScaleQuatAndPos(reticleScale, reticleOrientation, reticlePosition);
|
return glm::inverse(eyePose) * createMatFromScaleQuatAndPos(reticleScale, reticleOrientation, reticlePosition);
|
||||||
} else {
|
} else {
|
||||||
static const float CURSOR_PIXEL_SIZE = 32.0f;
|
static const float CURSOR_PIXEL_SIZE = 32.0f;
|
||||||
|
|
|
@ -75,9 +75,12 @@ RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityI
|
||||||
RenderableModelEntityItem::~RenderableModelEntityItem() { }
|
RenderableModelEntityItem::~RenderableModelEntityItem() { }
|
||||||
|
|
||||||
void RenderableModelEntityItem::setDimensions(const glm::vec3& value) {
|
void RenderableModelEntityItem::setDimensions(const glm::vec3& value) {
|
||||||
|
glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions
|
||||||
|
if (getDimensions() != newDimensions) {
|
||||||
_dimensionsInitialized = true;
|
_dimensionsInitialized = true;
|
||||||
ModelEntityItem::setDimensions(value);
|
ModelEntityItem::setDimensions(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures) {
|
QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures) {
|
||||||
// If textures are unset, revert to original textures
|
// If textures are unset, revert to original textures
|
||||||
|
@ -1160,7 +1163,6 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (model->getScaleToFitDimensions() != entity->getDimensions() ||
|
if (model->getScaleToFitDimensions() != entity->getDimensions() ||
|
||||||
model->getRegistrationPoint() != entity->getRegistrationPoint()) {
|
model->getRegistrationPoint() != entity->getRegistrationPoint()) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1605,6 +1605,48 @@ void EntityItem::setParentID(const QUuid& value) {
|
||||||
if (tree && !oldParentID.isNull()) {
|
if (tree && !oldParentID.isNull()) {
|
||||||
tree->removeFromChildrenOfAvatars(getThisPointer());
|
tree->removeFromChildrenOfAvatars(getThisPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t oldParentNoBootstrapping = 0;
|
||||||
|
uint32_t newParentNoBootstrapping = 0;
|
||||||
|
if (!value.isNull() && tree) {
|
||||||
|
EntityItemPointer entity = tree->findEntityByEntityItemID(value);
|
||||||
|
if (entity) {
|
||||||
|
newParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oldParentID.isNull() && tree) {
|
||||||
|
EntityItemPointer entity = tree->findEntityByEntityItemID(oldParentID);
|
||||||
|
if (entity) {
|
||||||
|
oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value.isNull() && (value == Physics::getSessionUUID() || value == AVATAR_SELF_ID)) {
|
||||||
|
newParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) {
|
||||||
|
if ((bool)(newParentNoBootstrapping & Simulation::NO_BOOTSTRAPPING)) {
|
||||||
|
markDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||||
|
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||||
|
if (object->getNestableType() == NestableType::Entity) {
|
||||||
|
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||||
|
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP | Simulation::NO_BOOTSTRAPPING);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||||
|
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||||
|
if (object->getNestableType() == NestableType::Entity) {
|
||||||
|
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||||
|
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||||
|
entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SpatiallyNestable::setParentID(value);
|
SpatiallyNestable::setParentID(value);
|
||||||
// children are forced to be kinematic
|
// children are forced to be kinematic
|
||||||
// may need to not collide with own avatar
|
// may need to not collide with own avatar
|
||||||
|
@ -1622,11 +1664,13 @@ void EntityItem::setDimensions(const glm::vec3& value) {
|
||||||
if (getDimensions() != newDimensions) {
|
if (getDimensions() != newDimensions) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_dimensions = newDimensions;
|
_dimensions = newDimensions;
|
||||||
_dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
|
||||||
_queryAACubeSet = false;
|
|
||||||
});
|
});
|
||||||
locationChanged();
|
locationChanged();
|
||||||
dimensionsChanged();
|
dimensionsChanged();
|
||||||
|
withWriteLock([&] {
|
||||||
|
_dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||||
|
_queryAACubeSet = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1832,40 +1876,9 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userMask & USER_COLLISION_GROUP_MY_AVATAR) {
|
if ((bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
|
||||||
bool iAmHoldingThis = false;
|
|
||||||
// if this entity is a descendant of MyAvatar, don't collide with MyAvatar. This avoids the
|
|
||||||
// "bootstrapping" problem where you can shoot yourself across the room by grabbing something
|
|
||||||
// and holding it against your own avatar.
|
|
||||||
if (isChildOfMyAvatar()) {
|
|
||||||
iAmHoldingThis = true;
|
|
||||||
}
|
|
||||||
// also, don't bootstrap our own avatar with a hold action
|
|
||||||
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
|
|
||||||
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
|
|
||||||
while (i != holdActions.end()) {
|
|
||||||
EntityDynamicPointer action = *i;
|
|
||||||
if (action->isMine()) {
|
|
||||||
iAmHoldingThis = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
QList<EntityDynamicPointer> farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB);
|
|
||||||
i = farGrabActions.begin();
|
|
||||||
while (i != farGrabActions.end()) {
|
|
||||||
EntityDynamicPointer action = *i;
|
|
||||||
if (action->isMine()) {
|
|
||||||
iAmHoldingThis = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iAmHoldingThis) {
|
|
||||||
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
|
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
|
mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1959,7 +1972,20 @@ bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityDyn
|
||||||
if (success) {
|
if (success) {
|
||||||
_allActionsDataCache = newDataCache;
|
_allActionsDataCache = newDataCache;
|
||||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||||
|
|
||||||
|
auto actionType = action->getType();
|
||||||
|
if (actionType == DYNAMIC_TYPE_HOLD || actionType == DYNAMIC_TYPE_FAR_GRAB) {
|
||||||
|
if (!(bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
|
||||||
|
_dirtyFlags |= Simulation::NO_BOOTSTRAPPING;
|
||||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||||
|
forEachDescendant([&](SpatiallyNestablePointer child) {
|
||||||
|
if (child->getNestableType() == NestableType::Entity) {
|
||||||
|
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(child);
|
||||||
|
entity->markDirtyFlags(Simulation::NO_BOOTSTRAPPING | Simulation::DIRTY_COLLISION_GROUP);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(entities) << "EntityItem::addActionInternal -- serializeActions failed";
|
qCDebug(entities) << "EntityItem::addActionInternal -- serializeActions failed";
|
||||||
}
|
}
|
||||||
|
@ -2000,6 +2026,29 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityItem::stillHasGrabActions() const {
|
||||||
|
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
|
||||||
|
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
|
||||||
|
while (i != holdActions.end()) {
|
||||||
|
EntityDynamicPointer action = *i;
|
||||||
|
if (action->isMine()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
QList<EntityDynamicPointer> farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB);
|
||||||
|
i = farGrabActions.begin();
|
||||||
|
while (i != farGrabActions.end()) {
|
||||||
|
EntityDynamicPointer action = *i;
|
||||||
|
if (action->isMine()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) {
|
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) {
|
||||||
_previouslyDeletedActions.insert(actionID, usecTimestampNow());
|
_previouslyDeletedActions.insert(actionID, usecTimestampNow());
|
||||||
if (_objectActions.contains(actionID)) {
|
if (_objectActions.contains(actionID)) {
|
||||||
|
@ -2013,7 +2062,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
||||||
|
|
||||||
action->setOwnerEntity(nullptr);
|
action->setOwnerEntity(nullptr);
|
||||||
action->setIsMine(false);
|
action->setIsMine(false);
|
||||||
_objectActions.remove(actionID);
|
|
||||||
|
|
||||||
if (simulation) {
|
if (simulation) {
|
||||||
action->removeFromSimulation(simulation);
|
action->removeFromSimulation(simulation);
|
||||||
|
@ -2022,7 +2070,23 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
||||||
bool success = true;
|
bool success = true;
|
||||||
serializeActions(success, _allActionsDataCache);
|
serializeActions(success, _allActionsDataCache);
|
||||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||||
|
auto removedActionType = action->getType();
|
||||||
|
if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) {
|
||||||
|
_dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING;
|
||||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||||
|
forEachDescendant([&](SpatiallyNestablePointer child) {
|
||||||
|
if (child->getNestableType() == NestableType::Entity) {
|
||||||
|
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(child);
|
||||||
|
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||||
|
entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct
|
||||||
|
// because they should have been set correctly when the action was added
|
||||||
|
// and/or when children were linked
|
||||||
|
}
|
||||||
|
_objectActions.remove(actionID);
|
||||||
setDynamicDataNeedsTransmit(true);
|
setDynamicDataNeedsTransmit(true);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,6 +470,7 @@ protected:
|
||||||
void setSimulated(bool simulated) { _simulated = simulated; }
|
void setSimulated(bool simulated) { _simulated = simulated; }
|
||||||
|
|
||||||
const QByteArray getDynamicDataInternal() const;
|
const QByteArray getDynamicDataInternal() const;
|
||||||
|
bool stillHasGrabActions() const;
|
||||||
void setDynamicDataInternal(QByteArray dynamicData);
|
void setDynamicDataInternal(QByteArray dynamicData);
|
||||||
|
|
||||||
virtual void dimensionsChanged() override;
|
virtual void dimensionsChanged() override;
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace Simulation {
|
||||||
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
|
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
|
||||||
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
|
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
|
||||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
|
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
|
||||||
|
const uint32_t NO_BOOTSTRAPPING = 0x4000;
|
||||||
|
|
||||||
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
|
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
|
||||||
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
|
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
|
||||||
|
|
|
@ -1006,15 +1006,12 @@ NetworkTexturePointer TextureCache::getResourceTexture(QUrl resourceTextureUrl)
|
||||||
if (!_spectatorCameraNetworkTexture) {
|
if (!_spectatorCameraNetworkTexture) {
|
||||||
_spectatorCameraNetworkTexture.reset(new NetworkTexture(resourceTextureUrl));
|
_spectatorCameraNetworkTexture.reset(new NetworkTexture(resourceTextureUrl));
|
||||||
}
|
}
|
||||||
if (_spectatorCameraFramebuffer) {
|
if (!_spectatorCameraFramebuffer) {
|
||||||
texture = _spectatorCameraFramebuffer->getRenderBuffer(0);
|
getSpectatorCameraFramebuffer(); // initialize frame buffer
|
||||||
if (texture) {
|
}
|
||||||
texture->setSource(SPECTATOR_CAMERA_FRAME_URL.toString().toStdString());
|
updateSpectatorCameraNetworkTexture();
|
||||||
_spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight());
|
|
||||||
return _spectatorCameraNetworkTexture;
|
return _spectatorCameraNetworkTexture;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
// FIXME: Generalize this, DRY up this code
|
// FIXME: Generalize this, DRY up this code
|
||||||
if (resourceTextureUrl == HMD_PREVIEW_FRAME_URL) {
|
if (resourceTextureUrl == HMD_PREVIEW_FRAME_URL) {
|
||||||
if (!_hmdPreviewNetworkTexture) {
|
if (!_hmdPreviewNetworkTexture) {
|
||||||
|
@ -1052,7 +1049,18 @@ const gpu::FramebufferPointer& TextureCache::getSpectatorCameraFramebuffer(int w
|
||||||
// If we aren't taking a screenshot, we might need to resize or create the camera buffer
|
// If we aren't taking a screenshot, we might need to resize or create the camera buffer
|
||||||
if (!_spectatorCameraFramebuffer || _spectatorCameraFramebuffer->getWidth() != width || _spectatorCameraFramebuffer->getHeight() != height) {
|
if (!_spectatorCameraFramebuffer || _spectatorCameraFramebuffer->getWidth() != width || _spectatorCameraFramebuffer->getHeight() != height) {
|
||||||
_spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, width, height));
|
_spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, width, height));
|
||||||
|
updateSpectatorCameraNetworkTexture();
|
||||||
emit spectatorCameraFramebufferReset();
|
emit spectatorCameraFramebufferReset();
|
||||||
}
|
}
|
||||||
return _spectatorCameraFramebuffer;
|
return _spectatorCameraFramebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureCache::updateSpectatorCameraNetworkTexture() {
|
||||||
|
if (_spectatorCameraFramebuffer && _spectatorCameraNetworkTexture) {
|
||||||
|
gpu::TexturePointer texture = _spectatorCameraFramebuffer->getRenderBuffer(0);
|
||||||
|
if (texture) {
|
||||||
|
texture->setSource(SPECTATOR_CAMERA_FRAME_URL.toString().toStdString());
|
||||||
|
_spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -171,6 +171,7 @@ public:
|
||||||
const gpu::FramebufferPointer& getHmdPreviewFramebuffer(int width, int height);
|
const gpu::FramebufferPointer& getHmdPreviewFramebuffer(int width, int height);
|
||||||
const gpu::FramebufferPointer& getSpectatorCameraFramebuffer();
|
const gpu::FramebufferPointer& getSpectatorCameraFramebuffer();
|
||||||
const gpu::FramebufferPointer& getSpectatorCameraFramebuffer(int width, int height);
|
const gpu::FramebufferPointer& getSpectatorCameraFramebuffer(int width, int height);
|
||||||
|
void updateSpectatorCameraNetworkTexture();
|
||||||
|
|
||||||
static const int DEFAULT_SPECTATOR_CAM_WIDTH { 2048 };
|
static const int DEFAULT_SPECTATOR_CAM_WIDTH { 2048 };
|
||||||
static const int DEFAULT_SPECTATOR_CAM_HEIGHT { 1024 };
|
static const int DEFAULT_SPECTATOR_CAM_HEIGHT { 1024 };
|
||||||
|
|
|
@ -88,3 +88,56 @@ void UserActivityLoggerScriptingInterface::doLogAction(QString action, QJsonObje
|
||||||
Q_ARG(QString, action),
|
Q_ARG(QString, action),
|
||||||
Q_ARG(QJsonObject, details));
|
Q_ARG(QJsonObject, details));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem) {
|
||||||
|
QJsonObject payload;
|
||||||
|
payload["marketplaceID"] = marketplaceID;
|
||||||
|
payload["cost"] = cost;
|
||||||
|
payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem;
|
||||||
|
doLogAction("commercePurchaseSuccess", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails) {
|
||||||
|
QJsonObject payload;
|
||||||
|
payload["marketplaceID"] = marketplaceID;
|
||||||
|
payload["cost"] = cost;
|
||||||
|
payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem;
|
||||||
|
payload["errorDetails"] = errorDetails;
|
||||||
|
doLogAction("commercePurchaseFailure", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserActivityLoggerScriptingInterface::commerceEntityRezzed(QString marketplaceID, QString source, QString type) {
|
||||||
|
QJsonObject payload;
|
||||||
|
payload["marketplaceID"] = marketplaceID;
|
||||||
|
payload["source"] = source;
|
||||||
|
payload["type"] = type;
|
||||||
|
doLogAction("commerceEntityRezzed", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserActivityLoggerScriptingInterface::commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain) {
|
||||||
|
QJsonObject payload;
|
||||||
|
payload["timestamp"] = timestamp;
|
||||||
|
payload["setupAttemptID"] = setupAttemptID;
|
||||||
|
payload["setupFlowVersion"] = setupFlowVersion;
|
||||||
|
payload["referrer"] = referrer;
|
||||||
|
payload["currentDomain"] = currentDomain;
|
||||||
|
doLogAction("commerceWalletSetupStarted", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserActivityLoggerScriptingInterface::commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName) {
|
||||||
|
QJsonObject payload;
|
||||||
|
payload["timestamp"] = timestamp;
|
||||||
|
payload["setupAttemptID"] = setupAttemptID;
|
||||||
|
payload["secondsElapsed"] = secondsElapsed;
|
||||||
|
payload["currentStepNumber"] = currentStepNumber;
|
||||||
|
payload["currentStepName"] = currentStepName;
|
||||||
|
doLogAction("commerceWalletSetupProgress", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserActivityLoggerScriptingInterface::commerceWalletSetupFinished(int timestamp, QString setupAttemptID, int secondsToComplete) {
|
||||||
|
QJsonObject payload;
|
||||||
|
payload["timestamp"] = timestamp;
|
||||||
|
payload["setupAttemptID"] = setupAttemptID;
|
||||||
|
payload["secondsToComplete"] = secondsToComplete;
|
||||||
|
doLogAction("commerceWalletSetupFinished", payload);
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,12 @@ public:
|
||||||
Q_INVOKABLE void bubbleToggled(bool newValue);
|
Q_INVOKABLE void bubbleToggled(bool newValue);
|
||||||
Q_INVOKABLE void bubbleActivated();
|
Q_INVOKABLE void bubbleActivated();
|
||||||
Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{});
|
Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{});
|
||||||
|
Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem);
|
||||||
|
Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails);
|
||||||
|
Q_INVOKABLE void commerceEntityRezzed(QString marketplaceID, QString source, QString type);
|
||||||
|
Q_INVOKABLE void commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain);
|
||||||
|
Q_INVOKABLE void commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName);
|
||||||
|
Q_INVOKABLE void commerceWalletSetupFinished(int timestamp, QString setupAttemptID, int secondsToComplete);
|
||||||
private:
|
private:
|
||||||
void doLogAction(QString action, QJsonObject details = {});
|
void doLogAction(QString action, QJsonObject details = {});
|
||||||
};
|
};
|
||||||
|
|
|
@ -700,7 +700,7 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() {
|
||||||
void EntityMotionState::clearIncomingDirtyFlags() {
|
void EntityMotionState::clearIncomingDirtyFlags() {
|
||||||
assert(entityTreeIsLocked());
|
assert(entityTreeIsLocked());
|
||||||
if (_body && _entity) {
|
if (_body && _entity) {
|
||||||
_entity->clearDirtyFlags();
|
_entity->clearDirtyFlags(DIRTY_PHYSICS_FLAGS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,23 +32,23 @@ void Transaction::removeItem(ItemID id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId) {
|
void Transaction::addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId) {
|
||||||
_addedTransitions.emplace_back(TransitionAdd{ id, transition, boundId });
|
_addedTransitions.emplace_back(id, transition, boundId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::removeTransitionFromItem(ItemID id) {
|
void Transaction::removeTransitionFromItem(ItemID id) {
|
||||||
_addedTransitions.emplace_back(TransitionAdd{ id, Transition::NONE, render::Item::INVALID_ITEM_ID });
|
_addedTransitions.emplace_back(id, Transition::NONE, render::Item::INVALID_ITEM_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::reApplyTransitionToItem(ItemID id) {
|
void Transaction::reApplyTransitionToItem(ItemID id) {
|
||||||
_reAppliedTransitions.emplace_back(TransitionReApply{ id });
|
_reAppliedTransitions.emplace_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::queryTransitionOnItem(ItemID id, TransitionQueryFunc func) {
|
void Transaction::queryTransitionOnItem(ItemID id, TransitionQueryFunc func) {
|
||||||
_queriedTransitions.emplace_back(TransitionQuery{ id, func });
|
_queriedTransitions.emplace_back(id, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
|
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
|
||||||
_updatedItems.emplace_back(Update{ id, functor });
|
_updatedItems.emplace_back(id, functor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::resetSelection(const Selection& selection) {
|
void Transaction::resetSelection(const Selection& selection) {
|
||||||
|
@ -56,28 +56,122 @@ void Transaction::resetSelection(const Selection& selection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::resetSelectionHighlight(const std::string& selectionName, const HighlightStyle& style) {
|
void Transaction::resetSelectionHighlight(const std::string& selectionName, const HighlightStyle& style) {
|
||||||
_highlightResets.emplace_back(HighlightReset{ selectionName, style });
|
_highlightResets.emplace_back(selectionName, style );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::removeHighlightFromSelection(const std::string& selectionName) {
|
void Transaction::removeHighlightFromSelection(const std::string& selectionName) {
|
||||||
_highlightRemoves.emplace_back(selectionName);
|
_highlightRemoves.emplace_back(selectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::querySelectionHighlight(const std::string& selectionName, SelectionHighlightQueryFunc func) {
|
void Transaction::querySelectionHighlight(const std::string& selectionName, const SelectionHighlightQueryFunc& func) {
|
||||||
_highlightQueries.emplace_back(HighlightQuery{ selectionName, func });
|
_highlightQueries.emplace_back(selectionName, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transaction::reserve(const std::vector<Transaction>& transactionContainer) {
|
||||||
|
size_t resetItemsCount = 0;
|
||||||
|
size_t removedItemsCount = 0;
|
||||||
|
size_t updatedItemsCount = 0;
|
||||||
|
size_t resetSelectionsCount = 0;
|
||||||
|
size_t addedTransitionsCount = 0;
|
||||||
|
size_t queriedTransitionsCount = 0;
|
||||||
|
size_t reAppliedTransitionsCount = 0;
|
||||||
|
size_t highlightResetsCount = 0;
|
||||||
|
size_t highlightRemovesCount = 0;
|
||||||
|
size_t highlightQueriesCount = 0;
|
||||||
|
|
||||||
|
for (const auto& transaction : transactionContainer) {
|
||||||
|
resetItemsCount += transaction._resetItems.size();
|
||||||
|
removedItemsCount += transaction._removedItems.size();
|
||||||
|
updatedItemsCount += transaction._updatedItems.size();
|
||||||
|
resetSelectionsCount += transaction._resetSelections.size();
|
||||||
|
addedTransitionsCount += transaction._addedTransitions.size();
|
||||||
|
queriedTransitionsCount += transaction._queriedTransitions.size();
|
||||||
|
reAppliedTransitionsCount += transaction._reAppliedTransitions.size();
|
||||||
|
highlightResetsCount += transaction._highlightResets.size();
|
||||||
|
highlightRemovesCount += transaction._highlightRemoves.size();
|
||||||
|
highlightQueriesCount += transaction._highlightQueries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetItems.reserve(resetItemsCount);
|
||||||
|
_removedItems.reserve(removedItemsCount);
|
||||||
|
_updatedItems.reserve(updatedItemsCount);
|
||||||
|
_resetSelections.reserve(resetSelectionsCount);
|
||||||
|
_addedTransitions.reserve(addedTransitionsCount);
|
||||||
|
_queriedTransitions.reserve(queriedTransitionsCount);
|
||||||
|
_reAppliedTransitions.reserve(reAppliedTransitionsCount);
|
||||||
|
_highlightResets.reserve(highlightResetsCount);
|
||||||
|
_highlightRemoves.reserve(highlightRemovesCount);
|
||||||
|
_highlightQueries.reserve(highlightQueriesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transaction::merge(const std::vector<Transaction>& transactionContainer) {
|
||||||
|
reserve(transactionContainer);
|
||||||
|
for (const auto& transaction : transactionContainer) {
|
||||||
|
merge(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Transaction::merge(std::vector<Transaction>&& transactionContainer) {
|
||||||
|
reserve(transactionContainer);
|
||||||
|
auto begin = std::make_move_iterator(transactionContainer.begin());
|
||||||
|
auto end = std::make_move_iterator(transactionContainer.end());
|
||||||
|
for (auto itr = begin; itr != end; ++itr) {
|
||||||
|
merge(*itr);
|
||||||
|
}
|
||||||
|
transactionContainer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void moveElements(T& target, T& source) {
|
||||||
|
target.insert(target.end(), std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()));
|
||||||
|
source.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void copyElements(T& target, const T& source) {
|
||||||
|
target.insert(target.end(), source.begin(), source.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Transaction::merge(Transaction&& transaction) {
|
||||||
|
moveElements(_resetItems, transaction._resetItems);
|
||||||
|
moveElements(_removedItems, transaction._removedItems);
|
||||||
|
moveElements(_updatedItems, transaction._updatedItems);
|
||||||
|
moveElements(_resetSelections, transaction._resetSelections);
|
||||||
|
moveElements(_addedTransitions, transaction._addedTransitions);
|
||||||
|
moveElements(_queriedTransitions, transaction._queriedTransitions);
|
||||||
|
moveElements(_reAppliedTransitions, transaction._reAppliedTransitions);
|
||||||
|
moveElements(_highlightResets, transaction._highlightResets);
|
||||||
|
moveElements(_highlightRemoves, transaction._highlightRemoves);
|
||||||
|
moveElements(_highlightQueries, transaction._highlightQueries);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::merge(const Transaction& transaction) {
|
void Transaction::merge(const Transaction& transaction) {
|
||||||
_resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end());
|
copyElements(_resetItems, transaction._resetItems);
|
||||||
_removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end());
|
copyElements(_removedItems, transaction._removedItems);
|
||||||
_updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end());
|
copyElements(_updatedItems, transaction._updatedItems);
|
||||||
_resetSelections.insert(_resetSelections.end(), transaction._resetSelections.begin(), transaction._resetSelections.end());
|
copyElements(_resetSelections, transaction._resetSelections);
|
||||||
_addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end());
|
copyElements(_addedTransitions, transaction._addedTransitions);
|
||||||
_queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end());
|
copyElements(_queriedTransitions, transaction._queriedTransitions);
|
||||||
_reAppliedTransitions.insert(_reAppliedTransitions.end(), transaction._reAppliedTransitions.begin(), transaction._reAppliedTransitions.end());
|
copyElements(_reAppliedTransitions, transaction._reAppliedTransitions);
|
||||||
_highlightResets.insert(_highlightResets.end(), transaction._highlightResets.begin(), transaction._highlightResets.end());
|
copyElements(_highlightResets, transaction._highlightResets);
|
||||||
_highlightRemoves.insert(_highlightRemoves.end(), transaction._highlightRemoves.begin(), transaction._highlightRemoves.end());
|
copyElements(_highlightRemoves, transaction._highlightRemoves);
|
||||||
_highlightQueries.insert(_highlightQueries.end(), transaction._highlightQueries.begin(), transaction._highlightQueries.end());
|
copyElements(_highlightQueries, transaction._highlightQueries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transaction::clear() {
|
||||||
|
_resetItems.clear();
|
||||||
|
_removedItems.clear();
|
||||||
|
_updatedItems.clear();
|
||||||
|
_resetSelections.clear();
|
||||||
|
_addedTransitions.clear();
|
||||||
|
_queriedTransitions.clear();
|
||||||
|
_reAppliedTransitions.clear();
|
||||||
|
_highlightResets.clear();
|
||||||
|
_highlightRemoves.clear();
|
||||||
|
_highlightQueries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,54 +196,50 @@ bool Scene::isAllocatedID(const ItemID& id) const {
|
||||||
|
|
||||||
/// Enqueue change batch to the scene
|
/// Enqueue change batch to the scene
|
||||||
void Scene::enqueueTransaction(const Transaction& transaction) {
|
void Scene::enqueueTransaction(const Transaction& transaction) {
|
||||||
_transactionQueueMutex.lock();
|
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||||
_transactionQueue.push(transaction);
|
_transactionQueue.emplace_back(transaction);
|
||||||
_transactionQueueMutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void consolidateTransaction(TransactionQueue& queue, Transaction& singleBatch) {
|
void Scene::enqueueTransaction(Transaction&& transaction) {
|
||||||
while (!queue.empty()) {
|
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||||
const auto& transaction = queue.front();
|
_transactionQueue.emplace_back(std::move(transaction));
|
||||||
singleBatch.merge(transaction);
|
|
||||||
queue.pop();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Scene::enqueueFrame() {
|
uint32_t Scene::enqueueFrame() {
|
||||||
PROFILE_RANGE(render, __FUNCTION__);
|
PROFILE_RANGE(render, __FUNCTION__);
|
||||||
Transaction consolidatedTransaction;
|
TransactionQueue localTransactionQueue;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||||
consolidateTransaction(_transactionQueue, consolidatedTransaction);
|
localTransactionQueue.swap(_transactionQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t frameNumber = 0;
|
Transaction consolidatedTransaction;
|
||||||
|
consolidatedTransaction.merge(std::move(localTransactionQueue));
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
||||||
_transactionFrames.push_back(consolidatedTransaction);
|
_transactionFrames.push_back(consolidatedTransaction);
|
||||||
_transactionFrameNumber++;
|
|
||||||
frameNumber = _transactionFrameNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return frameNumber;
|
return ++_transactionFrameNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Scene::processTransactionQueue() {
|
void Scene::processTransactionQueue() {
|
||||||
PROFILE_RANGE(render, __FUNCTION__);
|
PROFILE_RANGE(render, __FUNCTION__);
|
||||||
|
|
||||||
TransactionFrames queuedFrames;
|
static TransactionFrames queuedFrames;
|
||||||
{
|
{
|
||||||
// capture the queued frames and clear the queue
|
// capture the queued frames and clear the queue
|
||||||
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
||||||
queuedFrames = _transactionFrames;
|
queuedFrames.swap(_transactionFrames);
|
||||||
_transactionFrames.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// go through the queue of frames and process them
|
// go through the queue of frames and process them
|
||||||
for (auto& frame : queuedFrames) {
|
for (auto& frame : queuedFrames) {
|
||||||
processTransactionFrame(frame);
|
processTransactionFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queuedFrames.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::processTransactionFrame(const Transaction& transaction) {
|
void Scene::processTransactionFrame(const Transaction& transaction) {
|
||||||
|
|
|
@ -65,9 +65,14 @@ public:
|
||||||
|
|
||||||
void resetSelectionHighlight(const std::string& selectionName, const HighlightStyle& style = HighlightStyle());
|
void resetSelectionHighlight(const std::string& selectionName, const HighlightStyle& style = HighlightStyle());
|
||||||
void removeHighlightFromSelection(const std::string& selectionName);
|
void removeHighlightFromSelection(const std::string& selectionName);
|
||||||
void querySelectionHighlight(const std::string& selectionName, SelectionHighlightQueryFunc func);
|
void querySelectionHighlight(const std::string& selectionName, const SelectionHighlightQueryFunc& func);
|
||||||
|
|
||||||
|
void reserve(const std::vector<Transaction>& transactionContainer);
|
||||||
|
void merge(const std::vector<Transaction>& transactionContainer);
|
||||||
|
void merge(std::vector<Transaction>&& transactionContainer);
|
||||||
void merge(const Transaction& transaction);
|
void merge(const Transaction& transaction);
|
||||||
|
void merge(Transaction&& transaction);
|
||||||
|
void clear();
|
||||||
|
|
||||||
// Checkers if there is work to do when processing the transaction
|
// Checkers if there is work to do when processing the transaction
|
||||||
bool touchTransactions() const { return !_resetSelections.empty(); }
|
bool touchTransactions() const { return !_resetSelections.empty(); }
|
||||||
|
@ -107,7 +112,7 @@ protected:
|
||||||
HighlightRemoves _highlightRemoves;
|
HighlightRemoves _highlightRemoves;
|
||||||
HighlightQueries _highlightQueries;
|
HighlightQueries _highlightQueries;
|
||||||
};
|
};
|
||||||
typedef std::queue<Transaction> TransactionQueue;
|
typedef std::vector<Transaction> TransactionQueue;
|
||||||
|
|
||||||
|
|
||||||
// Scene is a container for Items
|
// Scene is a container for Items
|
||||||
|
@ -133,6 +138,9 @@ public:
|
||||||
// Enqueue transaction to the scene
|
// Enqueue transaction to the scene
|
||||||
void enqueueTransaction(const Transaction& transaction);
|
void enqueueTransaction(const Transaction& transaction);
|
||||||
|
|
||||||
|
// Enqueue transaction to the scene
|
||||||
|
void enqueueTransaction(Transaction&& transaction);
|
||||||
|
|
||||||
// Enqueue end of frame transactions boundary
|
// Enqueue end of frame transactions boundary
|
||||||
uint32_t enqueueFrame();
|
uint32_t enqueueFrame();
|
||||||
|
|
||||||
|
@ -187,7 +195,7 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
std::mutex _transactionFramesMutex;
|
std::mutex _transactionFramesMutex;
|
||||||
using TransactionFrames = std::list<Transaction>;
|
using TransactionFrames = std::vector<Transaction>;
|
||||||
TransactionFrames _transactionFrames;
|
TransactionFrames _transactionFrames;
|
||||||
uint32_t _transactionFrameNumber{ 0 };
|
uint32_t _transactionFrameNumber{ 0 };
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
#define hifi_PrioritySortUtil_h
|
#define hifi_PrioritySortUtil_h
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include "NumericalConstants.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
|
|
||||||
/* PrioritySortUtil is a helper for sorting 3D things relative to a ViewFrustum. To use:
|
/* PrioritySortUtil is a helper for sorting 3D things relative to a ViewFrustum. To use:
|
||||||
|
@ -32,11 +35,10 @@
|
||||||
|
|
||||||
(2) Make a PrioritySortUtil::PriorityQueue<Thing> and add them to the queue:
|
(2) Make a PrioritySortUtil::PriorityQueue<Thing> and add them to the queue:
|
||||||
|
|
||||||
PrioritySortUtil::Prioritizer prioritizer(viewFrustum);
|
PrioritySortUtil::PriorityQueue<SortableWrapper> sortedThings(viewFrustum);
|
||||||
std::priority_queue< PrioritySortUtil::Sortable<Thing> > sortedThings;
|
std::priority_queue< PrioritySortUtil::Sortable<Thing> > sortedThings;
|
||||||
for (thing in things) {
|
for (thing in things) {
|
||||||
float priority = prioritizer.computePriority(PrioritySortUtil::PrioritizableThing(thing));
|
sortedThings.push(SortableWrapper(thing));
|
||||||
sortedThings.push(PrioritySortUtil::Sortable<Thing> entry(thing, priority));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(3) Loop over your priority queue and do timeboxed work:
|
(3) Loop over your priority queue and do timeboxed work:
|
||||||
|
@ -65,6 +67,7 @@ namespace PrioritySortUtil {
|
||||||
virtual uint64_t getTimestamp() const = 0;
|
virtual uint64_t getTimestamp() const = 0;
|
||||||
|
|
||||||
void setPriority(float priority) { _priority = priority; }
|
void setPriority(float priority) { _priority = priority; }
|
||||||
|
float getPriority() const { return _priority; }
|
||||||
bool operator<(const Sortable& other) const { return _priority < other._priority; }
|
bool operator<(const Sortable& other) const { return _priority < other._priority; }
|
||||||
private:
|
private:
|
||||||
float _priority { 0.0f };
|
float _priority { 0.0f };
|
||||||
|
@ -109,11 +112,19 @@ namespace PrioritySortUtil {
|
||||||
glm::vec3 position = thing.getPosition();
|
glm::vec3 position = thing.getPosition();
|
||||||
glm::vec3 offset = position - _view.getPosition();
|
glm::vec3 offset = position - _view.getPosition();
|
||||||
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
||||||
float radius = thing.getRadius();
|
const float MIN_RADIUS = 0.1f; // WORKAROUND for zero size objects (we still want them to sort by distance)
|
||||||
|
float radius = glm::min(thing.getRadius(), MIN_RADIUS);
|
||||||
|
float cosineAngle = (glm::dot(offset, _view.getDirection()) / distance);
|
||||||
|
float age = (float)(usecTimestampNow() - thing.getTimestamp());
|
||||||
|
|
||||||
float priority = _angularWeight * (radius / distance)
|
// we modulatate "age" drift rate by the cosineAngle term to make periphrial objects sort forward
|
||||||
+ _centerWeight * (glm::dot(offset, _view.getDirection()) / distance)
|
// at a reduced rate but we don't want the "age" term to go zero or negative so we clamp it
|
||||||
+ _ageWeight * (float)(usecTimestampNow() - thing.getTimestamp());
|
const float MIN_COSINE_ANGLE_FACTOR = 0.1f;
|
||||||
|
float cosineAngleFactor = glm::max(cosineAngle, MIN_COSINE_ANGLE_FACTOR);
|
||||||
|
|
||||||
|
float priority = _angularWeight * glm::max(radius, MIN_RADIUS) / distance
|
||||||
|
+ _centerWeight * cosineAngle
|
||||||
|
+ _ageWeight * cosineAngleFactor * age;
|
||||||
|
|
||||||
// decrement priority of things outside keyhole
|
// decrement priority of things outside keyhole
|
||||||
if (distance - radius > _view.getCenterRadius()) {
|
if (distance - radius > _view.getCenterRadius()) {
|
||||||
|
|
|
@ -121,26 +121,20 @@ uint64_t uvec2ToUint64(const uvec2& v) {
|
||||||
class AudioHandler : public QObject, QRunnable {
|
class AudioHandler : public QObject, QRunnable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AudioHandler(QObject* container, const QString& deviceName, int runDelayMs = 0, QObject* parent = nullptr) : QObject(parent) {
|
AudioHandler(QSharedPointer<OffscreenQmlSurface> surface, const QString& deviceName, QObject* parent = nullptr) : QObject(parent) {
|
||||||
_container = container;
|
|
||||||
_newTargetDevice = deviceName;
|
_newTargetDevice = deviceName;
|
||||||
_runDelayMs = runDelayMs;
|
_surface = surface;
|
||||||
setAutoDelete(true);
|
setAutoDelete(true);
|
||||||
|
if (deviceName.size() > 0) {
|
||||||
QThreadPool::globalInstance()->start(this);
|
QThreadPool::globalInstance()->start(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
virtual ~AudioHandler() {
|
virtual ~AudioHandler() {
|
||||||
qDebug() << "Audio Handler Destroyed";
|
qDebug() << "Audio Handler Destroyed";
|
||||||
}
|
}
|
||||||
void run() override {
|
void run() override {
|
||||||
if (_newTargetDevice.isEmpty()) {
|
if (!_surface.isNull() && _surface->getRootItem() && !_surface->getCleaned()) {
|
||||||
return;
|
for (auto player : _surface->getRootItem()->findChildren<QMediaPlayer*>()) {
|
||||||
}
|
|
||||||
if (_runDelayMs > 0) {
|
|
||||||
QThread::msleep(_runDelayMs);
|
|
||||||
}
|
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
|
||||||
QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName();
|
|
||||||
for (auto player : _container->findChildren<QMediaPlayer*>()) {
|
|
||||||
auto mediaState = player->state();
|
auto mediaState = player->state();
|
||||||
QMediaService *svc = player->service();
|
QMediaService *svc = player->service();
|
||||||
if (nullptr == svc) {
|
if (nullptr == svc) {
|
||||||
|
@ -156,7 +150,7 @@ public:
|
||||||
for (int i = 0; i < outputs.size(); i++) {
|
for (int i = 0; i < outputs.size(); i++) {
|
||||||
QString output = outputs[i];
|
QString output = outputs[i];
|
||||||
QString description = out->outputDescription(output);
|
QString description = out->outputDescription(output);
|
||||||
if (description == deviceName) {
|
if (description == _newTargetDevice) {
|
||||||
deviceOuput = output;
|
deviceOuput = output;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -167,17 +161,18 @@ public:
|
||||||
// this will reset it back to a paused state
|
// this will reset it back to a paused state
|
||||||
if (mediaState == QMediaPlayer::State::PausedState) {
|
if (mediaState == QMediaPlayer::State::PausedState) {
|
||||||
player->pause();
|
player->pause();
|
||||||
} else if (mediaState == QMediaPlayer::State::StoppedState) {
|
}
|
||||||
|
else if (mediaState == QMediaPlayer::State::StoppedState) {
|
||||||
player->stop();
|
player->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << "QML Audio changed to " << deviceName;
|
}
|
||||||
|
qDebug() << "QML Audio changed to " << _newTargetDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _newTargetDevice;
|
QString _newTargetDevice;
|
||||||
QObject* _container;
|
QSharedPointer<OffscreenQmlSurface> _surface;
|
||||||
int _runDelayMs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OffscreenTextures {
|
class OffscreenTextures {
|
||||||
|
@ -502,6 +497,7 @@ QOpenGLContext* OffscreenQmlSurface::getSharedContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::cleanup() {
|
void OffscreenQmlSurface::cleanup() {
|
||||||
|
_isCleaned = true;
|
||||||
_canvas->makeCurrent();
|
_canvas->makeCurrent();
|
||||||
|
|
||||||
_renderControl->invalidate();
|
_renderControl->invalidate();
|
||||||
|
@ -600,6 +596,7 @@ OffscreenQmlSurface::OffscreenQmlSurface() {
|
||||||
|
|
||||||
OffscreenQmlSurface::~OffscreenQmlSurface() {
|
OffscreenQmlSurface::~OffscreenQmlSurface() {
|
||||||
QObject::disconnect(&_updateTimer);
|
QObject::disconnect(&_updateTimer);
|
||||||
|
disconnectAudioOutputTimer();
|
||||||
QObject::disconnect(qApp);
|
QObject::disconnect(qApp);
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -613,6 +610,15 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
||||||
void OffscreenQmlSurface::onAboutToQuit() {
|
void OffscreenQmlSurface::onAboutToQuit() {
|
||||||
_paused = true;
|
_paused = true;
|
||||||
QObject::disconnect(&_updateTimer);
|
QObject::disconnect(&_updateTimer);
|
||||||
|
disconnectAudioOutputTimer();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OffscreenQmlSurface::disconnectAudioOutputTimer() {
|
||||||
|
if (_audioOutputUpdateTimer.isActive()) {
|
||||||
|
_audioOutputUpdateTimer.stop();
|
||||||
|
}
|
||||||
|
QObject::disconnect(&_audioOutputUpdateTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::create() {
|
void OffscreenQmlSurface::create() {
|
||||||
|
@ -671,6 +677,14 @@ void OffscreenQmlSurface::create() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Setup the update of the QML media components with the current audio output device
|
||||||
|
QObject::connect(&_audioOutputUpdateTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
new AudioHandler(sharedFromThis(), _currentAudioOutputDevice);
|
||||||
|
});
|
||||||
|
int waitForAudioQmlMs = 200;
|
||||||
|
_audioOutputUpdateTimer.setInterval(waitForAudioQmlMs);
|
||||||
|
_audioOutputUpdateTimer.setSingleShot(true);
|
||||||
|
|
||||||
// When Quick says there is a need to render, we will not render immediately. Instead,
|
// When Quick says there is a need to render, we will not render immediately. Instead,
|
||||||
// a timer with a small interval is used to get better performance.
|
// a timer with a small interval is used to get better performance.
|
||||||
QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||||
|
@ -699,10 +713,11 @@ void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() {
|
||||||
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
|
||||||
} else {
|
} else {
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
auto audioIO = DependencyManager::get<AudioClient>();
|
||||||
QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName();
|
_currentAudioOutputDevice = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName();
|
||||||
int waitForAudioQmlMs = 500;
|
if (_audioOutputUpdateTimer.isActive()) {
|
||||||
// The audio device need to be change using oth
|
_audioOutputUpdateTimer.stop();
|
||||||
new AudioHandler(_rootItem, deviceName, waitForAudioQmlMs);
|
}
|
||||||
|
_audioOutputUpdateTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class QQuickItem;
|
||||||
|
|
||||||
using QmlContextCallback = std::function<void(QQmlContext*, QObject*)>;
|
using QmlContextCallback = std::function<void(QQmlContext*, QObject*)>;
|
||||||
|
|
||||||
class OffscreenQmlSurface : public QObject {
|
class OffscreenQmlSurface : public QObject, public QEnableSharedFromThis<OffscreenQmlSurface> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
|
Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
|
||||||
public:
|
public:
|
||||||
|
@ -75,6 +75,7 @@ public:
|
||||||
void pause();
|
void pause();
|
||||||
void resume();
|
void resume();
|
||||||
bool isPaused() const;
|
bool isPaused() const;
|
||||||
|
bool getCleaned() { return _isCleaned; }
|
||||||
|
|
||||||
void setBaseUrl(const QUrl& baseUrl);
|
void setBaseUrl(const QUrl& baseUrl);
|
||||||
QQuickItem* getRootItem();
|
QQuickItem* getRootItem();
|
||||||
|
@ -116,6 +117,7 @@ public slots:
|
||||||
void changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate = false);
|
void changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate = false);
|
||||||
void forceHtmlAudioOutputDeviceUpdate();
|
void forceHtmlAudioOutputDeviceUpdate();
|
||||||
void forceQmlAudioOutputDeviceUpdate();
|
void forceQmlAudioOutputDeviceUpdate();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void audioOutputDeviceChanged(const QString& deviceName);
|
void audioOutputDeviceChanged(const QString& deviceName);
|
||||||
|
|
||||||
|
@ -147,6 +149,7 @@ private:
|
||||||
void render();
|
void render();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
QJsonObject getGLContextData();
|
QJsonObject getGLContextData();
|
||||||
|
void disconnectAudioOutputTimer();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateQuick();
|
void updateQuick();
|
||||||
|
@ -170,6 +173,9 @@ private:
|
||||||
uint64_t _lastRenderTime { 0 };
|
uint64_t _lastRenderTime { 0 };
|
||||||
uvec2 _size;
|
uvec2 _size;
|
||||||
|
|
||||||
|
QTimer _audioOutputUpdateTimer;
|
||||||
|
QString _currentAudioOutputDevice;
|
||||||
|
|
||||||
// Texture management
|
// Texture management
|
||||||
TextureAndFence _latestTextureAndFence { 0, 0 };
|
TextureAndFence _latestTextureAndFence { 0, 0 };
|
||||||
|
|
||||||
|
@ -177,6 +183,7 @@ private:
|
||||||
bool _polish { true };
|
bool _polish { true };
|
||||||
bool _paused { true };
|
bool _paused { true };
|
||||||
bool _focusText { false };
|
bool _focusText { false };
|
||||||
|
bool _isCleaned{ false };
|
||||||
uint8_t _maxFps { 60 };
|
uint8_t _maxFps { 60 };
|
||||||
MouseTranslator _mouseTranslator { [](const QPointF& p) { return p.toPoint(); } };
|
MouseTranslator _mouseTranslator { [](const QPointF& p) { return p.toPoint(); } };
|
||||||
QWindow* _proxyWindow { nullptr };
|
QWindow* _proxyWindow { nullptr };
|
||||||
|
|
|
@ -337,6 +337,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
|
||||||
_poseStateMap.clear();
|
_poseStateMap.clear();
|
||||||
_buttonPressedMap.clear();
|
_buttonPressedMap.clear();
|
||||||
_validTrackedObjects.clear();
|
_validTrackedObjects.clear();
|
||||||
|
_trackedControllers = 0;
|
||||||
|
|
||||||
// While the keyboard is open, we defer strictly to the keyboard values
|
// While the keyboard is open, we defer strictly to the keyboard values
|
||||||
if (isOpenVrKeyboardShown()) {
|
if (isOpenVrKeyboardShown()) {
|
||||||
|
@ -369,14 +370,12 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int numTrackedControllers = 0;
|
|
||||||
if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
|
if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
|
||||||
numTrackedControllers++;
|
_trackedControllers++;
|
||||||
}
|
}
|
||||||
if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
|
if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
|
||||||
numTrackedControllers++;
|
_trackedControllers++;
|
||||||
}
|
}
|
||||||
_trackedControllers = numTrackedControllers;
|
|
||||||
|
|
||||||
calibrateFromHandController(inputCalibrationData);
|
calibrateFromHandController(inputCalibrationData);
|
||||||
calibrateFromUI(inputCalibrationData);
|
calibrateFromUI(inputCalibrationData);
|
||||||
|
@ -527,6 +526,7 @@ void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceInde
|
||||||
|
|
||||||
// but _validTrackedObjects remain in sensor frame
|
// but _validTrackedObjects remain in sensor frame
|
||||||
_validTrackedObjects.push_back(std::make_pair(poseIndex, pose));
|
_validTrackedObjects.push_back(std::make_pair(poseIndex, pose));
|
||||||
|
_trackedControllers++;
|
||||||
} else {
|
} else {
|
||||||
controller::Pose invalidPose;
|
controller::Pose invalidPose;
|
||||||
_poseStateMap[poseIndex] = invalidPose;
|
_poseStateMap[poseIndex] = invalidPose;
|
||||||
|
@ -758,9 +758,9 @@ void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const c
|
||||||
} else {
|
} else {
|
||||||
const mat4& mat = mat4();
|
const mat4& mat = mat4();
|
||||||
const vec3 zero = vec3();
|
const vec3 zero = vec3();
|
||||||
|
|
||||||
handleHeadPoseEvent(inputCalibrationData, mat, zero, zero);
|
handleHeadPoseEvent(inputCalibrationData, mat, zero, zero);
|
||||||
}
|
}
|
||||||
|
_trackedControllers++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
|
|
||||||
this.pointingAtTablet = function(controllerData) {
|
this.pointingAtTablet = function(controllerData) {
|
||||||
var rayPick = controllerData.rayPicks[this.hand];
|
var rayPick = controllerData.rayPicks[this.hand];
|
||||||
return (rayPick.objectID === HMD.tabletScreenID || rayPick.objectID === HMD.homeButtonID);
|
return (HMD.tabletScreenID && HMD.homeButtonID && (rayPick.objectID === HMD.tabletScreenID || rayPick.objectID === HMD.homeButtonID));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getOtherModule = function() {
|
this.getOtherModule = function() {
|
||||||
|
|
|
@ -81,7 +81,8 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.otherHandIsParent = function(props) {
|
this.otherHandIsParent = function(props) {
|
||||||
return this.getOtherModule().thisHandIsParent(props);
|
var otherModule = this.getOtherModule();
|
||||||
|
return (otherModule.thisHandIsParent(props) && otherModule.grabbing);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.startNearParentingGrabEntity = function (controllerData, targetProps) {
|
this.startNearParentingGrabEntity = function (controllerData, targetProps) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ var toolBar = (function() {
|
||||||
y: -TOOLBAR_MARGIN_Y - toolHeight
|
y: -TOOLBAR_MARGIN_Y - toolHeight
|
||||||
});
|
});
|
||||||
browseDirectoryButton = toolBar.addTool({
|
browseDirectoryButton = toolBar.addTool({
|
||||||
imageURL: toolIconUrl + "directory-01.svg",
|
imageURL: toolIconUrl + "directory.svg",
|
||||||
subImage: {
|
subImage: {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: Tool.IMAGE_WIDTH,
|
y: Tool.IMAGE_WIDTH,
|
||||||
|
|
|
@ -112,8 +112,8 @@ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
|
||||||
|
|
||||||
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
||||||
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
||||||
var MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "Show Lights and Particle Systems in Edit Mode";
|
var MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "Show Lights and Particle Systems in Create Mode";
|
||||||
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode";
|
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Create Mode";
|
||||||
|
|
||||||
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
|
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
|
||||||
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
|
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
|
||||||
|
|
|
@ -1415,6 +1415,9 @@ input#reset-to-natural-dimensions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- Order of Menu items for Primitive ----- */
|
/* ----- Order of Menu items for Primitive ----- */
|
||||||
|
/* Entity Menu classes are specified by selected entity
|
||||||
|
within entityProperties.js
|
||||||
|
*/
|
||||||
#properties-list.ShapeMenu #general,
|
#properties-list.ShapeMenu #general,
|
||||||
#properties-list.BoxMenu #general,
|
#properties-list.BoxMenu #general,
|
||||||
#properties-list.SphereMenu #general {
|
#properties-list.SphereMenu #general {
|
||||||
|
@ -1469,6 +1472,34 @@ input#reset-to-natural-dimensions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----- ParticleEffectMenu ----- */
|
||||||
|
#properties-list.ParticleEffectMenu #general {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
#properties-list.ParticleEffectMenu #collision-info {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
#properties-list.ParticleEffectMenu #physical {
|
||||||
|
order: 3;
|
||||||
|
}
|
||||||
|
#properties-list.ParticleEffectMenu #spatial {
|
||||||
|
order: 4;
|
||||||
|
}
|
||||||
|
#properties-list.ParticleEffectMenu #behavior {
|
||||||
|
order: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* items to hide */
|
||||||
|
#properties-list.ParticleEffectMenu #base-color-section,
|
||||||
|
#properties-list.ParticleEffectMenu #hyperlink,
|
||||||
|
#properties-list.ParticleEffectMenu #light,
|
||||||
|
#properties-list.ParticleEffectMenu #model,
|
||||||
|
#properties-list.ParticleEffectMenu #shape-list,
|
||||||
|
#properties-list.ParticleEffectMenu #text,
|
||||||
|
#properties-list.ParticleEffectMenu #web,
|
||||||
|
#properties-list.ParticleEffectMenu #zone {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----- Order of Menu items for Light ----- */
|
/* ----- Order of Menu items for Light ----- */
|
||||||
#properties-list.LightMenu #general {
|
#properties-list.LightMenu #general {
|
||||||
|
@ -1500,8 +1531,8 @@ input#reset-to-natural-dimensions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
/* items to hide */
|
/* items to hide */
|
||||||
#properties-list.LightMenu .shape-group.shape-section.property.dropdown,
|
#properties-list.LightMenu #shape-list,
|
||||||
#properties-list.LightMenu color-section.color-control1 {
|
#properties-list.LightMenu #base-color-section {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1536,8 +1567,8 @@ input#reset-to-natural-dimensions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
/* items to hide */
|
/* items to hide */
|
||||||
#properties-list.ModelMenu .shape-group.shape-section.property.dropdown,
|
#properties-list.ModelMenu #shape-list,
|
||||||
#properties-list.ModelMenu .color-section.color-control1 {
|
#properties-list.ModelMenu #base-color-section {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1572,8 +1603,8 @@ input#reset-to-natural-dimensions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
/* items to hide */
|
/* items to hide */
|
||||||
#properties-list.ZoneMenu .shape-group.shape-section.property.dropdown,
|
#properties-list.ZoneMenu #shape-list,
|
||||||
#properties-list.ZoneMenu .color-section.color-control1 {
|
#properties-list.ZoneMenu #base-color-section {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1608,8 +1639,8 @@ input#reset-to-natural-dimensions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
/* items to hide */
|
/* items to hide */
|
||||||
#properties-list.WebMenu .shape-group.shape-section.property.dropdown,
|
#properties-list.WebMenu #shape-list,
|
||||||
#properties-list.WebMenu .color-section.color-control1 {
|
#properties-list.WebMenu #base-color-section {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1645,8 +1676,8 @@ input#reset-to-natural-dimensions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
/* items to hide */
|
/* items to hide */
|
||||||
#properties-list.TextMenu .shape-group.shape-section.property.dropdown,
|
#properties-list.TextMenu #shape-list,
|
||||||
#properties-list.TextMenu .color-section.color-control1 {
|
#properties-list.TextMenu #base-color-section {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
|
|
||||||
|
|
||||||
<fieldset id="general" class="major">
|
<fieldset id="general" class="major">
|
||||||
<div class="shape-group shape-section property dropdown">
|
<div class="shape-group shape-section property dropdown" id="shape-list">
|
||||||
<label for="property-shape">Shape</label>
|
<label for="property-shape">Shape</label>
|
||||||
<select name="SelectShape" id="property-shape">
|
<select name="SelectShape" id="property-shape">
|
||||||
<option value="Cube">Box</option>
|
<option value="Cube">Box</option>
|
||||||
|
@ -66,12 +66,19 @@
|
||||||
<label for="property-name">Name</label>
|
<label for="property-name">Name</label>
|
||||||
<input type="text" id="property-name">
|
<input type="text" id="property-name">
|
||||||
</div>
|
</div>
|
||||||
<div class="physical-group color-section property color-control1">
|
<div class="physical-group color-section property rgb fstuple" id="base-color-section">
|
||||||
<div class="color-picker" id="property-color-control1"></div>
|
<div class="color-picker" id="property-color-control2"></div>
|
||||||
<label>Entity color</label>
|
<label>Entity color</label>
|
||||||
|
<div class="tuple">
|
||||||
|
<div><input type="number" class="red" id="property-color-red"><label for="property-color-red">Red:</label></div>
|
||||||
|
<div><input type="number" class="green" id="property-color-green"><label for="property-color-green">Green:</label></div>
|
||||||
|
<div><input type="number" class="blue" id="property-color-blue"><label for="property-color-blue">Blue:</label></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset id="collision-info">
|
|
||||||
|
<fieldset id="collision-info" class="major">
|
||||||
|
<legend class="section-header"> Collision<span>M</span> </legend>
|
||||||
<fieldset class="minor">
|
<fieldset class="minor">
|
||||||
<div class="behavior-group property checkbox">
|
<div class="behavior-group property checkbox">
|
||||||
<input type="checkbox" id="property-collisionless">
|
<input type="checkbox" id="property-collisionless">
|
||||||
|
@ -216,17 +223,6 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="minor">
|
|
||||||
<div class="physical-group color-section property rgb fstuple">
|
|
||||||
<div class="color-picker" id="property-color-control2"></div>
|
|
||||||
<label>Entity color</label>
|
|
||||||
<div class="tuple">
|
|
||||||
<div><input type="number" class="red" id="property-color-red"><label for="property-color-red">Red:</label></div>
|
|
||||||
<div><input type="number" class="green" id="property-color-green"><label for="property-color-green">Green:</label></div>
|
|
||||||
<div><input type="number" class="blue" id="property-color-blue"><label for="property-color-blue">Blue:</label></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// 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 alert, augmentSpinButtons, clearTimeout, console, document, Element, EventBridge,
|
||||||
|
HifiEntityUI, JSONEditor, openEventBridge, setUpKeyboardControl, setTimeout, window, _ $ */
|
||||||
|
|
||||||
var PI = 3.14159265358979;
|
var PI = 3.14159265358979;
|
||||||
var DEGREES_TO_RADIANS = PI / 180.0;
|
var DEGREES_TO_RADIANS = PI / 180.0;
|
||||||
var RADIANS_TO_DEGREES = 180.0 / PI;
|
var RADIANS_TO_DEGREES = 180.0 / PI;
|
||||||
|
@ -22,33 +25,33 @@ var ICON_FOR_TYPE = {
|
||||||
PolyVox: "",
|
PolyVox: "",
|
||||||
Multiple: "",
|
Multiple: "",
|
||||||
PolyLine: ""
|
PolyLine: ""
|
||||||
}
|
};
|
||||||
|
|
||||||
var EDITOR_TIMEOUT_DURATION = 1500;
|
var EDITOR_TIMEOUT_DURATION = 1500;
|
||||||
const KEY_P = 80; //Key code for letter p used for Parenting hotkey.
|
var KEY_P = 80; // Key code for letter p used for Parenting hotkey.
|
||||||
var colorPickers = [];
|
var colorPickers = [];
|
||||||
var lastEntityID = null;
|
var lastEntityID = null;
|
||||||
|
|
||||||
debugPrint = function(message) {
|
function debugPrint(message) {
|
||||||
EventBridge.emitWebEvent(
|
EventBridge.emitWebEvent(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: "print",
|
type: "print",
|
||||||
message: message
|
message: message
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
function enableChildren(el, selector) {
|
function enableChildren(el, selector) {
|
||||||
els = el.querySelectorAll(selector);
|
var elSelectors = el.querySelectorAll(selector);
|
||||||
for (var i = 0; i < els.length; i++) {
|
for (var selectorIndex = 0; selectorIndex < elSelectors.length; ++selectorIndex) {
|
||||||
els[i].removeAttribute('disabled');
|
elSelectors[selectorIndex].removeAttribute('disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableChildren(el, selector) {
|
function disableChildren(el, selector) {
|
||||||
els = el.querySelectorAll(selector);
|
var elSelectors = el.querySelectorAll(selector);
|
||||||
for (var i = 0; i < els.length; i++) {
|
for (var selectorIndex = 0; selectorIndex < elSelectors.length; ++selectorIndex) {
|
||||||
els[i].setAttribute('disabled', 'disabled');
|
elSelectors[selectorIndex].setAttribute('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,16 +106,6 @@ function createEmitCheckedPropertyUpdateFunction(propertyName) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmitCheckedToStringPropertyUpdateFunction(checkboxElement, name, propertyName) {
|
|
||||||
var newString = "";
|
|
||||||
if (checkboxElement.checked) {
|
|
||||||
newString += name + "";
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEmitGroupCheckedPropertyUpdateFunction(group, propertyName) {
|
function createEmitGroupCheckedPropertyUpdateFunction(group, propertyName) {
|
||||||
return function() {
|
return function() {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
|
@ -123,7 +116,7 @@ function createEmitGroupCheckedPropertyUpdateFunction(group, propertyName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmitNumberPropertyUpdateFunction(propertyName, decimals) {
|
function createEmitNumberPropertyUpdateFunction(propertyName, decimals) {
|
||||||
decimals = decimals == undefined ? 4 : decimals;
|
decimals = ((decimals === undefined) ? 4 : decimals);
|
||||||
return function() {
|
return function() {
|
||||||
var value = parseFloat(this.value).toFixed(decimals);
|
var value = parseFloat(this.value).toFixed(decimals);
|
||||||
updateProperty(propertyName, value);
|
updateProperty(propertyName, value);
|
||||||
|
@ -146,7 +139,9 @@ function createEmitTextPropertyUpdateFunction(propertyName) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createZoneComponentModeChangedFunction(zoneComponent, zoneComponentModeInherit, zoneComponentModeDisabled, zoneComponentModeEnabled) {
|
function createZoneComponentModeChangedFunction(zoneComponent, zoneComponentModeInherit,
|
||||||
|
zoneComponentModeDisabled, zoneComponentModeEnabled) {
|
||||||
|
|
||||||
return function() {
|
return function() {
|
||||||
var zoneComponentMode;
|
var zoneComponentMode;
|
||||||
|
|
||||||
|
@ -159,7 +154,7 @@ function createZoneComponentModeChangedFunction(zoneComponent, zoneComponentMode
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProperty(zoneComponent, zoneComponentMode);
|
updateProperty(zoneComponent, zoneComponentMode);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmitGroupTextPropertyUpdateFunction(group, propertyName) {
|
function createEmitGroupTextPropertyUpdateFunction(group, propertyName) {
|
||||||
|
@ -177,11 +172,11 @@ function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) {
|
||||||
properties[property] = {
|
properties[property] = {
|
||||||
x: elX.value,
|
x: elX.value,
|
||||||
y: elY.value,
|
y: elY.value,
|
||||||
z: elZ.value,
|
z: elZ.value
|
||||||
};
|
};
|
||||||
updateProperties(properties);
|
updateProperties(properties);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, elZ) {
|
function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, elZ) {
|
||||||
return function() {
|
return function() {
|
||||||
|
@ -190,11 +185,11 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el
|
||||||
properties[group][property] = {
|
properties[group][property] = {
|
||||||
x: elX.value,
|
x: elX.value,
|
||||||
y: elY.value,
|
y: elY.value,
|
||||||
z: elZ ? elZ.value : 0,
|
z: elZ ? elZ.value : 0
|
||||||
};
|
};
|
||||||
updateProperties(properties);
|
updateProperties(properties);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) {
|
function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) {
|
||||||
return function() {
|
return function() {
|
||||||
|
@ -202,17 +197,17 @@ function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY,
|
||||||
properties[property] = {
|
properties[property] = {
|
||||||
x: elX.value * multiplier,
|
x: elX.value * multiplier,
|
||||||
y: elY.value * multiplier,
|
y: elY.value * multiplier,
|
||||||
z: elZ.value * multiplier,
|
z: elZ.value * multiplier
|
||||||
};
|
};
|
||||||
updateProperties(properties);
|
updateProperties(properties);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createEmitColorPropertyUpdateFunction(property, elRed, elGreen, elBlue) {
|
function createEmitColorPropertyUpdateFunction(property, elRed, elGreen, elBlue) {
|
||||||
return function() {
|
return function() {
|
||||||
emitColorPropertyUpdate(property, elRed.value, elGreen.value, elBlue.value);
|
emitColorPropertyUpdate(property, elRed.value, elGreen.value, elBlue.value);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function emitColorPropertyUpdate(property, red, green, blue, group) {
|
function emitColorPropertyUpdate(property, red, green, blue, group) {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
|
@ -221,17 +216,17 @@ function emitColorPropertyUpdate(property, red, green, blue, group) {
|
||||||
properties[group][property] = {
|
properties[group][property] = {
|
||||||
red: red,
|
red: red,
|
||||||
green: green,
|
green: green,
|
||||||
blue: blue,
|
blue: blue
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
properties[property] = {
|
properties[property] = {
|
||||||
red: red,
|
red: red,
|
||||||
green: green,
|
green: green,
|
||||||
blue: blue,
|
blue: blue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
updateProperties(properties);
|
updateProperties(properties);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGreen, elBlue) {
|
function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGreen, elBlue) {
|
||||||
|
@ -241,11 +236,11 @@ function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGr
|
||||||
properties[group][property] = {
|
properties[group][property] = {
|
||||||
red: elRed.value,
|
red: elRed.value,
|
||||||
green: elGreen.value,
|
green: elGreen.value,
|
||||||
blue: elBlue.value,
|
blue: elBlue.value
|
||||||
};
|
};
|
||||||
updateProperties(properties);
|
updateProperties(properties);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function updateCheckedSubProperty(propertyName, propertyValue, subPropertyElement, subPropertyString) {
|
function updateCheckedSubProperty(propertyName, propertyValue, subPropertyElement, subPropertyString) {
|
||||||
if (subPropertyElement.checked) {
|
if (subPropertyElement.checked) {
|
||||||
|
@ -264,12 +259,12 @@ function setUserDataFromEditor(noUpdate) {
|
||||||
try {
|
try {
|
||||||
json = editor.get();
|
json = editor.get();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert('Invalid JSON code - look for red X in your code ', +e)
|
alert('Invalid JSON code - look for red X in your code ', +e);
|
||||||
}
|
}
|
||||||
if (json === null) {
|
if (json === null) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
var text = editor.getText()
|
var text = editor.getText();
|
||||||
if (noUpdate === true) {
|
if (noUpdate === true) {
|
||||||
EventBridge.emitWebEvent(
|
EventBridge.emitWebEvent(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
@ -277,7 +272,7 @@ function setUserDataFromEditor(noUpdate) {
|
||||||
type: "saveUserData",
|
type: "saveUserData",
|
||||||
properties: {
|
properties: {
|
||||||
userData: text
|
userData: text
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -297,10 +292,12 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) {
|
||||||
} else {
|
} else {
|
||||||
parsedData = JSON.parse(userDataElement.value);
|
parsedData = JSON.parse(userDataElement.value);
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
// TODO: Should an alert go here?
|
||||||
|
}
|
||||||
|
|
||||||
if (!(groupName in parsedData)) {
|
if (!(groupName in parsedData)) {
|
||||||
parsedData[groupName] = {}
|
parsedData[groupName] = {};
|
||||||
}
|
}
|
||||||
var keys = Object.keys(updateKeyPair);
|
var keys = Object.keys(updateKeyPair);
|
||||||
keys.forEach(function (key) {
|
keys.forEach(function (key) {
|
||||||
|
@ -322,16 +319,16 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (Object.keys(parsedData[groupName]).length == 0) {
|
if (Object.keys(parsedData[groupName]).length === 0) {
|
||||||
delete parsedData[groupName];
|
delete parsedData[groupName];
|
||||||
}
|
}
|
||||||
if (Object.keys(parsedData).length > 0) {
|
if (Object.keys(parsedData).length > 0) {
|
||||||
properties['userData'] = JSON.stringify(parsedData);
|
properties.userData = JSON.stringify(parsedData);
|
||||||
} else {
|
} else {
|
||||||
properties['userData'] = '';
|
properties.userData = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
userDataElement.value = properties['userData'];
|
userDataElement.value = properties.userData;
|
||||||
|
|
||||||
updateProperties(properties);
|
updateProperties(properties);
|
||||||
}
|
}
|
||||||
|
@ -340,13 +337,12 @@ function userDataChanger(groupName, keyName, values, userDataElement, defaultVal
|
||||||
val[keyName] = values;
|
val[keyName] = values;
|
||||||
def[keyName] = defaultValue;
|
def[keyName] = defaultValue;
|
||||||
multiDataUpdater(groupName, val, userDataElement, def);
|
multiDataUpdater(groupName, val, userDataElement, def);
|
||||||
};
|
}
|
||||||
|
|
||||||
function setTextareaScrolling(element) {
|
function setTextareaScrolling(element) {
|
||||||
var isScrolling = element.scrollHeight > element.offsetHeight;
|
var isScrolling = element.scrollHeight > element.offsetHeight;
|
||||||
element.setAttribute("scrolling", isScrolling ? "true" : "false");
|
element.setAttribute("scrolling", isScrolling ? "true" : "false");
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var editor = null;
|
var editor = null;
|
||||||
|
@ -364,7 +360,7 @@ function createJSONEditor() {
|
||||||
$('.jsoneditor-poweredBy').remove();
|
$('.jsoneditor-poweredBy').remove();
|
||||||
},
|
},
|
||||||
onError: function(e) {
|
onError: function(e) {
|
||||||
alert('JSON editor:' + e)
|
alert('JSON editor:' + e);
|
||||||
},
|
},
|
||||||
onChange: function() {
|
onChange: function() {
|
||||||
var currentJSONString = editor.getText();
|
var currentJSONString = editor.getText();
|
||||||
|
@ -372,22 +368,22 @@ function createJSONEditor() {
|
||||||
if (currentJSONString === '{"":""}') {
|
if (currentJSONString === '{"":""}') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$('#userdata-save').attr('disabled', false)
|
$('#userdata-save').attr('disabled', false);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
editor = new JSONEditor(container, options);
|
editor = new JSONEditor(container, options);
|
||||||
};
|
}
|
||||||
|
|
||||||
function hideNewJSONEditorButton() {
|
function hideNewJSONEditorButton() {
|
||||||
$('#userdata-new-editor').hide();
|
$('#userdata-new-editor').hide();
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
function hideClearUserDataButton() {
|
function hideClearUserDataButton() {
|
||||||
$('#userdata-clear').hide();
|
$('#userdata-clear').hide();
|
||||||
};
|
}
|
||||||
|
|
||||||
function showSaveUserDataButton() {
|
function showSaveUserDataButton() {
|
||||||
$('#userdata-save').show();
|
$('#userdata-save').show();
|
||||||
|
@ -401,65 +397,65 @@ function hideSaveUserDataButton() {
|
||||||
function showNewJSONEditorButton() {
|
function showNewJSONEditorButton() {
|
||||||
$('#userdata-new-editor').show();
|
$('#userdata-new-editor').show();
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
function showClearUserDataButton() {
|
function showClearUserDataButton() {
|
||||||
$('#userdata-clear').show();
|
$('#userdata-clear').show();
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
function showUserDataTextArea() {
|
function showUserDataTextArea() {
|
||||||
$('#property-user-data').show();
|
$('#property-user-data').show();
|
||||||
};
|
}
|
||||||
|
|
||||||
function hideUserDataTextArea() {
|
function hideUserDataTextArea() {
|
||||||
$('#property-user-data').hide();
|
$('#property-user-data').hide();
|
||||||
};
|
}
|
||||||
|
|
||||||
function showStaticUserData() {
|
function showStaticUserData() {
|
||||||
if (editor !== null) {
|
if (editor !== null) {
|
||||||
$('#static-userdata').show();
|
$('#static-userdata').show();
|
||||||
$('#static-userdata').css('height', $('#userdata-editor').height())
|
$('#static-userdata').css('height', $('#userdata-editor').height());
|
||||||
$('#static-userdata').text(editor.getText());
|
$('#static-userdata').text(editor.getText());
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function removeStaticUserData() {
|
function removeStaticUserData() {
|
||||||
$('#static-userdata').hide();
|
$('#static-userdata').hide();
|
||||||
};
|
}
|
||||||
|
|
||||||
function setEditorJSON(json) {
|
function setEditorJSON(json) {
|
||||||
editor.set(json)
|
editor.set(json);
|
||||||
if (editor.hasOwnProperty('expandAll')) {
|
if (editor.hasOwnProperty('expandAll')) {
|
||||||
editor.expandAll();
|
editor.expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
function getEditorJSON() {
|
function getEditorJSON() {
|
||||||
return editor.get();
|
return editor.get();
|
||||||
};
|
}
|
||||||
|
|
||||||
function deleteJSONEditor() {
|
function deleteJSONEditor() {
|
||||||
if (editor !== null) {
|
if (editor !== null) {
|
||||||
editor.destroy();
|
editor.destroy();
|
||||||
editor = null;
|
editor = null;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
var savedJSONTimer = null;
|
var savedJSONTimer = null;
|
||||||
|
|
||||||
function saveJSONUserData(noUpdate) {
|
function saveJSONUserData(noUpdate) {
|
||||||
setUserDataFromEditor(noUpdate);
|
setUserDataFromEditor(noUpdate);
|
||||||
$('#userdata-saved').show();
|
$('#userdata-saved').show();
|
||||||
$('#userdata-save').attr('disabled', true)
|
$('#userdata-save').attr('disabled', true);
|
||||||
if (savedJSONTimer !== null) {
|
if (savedJSONTimer !== null) {
|
||||||
clearTimeout(savedJSONTimer);
|
clearTimeout(savedJSONTimer);
|
||||||
}
|
}
|
||||||
savedJSONTimer = setTimeout(function() {
|
savedJSONTimer = setTimeout(function() {
|
||||||
$('#userdata-saved').hide();
|
$('#userdata-saved').hide();
|
||||||
|
|
||||||
}, 1500)
|
}, EDITOR_TIMEOUT_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindAllNonJSONEditorElements() {
|
function bindAllNonJSONEditorElements() {
|
||||||
|
@ -468,6 +464,8 @@ function bindAllNonJSONEditorElements() {
|
||||||
for (i = 0; i < inputs.length; i++) {
|
for (i = 0; i < inputs.length; i++) {
|
||||||
var input = inputs[i];
|
var input = inputs[i];
|
||||||
var field = $(input);
|
var field = $(input);
|
||||||
|
// TODO FIXME: (JSHint) Functions declared within loops referencing
|
||||||
|
// an outer scoped variable may lead to confusing semantics.
|
||||||
field.on('focus', function(e) {
|
field.on('focus', function(e) {
|
||||||
if (e.target.id === "userdata-new-editor" || e.target.id === "userdata-clear") {
|
if (e.target.id === "userdata-new-editor" || e.target.id === "userdata-clear") {
|
||||||
return;
|
return;
|
||||||
|
@ -477,7 +475,7 @@ function bindAllNonJSONEditorElements() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,7 +501,6 @@ function clearSelection() {
|
||||||
function loaded() {
|
function loaded() {
|
||||||
openEventBridge(function() {
|
openEventBridge(function() {
|
||||||
|
|
||||||
var allSections = [];
|
|
||||||
var elPropertiesList = document.getElementById("properties-list");
|
var elPropertiesList = document.getElementById("properties-list");
|
||||||
var elID = document.getElementById("property-id");
|
var elID = document.getElementById("property-id");
|
||||||
var elType = document.getElementById("property-type");
|
var elType = document.getElementById("property-type");
|
||||||
|
@ -589,21 +586,14 @@ function loaded() {
|
||||||
var elUserData = document.getElementById("property-user-data");
|
var elUserData = document.getElementById("property-user-data");
|
||||||
var elClearUserData = document.getElementById("userdata-clear");
|
var elClearUserData = document.getElementById("userdata-clear");
|
||||||
var elSaveUserData = document.getElementById("userdata-save");
|
var elSaveUserData = document.getElementById("userdata-save");
|
||||||
var elJSONEditor = document.getElementById("userdata-editor");
|
|
||||||
var elNewJSONEditor = document.getElementById('userdata-new-editor');
|
var elNewJSONEditor = document.getElementById('userdata-new-editor');
|
||||||
var elColorSections = document.querySelectorAll(".color-section");
|
var elColorControlVariant2 = document.getElementById("property-color-control2");
|
||||||
var elColorControl1 = document.getElementById("property-color-control1");
|
|
||||||
var elColorControl2 = document.getElementById("property-color-control2");
|
|
||||||
var elColorRed = document.getElementById("property-color-red");
|
var elColorRed = document.getElementById("property-color-red");
|
||||||
var elColorGreen = document.getElementById("property-color-green");
|
var elColorGreen = document.getElementById("property-color-green");
|
||||||
var elColorBlue = document.getElementById("property-color-blue");
|
var elColorBlue = document.getElementById("property-color-blue");
|
||||||
|
|
||||||
var elShapeSections = document.querySelectorAll(".shape-section");
|
|
||||||
allSections.push(elShapeSections);
|
|
||||||
var elShape = document.getElementById("property-shape");
|
var elShape = document.getElementById("property-shape");
|
||||||
|
|
||||||
var elLightSections = document.querySelectorAll(".light-section");
|
|
||||||
allSections.push(elLightSections);
|
|
||||||
var elLightSpotLight = document.getElementById("property-light-spot-light");
|
var elLightSpotLight = document.getElementById("property-light-spot-light");
|
||||||
var elLightColor = document.getElementById("property-light-color");
|
var elLightColor = document.getElementById("property-light-color");
|
||||||
var elLightColorRed = document.getElementById("property-light-color-red");
|
var elLightColorRed = document.getElementById("property-light-color-red");
|
||||||
|
@ -615,8 +605,6 @@ function loaded() {
|
||||||
var elLightExponent = document.getElementById("property-light-exponent");
|
var elLightExponent = document.getElementById("property-light-exponent");
|
||||||
var elLightCutoff = document.getElementById("property-light-cutoff");
|
var elLightCutoff = document.getElementById("property-light-cutoff");
|
||||||
|
|
||||||
var elModelSections = document.querySelectorAll(".model-section");
|
|
||||||
allSections.push(elModelSections);
|
|
||||||
var elModelURL = document.getElementById("property-model-url");
|
var elModelURL = document.getElementById("property-model-url");
|
||||||
var elShapeType = document.getElementById("property-shape-type");
|
var elShapeType = document.getElementById("property-shape-type");
|
||||||
var elCompoundShapeURL = document.getElementById("property-compound-shape-url");
|
var elCompoundShapeURL = document.getElementById("property-compound-shape-url");
|
||||||
|
@ -632,8 +620,6 @@ function loaded() {
|
||||||
var elModelTextures = document.getElementById("property-model-textures");
|
var elModelTextures = document.getElementById("property-model-textures");
|
||||||
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
||||||
|
|
||||||
var elWebSections = document.querySelectorAll(".web-section");
|
|
||||||
allSections.push(elWebSections);
|
|
||||||
var elWebSourceURL = document.getElementById("property-web-source-url");
|
var elWebSourceURL = document.getElementById("property-web-source-url");
|
||||||
var elWebDPI = document.getElementById("property-web-dpi");
|
var elWebDPI = document.getElementById("property-web-dpi");
|
||||||
|
|
||||||
|
@ -641,11 +627,7 @@ function loaded() {
|
||||||
|
|
||||||
var elHyperlinkHref = document.getElementById("property-hyperlink-href");
|
var elHyperlinkHref = document.getElementById("property-hyperlink-href");
|
||||||
|
|
||||||
var elHyperlinkSections = document.querySelectorAll(".hyperlink-section");
|
|
||||||
|
|
||||||
|
|
||||||
var elTextSections = document.querySelectorAll(".text-section");
|
|
||||||
allSections.push(elTextSections);
|
|
||||||
var elTextText = document.getElementById("property-text-text");
|
var elTextText = document.getElementById("property-text-text");
|
||||||
var elTextLineHeight = document.getElementById("property-text-line-height");
|
var elTextLineHeight = document.getElementById("property-text-line-height");
|
||||||
var elTextTextColor = document.getElementById("property-text-text-color");
|
var elTextTextColor = document.getElementById("property-text-text-color");
|
||||||
|
@ -653,13 +635,10 @@ function loaded() {
|
||||||
var elTextTextColorRed = document.getElementById("property-text-text-color-red");
|
var elTextTextColorRed = document.getElementById("property-text-text-color-red");
|
||||||
var elTextTextColorGreen = document.getElementById("property-text-text-color-green");
|
var elTextTextColorGreen = document.getElementById("property-text-text-color-green");
|
||||||
var elTextTextColorBlue = document.getElementById("property-text-text-color-blue");
|
var elTextTextColorBlue = document.getElementById("property-text-text-color-blue");
|
||||||
var elTextBackgroundColor = document.getElementById("property-text-background-color");
|
|
||||||
var elTextBackgroundColorRed = document.getElementById("property-text-background-color-red");
|
var elTextBackgroundColorRed = document.getElementById("property-text-background-color-red");
|
||||||
var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green");
|
var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green");
|
||||||
var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue");
|
var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue");
|
||||||
|
|
||||||
var elZoneSections = document.querySelectorAll(".zone-section");
|
|
||||||
allSections.push(elZoneSections);
|
|
||||||
var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled");
|
var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled");
|
||||||
|
|
||||||
var elZoneKeyLightColor = document.getElementById("property-zone-key-light-color");
|
var elZoneKeyLightColor = document.getElementById("property-zone-key-light-color");
|
||||||
|
@ -670,7 +649,6 @@ function loaded() {
|
||||||
var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
||||||
var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x");
|
var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x");
|
||||||
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
||||||
var elZoneKeyLightDirectionZ = document.getElementById("property-zone-key-light-direction-z");
|
|
||||||
var elZoneKeyLightAmbientURL = document.getElementById("property-zone-key-ambient-url");
|
var elZoneKeyLightAmbientURL = document.getElementById("property-zone-key-ambient-url");
|
||||||
|
|
||||||
var elZoneHazeModeInherit = document.getElementById("property-zone-haze-mode-inherit");
|
var elZoneHazeModeInherit = document.getElementById("property-zone-haze-mode-inherit");
|
||||||
|
@ -695,10 +673,6 @@ function loaded() {
|
||||||
|
|
||||||
var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend");
|
var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend");
|
||||||
|
|
||||||
var elZoneHazeAttenuateKeyLight = document.getElementById("property-zone-haze-attenuate-keylight");
|
|
||||||
var elZoneHazeKeyLightRange = document.getElementById("property-zone-haze-keylight-range");
|
|
||||||
var elZoneHazeKeyLightAltitude = document.getElementById("property-zone-haze-keylight-altitude");
|
|
||||||
|
|
||||||
var elZoneStageLatitude = document.getElementById("property-zone-stage-latitude");
|
var elZoneStageLatitude = document.getElementById("property-zone-stage-latitude");
|
||||||
var elZoneStageLongitude = document.getElementById("property-zone-stage-longitude");
|
var elZoneStageLongitude = document.getElementById("property-zone-stage-longitude");
|
||||||
var elZoneStageAltitude = document.getElementById("property-zone-stage-altitude");
|
var elZoneStageAltitude = document.getElementById("property-zone-stage-altitude");
|
||||||
|
@ -718,8 +692,6 @@ function loaded() {
|
||||||
var elZoneGhostingAllowed = document.getElementById("property-zone-ghosting-allowed");
|
var elZoneGhostingAllowed = document.getElementById("property-zone-ghosting-allowed");
|
||||||
var elZoneFilterURL = document.getElementById("property-zone-filter-url");
|
var elZoneFilterURL = document.getElementById("property-zone-filter-url");
|
||||||
|
|
||||||
var elPolyVoxSections = document.querySelectorAll(".poly-vox-section");
|
|
||||||
allSections.push(elPolyVoxSections);
|
|
||||||
var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x");
|
var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x");
|
||||||
var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y");
|
var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y");
|
||||||
var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
|
var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
|
||||||
|
@ -732,7 +704,7 @@ function loaded() {
|
||||||
var properties;
|
var properties;
|
||||||
EventBridge.scriptEventReceived.connect(function(data) {
|
EventBridge.scriptEventReceived.connect(function(data) {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
if (data.type == "server_script_status") {
|
if (data.type === "server_script_status") {
|
||||||
elServerScriptError.value = data.errorInfo;
|
elServerScriptError.value = data.errorInfo;
|
||||||
// If we just set elServerScriptError's diplay to block or none, we still end up with
|
// If we just set elServerScriptError's diplay to block or none, we still end up with
|
||||||
// it's parent contributing 21px bottom padding even when elServerScriptError is display:none.
|
// it's parent contributing 21px bottom padding even when elServerScriptError is display:none.
|
||||||
|
@ -744,18 +716,18 @@ function loaded() {
|
||||||
var ENTITY_SCRIPT_STATUS = {
|
var ENTITY_SCRIPT_STATUS = {
|
||||||
pending: "Pending",
|
pending: "Pending",
|
||||||
loading: "Loading",
|
loading: "Loading",
|
||||||
error_loading_script: "Error loading script",
|
error_loading_script: "Error loading script", // eslint-disable-line camelcase
|
||||||
error_running_script: "Error running script",
|
error_running_script: "Error running script", // eslint-disable-line camelcase
|
||||||
running: "Running",
|
running: "Running",
|
||||||
unloaded: "Unloaded",
|
unloaded: "Unloaded"
|
||||||
};
|
};
|
||||||
elServerScriptStatus.innerText = ENTITY_SCRIPT_STATUS[data.status] || data.status;
|
elServerScriptStatus.innerText = ENTITY_SCRIPT_STATUS[data.status] || data.status;
|
||||||
} else {
|
} else {
|
||||||
elServerScriptStatus.innerText = "Not running";
|
elServerScriptStatus.innerText = "Not running";
|
||||||
}
|
}
|
||||||
} else if (data.type == "update") {
|
} else if (data.type === "update") {
|
||||||
|
|
||||||
if (!data.selections || data.selections.length == 0) {
|
if (!data.selections || data.selections.length === 0) {
|
||||||
if (editor !== null && lastEntityID !== null) {
|
if (editor !== null && lastEntityID !== null) {
|
||||||
saveJSONUserData(true);
|
saveJSONUserData(true);
|
||||||
deleteJSONEditor();
|
deleteJSONEditor();
|
||||||
|
@ -775,20 +747,19 @@ function loaded() {
|
||||||
|
|
||||||
for (var i = 0; i < selections.length; i++) {
|
for (var i = 0; i < selections.length; i++) {
|
||||||
ids.push(selections[i].id);
|
ids.push(selections[i].id);
|
||||||
var type = selections[i].properties.type;
|
var currentSelectedType = selections[i].properties.type;
|
||||||
if (types[type] === undefined) {
|
if (types[currentSelectedType] === undefined) {
|
||||||
types[type] = 0;
|
types[currentSelectedType] = 0;
|
||||||
numTypes += 1;
|
numTypes += 1;
|
||||||
}
|
}
|
||||||
types[type]++;
|
types[currentSelectedType]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
var type;
|
var type = "Multiple";
|
||||||
if (numTypes === 1) {
|
if (numTypes === 1) {
|
||||||
type = selections[0].properties.type;
|
type = selections[0].properties.type;
|
||||||
} else {
|
|
||||||
type = "Multiple";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elType.innerHTML = type + " (" + data.selections.length + ")";
|
elType.innerHTML = type + " (" + data.selections.length + ")";
|
||||||
elTypeIcon.innerHTML = ICON_FOR_TYPE[type];
|
elTypeIcon.innerHTML = ICON_FOR_TYPE[type];
|
||||||
elTypeIcon.style.display = "inline-block";
|
elTypeIcon.style.display = "inline-block";
|
||||||
|
@ -809,7 +780,9 @@ function loaded() {
|
||||||
lastEntityID = '"' + properties.id + '"';
|
lastEntityID = '"' + properties.id + '"';
|
||||||
elID.value = properties.id;
|
elID.value = properties.id;
|
||||||
|
|
||||||
|
// Create class name for css ruleset filtering
|
||||||
elPropertiesList.className = properties.type + 'Menu';
|
elPropertiesList.className = properties.type + 'Menu';
|
||||||
|
|
||||||
elType.innerHTML = properties.type;
|
elType.innerHTML = properties.type;
|
||||||
elTypeIcon.innerHTML = ICON_FOR_TYPE[properties.type];
|
elTypeIcon.innerHTML = ICON_FOR_TYPE[properties.type];
|
||||||
elTypeIcon.style.display = "inline-block";
|
elTypeIcon.style.display = "inline-block";
|
||||||
|
@ -883,13 +856,13 @@ function loaded() {
|
||||||
elCloneableLifetime.value = 300;
|
elCloneableLifetime.value = 300;
|
||||||
|
|
||||||
var grabbablesSet = false;
|
var grabbablesSet = false;
|
||||||
var parsedUserData = {}
|
var parsedUserData = {};
|
||||||
try {
|
try {
|
||||||
parsedUserData = JSON.parse(properties.userData);
|
parsedUserData = JSON.parse(properties.userData);
|
||||||
|
|
||||||
if ("grabbableKey" in parsedUserData) {
|
if ("grabbableKey" in parsedUserData) {
|
||||||
grabbablesSet = true;
|
grabbablesSet = true;
|
||||||
var grabbableData = parsedUserData["grabbableKey"];
|
var grabbableData = parsedUserData.grabbableKey;
|
||||||
if ("grabbable" in grabbableData) {
|
if ("grabbable" in grabbableData) {
|
||||||
elGrabbable.checked = grabbableData.grabbable;
|
elGrabbable.checked = grabbableData.grabbable;
|
||||||
} else {
|
} else {
|
||||||
|
@ -928,6 +901,7 @@ function loaded() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// TODO: What should go here?
|
||||||
}
|
}
|
||||||
if (!grabbablesSet) {
|
if (!grabbablesSet) {
|
||||||
elGrabbable.checked = true;
|
elGrabbable.checked = true;
|
||||||
|
@ -968,19 +942,21 @@ function loaded() {
|
||||||
elDescription.value = properties.description;
|
elDescription.value = properties.description;
|
||||||
|
|
||||||
|
|
||||||
if (properties.type == "Shape" || properties.type == "Box" || properties.type == "Sphere") {
|
if (properties.type === "Shape" || properties.type === "Box" || properties.type === "Sphere") {
|
||||||
elShape.value = properties.shape;
|
elShape.value = properties.shape;
|
||||||
setDropdownText(elShape);
|
setDropdownText(elShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.type == "Shape" || properties.type == "Box" || properties.type == "Sphere" || properties.type == "ParticleEffect") {
|
if (properties.type === "Shape" || properties.type === "Box" ||
|
||||||
|
properties.type === "Sphere" || properties.type === "ParticleEffect") {
|
||||||
elColorRed.value = properties.color.red;
|
elColorRed.value = properties.color.red;
|
||||||
elColorGreen.value = properties.color.green;
|
elColorGreen.value = properties.color.green;
|
||||||
elColorBlue.value = properties.color.blue;
|
elColorBlue.value = properties.color.blue;
|
||||||
elColorControl1.style.backgroundColor = elColorControl2.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
|
elColorControlVariant2.style.backgroundColor = "rgb(" + properties.color.red + "," +
|
||||||
|
properties.color.green + "," + properties.color.blue + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.type == "Model") {
|
if (properties.type === "Model") {
|
||||||
elModelURL.value = properties.modelURL;
|
elModelURL.value = properties.modelURL;
|
||||||
elShapeType.value = properties.shapeType;
|
elShapeType.value = properties.shapeType;
|
||||||
setDropdownText(elShapeType);
|
setDropdownText(elShapeType);
|
||||||
|
@ -998,24 +974,26 @@ function loaded() {
|
||||||
setTextareaScrolling(elModelTextures);
|
setTextareaScrolling(elModelTextures);
|
||||||
elModelOriginalTextures.value = properties.originalTextures;
|
elModelOriginalTextures.value = properties.originalTextures;
|
||||||
setTextareaScrolling(elModelOriginalTextures);
|
setTextareaScrolling(elModelOriginalTextures);
|
||||||
} else if (properties.type == "Web") {
|
} else if (properties.type === "Web") {
|
||||||
elWebSourceURL.value = properties.sourceUrl;
|
elWebSourceURL.value = properties.sourceUrl;
|
||||||
elWebDPI.value = properties.dpi;
|
elWebDPI.value = properties.dpi;
|
||||||
} else if (properties.type == "Text") {
|
} else if (properties.type === "Text") {
|
||||||
elTextText.value = properties.text;
|
elTextText.value = properties.text;
|
||||||
elTextLineHeight.value = properties.lineHeight.toFixed(4);
|
elTextLineHeight.value = properties.lineHeight.toFixed(4);
|
||||||
elTextFaceCamera.checked = properties.faceCamera;
|
elTextFaceCamera.checked = properties.faceCamera;
|
||||||
elTextTextColor.style.backgroundColor = "rgb(" + properties.textColor.red + "," + properties.textColor.green + "," + properties.textColor.blue + ")";
|
elTextTextColor.style.backgroundColor = "rgb(" + properties.textColor.red + "," +
|
||||||
|
properties.textColor.green + "," + properties.textColor.blue + ")";
|
||||||
elTextTextColorRed.value = properties.textColor.red;
|
elTextTextColorRed.value = properties.textColor.red;
|
||||||
elTextTextColorGreen.value = properties.textColor.green;
|
elTextTextColorGreen.value = properties.textColor.green;
|
||||||
elTextTextColorBlue.value = properties.textColor.blue;
|
elTextTextColorBlue.value = properties.textColor.blue;
|
||||||
elTextBackgroundColorRed.value = properties.backgroundColor.red;
|
elTextBackgroundColorRed.value = properties.backgroundColor.red;
|
||||||
elTextBackgroundColorGreen.value = properties.backgroundColor.green;
|
elTextBackgroundColorGreen.value = properties.backgroundColor.green;
|
||||||
elTextBackgroundColorBlue.value = properties.backgroundColor.blue;
|
elTextBackgroundColorBlue.value = properties.backgroundColor.blue;
|
||||||
} else if (properties.type == "Light") {
|
} else if (properties.type === "Light") {
|
||||||
elLightSpotLight.checked = properties.isSpotlight;
|
elLightSpotLight.checked = properties.isSpotlight;
|
||||||
|
|
||||||
elLightColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
|
elLightColor.style.backgroundColor = "rgb(" + properties.color.red + "," +
|
||||||
|
properties.color.green + "," + properties.color.blue + ")";
|
||||||
elLightColorRed.value = properties.color.red;
|
elLightColorRed.value = properties.color.red;
|
||||||
elLightColorGreen.value = properties.color.green;
|
elLightColorGreen.value = properties.color.green;
|
||||||
elLightColorBlue.value = properties.color.blue;
|
elLightColorBlue.value = properties.color.blue;
|
||||||
|
@ -1024,9 +1002,10 @@ function loaded() {
|
||||||
elLightFalloffRadius.value = properties.falloffRadius.toFixed(1);
|
elLightFalloffRadius.value = properties.falloffRadius.toFixed(1);
|
||||||
elLightExponent.value = properties.exponent.toFixed(2);
|
elLightExponent.value = properties.exponent.toFixed(2);
|
||||||
elLightCutoff.value = properties.cutoff.toFixed(2);
|
elLightCutoff.value = properties.cutoff.toFixed(2);
|
||||||
} else if (properties.type == "Zone") {
|
} else if (properties.type === "Zone") {
|
||||||
elZoneStageSunModelEnabled.checked = properties.stage.sunModelEnabled;
|
elZoneStageSunModelEnabled.checked = properties.stage.sunModelEnabled;
|
||||||
elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," + properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")";
|
elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," +
|
||||||
|
properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")";
|
||||||
elZoneKeyLightColorRed.value = properties.keyLight.color.red;
|
elZoneKeyLightColorRed.value = properties.keyLight.color.red;
|
||||||
elZoneKeyLightColorGreen.value = properties.keyLight.color.green;
|
elZoneKeyLightColorGreen.value = properties.keyLight.color.green;
|
||||||
elZoneKeyLightColorBlue.value = properties.keyLight.color.blue;
|
elZoneKeyLightColorBlue.value = properties.keyLight.color.blue;
|
||||||
|
@ -1036,9 +1015,9 @@ function loaded() {
|
||||||
elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2);
|
elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2);
|
||||||
elZoneKeyLightAmbientURL.value = properties.keyLight.ambientURL;
|
elZoneKeyLightAmbientURL.value = properties.keyLight.ambientURL;
|
||||||
|
|
||||||
elZoneHazeModeInherit.checked = (properties.hazeMode == 'inherit');
|
elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit');
|
||||||
elZoneHazeModeDisabled.checked = (properties.hazeMode == 'disabled');
|
elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled');
|
||||||
elZoneHazeModeEnabled.checked = (properties.hazeMode == 'enabled');
|
elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled');
|
||||||
|
|
||||||
elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0);
|
elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0);
|
||||||
elZoneHazeColor.style.backgroundColor = "rgb(" +
|
elZoneHazeColor.style.backgroundColor = "rgb(" +
|
||||||
|
@ -1069,10 +1048,6 @@ function loaded() {
|
||||||
|
|
||||||
elZoneHazeBackgroundBlend.value = properties.haze.hazeBackgroundBlend.toFixed(2);
|
elZoneHazeBackgroundBlend.value = properties.haze.hazeBackgroundBlend.toFixed(2);
|
||||||
|
|
||||||
// elZoneHazeAttenuateKeyLight.checked = properties.haze.hazeAttenuateKeyLight;
|
|
||||||
// elZoneHazeKeyLightRange.value = properties.haze.hazeKeyLightRange.toFixed(0);
|
|
||||||
// elZoneHazeKeyLightAltitude.value = properties.haze.hazeKeyLightAltitude.toFixed(0);
|
|
||||||
|
|
||||||
elZoneStageLatitude.value = properties.stage.latitude.toFixed(2);
|
elZoneStageLatitude.value = properties.stage.latitude.toFixed(2);
|
||||||
elZoneStageLongitude.value = properties.stage.longitude.toFixed(2);
|
elZoneStageLongitude.value = properties.stage.longitude.toFixed(2);
|
||||||
elZoneStageAltitude.value = properties.stage.altitude.toFixed(2);
|
elZoneStageAltitude.value = properties.stage.altitude.toFixed(2);
|
||||||
|
@ -1085,7 +1060,8 @@ function loaded() {
|
||||||
elZoneBackgroundMode.value = properties.backgroundMode;
|
elZoneBackgroundMode.value = properties.backgroundMode;
|
||||||
setDropdownText(elZoneBackgroundMode);
|
setDropdownText(elZoneBackgroundMode);
|
||||||
|
|
||||||
elZoneSkyboxColor.style.backgroundColor = "rgb(" + properties.skybox.color.red + "," + properties.skybox.color.green + "," + properties.skybox.color.blue + ")";
|
elZoneSkyboxColor.style.backgroundColor = "rgb(" + properties.skybox.color.red + "," +
|
||||||
|
properties.skybox.color.green + "," + properties.skybox.color.blue + ")";
|
||||||
elZoneSkyboxColorRed.value = properties.skybox.color.red;
|
elZoneSkyboxColorRed.value = properties.skybox.color.red;
|
||||||
elZoneSkyboxColorGreen.value = properties.skybox.color.green;
|
elZoneSkyboxColorGreen.value = properties.skybox.color.green;
|
||||||
elZoneSkyboxColorBlue.value = properties.skybox.color.blue;
|
elZoneSkyboxColorBlue.value = properties.skybox.color.blue;
|
||||||
|
@ -1095,8 +1071,9 @@ function loaded() {
|
||||||
elZoneGhostingAllowed.checked = properties.ghostingAllowed;
|
elZoneGhostingAllowed.checked = properties.ghostingAllowed;
|
||||||
elZoneFilterURL.value = properties.filterURL;
|
elZoneFilterURL.value = properties.filterURL;
|
||||||
|
|
||||||
showElements(document.getElementsByClassName('skybox-section'), elZoneBackgroundMode.value == 'skybox');
|
showElements(document.getElementsByClassName('skybox-section'),
|
||||||
} else if (properties.type == "PolyVox") {
|
elZoneBackgroundMode.value === 'skybox');
|
||||||
|
} else if (properties.type === "PolyVox") {
|
||||||
elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
|
elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
|
||||||
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
|
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
|
||||||
elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2);
|
elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2);
|
||||||
|
@ -1250,7 +1227,8 @@ function loaded() {
|
||||||
});
|
});
|
||||||
|
|
||||||
var numberListener = function (event) {
|
var numberListener = function (event) {
|
||||||
userDataChanger("grabbableKey", event.target.getAttribute("data-user-data-type"), parseInt(event.target.value), elUserData, false);
|
userDataChanger("grabbableKey",
|
||||||
|
event.target.getAttribute("data-user-data-type"), parseInt(event.target.value), elUserData, false);
|
||||||
};
|
};
|
||||||
elCloneableLifetime.addEventListener('change', numberListener);
|
elCloneableLifetime.addEventListener('change', numberListener);
|
||||||
elCloneableLimit.addEventListener('change', numberListener);
|
elCloneableLimit.addEventListener('change', numberListener);
|
||||||
|
@ -1279,7 +1257,7 @@ function loaded() {
|
||||||
showUserDataTextArea();
|
showUserDataTextArea();
|
||||||
showNewJSONEditorButton();
|
showNewJSONEditorButton();
|
||||||
hideSaveUserDataButton();
|
hideSaveUserDataButton();
|
||||||
updateProperty('userData', elUserData.value)
|
updateProperty('userData', elUserData.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
elSaveUserData.addEventListener("click", function() {
|
elSaveUserData.addEventListener("click", function() {
|
||||||
|
@ -1303,24 +1281,6 @@ function loaded() {
|
||||||
elColorRed.addEventListener('change', colorChangeFunction);
|
elColorRed.addEventListener('change', colorChangeFunction);
|
||||||
elColorGreen.addEventListener('change', colorChangeFunction);
|
elColorGreen.addEventListener('change', colorChangeFunction);
|
||||||
elColorBlue.addEventListener('change', colorChangeFunction);
|
elColorBlue.addEventListener('change', colorChangeFunction);
|
||||||
colorPickers.push($('#property-color-control1').colpick({
|
|
||||||
colorScheme: 'dark',
|
|
||||||
layout: 'hex',
|
|
||||||
color: '000000',
|
|
||||||
onShow: function(colpick) {
|
|
||||||
$('#property-color-control1').attr('active', 'true');
|
|
||||||
},
|
|
||||||
onHide: function(colpick) {
|
|
||||||
$('#property-color-control1').attr('active', 'false');
|
|
||||||
},
|
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
|
||||||
$(el).css('background-color', '#' + hex);
|
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
|
||||||
// Keep the companion control in sync
|
|
||||||
elColorControl2.style.backgroundColor = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
colorPickers.push($('#property-color-control2').colpick({
|
colorPickers.push($('#property-color-control2').colpick({
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
|
@ -1335,9 +1295,6 @@ function loaded() {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
$(el).colpickHide();
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
||||||
// Keep the companion control in sync
|
|
||||||
elColorControl1.style.backgroundColor = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -1382,12 +1339,16 @@ function loaded() {
|
||||||
elModelAnimationURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('animation', 'url'));
|
elModelAnimationURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('animation', 'url'));
|
||||||
elModelAnimationPlaying.addEventListener('change',createEmitGroupCheckedPropertyUpdateFunction('animation', 'running'));
|
elModelAnimationPlaying.addEventListener('change',createEmitGroupCheckedPropertyUpdateFunction('animation', 'running'));
|
||||||
elModelAnimationFPS.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'fps'));
|
elModelAnimationFPS.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'fps'));
|
||||||
elModelAnimationFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'currentFrame'));
|
elModelAnimationFrame.addEventListener('change',
|
||||||
elModelAnimationFirstFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'firstFrame'));
|
createEmitGroupNumberPropertyUpdateFunction('animation', 'currentFrame'));
|
||||||
elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
|
elModelAnimationFirstFrame.addEventListener('change',
|
||||||
|
createEmitGroupNumberPropertyUpdateFunction('animation', 'firstFrame'));
|
||||||
|
elModelAnimationLastFrame.addEventListener('change',
|
||||||
|
createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
|
||||||
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
|
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
|
||||||
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
|
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
|
||||||
elModelAnimationAllowTranslation.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'allowTranslation'));
|
elModelAnimationAllowTranslation.addEventListener('change',
|
||||||
|
createEmitGroupCheckedPropertyUpdateFunction('animation', 'allowTranslation'));
|
||||||
|
|
||||||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||||
|
|
||||||
|
@ -1439,7 +1400,8 @@ function loaded() {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
elZoneStageSunModelEnabled.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage', 'sunModelEnabled'));
|
elZoneStageSunModelEnabled.addEventListener('change',
|
||||||
|
createEmitGroupCheckedPropertyUpdateFunction('stage', 'sunModelEnabled'));
|
||||||
colorPickers.push($('#property-zone-key-light-color').colpick({
|
colorPickers.push($('#property-zone-key-light-color').colpick({
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
|
@ -1456,18 +1418,26 @@ function loaded() {
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
|
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight', 'color', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
|
var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight', 'color',
|
||||||
|
elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
|
||||||
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
|
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||||
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
|
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||||
elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction);
|
elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||||
elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight', 'intensity'));
|
elZoneKeyLightIntensity.addEventListener('change',
|
||||||
elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight', 'ambientIntensity'));
|
createEmitGroupNumberPropertyUpdateFunction('keyLight', 'intensity'));
|
||||||
elZoneKeyLightAmbientURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('keyLight', 'ambientURL'));
|
elZoneKeyLightAmbientIntensity.addEventListener('change',
|
||||||
var zoneKeyLightDirectionChangeFunction = createEmitGroupVec3PropertyUpdateFunction('keyLight', 'direction', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY);
|
createEmitGroupNumberPropertyUpdateFunction('keyLight', 'ambientIntensity'));
|
||||||
|
elZoneKeyLightAmbientURL.addEventListener('change',
|
||||||
|
createEmitGroupTextPropertyUpdateFunction('keyLight', 'ambientURL'));
|
||||||
|
var zoneKeyLightDirectionChangeFunction =
|
||||||
|
createEmitGroupVec3PropertyUpdateFunction('keyLight', 'direction',
|
||||||
|
elZoneKeyLightDirectionX, elZoneKeyLightDirectionY);
|
||||||
elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||||
elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||||
|
|
||||||
var hazeModeChanged = createZoneComponentModeChangedFunction('hazeMode', elZoneHazeModeInherit, elZoneHazeModeDisabled, elZoneHazeModeEnabled)
|
var hazeModeChanged =
|
||||||
|
createZoneComponentModeChangedFunction('hazeMode', elZoneHazeModeInherit,
|
||||||
|
elZoneHazeModeDisabled, elZoneHazeModeEnabled);
|
||||||
elZoneHazeModeInherit.addEventListener('change', hazeModeChanged);
|
elZoneHazeModeInherit.addEventListener('change', hazeModeChanged);
|
||||||
elZoneHazeModeDisabled.addEventListener('change', hazeModeChanged);
|
elZoneHazeModeDisabled.addEventListener('change', hazeModeChanged);
|
||||||
elZoneHazeModeEnabled.addEventListener('change', hazeModeChanged);
|
elZoneHazeModeEnabled.addEventListener('change', hazeModeChanged);
|
||||||
|
@ -1524,23 +1494,23 @@ function loaded() {
|
||||||
elZoneHazeGlareColorGreen.addEventListener('change', zoneHazeGlareColorChangeFunction);
|
elZoneHazeGlareColorGreen.addEventListener('change', zoneHazeGlareColorChangeFunction);
|
||||||
elZoneHazeGlareColorBlue.addEventListener('change', zoneHazeGlareColorChangeFunction);
|
elZoneHazeGlareColorBlue.addEventListener('change', zoneHazeGlareColorChangeFunction);
|
||||||
|
|
||||||
elZoneHazeEnableGlare.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('haze', 'hazeEnableGlare'));
|
elZoneHazeEnableGlare.addEventListener('change',
|
||||||
|
createEmitGroupCheckedPropertyUpdateFunction('haze', 'hazeEnableGlare'));
|
||||||
elZonehazeGlareAngle.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeGlareAngle'));
|
elZonehazeGlareAngle.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeGlareAngle'));
|
||||||
|
|
||||||
elZoneHazeAltitudeEffect.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('haze', 'hazeAltitudeEffect'));
|
elZoneHazeAltitudeEffect.addEventListener('change',
|
||||||
|
createEmitGroupCheckedPropertyUpdateFunction('haze', 'hazeAltitudeEffect'));
|
||||||
elZoneHazeCeiling.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeCeiling'));
|
elZoneHazeCeiling.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeCeiling'));
|
||||||
elZoneHazeBaseRef.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBaseRef'));
|
elZoneHazeBaseRef.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBaseRef'));
|
||||||
|
|
||||||
elZoneHazeBackgroundBlend.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend'));
|
elZoneHazeBackgroundBlend.addEventListener('change',
|
||||||
|
createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend'));
|
||||||
// elZoneHazeAttenuateKeyLight.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('haze', 'hazeAttenuateKeyLight'));
|
|
||||||
// elZoneHazeKeyLightRange.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeKeyLightRange'));
|
|
||||||
// elZoneHazeKeyLightAltitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeKeyLightAltitude'));
|
|
||||||
|
|
||||||
elZoneStageLatitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'latitude'));
|
elZoneStageLatitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'latitude'));
|
||||||
elZoneStageLongitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'longitude'));
|
elZoneStageLongitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'longitude'));
|
||||||
elZoneStageAltitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'altitude'));
|
elZoneStageAltitude.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'altitude'));
|
||||||
elZoneStageAutomaticHourDay.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage', 'automaticHourDay'));
|
elZoneStageAutomaticHourDay.addEventListener('change',
|
||||||
|
createEmitGroupCheckedPropertyUpdateFunction('stage', 'automaticHourDay'));
|
||||||
elZoneStageDay.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'day'));
|
elZoneStageDay.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'day'));
|
||||||
elZoneStageHour.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'hour'));
|
elZoneStageHour.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('stage', 'hour'));
|
||||||
|
|
||||||
|
@ -1587,26 +1557,26 @@ function loaded() {
|
||||||
elMoveSelectionToGrid.addEventListener("click", function() {
|
elMoveSelectionToGrid.addEventListener("click", function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "action",
|
type: "action",
|
||||||
action: "moveSelectionToGrid",
|
action: "moveSelectionToGrid"
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
elMoveAllToGrid.addEventListener("click", function() {
|
elMoveAllToGrid.addEventListener("click", function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "action",
|
type: "action",
|
||||||
action: "moveAllToGrid",
|
action: "moveAllToGrid"
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
elResetToNaturalDimensions.addEventListener("click", function() {
|
elResetToNaturalDimensions.addEventListener("click", function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "action",
|
type: "action",
|
||||||
action: "resetToNaturalDimensions",
|
action: "resetToNaturalDimensions"
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
elRescaleDimensionsButton.addEventListener("click", function() {
|
elRescaleDimensionsButton.addEventListener("click", function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "action",
|
type: "action",
|
||||||
action: "rescaleDimensions",
|
action: "rescaleDimensions",
|
||||||
percentage: parseFloat(elRescaleDimensionsPct.value),
|
percentage: parseFloat(elRescaleDimensionsPct.value)
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
elReloadScriptsButton.addEventListener("click", function() {
|
elReloadScriptsButton.addEventListener("click", function() {
|
||||||
|
@ -1638,7 +1608,7 @@ function loaded() {
|
||||||
var ev = document.createEvent("HTMLEvents");
|
var ev = document.createEvent("HTMLEvents");
|
||||||
ev.initEvent("change", true, true);
|
ev.initEvent("change", true, true);
|
||||||
document.activeElement.dispatchEvent(ev);
|
document.activeElement.dispatchEvent(ev);
|
||||||
}
|
};
|
||||||
|
|
||||||
// For input and textarea elements, select all of the text on focus
|
// For input and textarea elements, select all of the text on focus
|
||||||
// WebKit-based browsers, such as is used with QWebView, have a quirk
|
// WebKit-based browsers, such as is used with QWebView, have a quirk
|
||||||
|
@ -1653,13 +1623,17 @@ function loaded() {
|
||||||
for (var i = 0; i < els.length; i++) {
|
for (var i = 0; i < els.length; i++) {
|
||||||
var clicked = false;
|
var clicked = false;
|
||||||
var originalText;
|
var originalText;
|
||||||
|
// TODO FIXME: (JSHint) Functions declared within loops referencing
|
||||||
|
// an outer scoped variable may lead to confusing semantics.
|
||||||
els[i].onfocus = function(e) {
|
els[i].onfocus = function(e) {
|
||||||
originalText = this.value;
|
originalText = this.value;
|
||||||
this.select();
|
this.select();
|
||||||
clicked = false;
|
clicked = false;
|
||||||
};
|
};
|
||||||
|
// TODO FIXME: (JSHint) Functions declared within loops referencing
|
||||||
|
// an outer scoped variable may lead to confusing semantics.
|
||||||
els[i].onmouseup = function(e) {
|
els[i].onmouseup = function(e) {
|
||||||
if (!clicked && originalText == this.value) {
|
if (!clicked && originalText === this.value) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
clicked = true;
|
clicked = true;
|
||||||
|
@ -1674,15 +1648,15 @@ function loaded() {
|
||||||
var toggleCollapsedEvent = function(event) {
|
var toggleCollapsedEvent = function(event) {
|
||||||
var element = event.target.parentNode.parentNode;
|
var element = event.target.parentNode.parentNode;
|
||||||
var isCollapsed = element.dataset.collapsed !== "true";
|
var isCollapsed = element.dataset.collapsed !== "true";
|
||||||
element.dataset.collapsed = isCollapsed ? "true" : false
|
element.dataset.collapsed = isCollapsed ? "true" : false;
|
||||||
element.setAttribute("collapsed", isCollapsed ? "true" : "false");
|
element.setAttribute("collapsed", isCollapsed ? "true" : "false");
|
||||||
element.getElementsByTagName("span")[0].textContent = isCollapsed ? "L" : "M";
|
element.getElementsByTagName("span")[0].textContent = isCollapsed ? "L" : "M";
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0, length = elCollapsible.length; i < length; i++) {
|
for (var collapseIndex = 0, numCollapsibles = elCollapsible.length; collapseIndex < numCollapsibles; ++collapseIndex) {
|
||||||
var element = elCollapsible[i];
|
var curCollapsibleElement = elCollapsible[collapseIndex];
|
||||||
element.addEventListener("click", toggleCollapsedEvent, true);
|
curCollapsibleElement.addEventListener("click", toggleCollapsedEvent, true);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// Textarea scrollbars
|
// Textarea scrollbars
|
||||||
|
@ -1690,17 +1664,17 @@ function loaded() {
|
||||||
|
|
||||||
var textareaOnChangeEvent = function(event) {
|
var textareaOnChangeEvent = function(event) {
|
||||||
setTextareaScrolling(event.target);
|
setTextareaScrolling(event.target);
|
||||||
}
|
};
|
||||||
|
|
||||||
for (var i = 0, length = elTextareas.length; i < length; i++) {
|
for (var textAreaIndex = 0, numTextAreas = elTextareas.length; textAreaIndex < numTextAreas; ++textAreaIndex) {
|
||||||
var element = elTextareas[i];
|
var curTextAreaElement = elTextareas[textAreaIndex];
|
||||||
setTextareaScrolling(element);
|
setTextareaScrolling(curTextAreaElement);
|
||||||
element.addEventListener("input", textareaOnChangeEvent, false);
|
curTextAreaElement.addEventListener("input", textareaOnChangeEvent, false);
|
||||||
element.addEventListener("change", textareaOnChangeEvent, false);
|
curTextAreaElement.addEventListener("change", textareaOnChangeEvent, false);
|
||||||
/* FIXME: Detect and update textarea scrolling attribute on resize. Unfortunately textarea doesn't have a resize
|
/* FIXME: Detect and update textarea scrolling attribute on resize. Unfortunately textarea doesn't have a resize
|
||||||
event; mouseup is a partial stand-in but doesn't handle resizing if mouse moves outside textarea rectangle. */
|
event; mouseup is a partial stand-in but doesn't handle resizing if mouse moves outside textarea rectangle. */
|
||||||
element.addEventListener("mouseup", textareaOnChangeEvent, false);
|
curTextAreaElement.addEventListener("mouseup", textareaOnChangeEvent, false);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Dropdowns
|
// Dropdowns
|
||||||
// For each dropdown the following replacement is created in place of the oriringal dropdown...
|
// For each dropdown the following replacement is created in place of the oriringal dropdown...
|
||||||
|
@ -1749,22 +1723,23 @@ function loaded() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var elDropdowns = document.getElementsByTagName("select");
|
var elDropdowns = document.getElementsByTagName("select");
|
||||||
for (var i = 0; i < elDropdowns.length; i++) {
|
for (var dropDownIndex = 0; dropDownIndex < elDropdowns.length; ++dropDownIndex) {
|
||||||
var options = elDropdowns[i].getElementsByTagName("option");
|
var options = elDropdowns[dropDownIndex].getElementsByTagName("option");
|
||||||
var selectedOption = 0;
|
var selectedOption = 0;
|
||||||
for (var j = 0; j < options.length; j++) {
|
for (var optionIndex = 0; optionIndex < options.length; ++optionIndex) {
|
||||||
if (options[j].getAttribute("selected") === "selected") {
|
if (options[optionIndex].getAttribute("selected") === "selected") {
|
||||||
selectedOption = j;
|
selectedOption = optionIndex;
|
||||||
|
// TODO: Shouldn't there be a break here?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var div = elDropdowns[i].parentNode;
|
var div = elDropdowns[dropDownIndex].parentNode;
|
||||||
|
|
||||||
var dl = document.createElement("dl");
|
var dl = document.createElement("dl");
|
||||||
div.appendChild(dl);
|
div.appendChild(dl);
|
||||||
|
|
||||||
var dt = document.createElement("dt");
|
var dt = document.createElement("dt");
|
||||||
dt.name = elDropdowns[i].name;
|
dt.name = elDropdowns[dropDownIndex].name;
|
||||||
dt.id = elDropdowns[i].id;
|
dt.id = elDropdowns[dropDownIndex].id;
|
||||||
dt.addEventListener("click", toggleDropdown, true);
|
dt.addEventListener("click", toggleDropdown, true);
|
||||||
dl.appendChild(dt);
|
dl.appendChild(dt);
|
||||||
|
|
||||||
|
@ -1773,9 +1748,9 @@ function loaded() {
|
||||||
span.textContent = options[selectedOption].firstChild.textContent;
|
span.textContent = options[selectedOption].firstChild.textContent;
|
||||||
dt.appendChild(span);
|
dt.appendChild(span);
|
||||||
|
|
||||||
var span = document.createElement("span");
|
var spanCaratDown = document.createElement("span");
|
||||||
span.textContent = "5"; // caratDn
|
spanCaratDown.textContent = "5"; // caratDn
|
||||||
dt.appendChild(span);
|
dt.appendChild(spanCaratDown);
|
||||||
|
|
||||||
var dd = document.createElement("dd");
|
var dd = document.createElement("dd");
|
||||||
dl.appendChild(dd);
|
dl.appendChild(dd);
|
||||||
|
@ -1783,10 +1758,10 @@ function loaded() {
|
||||||
var ul = document.createElement("ul");
|
var ul = document.createElement("ul");
|
||||||
dd.appendChild(ul);
|
dd.appendChild(ul);
|
||||||
|
|
||||||
for (var j = 0; j < options.length; j++) {
|
for (var listOptionIndex = 0; listOptionIndex < options.length; ++listOptionIndex) {
|
||||||
var li = document.createElement("li");
|
var li = document.createElement("li");
|
||||||
li.setAttribute("value", options[j].value);
|
li.setAttribute("value", options[listOptionIndex].value);
|
||||||
li.textContent = options[j].firstChild.textContent;
|
li.textContent = options[listOptionIndex].firstChild.textContent;
|
||||||
li.addEventListener("click", setDropdownValue);
|
li.addEventListener("click", setDropdownValue);
|
||||||
ul.appendChild(li);
|
ul.appendChild(li);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ function setUpKeyboardControl() {
|
||||||
var KEYBOARD_HEIGHT = 200;
|
var KEYBOARD_HEIGHT = 200;
|
||||||
|
|
||||||
function raiseKeyboard() {
|
function raiseKeyboard() {
|
||||||
|
window.isKeyboardRaised = true;
|
||||||
|
window.isNumericKeyboard = this.type === "number";
|
||||||
|
|
||||||
if (lowerTimer !== null) {
|
if (lowerTimer !== null) {
|
||||||
clearTimeout(lowerTimer);
|
clearTimeout(lowerTimer);
|
||||||
lowerTimer = null;
|
lowerTimer = null;
|
||||||
|
@ -35,6 +38,9 @@ function setUpKeyboardControl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLowerKeyboard() {
|
function doLowerKeyboard() {
|
||||||
|
window.isKeyboardRaised = false;
|
||||||
|
window.isNumericKeyboard = false;
|
||||||
|
|
||||||
EventBridge.emitWebEvent("_LOWER_KEYBOARD");
|
EventBridge.emitWebEvent("_LOWER_KEYBOARD");
|
||||||
lowerTimer = null;
|
lowerTimer = null;
|
||||||
isRaised = false;
|
isRaised = false;
|
||||||
|
|
|
@ -118,15 +118,16 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
Overlays.deleteOverlay(this.webOverlayID);
|
Overlays.deleteOverlay(this.webOverlayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2) * (1 / sensorScaleFactor);
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) / sensorScaleFactor;
|
||||||
var WEB_ENTITY_Y_OFFSET = 0.004 * (1 / sensorScaleFactor);
|
var WEB_ENTITY_Y_OFFSET = 0.004;
|
||||||
|
var screenWidth = 0.82 * tabletWidth;
|
||||||
|
var screenHeight = 0.81 * tabletHeight;
|
||||||
this.webOverlayID = Overlays.addOverlay("web3d", {
|
this.webOverlayID = Overlays.addOverlay("web3d", {
|
||||||
name: "WebTablet Web",
|
name: "WebTablet Web",
|
||||||
url: url,
|
url: url,
|
||||||
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
localRotation: Quat.angleAxis(180, Y_AXIS),
|
localRotation: Quat.angleAxis(180, Y_AXIS),
|
||||||
resolution: this.getTabletTextureResolution(),
|
dimensions: {x: screenWidth, y: screenHeight, z: 0.1},
|
||||||
dpi: tabletDpi,
|
dpi: tabletDpi,
|
||||||
color: { red: 255, green: 255, blue: 255 },
|
color: { red: 255, green: 255, blue: 255 },
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
|
@ -136,12 +137,15 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
visible: visible
|
visible: visible
|
||||||
});
|
});
|
||||||
|
|
||||||
var HOME_BUTTON_Y_OFFSET = ((tabletHeight / 2) - (tabletHeight / 20)) * (1 / sensorScaleFactor);
|
var HOME_BUTTON_Y_OFFSET = ((tabletHeight / 2) - (tabletHeight / 20)) * (1 / sensorScaleFactor) - 0.003;
|
||||||
this.homeButtonID = Overlays.addOverlay("sphere", {
|
// FIXME: Circle3D overlays currently at the wrong dimensions, so we need to account for that here
|
||||||
|
var homeButtonDim = 4.0 * tabletScaleFactor / 3.0;
|
||||||
|
this.homeButtonID = Overlays.addOverlay("circle3d", {
|
||||||
name: "homeButton",
|
name: "homeButton",
|
||||||
localPosition: {x: -0.001, y: -HOME_BUTTON_Y_OFFSET, z: 0.0},
|
localPosition: { x: 0.0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
localRotation: { x: 0, y: 1, z: 0, w: 0},
|
localRotation: { x: 0, y: 1, z: 0, w: 0},
|
||||||
dimensions: { x: 4 * tabletScaleFactor, y: 4 * tabletScaleFactor, z: 4 * tabletScaleFactor},
|
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim },
|
||||||
|
solid: true,
|
||||||
alpha: 0.0,
|
alpha: 0.0,
|
||||||
visible: visible,
|
visible: visible,
|
||||||
drawInFront: false,
|
drawInFront: false,
|
||||||
|
@ -151,14 +155,14 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
|
|
||||||
this.homeButtonHighlightID = Overlays.addOverlay("circle3d", {
|
this.homeButtonHighlightID = Overlays.addOverlay("circle3d", {
|
||||||
name: "homeButtonHighlight",
|
name: "homeButtonHighlight",
|
||||||
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET + 0.003, z: -0.0158 },
|
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||||
dimensions: { x: 4 * tabletScaleFactor, y: 4 * tabletScaleFactor, z: 4 * tabletScaleFactor },
|
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim },
|
||||||
|
color: { red: 255, green: 255, blue: 255 },
|
||||||
solid: true,
|
solid: true,
|
||||||
innerRadius: 0.9,
|
innerRadius: 0.9,
|
||||||
ignoreIntersection: true,
|
ignoreIntersection: true,
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
color: { red: 255, green: 255, blue: 255 },
|
|
||||||
visible: visible,
|
visible: visible,
|
||||||
drawInFront: false,
|
drawInFront: false,
|
||||||
parentID: this.tabletEntityID,
|
parentID: this.tabletEntityID,
|
||||||
|
@ -265,11 +269,16 @@ WebTablet.prototype.setLandscape = function(newLandscapeValue) {
|
||||||
|
|
||||||
this.landscape = newLandscapeValue;
|
this.landscape = newLandscapeValue;
|
||||||
Overlays.editOverlay(this.tabletEntityID,
|
Overlays.editOverlay(this.tabletEntityID,
|
||||||
{ rotation: this.landscape ? Quat.multiply(Camera.orientation, ROT_LANDSCAPE) :
|
{ rotation: Quat.multiply(Camera.orientation, this.landscape ? ROT_LANDSCAPE : ROT_Y_180) });
|
||||||
Quat.multiply(Camera.orientation, ROT_Y_180) });
|
|
||||||
|
var tabletWidth = getTabletWidthFromSettings() * MyAvatar.sensorToWorldScale;
|
||||||
|
var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x;
|
||||||
|
var tabletHeight = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor;
|
||||||
|
var screenWidth = 0.82 * tabletWidth;
|
||||||
|
var screenHeight = 0.81 * tabletHeight;
|
||||||
Overlays.editOverlay(this.webOverlayID, {
|
Overlays.editOverlay(this.webOverlayID, {
|
||||||
resolution: this.getTabletTextureResolution(),
|
rotation: Quat.multiply(Camera.orientation, ROT_LANDSCAPE_WINDOW),
|
||||||
rotation: Quat.multiply(Camera.orientation, ROT_LANDSCAPE_WINDOW)
|
dimensions: {x: this.landscape ? screenHeight : screenWidth, y: this.landscape ? screenWidth : screenHeight, z: 0.1}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -505,33 +514,19 @@ WebTablet.prototype.getPosition = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.mousePressEvent = function (event) {
|
WebTablet.prototype.mousePressEvent = function (event) {
|
||||||
|
if (!HMD.active) {
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
var entityPickResults;
|
var tabletBackPickResults = Overlays.findRayIntersection(pickRay, true, [this.tabletEntityID]);
|
||||||
entityPickResults = Overlays.findRayIntersection(pickRay, true, [this.tabletEntityID]);
|
if (tabletBackPickResults.intersects) {
|
||||||
if (entityPickResults.intersects && (entityPickResults.entityID === this.tabletEntityID ||
|
var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.webOverlayID, this.homeButtonID]);
|
||||||
entityPickResults.overlayID === this.tabletEntityID)) {
|
if (!overlayPickResults.intersects) {
|
||||||
var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.webOverlayID, this.homeButtonID], []);
|
|
||||||
if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) {
|
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
var onHomeScreen = tablet.onHomeScreen();
|
|
||||||
var isMessageOpen = tablet.isMessageDialogOpen();
|
|
||||||
if (onHomeScreen) {
|
|
||||||
if (isMessageOpen === false) {
|
|
||||||
HMD.closeTablet();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isMessageOpen === false) {
|
|
||||||
tablet.gotoHomeScreen();
|
|
||||||
this.setHomeButtonTexture();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!HMD.active && (!overlayPickResults.intersects || overlayPickResults.overlayID !== this.webOverlayID)) {
|
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
var invCameraXform = new Xform(Camera.orientation, Camera.position).inv();
|
var invCameraXform = new Xform(Camera.orientation, Camera.position).inv();
|
||||||
this.initialLocalIntersectionPoint = invCameraXform.xformPoint(entityPickResults.intersection);
|
this.initialLocalIntersectionPoint = invCameraXform.xformPoint(tabletBackPickResults.intersection);
|
||||||
this.initialLocalPosition = Overlays.getProperty(this.tabletEntityID, "localPosition");
|
this.initialLocalPosition = Overlays.getProperty(this.tabletEntityID, "localPosition");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.cameraModeChanged = function (newMode) {
|
WebTablet.prototype.cameraModeChanged = function (newMode) {
|
||||||
|
|
|
@ -272,22 +272,8 @@ projectOntoEntityXYPlane = function (entityID, worldPos, props) {
|
||||||
projectOntoOverlayXYPlane = function projectOntoOverlayXYPlane(overlayID, worldPos) {
|
projectOntoOverlayXYPlane = function projectOntoOverlayXYPlane(overlayID, worldPos) {
|
||||||
var position = Overlays.getProperty(overlayID, "position");
|
var position = Overlays.getProperty(overlayID, "position");
|
||||||
var rotation = Overlays.getProperty(overlayID, "rotation");
|
var rotation = Overlays.getProperty(overlayID, "rotation");
|
||||||
var dimensions;
|
var dimensions = Overlays.getProperty(overlayID, "dimensions");
|
||||||
|
dimensions.z = 0.01; // we are projecting onto the XY plane of the overlay, so ignore the z dimension
|
||||||
var dpi = Overlays.getProperty(overlayID, "dpi");
|
|
||||||
if (dpi) {
|
|
||||||
// Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale.
|
|
||||||
var resolution = Overlays.getProperty(overlayID, "resolution");
|
|
||||||
resolution.z = 1; // Circumvent divide-by-zero.
|
|
||||||
var scale = Overlays.getProperty(overlayID, "dimensions");
|
|
||||||
scale.z = 0.01; // overlay dimensions are 2D, not 3D.
|
|
||||||
dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale);
|
|
||||||
} else {
|
|
||||||
dimensions = Overlays.getProperty(overlayID, "dimensions");
|
|
||||||
if (dimensions.z) {
|
|
||||||
dimensions.z = 0.01; // overlay dimensions are 2D, not 3D.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT);
|
return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT);
|
||||||
};
|
};
|
||||||
|
|
|
@ -169,32 +169,12 @@ function calculateTouchTargetFromOverlay(touchTip, overlayID) {
|
||||||
// calclulate normalized position
|
// calclulate normalized position
|
||||||
var invRot = Quat.inverse(overlayRotation);
|
var invRot = Quat.inverse(overlayRotation);
|
||||||
var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(position, overlayPosition));
|
var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(position, overlayPosition));
|
||||||
var dpi = Overlays.getProperty(overlayID, "dpi");
|
|
||||||
|
|
||||||
var dimensions;
|
var dimensions = Overlays.getProperty(overlayID, "dimensions");
|
||||||
if (dpi) {
|
|
||||||
// Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property
|
|
||||||
// is used as a scale.
|
|
||||||
var resolution = Overlays.getProperty(overlayID, "resolution");
|
|
||||||
if (resolution === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolution.z = 1; // Circumvent divide-by-zero.
|
|
||||||
var scale = Overlays.getProperty(overlayID, "dimensions");
|
|
||||||
if (scale === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scale.z = 0.01; // overlay dimensions are 2D, not 3D.
|
|
||||||
dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale);
|
|
||||||
} else {
|
|
||||||
dimensions = Overlays.getProperty(overlayID, "dimensions");
|
|
||||||
if (dimensions === undefined) {
|
if (dimensions === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!dimensions.z) {
|
dimensions.z = 0.01; // we are projecting onto the XY plane of the overlay, so ignore the z dimension
|
||||||
dimensions.z = 0.01; // sometimes overlay dimensions are 2D, not 3D.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var invDimensions = { x: 1 / dimensions.x, y: 1 / dimensions.y, z: 1 / dimensions.z };
|
var invDimensions = { x: 1 / dimensions.x, y: 1 / dimensions.y, z: 1 / dimensions.z };
|
||||||
var normalizedPosition = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), DEFAULT_REGISTRATION_POINT);
|
var normalizedPosition = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), DEFAULT_REGISTRATION_POINT);
|
||||||
|
|
||||||
|
|
|
@ -400,25 +400,28 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride)
|
||||||
});
|
});
|
||||||
|
|
||||||
// update webOverlay
|
// update webOverlay
|
||||||
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2) * sensorScaleOffsetOverride;
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) * sensorScaleOffsetOverride;
|
||||||
var WEB_ENTITY_Y_OFFSET = 0.004 * sensorScaleOffsetOverride;
|
var WEB_ENTITY_Y_OFFSET = 0.004 * sensorScaleFactor * sensorScaleOffsetOverride;
|
||||||
|
var screenWidth = 0.82 * tabletWidth;
|
||||||
|
var screenHeight = 0.81 * tabletHeight;
|
||||||
|
var landscape = Tablet.getTablet("com.highfidelity.interface.tablet.system").landscape;
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, {
|
Overlays.editOverlay(HMD.tabletScreenID, {
|
||||||
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
|
dimensions: {x: landscape ? screenHeight : screenWidth, y: landscape ? screenWidth : screenHeight, z: 0.1},
|
||||||
dpi: tabletDpi
|
dpi: tabletDpi
|
||||||
});
|
});
|
||||||
|
|
||||||
// update homeButton
|
// update homeButton
|
||||||
var HOME_BUTTON_Y_OFFSET = ((tabletHeight / 2) - (tabletHeight / 20)) * sensorScaleOffsetOverride;
|
var HOME_BUTTON_Y_OFFSET = ((tabletHeight / 2) - (tabletHeight / 20) - 0.003 * sensorScaleFactor) * sensorScaleOffsetOverride;
|
||||||
var homeButtonDim = 4 * tabletScaleFactor;
|
// FIXME: Circle3D overlays currently at the wrong dimensions, so we need to account for that here
|
||||||
|
var homeButtonDim = 4.0 * tabletScaleFactor / 3.0;
|
||||||
Overlays.editOverlay(HMD.homeButtonID, {
|
Overlays.editOverlay(HMD.homeButtonID, {
|
||||||
localPosition: {x: -0.001, y: -HOME_BUTTON_Y_OFFSET, z: 0.0},
|
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Circle3D overlays render at 1.5x their proper dimensions
|
|
||||||
var highlightDim = homeButtonDim / 3.0;
|
|
||||||
Overlays.editOverlay(HMD.homeButtonHighlightID, {
|
Overlays.editOverlay(HMD.homeButtonHighlightID, {
|
||||||
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET + 0.003, z: -0.0158 },
|
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
dimensions: { x: highlightDim, y: highlightDim, z: highlightDim }
|
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -110,8 +110,10 @@
|
||||||
var filterText; // Used for updating Purchases QML
|
var filterText; // Used for updating Purchases QML
|
||||||
function onScreenChanged(type, url) {
|
function onScreenChanged(type, url) {
|
||||||
onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1;
|
onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1;
|
||||||
onCommerceScreen = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH_BASE) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH || url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1);
|
onWalletScreen = url.indexOf(MARKETPLACE_WALLET_QML_PATH) !== -1;
|
||||||
wireEventBridge(onCommerceScreen);
|
onCommerceScreen = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH_BASE) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH
|
||||||
|
|| url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1);
|
||||||
|
wireEventBridge(onMarketplaceScreen || onCommerceScreen || onWalletScreen);
|
||||||
|
|
||||||
if (url === MARKETPLACE_PURCHASES_QML_PATH) {
|
if (url === MARKETPLACE_PURCHASES_QML_PATH) {
|
||||||
tablet.sendToQml({
|
tablet.sendToQml({
|
||||||
|
@ -122,7 +124,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// for toolbar mode: change button to active when window is first openend, false otherwise.
|
// for toolbar mode: change button to active when window is first openend, false otherwise.
|
||||||
marketplaceButton.editProperties({ isActive: onMarketplaceScreen || onCommerceScreen });
|
marketplaceButton.editProperties({ isActive: (onMarketplaceScreen || onCommerceScreen) && !onWalletScreen });
|
||||||
if (type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1) {
|
if (type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1) {
|
||||||
ContextOverlay.isInMarketplaceInspectionMode = true;
|
ContextOverlay.isInMarketplaceInspectionMode = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -322,6 +324,11 @@
|
||||||
} else if (parsedJsonMessage.type === "LOGIN") {
|
} else if (parsedJsonMessage.type === "LOGIN") {
|
||||||
openLoginWindow();
|
openLoginWindow();
|
||||||
} else if (parsedJsonMessage.type === "WALLET_SETUP") {
|
} else if (parsedJsonMessage.type === "WALLET_SETUP") {
|
||||||
|
wireEventBridge(true);
|
||||||
|
tablet.sendToQml({
|
||||||
|
method: 'updateWalletReferrer',
|
||||||
|
referrer: "marketplace cta"
|
||||||
|
});
|
||||||
openWallet();
|
openWallet();
|
||||||
} else if (parsedJsonMessage.type === "MY_ITEMS") {
|
} else if (parsedJsonMessage.type === "MY_ITEMS") {
|
||||||
referrerURL = MARKETPLACE_URL_INITIAL;
|
referrerURL = MARKETPLACE_URL_INITIAL;
|
||||||
|
@ -399,6 +406,7 @@
|
||||||
referrer: "purchases"
|
referrer: "purchases"
|
||||||
});
|
});
|
||||||
openWallet();
|
openWallet();
|
||||||
|
break;
|
||||||
case 'checkout_walletNotSetUp':
|
case 'checkout_walletNotSetUp':
|
||||||
wireEventBridge(true);
|
wireEventBridge(true);
|
||||||
tablet.sendToQml({
|
tablet.sendToQml({
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Overlays.getProperty(HMD.homeButtonID, "type") != "sphere" ||
|
if (Overlays.getProperty(HMD.homeButtonID, "type") != "circle3d" ||
|
||||||
Overlays.getProperty(HMD.tabletScreenID, "type") != "web3d") {
|
Overlays.getProperty(HMD.tabletScreenID, "type") != "web3d") {
|
||||||
if (debugTablet) {
|
if (debugTablet) {
|
||||||
print("TABLET is invalid due to other");
|
print("TABLET is invalid due to other");
|
||||||
|
|