Merging upstream

This commit is contained in:
samcake 2018-04-19 12:20:10 -07:00
commit a6bd589f4f
116 changed files with 3753 additions and 1967 deletions

View file

@ -14,8 +14,8 @@ Should you choose not to install Qt5 via a package manager that handles dependen
Install qt:
```bash
wget http://debian.highfidelity.com/pool/h/hi/hifi-qt5.10.1_5.10.1_amd64.deb
sudo dpkg -i hifi-qt5.10.1_5.10.1_amd64.deb
wget http://debian.highfidelity.com/pool/h/hi/hifiqt5.10.1_5.10.1_amd64.deb
sudo dpkg -i hifiqt5.10.1_5.10.1_amd64.deb
```
Install build dependencies:

View file

@ -61,13 +61,13 @@ static const ScriptBakeVersion CURRENT_SCRIPT_BAKE_VERSION = (ScriptBakeVersion)
BakedAssetType assetTypeForExtension(const QString& extension) {
auto extensionLower = extension.toLower();
if (BAKEABLE_MODEL_EXTENSIONS.contains(extensionLower)) {
return Model;
return BakedAssetType::Model;
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extensionLower.toLocal8Bit())) {
return Texture;
return BakedAssetType::Texture;
} else if (BAKEABLE_SCRIPT_EXTENSIONS.contains(extensionLower)) {
return Script;
return BakedAssetType::Script;
}
return Undefined;
return BakedAssetType::Undefined;
}
BakedAssetType assetTypeForFilename(const QString& filename) {
@ -82,11 +82,11 @@ BakedAssetType assetTypeForFilename(const QString& filename) {
QString bakedFilenameForAssetType(BakedAssetType type) {
switch (type) {
case Model:
case BakedAssetType::Model:
return BAKED_MODEL_SIMPLE_NAME;
case Texture:
case BakedAssetType::Texture:
return BAKED_TEXTURE_SIMPLE_NAME;
case Script:
case BakedAssetType::Script:
return BAKED_SCRIPT_SIMPLE_NAME;
default:
return "";
@ -95,11 +95,11 @@ QString bakedFilenameForAssetType(BakedAssetType type) {
BakeVersion currentBakeVersionForAssetType(BakedAssetType type) {
switch (type) {
case Model:
case BakedAssetType::Model:
return (BakeVersion)CURRENT_MODEL_BAKE_VERSION;
case Texture:
case BakedAssetType::Texture:
return (BakeVersion)CURRENT_TEXTURE_BAKE_VERSION;
case Script:
case BakedAssetType::Script:
return (BakeVersion)CURRENT_SCRIPT_BAKE_VERSION;
default:
return 0;
@ -222,7 +222,7 @@ bool AssetServer::needsToBeBaked(const AssetUtils::AssetPath& path, const AssetU
BakedAssetType type = assetTypeForFilename(path);
if (type == Undefined) {
if (type == BakedAssetType::Undefined) {
return false;
}
@ -241,7 +241,7 @@ bool AssetServer::needsToBeBaked(const AssetUtils::AssetPath& path, const AssetU
AssetMeta meta;
std::tie(loaded, meta) = readMetaFile(assetHash);
if (type == Texture && !loaded) {
if (type == BakedAssetType::Texture && !loaded) {
return false;
}
@ -1546,7 +1546,7 @@ bool AssetServer::setBakingEnabled(const AssetUtils::AssetPathList& paths, bool
auto it = _fileMappings.find(path);
if (it != _fileMappings.end()) {
auto type = assetTypeForFilename(path);
if (type == Undefined) {
if (type == BakedAssetType::Undefined) {
continue;
}
QString bakedFilename = bakedFilenameForAssetType(type);

View file

@ -27,7 +27,7 @@ using BakeVersion = int;
static const BakeVersion INITIAL_BAKE_VERSION = 0;
static const BakeVersion NEEDS_BAKING_BAKE_VERSION = -1;
enum BakedAssetType : int {
enum class BakedAssetType : int {
Model = 0,
Texture,
Script,

View file

@ -611,22 +611,14 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) {
// let the NodeList do its checks now (but pass it the sourceNode so it doesn't need to look it up again)
return nodeList->isPacketVerifiedWithSource(packet, sourceNode.data());
} else {
static const QString UNKNOWN_REGEX = "Packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unmatched IP for UUID";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(UNKNOWN_REGEX);
qDebug() << "Packet of type" << headerType
<< "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceID);
HIFI_FDEBUG("Packet of type" << headerType
<< "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceID));
return false;
}
} else {
static const QString UNKNOWN_REGEX = "Packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unknown node with UUID";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(UNKNOWN_REGEX);
qDebug() << "Packet of type" << headerType
<< "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID);
HIFI_FDEBUG("Packet of type" << headerType
<< "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID));
return false;
}
@ -1242,31 +1234,16 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer<ReceivedMessage
auto it = find_if(_acSubnetWhitelist.begin(), _acSubnetWhitelist.end(), isHostAddressInSubnet);
if (it == _acSubnetWhitelist.end()) {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
"Received an assignment connect request from a disallowed ip address: [^ ]+");
qDebug() << "Received an assignment connect request from a disallowed ip address:"
<< senderAddr.toString();
HIFI_FDEBUG("Received an assignment connect request from a disallowed ip address:"
<< senderAddr.toString());
return;
}
// Suppress these for Assignment::AgentType to once per 5 seconds
static QElapsedTimer noisyMessageTimer;
static bool wasNoisyTimerStarted = false;
if (!wasNoisyTimerStarted) {
noisyMessageTimer.start();
wasNoisyTimerStarted = true;
}
const qint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000;
if (requestAssignment.getType() != Assignment::AgentType
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
("Received a request for assignment type [^ ]+ from [^ ]+");
static bool printedAssignmentTypeMessage = false;
if (!printedAssignmentTypeMessage && requestAssignment.getType() != Assignment::AgentType) {
printedAssignmentTypeMessage = true;
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
<< "from" << message->getSenderSockAddr();
noisyMessageTimer.restart();
}
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
@ -1300,13 +1277,11 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer<ReceivedMessage
_gatekeeper.addPendingAssignedNode(uniqueAssignment.getUUID(), assignmentToDeploy->getUUID(),
requestAssignment.getWalletUUID(), requestAssignment.getNodeVersion());
} else {
if (requestAssignment.getType() != Assignment::AgentType
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
static bool printedAssignmentRequestMessage = false;
if (!printedAssignmentRequestMessage && requestAssignment.getType() != Assignment::AgentType) {
printedAssignmentRequestMessage = true;
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
<< "from" << message->getSenderSockAddr();
noisyMessageTimer.restart();
}
}
}
@ -1552,10 +1527,12 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
callbackParameters.jsonCallbackReceiver = this;
callbackParameters.jsonCallbackMethod = "handleSuccessfulICEServerAddressUpdate";
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
("Updating ice-server address in High Fidelity Metaverse API to [^ \n]+");
qDebug() << "Updating ice-server address in High Fidelity Metaverse API to"
<< (_iceServerSocket.isNull() ? "" : _iceServerSocket.getAddress().toString());
static bool printedIceServerMessage = false;
if (!printedIceServerMessage) {
printedIceServerMessage = true;
qDebug() << "Updating ice-server address in High Fidelity Metaverse API to"
<< (_iceServerSocket.isNull() ? "" : _iceServerSocket.getAddress().toString());
}
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";

View file

@ -180,8 +180,9 @@ else ()
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
endif ()
if (BUILD_TOOLS AND NPM_EXECUTABLE)
# require JSDoc to be build before interface is deployed (Console Auto-complete)
# require JSDoc to be build before interface is deployed
add_dependencies(resources jsdoc)
endif()
@ -321,6 +322,13 @@ if (APPLE)
"${RESOURCES_DEV_DIR}/scripts"
)
# copy JSDoc files beside the executable
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
"${RESOURCES_DEV_DIR}/jsdoc"
)
# call the fixup_interface macro to add required bundling commands for installation
fixup_interface()
@ -349,6 +357,13 @@ else()
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
)
# copy JSDoc files beside the executable
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
"${INTERFACE_EXEC_DIR}/jsdoc"
)
# link target to external libraries
if (WIN32)
target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib)

View file

@ -25,7 +25,6 @@
<glyph glyph-name="web" unicode="&#113;" d="M438 390c0 8-6 15-14 15l-333 0c-8 0-15-7-15-15l0-298c0-8 7-14 15-14l333 0c8 0 14 6 14 14z m-219-8l172 0c8 0 15-7 15-16 0-9-7-16-15-16l-172 0c-8 0-15 7-15 16 0 9 7 16 15 16z m-47 1c9 0 16-7 16-16 0-10-7-17-16-17-10 0-17 7-17 17 0 9 7 16 17 16z m-51 0c9 0 17-7 17-16 0-10-8-17-17-17-9 0-17 7-17 17 0 9 8 16 17 16z m291-276l-308 0 0 219 308 0z m-250 84l-15 0-20 60 13 0 14-45 15 45 13 0 15-45 14 45 13 0-20-60-14 0-14 41z m137 25l-46 0c0-5 2-8 6-11 3-2 8-4 12-4 8 0 13 3 17 7l7-8c-6-6-14-9-25-9-8 0-15 2-21 8-6 5-9 13-9 22 0 9 3 17 9 22 6 6 13 9 21 9 8 0 15-3 21-8 6-5 8-11 8-20z m-46 9l34 0c0 5-2 9-5 12-3 3-7 4-11 4-5 0-9-1-13-4-3-3-5-7-5-12z m101 27c8 0 14-3 20-9 6-5 9-12 9-22 0-9-3-16-9-22-5-6-12-8-19-8-8 0-15 3-21 9l0-9-12 0 0 83 12 0 0-34c5 8 12 12 20 12z m-20-31c0-6 2-10 5-14 4-4 8-5 13-5 5 0 9 1 13 5 3 4 5 8 5 14 0 6-2 10-5 14-4 4-8 6-13 6-5 0-9-2-13-6-3-4-5-8-5-14z"/>
<glyph glyph-name="web-2" unicode="&#114;" d="M438 390c0 8-6 15-14 15l-333 0c-8 0-15-7-15-15l0-298c0-8 7-14 15-14l333 0c8 0 14 6 14 14z m-219-8l172 0c8 0 15-7 15-16 0-9-7-16-15-16l-172 0c-8 0-15 7-15 16 0 9 7 16 15 16z m-47 1c9 0 16-7 16-16 0-10-7-17-16-17-10 0-17 7-17 17 0 9 7 16 17 16z m-51 0c9 0 17-7 17-16 0-10-8-17-17-17-9 0-17 7-17 17 0 9 8 16 17 16z m291-276l-308 0 0 219 308 0z"/>
<glyph glyph-name="edit" unicode="&#115;" d="M196 214c-27-27-54-54-81-81-6 6-13 13-19 19 27 27 54 54 81 81l-22 21c-31-31-61-62-92-92-7-7-11-13-12-22-3-25-7-50-11-76 3 0 4 0 6 0 24 5 48 10 72 15 5 1 10 4 13 7 32 32 64 64 96 96z m126 207c10 10 21 21 33 32 4 4 10 4 14 0 19-19 38-38 57-57 4-5 4-10 0-15-11-11-22-22-34-33-23 24-46 48-70 73z m23-181c-5-1-8 0-11 3-8 8-15 15-23 23 18 18 37 37 55 55 2 2 4 4 4 4-24 25-47 49-71 74-2-2-3-4-5-6-18-18-37-37-55-55-34 34-67 67-101 101-2 2-5 5-8 7-18 14-42 12-57-5-15-17-14-42 2-58 50-51 101-101 151-151 17-16 33-33 50-49 2-3 3-5 2-8-2-8-4-15-4-23-4-48 27-90 73-102 20-5 39-4 58 4-1 2-3 3-5 4-14 14-28 28-42 42-10 11-11 26-2 36 8 8 16 16 24 24 11 10 24 10 35 0 2-1 4-4 6-6 15-14 29-28 43-42 0 0 1 0 2 1 1 8 3 16 4 24 7 69-59 123-125 103z m-243 162c-7 0-14 6-14 14 0 8 6 14 14 14 8 0 15-6 15-14 0-7-7-14-15-14z m198-46c6-6 13-12 19-19-13-13-26-26-39-39-7 6-13 12-20 19 14 13 27 26 40 39z"/>
<glyph glyph-name="market" unicode="&#116;" d="M88 370c3 0 7 0 10 0 6 0 11-1 15-2 9-2 16-8 20-16 3-5 4-10 6-15 2-6 3-13 5-19 3-10 5-19 8-27 2-6 3-13 5-19 3-7 5-15 7-23 3-9 6-19 9-30 0-2 1-4 1-6 2-8 5-17 9-24 3-7 8-12 13-15 6-3 13-5 22-6 2 0 5 0 7 0l21 0 57 0c25 0 50 0 75 0 12 0 25 0 37 0 1 0 1 0 2 0 6 0 13 0 17 2 5 3 7 9 9 16l3 10c0 0 0 0 0 0 0 2 1 3 1 3 5 20 11 40 17 60 1 4 2 9 4 13 2 8 4 16 7 24 2 7 4 16 0 22-3 4-9 5-14 5-6 0-188-2-284-4l-4 0-5 22c0 3-1 6-2 9 0 3-1 5-1 7-1 2-1 3-1 4-1 4-2 7-3 11-2 6-6 12-11 17-5 5-11 8-17 9-3 1-6 1-10 1-5 1-9 1-14 1-19 0-38 0-59 0-1 0-3 0-4 0-3 0-7 0-10-1-3 0-6-2-8-4-3-5-4-11-2-17 2-5 6-6 9-7 4-1 8-1 13-1 5 0 10 0 16 0l16 0c3 0 5 0 8 0z m353-78l-26-92-6-4-2 0c-2 0-21 0-55 0-50 0-118-1-125-1l-1-1 0 0c-6 0-12 2-16 6-4 4-6 10-8 16-3 12-6 25-10 39-1 4-2 8-3 12-2 4-3 8-4 13l-4 12z m-194-164c-9 0-15-2-20-7-5-5-8-11-8-20 0-8 3-16 8-21 5-5 13-8 20-8 17 0 30 12 30 28 0 8-3 15-9 20-5 6-12 8-21 8z m139 0c-9 0-16-2-21-6-5-6-8-13-8-21 0-9 3-16 8-21 5-6 12-8 21-8 16 0 29 13 29 29 0 8-3 14-8 20-5 5-13 7-21 7z"/>
<glyph glyph-name="directory" unicode="&#117;" d="M432 451l-99-38c-2 0-3-1-4-1-3 1-5 2-8 2l-116 38c-8 3-15 6-30-1l-91-35c-17-5-32-16-32-31l0-303c0-15 14-27 32-27l99 38c3 1 6 2 9 4 1-1 3-2 4-2 3-1 5-2 7-3 0 0 1 0 1-1 0 0 1 0 1 0l116-38 0 0c8-1 12-1 21 3l90 34c13 6 32 16 32 31l0 304c0 14-14 26-32 26z m-351-371c-1 0-1 1-1 2l0 303c0 2 5 6 14 9l1 0 1 1 89 34c1-1 0-1 0-2l0-303c0-1-3-4-16-10z m356 42c-1-2-5-5-17-11l-90-34c0 1-1 1-1 2l0 304c0 1 5 5 14 8l1 0 1 1 91 34c0 0 1-1 1-1z"/>
<glyph glyph-name="menu" unicode="&#118;" d="M257 22c-60 0-119 22-164 67-44 44-68 102-68 164 0 62 24 120 68 163 90 91 237 91 327 0 44-43 68-101 68-163 0-62-24-120-68-164-45-45-104-67-163-67z m0 431c-52 0-103-20-142-59-38-38-58-88-58-141 0-54 20-104 58-142 78-78 205-78 283 0 38 38 59 88 59 142 0 53-21 103-59 141-39 39-90 59-141 59z m101-133l-203 0c-8 0-15 7-15 15 0 8 7 15 15 15l203 0c8 0 14-7 14-15 0-8-6-15-14-15z m0-84l-203 0c-8 0-15 7-15 15 0 8 7 15 15 15l203 0c8 0 14-7 14-15 0-8-6-15-14-15z m0-81l-203 0c-8 0-15 7-15 15 0 8 7 14 15 14l203 0c8 0 14-6 14-14 0-8-6-15-14-15z"/>
<glyph glyph-name="close" unicode="&#119;" d="M258 19c-59 0-118 23-163 68-44 43-68 101-68 163 0 62 24 120 68 164 90 90 237 90 327 0 44-44 68-102 68-164 0-62-24-120-68-163-45-45-104-68-164-68z m0 431c-51 0-102-19-141-58-38-38-59-88-59-142 0-53 21-103 59-141 78-78 205-78 283 0 38 38 58 88 58 141 0 54-20 104-58 142-39 39-90 58-142 58z m25-200l67 67c7 7 7 18 0 25-7 7-18 7-25 0l-67-67-66 67c-7 7-18 7-25 0-7-7-7-18 0-25l66-67-66-66c-7-7-7-18 0-25 7-7 18-7 25 0l66 66 67-66c7-7 18-7 25 0 7 7 7 18 0 25z"/>
@ -145,4 +144,14 @@
<glyph glyph-name="rez" unicode="&#57381;" d="M373 321c-2 5-6 8-11 8l-49 8 55 61c4 4 5 9 3 14-2 5-7 8-12 8 0 0 0 0 0 0l-114-1c-5-1-10-4-12-9l-54-136c-1-4-1-8 1-11 2-4 6-6 9-7l38-5-54-136c-2-6 0-13 6-16 2-1 4-2 7-2 3 0 7 2 10 5l175 206c3 4 3 9 2 13z"/>
<glyph glyph-name="keyboard-collapse" unicode="&#57387;" d="M373 249l-26 0 0 25 26 0z m-35 0l-27 0 0 25 27 0z m-36 0l-27 0 0 25 27 0z m-36 0l-26 0 0 25 26 0z m-35 0l-27 0 0 25 27 0z m-36 0l-27 0 0 25 27 0z m-36 0l-26 0 0 25 26 0z m224-1l18 0c7 0 13 6 13 13 0 7-6 13-13 13l-18 0m-262 0l-17 0c-7 0-13-6-13-13 0-7 6-13 13-13l17 0m252 39l-31 0 0 25 31 0z m-42 0l-31 0 0 25 31 0z m-41 0l-32 0 0 25 32 0z m-42 0l-32 0 0 25 32 0z m-42 0l-32 0 0 25 32 0z m-41 0l-32 0 0 25 32 0z m218-1l18 0c7 0 13 6 13 13 0 8-6 14-13 14l-18 0m-262 0l-17 0c-7 0-13-6-13-14 0-7 6-13 13-13l17 0m288-124l-315 0c-33 0-59 28-59 61l0 76c0 34 26 61 59 61l315 0c33 0 59-27 59-61l0-76c1-33-26-61-59-61z m-315 172c-18 0-33-16-33-34l0-77c0-19 15-34 33-34l315 0c18 0 33 15 33 34l0 77c0 19-15 34-33 34z m248-99l32 0 0-25-32 0z m-41 0l31 0 0-25-31 0z m-42 0l31 0 0-25-31 0z m-43 0l32 0 0-25-32 0z m-42 0l32 0 0-25-32 0z m-41 0l31 0 0-25-31 0z m250-26l18 0c7 0 13 6 13 14 0 7-6 13-13 13l-18 0m-262 0l-17 0c-7 0-13-6-13-13 0-8 6-13 13-13l17 0m81-82l50-50 53 54-107 0"/>
<glyph glyph-name="image" unicode="&#57386;" d="M257 428c52 0 104 0 156 0 24 0 37-13 37-37 1-90 1-179 0-269 0-25-13-38-39-38-103 0-207 0-311 0-26 0-39 13-39 40 0 88 0 176 0 263 0 28 13 41 41 41 51 0 103 0 155 0z m167-263c0 7 0 10 0 14 0 69 0 138 0 206 0 17 0 17-17 17-101 0-202 0-303 0-16 0-17-1-17-17 0-58 0-115 0-173 0-3 0-7 0-12 8 3 14 6 19 9 17 8 30 7 44-6 5-5 10-10 15-15 5-7 11-8 19-4 40 21 81 41 121 61 19 10 31 8 46-7 9-9 18-18 27-27 15-15 29-29 46-46z m-328-54c7 0 11-1 15-1 98 0 197 0 296 0 6 0 14 2 16 6 5 7 0 14-6 20-27 26-54 53-80 80-8 9-15 9-26 4-67-35-135-68-203-102-3-2-6-4-12-7z m-8 26c21 10 40 20 63 31-8 7-14 12-20 17-2 2-7 3-10 3-30-9-36-17-34-48 0 0 0-1 1-3z m134 169c1-25-21-46-46-46-25-1-46 20-47 46 0 25 21 46 47 47 25 0 46-21 46-47z m-46 22c-12 0-22-9-22-21 0-13 9-22 21-23 13 0 23 9 23 22 0 13-10 22-22 22z"/>
<glyph glyph-name="environments" unicode="&#57388;" d="M256 454c-110 0-199-89-199-199 0-110 89-199 199-199 0 0 0 0 0 0l2-1 0 1c109 1 197 90 197 199 0 110-89 199-199 199z m114-204l0 0 0 5c0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 2l0 4 0 0c-1 22-4 43-10 63 21 5 36 11 46 15 15-26 24-56 24-87 0-30-8-59-23-85-8 4-23 11-47 16 6 21 9 42 10 64z m-19 102c-13 30-30 53-46 69 34-10 64-30 86-57-9-4-22-8-40-12z m-6-95c0-23-4-45-11-66-20 4-42 6-65 6l0 120c23 1 45 3 66 6 6-21 10-43 10-66z m-46-170c17 17 37 41 52 75 20-5 34-10 42-13-24-31-57-53-94-62z m-30 256l0 77c17-14 40-37 56-73-17-2-36-4-56-4z m0-248l0 77c20-1 39-3 56-5-16-35-40-59-56-72z m-83 252c17 35 40 59 56 73l0-77c-19 0-38 1-56 4z m-19-90c0 23 4 45 10 65 20-3 42-5 65-5l0-120c-23 0-45-1-65-4-6 20-10 42-10 64z m-47 106c22 28 52 48 86 58-15-16-33-39-46-70-18 4-31 8-40 12z m40-199c15-36 37-61 53-77-38 10-72 32-96 64 9 4 24 9 43 13z m82 8l0-77c-16 13-39 37-56 73 18 2 37 3 56 4z m-100 92l-1 0 0-4c0-1 0-1 0-2 0 0 0 0 0-1 0 0 0 0 0-1 0 0 0-1 0-1l0-5 1 0c0-21 4-42 10-62-23-5-39-10-49-15-14 25-21 53-21 82 0 30 8 60 23 86 10-4 25-10 47-14-6-20-10-41-10-63z"/>
<glyph glyph-name="wand" unicode="&#57389;" d="M438 107l-80 78c-5 5-12 7-18 6l-77 78c-5 5-14 5-19 0-5-5-6-14 0-19l77-79c0-6 2-12 7-17l80-78c5-4 10-6 15-6 6 0 12 2 16 6 8 9 8 22-1 31z m-185 209l-28 0 0 27c0 6-5 11-12 11-6 0-11-5-11-11l0-27-27 0c-6 0-11-5-11-12 0-6 5-11 11-11l27 0 0-28c0-6 5-11 11-11 7 0 12 5 12 11l0 28 28 0c6 0 11 5 11 11 0 7-5 12-11 12z m51-22c-6 0-10 4-10 10 0 5 4 10 10 10 15 0 31 0 45 0 6 0 10-5 10-10 0-6-4-10-10-10-14 0-30 0-45 0 0 0 0 0 0 0z m-184 0c0 0 0 0 0 0-12 0-26 0-40 0 0 0 0 0 0 0-5 0-10 4-10 10 0 5 5 10 10 10 14 0 28 0 41 0 5 0 10-5 10-10-1-6-5-10-11-10z m94-129c-5 0-10 4-10 9 0 14 0 26 0 40 0 5 5 9 10 9 0 0 0 0 0 0 6 0 10-5 10-10 0-13 0-25 0-38 0-6-4-10-10-10 0 0 0 0 0 0z m0 223c-5 0-10 4-10 9 0 14 0 26 0 40 0 5 5 9 10 9 6 0 10-5 10-10 0-13 0-25 0-38 0-6-4-10-10-10 0 0 0 0 0 0z m-68-26c-2 0-4 0-6 2-6 5-11 10-16 15-4 5-8 9-12 13-4 4-5 10-1 14 4 4 10 4 14 1 5-5 9-9 14-14 4-5 9-10 14-14 4-4 4-10 1-14-2-2-5-3-8-3z m-24-159c-3 0-5 1-7 3-4 3-4 10-1 14 5 5 9 10 14 14 5 4 9 8 12 12 4 4 10 5 14 1 4-4 5-10 1-14-4-5-9-10-13-14-5-4-9-8-13-12-2-2-4-4-7-4z m157 157c-3 0-5 1-6 2-5 3-6 10-2 14 4 6 10 11 15 16 5 4 10 8 13 12 3 5 10 6 14 2 4-3 5-9 2-14-5-6-10-10-15-15-5-4-10-8-13-13-2-2-5-4-8-4z"/>
<glyph glyph-name="market" unicode="&#116;" d="M428 332c-2 4-7 7-12 7-5 1-10 1-14 1-5 0-10 1-15 1-27 1-51 2-75 3-23 1-47 2-74 3-10 0-18 1-27 1-9 0-18 1-27 1l-1 0 0 1c-2 8-8 26-12 39-2 5-3 9-4 12-2 8-7 12-16 12l-48 0c-9 0-16-6-16-15 0-8 7-14 16-14l32 0c5 0 7-3 8-7l0 0c6-25 13-51 19-76 7-24 13-50 19-75 2-9 3-16 0-24-1-4-2-9-3-14-1-4-2-9-3-14-2-8-2-14 1-17 3-4 8-6 16-6l190 0c4 1 7 3 9 6 3 3 4 8 3 12-1 8-7 12-17 12l-170 0 1 1c0 1 1 4 1 6 2 7 5 17 4 20l0 1c1 6 5 10 12 10 8 0 16 0 24 0 43 2 87 3 128 5 8 1 12 4 15 10 8 15 29 65 36 86l0 0c3 4 3 8 0 12z m-45-224c0-16-13-30-29-30-16 0-29 13-29 30 0 15 13 30 29 30 16-1 29-15 29-30z m-177 1c0-16-14-29-29-29-16 0-29 14-29 29 0 17 13 30 29 30 16-1 29-14 29-30z"/>
<glyph glyph-name="wear" unicode="&#57390;" d="M451 180c3 1 5 4 6 7 1 3 1 7-1 10-2 3-4 5-8 6-3 1-6 1-10-1-6-4-13-5-19-6-3-1-6-1-7-1-1 0-1 0-1 0l-1 0-26 0 0 66c0 9-3 43-27 73-24 29-58 44-101 44-54 0-84-24-100-44-24-30-26-64-27-73l0-66-17 0c-2 0-4 0-8 1-8 1-17 3-27 7-7 3-14-1-17-7-2-7 1-14 8-17 14-6 27-8 33-9 3 0 6 0 8-1 1 0 1 0 2 0l299 0c1 0 2 0 3 0l0 0c2 1 6 1 10 2 6 1 18 3 28 9z m-295 80c0 15 6 39 20 58 18 22 45 34 80 34 35 0 62-12 80-34 15-19 21-43 22-58l0-6-202 0z m202-65l-202 0 0 33 202 0z"/>
<glyph glyph-name="certificate" unicode="&#57392;" d="M168 320l172 0c7 0 14 6 14 14 0 7-7 13-14 13l-172 0c-8 0-14-6-14-13 0-8 6-14 14-14z m0-55l63 0c7 0 13 6 13 13 0 8-6 13-13 13l-63 0c-8 0-14-5-14-13 0-7 6-13 14-13z m0-57l46 0c8 0 14 6 14 14 0 7-6 14-14 14l-46 0c-8 0-14-7-14-14 0-8 6-14 14-14z m-65 210l0-283 139 0c7 0 12 6 12 13 0 6-5 12-12 12l-114 0 0 233 256 0 0-83c0-7 6-12 13-12 6 0 12 5 12 12l0 108z m304-200c0 43-35 78-78 78-43 0-78-35-78-78 0-27 14-52 37-66l-3-69c0-5 2-9 6-11 5-3 10-2 13 1l27 20 26-21c2-2 5-3 8-3 2 0 4 0 5 1 4 2 7 7 7 12l-4 72c21 14 34 38 34 64z m-68-101c-4 4-10 4-14 1l-15-11 1 36c6-2 12-2 18-2 7 0 14 1 20 2l2-36z"/>
<glyph glyph-name="gift" unicode="&#57393;" d="M342 330c1 1 3 2 4 3 19 17 21 47 4 66-9 10-22 16-35 16-6 0-12-1-17-3-6 19-24 33-45 33-22 0-41-15-46-35-5 2-11 3-17 3-13 0-26-6-35-16-17-20-15-50 5-66 0 0 0 0 0-1l-82 0 0-84 27 0 0-166 298 0 0 166 27 0 0 84z m-45 50l0 1c1 1 2 2 4 3 5 5 10 6 14 6 6 0 12-3 16-8 4-4 6-9 5-15 0-6-3-11-7-15-2-2-3-3-4-3l0 0 0 0c-5-1-27-10-52-18 10 22 22 44 24 49z m-44 40c12 0 21-9 21-21 0-3 0-4 0-5l0 0 0 0c-2-5-11-24-21-48-10 23-19 42-21 47l0 1c0 1-1 3-1 5 0 12 10 21 22 21z m-79-40c4 5 10 8 16 8 4 0 9-1 14-5 2-2 3-3 4-4l0 0 0 0c2-5 11-23 22-47-24 7-44 13-49 15l-1 0c-1 1-2 2-4 3-9 8-10 21-2 30z m67-274l-110 0 0 140 110 0z m0 166l-137 0 0 32 137 0z m136-166l-111 0 0 140 111 0z m27 166l-138 0 0 32 138 0z"/>
<glyph glyph-name="update" unicode="&#57394;" d="M380 170c-7 0-13-6-13-13l0-12c0-5-4-9-9-9l-203 0c-5 0-9 4-9 9l0 114 33-27c6-4 14-4 19 2 4 5 4 13-2 18l-54 47c-3 2-5 3-8 3-4 0-7-1-9-3l-54-47c-6-5-6-13-1-18 4-6 13-6 18-1l32 26 0-114c0-19 16-35 35-35l203 0c19 0 35 16 35 35l0 12c0 7-6 13-13 13z m-248 153c7 0 13 5 13 13l0 12c0 5 4 8 9 8l203 0c5 0 9-4 9-8l0-115-33 27c-5 5-14 4-18-1-5-6-5-14 1-19l54-47c3-2 5-3 9-3 3 0 6 1 8 3l54 47c6 5 6 13 2 19-5 5-13 6-19 1l-32-27 0 115c0 19-16 34-35 34l-203 0c-19 0-35-15-35-34l0-12c0-8 6-13 13-13z"/>
<glyph glyph-name="uninstall" unicode="&#57395;" d="M83 227c-7 0-13-6-13-13l0-78c0-19 16-35 35-35l297 0c19 0 35 16 35 35l0 78c0 7-6 13-13 13-7 0-13-6-13-13l0-78c0-5-4-9-9-9l-297 0c-5 0-9 4-9 9l0 78c0 7-6 13-13 13z m191 47l50 50c5 5 5 14 0 19-5 5-13 5-19 0l-50-50-50 50c-5 5-13 5-19 0-5-5-5-14 0-19l50-50-50-50c-5-5-5-14 0-19 5-5 14-5 19 0l50 50 50-50c5-5 14-5 19 0 5 5 5 14 0 19z"/>
<glyph glyph-name="install" unicode="&#57391;" d="M83 227c-7 0-13-6-13-13l0-78c0-19 16-35 35-35l297 0c19 0 35 16 35 35l0 78c0 7-6 13-13 13-7 0-13-6-13-13l0-78c0-5-4-9-9-9l-297 0c-5 0-9 4-9 9l0 78c0 7-6 13-13 13z m170 171l0-155-33 27c-6 5-14 5-19-1-4-5-4-14 2-18l54-48c3-2 5-3 8-3 3 0 7 1 9 3l54 48c5 4 6 13 1 18-4 5-13 6-18 1l-32-27 0 154c0 8-6 13-13 13-7 0-13-5-13-12z"/>
<glyph glyph-name="ellipsis-vertical" unicode="&#57396;" d="M276 178c0-14-11-24-24-24-14 0-25 10-25 24 0 13 11 24 25 24 13 0 24-11 24-24z m0 78c0-14-11-24-24-24-14 0-25 10-25 24 0 13 11 24 25 24 13 0 24-11 24-24z m0 78c0-14-11-24-24-24-14 0-25 10-25 24 0 13 11 24 25 24 13 0 24-11 24-24z"/>
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View file

@ -12,7 +12,7 @@
<body>
<div class="container">
<h1>HiFi Glyphs</h1>
<p class="small">This font was created for use in<a href="http://highfidelity.io/">High Fidelity</a></p>
<p class="small">This font was created for use in <a href="http://highfidelity.io/">High Fidelity</a></p>
<h2>CSS mapping</h2>
<ul class="glyphs css-mapping">
<li>
@ -87,10 +87,6 @@
<div class="icon icon-edit"></div>
<input type="text" readonly="readonly" value="edit">
</li>
<li>
<div class="icon icon-market"></div>
<input type="text" readonly="readonly" value="market">
</li>
<li>
<div class="icon icon-directory"></div>
<input type="text" readonly="readonly" value="directory">
@ -567,6 +563,46 @@
<div class="icon icon-image"></div>
<input type="text" readonly="readonly" value="image">
</li>
<li>
<div class="icon icon-environments"></div>
<input type="text" readonly="readonly" value="environments">
</li>
<li>
<div class="icon icon-wand"></div>
<input type="text" readonly="readonly" value="wand">
</li>
<li>
<div class="icon icon-market"></div>
<input type="text" readonly="readonly" value="market">
</li>
<li>
<div class="icon icon-wear"></div>
<input type="text" readonly="readonly" value="wear">
</li>
<li>
<div class="icon icon-certificate"></div>
<input type="text" readonly="readonly" value="certificate">
</li>
<li>
<div class="icon icon-gift"></div>
<input type="text" readonly="readonly" value="gift">
</li>
<li>
<div class="icon icon-update"></div>
<input type="text" readonly="readonly" value="update">
</li>
<li>
<div class="icon icon-uninstall"></div>
<input type="text" readonly="readonly" value="uninstall">
</li>
<li>
<div class="icon icon-install"></div>
<input type="text" readonly="readonly" value="install">
</li>
<li>
<div class="icon icon-ellipsis-vertical"></div>
<input type="text" readonly="readonly" value="ellipsis-vertical">
</li>
</ul>
<h2>Character mapping</h2>
<ul class="glyphs character-mapping">
@ -642,10 +678,6 @@
<div data-icon="s" class="icon"></div>
<input type="text" readonly="readonly" value="s">
</li>
<li>
<div data-icon="t" class="icon"></div>
<input type="text" readonly="readonly" value="t">
</li>
<li>
<div data-icon="u" class="icon"></div>
<input type="text" readonly="readonly" value="u">
@ -1122,6 +1154,46 @@
<div data-icon="&#xe02a;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe02a;">
</li>
<li>
<div data-icon="&#xe02c;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe02c;">
</li>
<li>
<div data-icon="&#xe02d;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe02d;">
</li>
<li>
<div data-icon="t" class="icon"></div>
<input type="text" readonly="readonly" value="t">
</li>
<li>
<div data-icon="&#xe02e;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe02e;">
</li>
<li>
<div data-icon="&#xe030;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe030;">
</li>
<li>
<div data-icon="&#xe031;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe031;">
</li>
<li>
<div data-icon="&#xe032;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe032;">
</li>
<li>
<div data-icon="&#xe033;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe033;">
</li>
<li>
<div data-icon="&#xe02f;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe02f;">
</li>
<li>
<div data-icon="&#xe034;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe034;">
</li>
</ul>
</div>
<script>(function() {

View file

@ -92,9 +92,6 @@
.icon-edit:before {
content: "\73";
}
.icon-market:before {
content: "\74";
}
.icon-directory:before {
content: "\75";
}
@ -452,3 +449,33 @@
.icon-image:before {
content: "\e02a";
}
.icon-environments:before {
content: "\e02c";
}
.icon-wand:before {
content: "\e02d";
}
.icon-market:before {
content: "\74";
}
.icon-wear:before {
content: "\e02e";
}
.icon-certificate:before {
content: "\e030";
}
.icon-gift:before {
content: "\e031";
}
.icon-update:before {
content: "\e032";
}
.icon-uninstall:before {
content: "\e033";
}
.icon-install:before {
content: "\e02f";
}
.icon-ellipsis-vertical:before {
content: "\e034";
}

View file

@ -8,8 +8,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
@ -28,17 +29,11 @@ TextField {
property int roundedBorderRadius: 4
property bool error: false;
property bool hasClearButton: false;
property alias textColor: textField.color
property string leftPermanentGlyph: "";
property string centerPlaceholderGlyph: "";
placeholderText: textField.placeholderText
property bool rightAnchorSet: false;
anchors.onRightChanged: {
rightAnchorSet = true;
}
font.family: "Fira Sans"
font.pixelSize: hifi.fontSizes.textFieldInput
height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered.
@ -49,56 +44,42 @@ TextField {
// workaround for https://bugreports.qt.io/browse/QTBUG-49297
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
event.accepted = true;
case Qt.Key_Return:
case Qt.Key_Enter:
event.accepted = true;
// emit accepted signal manually
if (acceptableInput) {
accepted();
}
// emit accepted signal manually
if (acceptableInput) {
accepted();
}
}
}
Text {
id: placeholder
x: textField.leftPadding
y: textField.topPadding
width: textField.width - (textField.leftPadding + textField.rightPadding)
height: textField.height - (textField.topPadding + textField.bottomPadding)
text: textField.placeholderText
font: textField.font
color: textField.placeholderTextColor
verticalAlignment: textField.verticalAlignment
visible: !textField.length && !textField.preeditText && (!textField.activeFocus || textField.horizontalAlignment !== Qt.AlignHCenter)
elide: Text.ElideRight
}
color: {
if (isLightColorScheme) {
if (textField.activeFocus) {
hifi.colors.black
style: TextFieldStyle {
id: style;
textColor: {
if (isLightColorScheme) {
if (textField.activeFocus) {
hifi.colors.black
} else {
hifi.colors.lightGray
}
} else if (isFaintGrayColorScheme) {
if (textField.activeFocus) {
hifi.colors.black
} else {
hifi.colors.lightGray
}
} else {
hifi.colors.lightGray
}
} else if (isFaintGrayColorScheme) {
if (textField.activeFocus) {
hifi.colors.black
} else {
hifi.colors.lightGray
}
} else {
if (textField.activeFocus) {
hifi.colors.white
} else {
hifi.colors.lightGrayText
if (textField.activeFocus) {
hifi.colors.white
} else {
hifi.colors.lightGrayText
}
}
}
}
background: Rectangle {
color: {
background: Rectangle {
color: {
if (isLightColorScheme) {
if (textField.activeFocus) {
hifi.colors.white
@ -119,22 +100,22 @@ TextField {
}
}
}
border.color: textField.error ? hifi.colors.redHighlight :
border.color: textField.error ? hifi.colors.redHighlight :
(textField.activeFocus ? hifi.colors.primaryHighlight : (hasDefocusedBorder ? (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray) : color))
border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0
border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0
radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? roundedBorderRadius : 0)
HiFiGlyphs {
HiFiGlyphs {
text: textField.leftPermanentGlyph;
color: textColor;
size: hifi.fontSizes.textFieldSearchIcon;
anchors.left: parent.left;
anchors.verticalCenter: parent.verticalCenter;
anchors.leftMargin: hifi.dimensions.textPadding - 2;
visible: text;
}
color: textColor;
size: hifi.fontSizes.textFieldSearchIcon;
anchors.left: parent.left;
anchors.verticalCenter: parent.verticalCenter;
anchors.leftMargin: hifi.dimensions.textPadding - 2;
visible: text;
}
HiFiGlyphs {
HiFiGlyphs {
text: textField.centerPlaceholderGlyph;
color: textColor;
size: parent.height;
@ -144,57 +125,48 @@ TextField {
}
HiFiGlyphs {
text: hifi.glyphs.search
color: textColor
size: hifi.fontSizes.textFieldSearchIcon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: hifi.dimensions.textPadding - 2
visible: isSearchField
}
text: hifi.glyphs.search
color: textColor
size: hifi.fontSizes.textFieldSearchIcon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: hifi.dimensions.textPadding - 2
visible: isSearchField
}
HiFiGlyphs {
text: hifi.glyphs.error
color: textColor
size: 40
anchors.right: parent.right
anchors.rightMargin: hifi.dimensions.textPadding - 2
anchors.verticalCenter: parent.verticalCenter
visible: hasClearButton && textField.text !== "";
HiFiGlyphs {
text: hifi.glyphs.error
color: textColor
size: 40
anchors.right: parent.right
anchors.rightMargin: hifi.dimensions.textPadding - 2
anchors.verticalCenter: parent.verticalCenter
visible: hasClearButton && textField.text !== "";
MouseArea {
anchors.fill: parent;
onClicked: {
textField.text = "";
MouseArea {
anchors.fill: parent;
onClicked: {
textField.text = "";
}
}
}
}
placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding
}
property color placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
leftPadding: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
rightPadding: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding
HifiControls.Label {
id: textFieldLabel
text: textField.label
colorScheme: textField.colorScheme
anchors.left: parent.left
Binding on anchors.right {
when: rightAnchorSet
value: textField.right
}
Binding on wrapMode {
when: rightAnchorSet
value: Text.WordWrap
}
anchors.right: parent.right
anchors.bottom: parent.top
anchors.bottomMargin: 3
wrapMode: Text.WordWrap
visible: label != ""
}
}

View file

@ -257,9 +257,14 @@ Rectangle {
lightboxPopup.bodyImageSource = msg.securityImageSource;
lightboxPopup.bodyText = lightboxPopup.securityPicBodyText;
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "GO TO WALLET";
lightboxPopup.button2method = "sendToParent({method: 'checkout_openWallet'});";
lightboxPopup.button2method = function() {
lightboxPopup.visible = false;
sendToScript({method: 'checkout_openWallet'});
};
lightboxPopup.visible = true;
} else {
sendToScript(msg);
@ -623,10 +628,16 @@ Rectangle {
lightboxPopup.bodyText = "You will not be able to replace this domain's content with <b>" + root.itemName +
" </b>until the server owner gives you 'Replace Content' permissions.<br><br>Are you sure you want to purchase this content set?";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = "Commerce.buy('" + root.itemId + "', " + root.itemPrice + ");" +
"root.visible = false; buyButton.enabled = false; loading.visible = true;";
lightboxPopup.button2method = function() {
Commerce.buy(root.itemId, root.itemPrice);
lightboxPopup.visible = false;
buyButton.enabled = false;
loading.visible = true;
};
lightboxPopup.visible = true;
} else {
buyButton.enabled = false;
@ -771,19 +782,30 @@ Rectangle {
"<a href='https://docs.highfidelity.com/create-and-explore/start-working-in-your-sandbox/restoring-sandbox-content'>" +
"click here to open info on your desktop browser.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "', '" + root.certificateId + "');" +
"root.visible = false;rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start();" +
"UserActivityLogger.commerceEntityRezzed('" + root.itemId + "', 'checkout', '" + root.itemType + "');";
lightboxPopup.button2method = function() {
Commerce.replaceContentSet(root.itemHref);
lightboxPopup.visible = false;
rezzedNotifContainer.visible = true;
rezzedNotifContainerTimer.start();
UserActivityLogger.commerceEntityRezzed(root.itemId, 'checkout', root.itemType);
};
lightboxPopup.visible = true;
} else if (root.itemType === "avatar") {
lightboxPopup.titleText = "Change Avatar";
lightboxPopup.bodyText = "This will change your current avatar to " + root.itemName + " while retaining your wearables.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = "MyAvatar.useFullAvatarURL('" + root.itemHref + "'); root.visible = false;";
lightboxPopup.button2method = function() {
MyAvatar.useFullAvatarURL(root.itemHref);
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else if (root.itemType === "app") {
if (root.isInstalled) {
@ -822,9 +844,14 @@ Rectangle {
lightboxPopup.bodyText = "You don't have permission to rez certified items in this domain.<br><br>" +
"Use the <b>GOTO app</b> to visit another domain or <b>go to your own sandbox.</b>";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "OPEN GOTO";
lightboxPopup.button2method = "sendToParent({method: 'purchases_openGoTo'});";
lightboxPopup.button2method = function() {
sendToScript({method: 'purchases_openGoTo'});
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
}
}
@ -918,7 +945,9 @@ Rectangle {
lightboxPopup.bodyText = 'Your item is marked "pending" while your purchase is being confirmed.<br><br>' +
'Confirmations usually take about 90 seconds.';
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
}
}

View file

@ -26,10 +26,10 @@ Rectangle {
property string bodyText;
property string button1color: hifi.buttons.noneBorderlessGray;
property string button1text;
property string button1method;
property string button2color: hifi.buttons.noneBorderless;
property var button1method;
property string button2color: hifi.buttons.blue;
property string button2text;
property string button2method;
property var button2method;
property string buttonLayout: "leftright";
readonly property string securityPicBodyText: "When you see your Security Pic, your actions and data are securely making use of your " +
@ -72,7 +72,7 @@ Rectangle {
anchors.right: parent.right;
anchors.rightMargin: 30;
height: paintedHeight;
color: hifi.colors.baseGray;
color: hifi.colors.black;
size: 24;
verticalAlignment: Text.AlignTop;
wrapMode: Text.WordWrap;
@ -104,7 +104,7 @@ Rectangle {
anchors.right: parent.right;
anchors.rightMargin: 30;
height: paintedHeight;
color: hifi.colors.baseGray;
color: hifi.colors.black;
size: 20;
verticalAlignment: Text.AlignTop;
wrapMode: Text.WordWrap;
@ -129,15 +129,15 @@ Rectangle {
colorScheme: hifi.colorSchemes.light;
anchors.top: root.buttonLayout === "leftright" ? parent.top : parent.top;
anchors.left: parent.left;
anchors.leftMargin: 10;
anchors.leftMargin: root.buttonLayout === "leftright" ? 30 : 10;
anchors.right: root.buttonLayout === "leftright" ? undefined : parent.right;
anchors.rightMargin: root.buttonLayout === "leftright" ? undefined : 10;
width: root.buttonLayout === "leftright" ? (root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2) :
(undefined);
height: 50;
height: 40;
text: root.button1text;
onClicked: {
eval(button1method);
button1method();
}
}
@ -152,12 +152,12 @@ Rectangle {
anchors.left: root.buttonLayout === "leftright" ? undefined : parent.left;
anchors.leftMargin: root.buttonLayout === "leftright" ? undefined : 10;
anchors.right: parent.right;
anchors.rightMargin: 10;
anchors.rightMargin: root.buttonLayout === "leftright" ? 30 : 10;
width: root.buttonLayout === "leftright" ? parent.width/2 - anchors.rightMargin*2 : undefined;
height: 50;
height: 40;
text: root.button2text;
onClicked: {
eval(button2method);
button2method();
}
}
}
@ -174,10 +174,10 @@ Rectangle {
root.bodyText = "";
root.button1color = hifi.buttons.noneBorderlessGray;
root.button1text = "";
root.button1method = "";
root.button2color = hifi.buttons.noneBorderless;
root.button1method = function() {};
root.button2color = hifi.buttons.blue;
root.button2text = "";
root.button2method = "";
root.button2method = function() {};
root.buttonLayout = "leftright";
}
//

View file

@ -1,6 +1,6 @@
//
// ConnectionItem.qml
// qml/hifi/commerce/wallet/sendMoney
// qml/hifi/commerce/common/sendAsset
//
// ConnectionItem
//
@ -113,7 +113,7 @@ Item {
text: "CHOOSE";
onClicked: {
var msg = { method: 'chooseConnection', userName: root.userName, profilePicUrl: root.profilePicUrl };
sendToSendMoney(msg);
sendToParent(msg);
}
}
}
@ -121,7 +121,7 @@ Item {
//
// FUNCTION DEFINITIONS START
//
signal sendToSendMoney(var msg);
signal sendToParent(var msg);
//
// FUNCTION DEFINITIONS END
//

View file

@ -1,6 +1,6 @@
//
// RecipientDisplay.qml
// qml/hifi/commerce/wallet/sendMoney
// qml/hifi/commerce/common/sendAsset
//
// RecipientDisplay
//
@ -18,7 +18,7 @@ import QtGraphicalEffects 1.0
import "../../../../styles-uit"
import "../../../../controls-uit" as HifiControlsUit
import "../../../../controls" as HifiControls
import "../../common" as HifiCommerceCommon
import "../" as HifiCommerceCommon
Item {
HifiConstants { id: hifi; }

View file

@ -13,7 +13,6 @@
import Hifi 1.0 as Hifi
import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../../../styles-uit"
@ -22,14 +21,11 @@ import "../../../controls" as HifiControls
import "../wallet" as HifiWallet
import TabletScriptingInterface 1.0
// references XXX from root context
Item {
HifiConstants { id: hifi; }
id: root;
property string purchaseStatus;
property bool purchaseStatusChanged;
property string itemName;
property string itemId;
property string itemPreviewImageUrl;
@ -46,16 +42,18 @@ Item {
property var buttonGlyph: [hifi.glyphs.wand, hifi.glyphs.hat, hifi.glyphs.globe, hifi.glyphs.install, hifi.glyphs.avatar];
property bool showConfirmation: false;
property bool hasPermissionToRezThis;
property bool permissionExplanationCardVisible;
property bool cardBackVisible;
property bool isInstalled;
property string wornEntityID;
property string upgradeUrl;
property string upgradeTitle;
property bool updateAvailable: root.upgradeUrl !== "" && !root.isShowingMyItems;
property bool isShowingMyItems;
property string originalStatusText;
property string originalStatusColor;
height: (root.upgradeUrl === "" || root.isShowingMyItems) ? 110 : 150;
height: 102;
width: parent.width;
Connections {
@ -99,16 +97,6 @@ Item {
}
}
onPurchaseStatusChangedChanged: {
if (root.purchaseStatusChanged === true && root.purchaseStatus === "confirmed") {
root.originalStatusText = statusText.text;
root.originalStatusColor = statusText.color;
statusText.text = "CONFIRMED!";
statusText.color = hifi.colors.blueAccent;
confirmedTimer.start();
}
}
onShowConfirmationChanged: {
if (root.showConfirmation) {
rezzedNotifContainer.visible = true;
@ -118,35 +106,307 @@ Item {
}
}
Timer {
id: confirmedTimer;
interval: 3000;
onTriggered: {
statusText.text = root.originalStatusText;
statusText.color = root.originalStatusColor;
root.purchaseStatusChanged = false;
Rectangle {
id: background;
z: 10;
color: Qt.rgba(0, 0, 0, 0.25);
anchors.fill: parent;
}
Flipable {
id: flipable;
z: 50;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.top: parent.top;
height: root.height - 2;
front: mainContainer;
back: Rectangle {
anchors.fill: parent;
color: hifi.colors.white;
Item {
id: closeContextMenuContainer;
anchors.right: parent.right;
anchors.rightMargin: 8;
anchors.top: parent.top;
anchors.topMargin: 8;
width: 30;
height: width;
HiFiGlyphs {
id: closeContextMenuGlyph;
text: hifi.glyphs.close;
anchors.fill: parent;
size: 26;
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
color: hifi.colors.black;
}
MouseArea {
anchors.fill: parent;
hoverEnabled: enabled;
onClicked: {
root.sendToPurchases({ method: 'flipCard', closeAll: true });
}
onEntered: {
closeContextMenuGlyph.text = hifi.glyphs.closeInverted;
}
onExited: {
closeContextMenuGlyph.text = hifi.glyphs.close;
}
}
}
Rectangle {
id: contextCard;
z: 2;
anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.right: closeContextMenuContainer.left;
anchors.rightMargin: 8;
color: hifi.colors.white;
Component {
id: contextCardButton;
Item {
property alias buttonGlyphText: buttonGlyph.text;
property alias buttonText: buttonText.text;
property string buttonColor: hifi.colors.black;
property string buttonColor_hover: hifi.colors.blueHighlight;
property alias enabled: buttonMouseArea.enabled;
property var buttonClicked;
HiFiGlyphs {
id: buttonGlyph;
anchors.top: parent.top;
anchors.topMargin: 4;
anchors.horizontalCenter: parent.horizontalCenter;
anchors.bottom: parent.verticalCenter;
width: parent.width;
size: 40;
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
color: buttonMouseArea.enabled ? buttonColor : hifi.colors.lightGrayText;
}
RalewayRegular {
id: buttonText;
anchors.top: parent.verticalCenter;
anchors.topMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 12;
anchors.horizontalCenter: parent.horizontalCenter;
width: parent.width;
color: buttonMouseArea.enabled ? buttonColor : hifi.colors.lightGrayText;
size: 16;
wrapMode: Text.Wrap;
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
MouseArea {
id: buttonMouseArea;
anchors.fill: parent;
hoverEnabled: enabled;
onClicked: {
parent.buttonClicked();
}
onEntered: {
buttonGlyph.color = buttonColor_hover;
buttonText.color = buttonColor_hover;
}
onExited: {
buttonGlyph.color = buttonColor;
buttonText.color = buttonColor;
}
}
}
}
Loader {
id: giftButton;
visible: !root.isShowingMyItems;
sourceComponent: contextCardButton;
anchors.right: parent.right;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: 62;
onLoaded: {
item.enabled = (root.purchaseStatus === "confirmed");
item.buttonGlyphText = hifi.glyphs.gift;
item.buttonText = "Gift";
item.buttonClicked = function() {
sendToPurchases({ method: 'flipCard', closeAll: true });
sendToPurchases({
method: 'giftAsset',
itemName: root.itemName,
certId: root.certificateId,
itemType: root.itemType,
itemHref: root.itemHref,
isInstalled: root.isInstalled,
wornEntityID: root.wornEntityID,
effectImage: root.itemPreviewImageUrl
});
}
}
}
Loader {
id: marketplaceButton;
sourceComponent: contextCardButton;
anchors.right: giftButton.visible ? giftButton.left : parent.right;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: 100;
onLoaded: {
item.buttonGlyphText = hifi.glyphs.market;
item.buttonText = "View in Marketplace";
item.buttonClicked = function() {
sendToPurchases({ method: 'flipCard', closeAll: true });
sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId});
}
}
}
Loader {
id: certificateButton;
sourceComponent: contextCardButton;
anchors.right: marketplaceButton.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: 100;
onLoaded: {
item.buttonGlyphText = hifi.glyphs.certificate;
item.buttonText = "View Certificate";
item.buttonClicked = function() {
sendToPurchases({ method: 'flipCard', closeAll: true });
sendToPurchases({method: 'purchases_itemCertificateClicked', itemCertificateId: root.certificateId});
}
}
}
Loader {
id: uninstallButton;
visible: root.isInstalled;
sourceComponent: contextCardButton;
anchors.right: certificateButton.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: 78;
onLoaded: {
item.buttonGlyphText = hifi.glyphs.uninstall;
item.buttonText = "Uninstall";
item.buttonClicked = function() {
sendToPurchases({ method: 'flipCard', closeAll: true });
Commerce.uninstallApp(root.itemHref);
}
}
}
Loader {
id: updateButton;
visible: root.updateAvailable;
sourceComponent: contextCardButton;
anchors.right: uninstallButton.visible ? uninstallButton.left : certificateButton.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: 84;
onLoaded: {
item.buttonGlyphText = hifi.glyphs.update;
item.buttonText = "Update";
item.buttonColor = "#E2334D";
item.buttonClicked = function() {
sendToPurchases({ method: 'flipCard', closeAll: true });
sendToPurchases({method: 'updateItemClicked', itemId: root.itemId, itemEdition: root.itemEdition, upgradeUrl: root.upgradeUrl});
}
}
}
}
Rectangle {
id: permissionExplanationCard;
z: 1;
anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.right: closeContextMenuContainer.left;
anchors.rightMargin: 8;
color: hifi.colors.white;
RalewayRegular {
id: permissionExplanationText;
anchors.fill: parent;
text: {
if (root.itemType === "contentSet") {
"You do not have 'Replace Content' permissions in this domain. <a href='#replaceContentPermission'>Learn more</a>";
} else if (root.itemType === "entity") {
"You do not have 'Rez Certified' permissions in this domain. <a href='#rezCertifiedPermission'>Learn more</a>";
} else {
"Hey! You're not supposed to see this. How is it even possible that you're here? Are you a developer???"
}
}
size: 16;
color: hifi.colors.baseGray;
wrapMode: Text.Wrap;
verticalAlignment: Text.AlignVCenter;
onLinkActivated: {
sendToPurchases({method: 'showPermissionsExplanation', itemType: root.itemType});
}
}
}
}
transform: Rotation {
id: rotation;
origin.x: flipable.width/2;
origin.y: flipable.height/2;
axis.x: 1;
axis.y: 0;
axis.z: 0;
angle: 0;
}
states: State {
name: "back";
PropertyChanges {
target: rotation;
angle: 180;
}
when: root.cardBackVisible;
}
transitions: Transition {
SmoothedAnimation {
target: rotation;
property: "angle";
velocity: 600;
}
}
}
Rectangle {
id: mainContainer;
z: 51;
// Style
color: hifi.colors.white;
// Size
anchors.left: parent.left;
anchors.leftMargin: 16;
anchors.right: parent.right;
anchors.rightMargin: 16;
anchors.verticalCenter: parent.verticalCenter;
height: root.height - 10;
// START "incorrect indentation to prevent insane diffs"
Item {
id: itemContainer;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.top: parent.top;
height: 100;
height: root.height - 2;
Image {
id: itemPreviewImage;
@ -154,8 +414,9 @@ Item {
anchors.left: parent.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: height;
width: height * 1.78;
fillMode: Image.PreserveAspectCrop;
mipmap: true;
MouseArea {
anchors.fill: parent;
@ -165,218 +426,53 @@ Item {
}
}
TextMetrics {
id: itemNameTextMetrics;
font: itemName.font;
text: itemName.text;
}
RalewaySemiBold {
RalewayRegular {
id: itemName;
anchors.top: itemPreviewImage.top;
anchors.top: parent.top;
anchors.topMargin: 4;
anchors.left: itemPreviewImage.right;
anchors.leftMargin: 8;
width: !noPermissionGlyph.visible ? (buttonContainer.x - itemPreviewImage.x - itemPreviewImage.width - anchors.leftMargin) :
Math.min(itemNameTextMetrics.tightBoundingRect.width + 2,
buttonContainer.x - itemPreviewImage.x - itemPreviewImage.width - anchors.leftMargin - noPermissionGlyph.width + 2);
anchors.leftMargin: 10;
anchors.right: contextMenuButtonContainer.left;
anchors.rightMargin: 4;
height: paintedHeight;
// Text size
size: 24;
size: 20;
// Style
color: hifi.colors.blueAccent;
color: hifi.colors.black;
text: root.itemName;
elide: Text.ElideRight;
// Alignment
horizontalAlignment: Text.AlignLeft;
verticalAlignment: Text.AlignVCenter;
MouseArea {
anchors.fill: parent;
hoverEnabled: enabled;
onClicked: {
sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId});
}
onEntered: {
itemName.color = hifi.colors.blueHighlight;
}
onExited: {
itemName.color = hifi.colors.blueAccent;
}
}
}
HiFiGlyphs {
id: noPermissionGlyph;
visible: !root.hasPermissionToRezThis;
anchors.verticalCenter: itemName.verticalCenter;
anchors.left: itemName.right;
anchors.leftMargin: itemName.truncated ? -10 : -2;
text: hifi.glyphs.info;
// Size
size: 40;
width: 32;
// Style
color: hifi.colors.redAccent;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
onEntered: {
noPermissionGlyph.color = hifi.colors.redHighlight;
}
onExited: {
noPermissionGlyph.color = hifi.colors.redAccent;
}
onClicked: {
root.sendToPurchases({ method: 'openPermissionExplanationCard' });
}
}
}
Rectangle {
id: permissionExplanationCard;
z: 995;
visible: root.permissionExplanationCardVisible;
anchors.fill: parent;
color: hifi.colors.white;
RalewayRegular {
id: permissionExplanationText;
text: {
if (root.itemType === "contentSet") {
"You do not have 'Replace Content' permissions in this domain. <a href='#replaceContentPermission'>Learn more</a>";
} else if (root.itemType === "entity") {
"You do not have 'Rez Certified' permissions in this domain. <a href='#rezCertifiedPermission'>Learn more</a>";
} else {
""
}
}
size: 16;
anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.right: permissionExplanationGlyph.left;
color: hifi.colors.baseGray;
wrapMode: Text.WordWrap;
verticalAlignment: Text.AlignVCenter;
onLinkActivated: {
sendToPurchases({method: 'showPermissionsExplanation', itemType: root.itemType});
}
}
// "Close" button
HiFiGlyphs {
id: permissionExplanationGlyph;
text: hifi.glyphs.close;
color: hifi.colors.baseGray;
size: 26;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.right: parent.right;
width: 77;
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
onEntered: {
parent.text = hifi.glyphs.closeInverted;
}
onExited: {
parent.text = hifi.glyphs.close;
}
onClicked: {
root.sendToPurchases({ method: 'openPermissionExplanationCard', closeAll: true });
}
}
}
}
Item {
id: certificateContainer;
anchors.top: itemName.bottom;
anchors.topMargin: 4;
anchors.left: itemName.left;
anchors.right: buttonContainer.left;
anchors.rightMargin: 2;
height: 24;
HiFiGlyphs {
id: certificateIcon;
text: hifi.glyphs.scriptNew;
// Size
size: 30;
// Anchors
anchors.top: parent.top;
anchors.left: parent.left;
anchors.bottom: parent.bottom;
width: 32;
// Style
color: hifi.colors.black;
}
RalewayRegular {
id: viewCertificateText;
text: "VIEW CERTIFICATE";
size: 13;
anchors.left: certificateIcon.right;
anchors.leftMargin: 4;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.right: parent.right;
color: hifi.colors.black;
}
MouseArea {
anchors.fill: parent;
hoverEnabled: enabled;
onClicked: {
sendToPurchases({method: 'purchases_itemCertificateClicked', itemCertificateId: root.certificateId});
}
onEntered: {
certificateIcon.color = hifi.colors.lightGray;
viewCertificateText.color = hifi.colors.lightGray;
}
onExited: {
certificateIcon.color = hifi.colors.black;
viewCertificateText.color = hifi.colors.black;
}
}
}
Item {
id: editionContainer;
RalewayRegular {
id: editionNumberText;
visible: root.displayedItemCount > 1 && !statusContainer.visible;
anchors.left: itemName.left;
anchors.top: certificateContainer.bottom;
anchors.topMargin: 8;
anchors.bottom: parent.bottom;
anchors.right: buttonContainer.left;
anchors.rightMargin: 2;
RalewayRegular {
anchors.left: parent.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: paintedWidth;
text: "#" + root.itemEdition;
size: 13;
color: hifi.colors.black;
verticalAlignment: Text.AlignTop;
}
anchors.right: itemName.right;
anchors.top: itemName.bottom;
anchors.topMargin: 4;
anchors.bottom: buttonContainer.top;
anchors.bottomMargin: 4;
width: itemName.width;
text: "Edition #" + root.itemEdition;
size: 13;
color: hifi.colors.black;
verticalAlignment: Text.AlignVCenter;
}
Item {
id: statusContainer;
visible: root.purchaseStatus === "pending" || root.purchaseStatus === "invalidated" || root.purchaseStatusChanged || root.numberSold > -1;
visible: root.purchaseStatus === "pending" || root.purchaseStatus === "invalidated" || root.numberSold > -1;
anchors.left: itemName.left;
anchors.top: certificateContainer.bottom;
anchors.topMargin: 8;
anchors.bottom: parent.bottom;
anchors.right: buttonContainer.left;
anchors.rightMargin: 2;
anchors.right: itemName.right;
anchors.top: itemName.bottom;
anchors.topMargin: 4;
anchors.bottom: buttonContainer.top;
anchors.bottomMargin: 4;
RalewaySemiBold {
RalewayRegular {
id: statusText;
anchors.left: parent.left;
anchors.top: parent.top;
@ -393,7 +489,7 @@ Item {
""
}
}
size: 18;
size: 13;
color: {
if (root.purchaseStatus === "pending") {
hifi.colors.blueAccent
@ -418,10 +514,10 @@ Item {
}
}
// Size
size: 36;
size: 34;
// Anchors
anchors.top: parent.top;
anchors.topMargin: -8;
anchors.topMargin: -10;
anchors.left: statusText.right;
anchors.bottom: parent.bottom;
// Style
@ -468,6 +564,50 @@ Item {
}
}
Item {
id: contextMenuButtonContainer;
anchors.right: parent.right;
anchors.rightMargin: 8;
anchors.top: parent.top;
anchors.topMargin: 8;
width: 30;
height: width;
Rectangle {
visible: root.updateAvailable;
anchors.fill: parent;
radius: height;
border.width: 1;
border.color: "#E2334D";
}
HiFiGlyphs {
id: contextMenuGlyph;
text: hifi.glyphs.verticalEllipsis;
anchors.fill: parent;
size: 46;
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
color: root.updateAvailable ? "#E2334D" : hifi.colors.black;
}
MouseArea {
anchors.fill: parent;
hoverEnabled: enabled;
onClicked: {
contextCard.z = 1;
permissionExplanationCard.z = 0;
root.sendToPurchases({ method: 'flipCard' });
}
onEntered: {
contextMenuGlyph.color = root.updateAvailable ? hifi.colors.redHighlight : hifi.colors.blueHighlight;
}
onExited: {
contextMenuGlyph.color = root.updateAvailable ? "#E2334D" : hifi.colors.black;
}
}
}
Rectangle {
id: rezzedNotifContainer;
z: 998;
@ -489,62 +629,22 @@ Item {
horizontalAlignment: Text.AlignHCenter;
}
Timer {
id: rezzedNotifContainerTimer;
interval: 2000;
onTriggered: rezzedNotifContainer.visible = false
}
}
Rectangle {
id: appButtonContainer;
color: hifi.colors.white;
z: 994;
visible: root.isInstalled;
anchors.fill: buttonContainer;
HifiControlsUit.Button {
id: openAppButton;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top;
anchors.right: parent.right;
anchors.left: parent.left;
width: 92;
height: 44;
text: "OPEN"
onClicked: {
Commerce.openApp(root.itemHref);
}
}
HifiControlsUit.Button {
id: uninstallAppButton;
color: hifi.buttons.noneBorderless;
colorScheme: hifi.colorSchemes.light;
anchors.bottom: parent.bottom;
anchors.right: parent.right;
anchors.left: parent.left;
height: 44;
text: "UNINSTALL"
onClicked: {
Commerce.uninstallApp(root.itemHref);
}
Timer {
id: rezzedNotifContainerTimer;
interval: 2000;
onTriggered: rezzedNotifContainer.visible = false
}
}
Button {
id: buttonContainer;
property int color: hifi.buttons.blue;
property int colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top;
anchors.topMargin: 4;
anchors.left: itemName.left;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
anchors.right: parent.right;
anchors.rightMargin: 4;
width: height;
anchors.bottomMargin: 8;
width: 160;
height: 40;
enabled: root.hasPermissionToRezThis &&
root.purchaseStatus !== "invalidated" &&
MyAvatar.skeletonModelURL !== root.itemHref;
@ -568,8 +668,12 @@ Item {
} else if (root.itemType === "avatar") {
sendToPurchases({method: 'showChangeAvatarLightbox', itemName: root.itemName, itemHref: root.itemHref});
} else if (root.itemType === "app") {
// "Run" and "Uninstall" buttons are separate.
Commerce.installApp(root.itemHref);
if (root.isInstalled) {
Commerce.openApp(root.itemHref);
} else {
// "Run" and "Uninstall" buttons are separate.
Commerce.installApp(root.itemHref);
}
} else {
sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, itemType: root.itemType});
root.showConfirmation = true;
@ -612,93 +716,76 @@ Item {
}
label: Item {
TextMetrics {
id: rezIconTextMetrics;
font: rezIcon.font;
text: rezIcon.text;
}
HiFiGlyphs {
id: rezIcon;
text: (root.buttonGlyph)[itemTypesArray.indexOf(root.itemType)];
// Size
size: 60;
// Anchors
anchors.top: parent.top;
anchors.topMargin: 0;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.right: rezIconLabel.left;
anchors.rightMargin: 2;
anchors.verticalCenter: parent.verticalCenter;
size: 36;
horizontalAlignment: Text.AlignHCenter;
// Style
color: enabled ? hifi.buttons.textColor[control.color]
: hifi.buttons.disabledTextColor[control.colorScheme]
: hifi.buttons.disabledTextColor[control.colorScheme]
}
TextMetrics {
id: rezIconLabelTextMetrics;
font: rezIconLabel.font;
text: rezIconLabel.text;
}
RalewayBold {
id: rezIconLabel;
anchors.top: rezIcon.bottom;
anchors.topMargin: -4;
anchors.right: parent.right;
anchors.left: parent.left;
anchors.bottom: parent.bottom;
font.capitalization: Font.AllUppercase
color: enabled ? hifi.buttons.textColor[control.color]
: hifi.buttons.disabledTextColor[control.colorScheme]
text: root.isInstalled ? "OPEN" : (MyAvatar.skeletonModelURL === root.itemHref ? "CURRENT" : (root.buttonTextNormal)[itemTypesArray.indexOf(root.itemType)]);
anchors.verticalCenter: parent.verticalCenter;
width: rezIconLabelTextMetrics.width;
x: parent.width/2 - rezIconLabelTextMetrics.width/2 + rezIconTextMetrics.width/2;
size: 15;
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: MyAvatar.skeletonModelURL === root.itemHref ? "CURRENT" : (root.buttonTextNormal)[itemTypesArray.indexOf(root.itemType)];
font.capitalization: Font.AllUppercase;
verticalAlignment: Text.AlignVCenter;
horizontalAlignment: Text.AlignHCenter;
color: enabled ? hifi.buttons.textColor[control.color]
: hifi.buttons.disabledTextColor[control.colorScheme]
}
}
}
}
}
// END "incorrect indentation to prevent insane diffs"
HiFiGlyphs {
id: noPermissionGlyph;
visible: !root.hasPermissionToRezThis;
anchors.verticalCenter: buttonContainer.verticalCenter;
anchors.left: buttonContainer.left;
anchors.right: buttonContainer.right;
anchors.rightMargin: -40;
text: hifi.glyphs.info;
// Size
size: 44;
// Style
color: hifi.colors.redAccent;
horizontalAlignment: Text.AlignRight;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
Rectangle {
id: upgradeAvailableContainer;
visible: root.upgradeUrl !== "" && !root.isShowingMyItems;
anchors.top: itemContainer.bottom;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
color: "#B5EAFF";
RalewayRegular {
id: updateAvailableText;
text: "UPDATE AVAILABLE";
size: 13;
anchors.left: parent.left;
anchors.leftMargin: 12;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: paintedWidth;
color: hifi.colors.black;
verticalAlignment: Text.AlignVCenter;
}
RalewaySemiBold {
id: updateNowText;
text: "<font color='#0093C5'><a href='#'>Update this item now</a></font>";
size: 13;
anchors.left: updateAvailableText.right;
anchors.leftMargin: 16;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: paintedWidth;
color: hifi.colors.black;
verticalAlignment: Text.AlignVCenter;
onLinkActivated: {
sendToPurchases({method: 'updateItemClicked', itemId: root.itemId, itemEdition: root.itemEdition, upgradeUrl: root.upgradeUrl});
onEntered: {
noPermissionGlyph.color = hifi.colors.redHighlight;
}
onExited: {
noPermissionGlyph.color = hifi.colors.redAccent;
}
onClicked: {
contextCard.z = 0;
permissionExplanationCard.z = 1;
root.sendToPurchases({ method: 'flipCard' });
}
}
}
}
DropShadow {
anchors.fill: mainContainer;
horizontalOffset: 0;
verticalOffset: 4;
radius: 4.0;
samples: 9
color: Qt.rgba(0, 0, 0, 0.25);
source: mainContainer;
}
//
// FUNCTION DEFINITIONS START
//

View file

@ -19,6 +19,7 @@ import "../../../controls" as HifiControls
import "../wallet" as HifiWallet
import "../common" as HifiCommerceCommon
import "../inspectionCertificate" as HifiInspectionCertificate
import "../common/sendAsset" as HifiSendAsset
// references XXX from root context
@ -31,7 +32,6 @@ Rectangle {
property bool securityImageResultReceived: false;
property bool purchasesReceived: false;
property bool punctuationMode: false;
property bool pendingInventoryReply: true;
property bool isShowingMyItems: false;
property bool isDebuggingFirstUseTutorial: false;
property int pendingItemCount: 0;
@ -114,12 +114,6 @@ Rectangle {
purchasesContentsList.positionViewAtIndex(currentIndex, ListView.Beginning);
}
if (root.pendingInventoryReply && root.pendingItemCount > 0) {
inventoryTimer.start();
}
root.pendingInventoryReply = false;
}
onAvailableUpdatesResult: {
@ -142,7 +136,7 @@ Rectangle {
HifiInspectionCertificate.InspectionCertificate {
id: inspectionCertificate;
z: 999;
z: 998;
visible: false;
anchors.fill: parent;
@ -155,6 +149,7 @@ Rectangle {
HifiCommerceCommon.CommerceLightbox {
id: lightboxPopup;
z: 999;
visible: false;
anchors.fill: parent;
@ -169,12 +164,33 @@ Rectangle {
}
}
HifiSendAsset.SendAsset {
id: sendAsset;
z: 998;
visible: root.activeView === "giftAsset";
anchors.fill: parent;
parentAppTitleBarHeight: 70;
parentAppNavBarHeight: 0;
Connections {
onSendSignalToParent: {
if (msg.method === 'sendAssetHome_back' || msg.method === 'closeSendAsset') {
root.activeView = "purchasesMain";
Commerce.inventory();
Commerce.getAvailableUpdates();
} else {
sendToScript(msg);
}
}
}
}
//
// TITLE BAR START
//
HifiCommerceCommon.EmulatedMarketplaceHeader {
id: titleBarContainer;
z: 998;
z: 997;
visible: !needsLogIn.visible;
// Size
width: parent.width;
@ -191,9 +207,14 @@ Rectangle {
lightboxPopup.bodyImageSource = msg.securityImageSource;
lightboxPopup.bodyText = lightboxPopup.securityPicBodyText;
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "GO TO WALLET";
lightboxPopup.button2method = "sendToParent({method: 'purchases_openWallet'});";
lightboxPopup.button2method = function() {
sendToScript({method: 'purchases_openWallet'});
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else {
sendToScript(msg);
@ -308,7 +329,7 @@ Rectangle {
// FILTER BAR START
//
Item {
z: 997;
z: 996;
id: filterBarContainer;
// Size
height: 40;
@ -316,7 +337,7 @@ Rectangle {
anchors.left: parent.left;
anchors.leftMargin: 8;
anchors.right: parent.right;
anchors.rightMargin: 16;
anchors.rightMargin: 8;
anchors.top: parent.top;
anchors.topMargin: 4;
@ -341,6 +362,7 @@ Rectangle {
colorScheme: hifi.colorSchemes.faintGray;
anchors.top: parent.top;
anchors.right: parent.right;
anchors.rightMargin: 8;
anchors.left: myText.right;
anchors.leftMargin: 16;
textFieldHeight: 39;
@ -396,7 +418,7 @@ Rectangle {
//
HifiControlsUit.Separator {
z: 996;
z: 995;
id: separator;
colorScheme: 2;
anchors.left: parent.left;
@ -426,7 +448,6 @@ Rectangle {
snapMode: ListView.SnapToItem;
// Anchors
anchors.top: separator.bottom;
anchors.topMargin: 12;
anchors.left: parent.left;
anchors.bottom: updatesAvailableBanner.visible ? updatesAvailableBanner.top : parent.bottom;
width: parent.width;
@ -437,13 +458,13 @@ Rectangle {
itemHref: download_url;
certificateId: certificate_id;
purchaseStatus: status;
purchaseStatusChanged: statusChanged;
itemEdition: model.edition_number;
numberSold: model.number_sold;
limitedRun: model.limited_run;
displayedItemCount: model.displayedItemCount;
permissionExplanationCardVisible: model.permissionExplanationCardVisible;
cardBackVisible: model.cardBackVisible;
isInstalled: model.isInstalled;
wornEntityID: model.wornEntityID;
upgradeUrl: model.upgrade_url;
upgradeTitle: model.upgrade_title;
itemType: model.itemType;
@ -457,6 +478,11 @@ Rectangle {
sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId});
} else if (msg.method === "purchases_rezClicked") {
sendToScript({method: 'purchases_rezClicked', itemHref: itemHref, itemType: itemType});
// Race condition - Wearable might not be rezzed by the time the "currently worn wearbles" model is created
if (itemType === "wearable") {
sendToScript({ method: 'purchases_updateWearables' });
}
} else if (msg.method === 'purchases_itemCertificateClicked') {
inspectionCertificate.visible = true;
inspectionCertificate.isLightbox = true;
@ -466,14 +492,18 @@ Rectangle {
lightboxPopup.bodyText = 'Your item is marked "invalidated" because this item has been suspended ' +
"from the Marketplace due to a claim against its author.";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
} else if (msg.method === "showPendingLightbox") {
lightboxPopup.titleText = "Item Pending";
lightboxPopup.bodyText = 'Your item is marked "pending" while your purchase is being confirmed. ' +
"Usually, purchases take about 90 seconds to confirm.";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
} else if (msg.method === "showReplaceContentLightbox") {
lightboxPopup.titleText = "Replace Content";
@ -483,17 +513,27 @@ Rectangle {
"<a href='https://docs.highfidelity.com/create-and-explore/start-working-in-your-sandbox/restoring-sandbox-content'>" +
"click here to open info on your desktop browser.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "', '" + msg.certID + "'); root.visible = false;";
lightboxPopup.button2method = function() {
Commerce.replaceContentSet(msg.itemHref, msg.certID);
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else if (msg.method === "showChangeAvatarLightbox") {
lightboxPopup.titleText = "Change Avatar";
lightboxPopup.bodyText = "This will change your current avatar to " + msg.itemName + " while retaining your wearables.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = "MyAvatar.useFullAvatarURL('" + msg.itemHref + "'); root.visible = false;";
lightboxPopup.button2method = function() {
MyAvatar.useFullAvatarURL(msg.itemHref);
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else if (msg.method === "showPermissionsExplanation") {
if (msg.itemType === "entity") {
@ -501,27 +541,86 @@ Rectangle {
lightboxPopup.bodyText = "You don't have permission to rez certified items in this domain.<br><br>" +
"Use the <b>GOTO app</b> to visit another domain or <b>go to your own sandbox.</b>";
lightboxPopup.button2text = "OPEN GOTO";
lightboxPopup.button2method = "sendToParent({method: 'purchases_openGoTo'});";
lightboxPopup.button2method = function() {
sendToScript({method: 'purchases_openGoTo'});
lightboxPopup.visible = false;
};
} else if (msg.itemType === "contentSet") {
lightboxPopup.titleText = "Replace Content Permission";
lightboxPopup.bodyText = "You do not have the permission 'Replace Content' in this <b>domain's server settings</b>. The domain owner " +
"must enable it for you before you can replace content sets in this domain.";
}
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
} else if (msg.method === "setFilterText") {
filterBar.text = msg.filterText;
} else if (msg.method === "openPermissionExplanationCard") {
} else if (msg.method === "flipCard") {
for (var i = 0; i < filteredPurchasesModel.count; i++) {
if (i !== index || msg.closeAll) {
filteredPurchasesModel.setProperty(i, "permissionExplanationCardVisible", false);
filteredPurchasesModel.setProperty(i, "cardBackVisible", false);
} else {
filteredPurchasesModel.setProperty(i, "permissionExplanationCardVisible", true);
filteredPurchasesModel.setProperty(i, "cardBackVisible", true);
}
}
} else if (msg.method === "updateItemClicked") {
sendToScript(msg);
} else if (msg.method === "giftAsset") {
sendAsset.assetName = msg.itemName;
sendAsset.assetCertID = msg.certId;
sendAsset.sendingPubliclyEffectImage = msg.effectImage;
if (msg.itemType === "avatar" && MyAvatar.skeletonModelURL === msg.itemHref) {
lightboxPopup.titleText = "Change Avatar to Default";
lightboxPopup.bodyText = "You are currently wearing the avatar that you are trying to gift.<br><br>" +
"If you proceed, your avatar will be changed to the default avatar.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = function() {
MyAvatar.skeletonModelURL = '';
root.activeView = "giftAsset";
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else if (msg.itemType === "app" && msg.isInstalled) {
lightboxPopup.titleText = "Uninstall App";
lightboxPopup.bodyText = "You are currently using the app that you are trying to gift.<br><br>" +
"If you proceed, the app will be uninstalled.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = function() {
Commerce.uninstallApp(msg.itemHref);
root.activeView = "giftAsset";
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else if (msg.itemType === "wearable" && msg.wornEntityID !== '') {
lightboxPopup.titleText = "Remove Wearable";
lightboxPopup.bodyText = "You are currently wearing the wearable that you are trying to send.<br><br>" +
"If you proceed, this wearable will be removed.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.button2text = "CONFIRM";
lightboxPopup.button2method = function() {
Entities.deleteEntity(msg.wornEntityID);
filteredPurchasesModel.setProperty(index, 'wornEntityID', '');
root.activeView = "giftAsset";
lightboxPopup.visible = false;
};
lightboxPopup.visible = true;
} else {
root.activeView = "giftAsset";
}
}
}
}
@ -693,6 +792,7 @@ Rectangle {
HifiControlsUit.Keyboard {
id: keyboard;
z: 999;
raised: HMD.mounted && parent.keyboardRaised;
numeric: parent.punctuationMode;
anchors {
@ -702,26 +802,6 @@ Rectangle {
}
}
onVisibleChanged: {
if (!visible) {
inventoryTimer.stop();
}
}
Timer {
id: inventoryTimer;
interval: 4000; // Change this back to 90000 after demo
//interval: 90000;
onTriggered: {
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
console.log("Refreshing Purchases...");
root.pendingInventoryReply = true;
Commerce.inventory();
Commerce.getAvailableUpdates();
}
}
}
//
// FUNCTION DEFINITIONS START
//
@ -833,10 +913,12 @@ Rectangle {
continue;
}
filteredPurchasesModel.append(tempPurchasesModel.get(i));
filteredPurchasesModel.setProperty(i, 'permissionExplanationCardVisible', false);
filteredPurchasesModel.setProperty(i, 'cardBackVisible', false);
filteredPurchasesModel.setProperty(i, 'isInstalled', ((root.installedApps).indexOf(currentId) > -1));
filteredPurchasesModel.setProperty(i, 'wornEntityID', '');
}
sendToScript({ method: 'purchases_updateWearables' });
populateDisplayedItemCounts();
sortByDate();
}
@ -863,6 +945,19 @@ Rectangle {
}
}
}
function updateCurrentlyWornWearables(wearables) {
for (var i = 0; i < filteredPurchasesModel.count; i++) {
for (var j = 0; j < wearables.length; j++) {
if (filteredPurchasesModel.get(i).itemType === "wearable" &&
wearables[j].entityCertID === filteredPurchasesModel.get(i).certificate_id &&
wearables[j].entityEdition.toString() === filteredPurchasesModel.get(i).edition_number) {
filteredPurchasesModel.setProperty(i, 'wornEntityID', wearables[j].entityID);
break;
}
}
}
}
//
// Function Name: fromScript()
@ -890,6 +985,16 @@ Rectangle {
case 'purchases_showMyItems':
root.isShowingMyItems = true;
break;
case 'updateConnections':
sendAsset.updateConnections(message.connections);
break;
case 'selectRecipient':
case 'updateSelectedRecipientUsername':
sendAsset.fromScript(message);
break;
case 'updateWearables':
updateCurrentlyWornWearables(message.wornWearables);
break;
default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
}

View file

@ -143,7 +143,9 @@ Item {
lightboxPopup.bodyImageSource = titleBarSecurityImage.source;
lightboxPopup.bodyText = lightboxPopup.securityPicBodyText;
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
}
}

View file

@ -42,18 +42,6 @@ Item {
}
}
}
// This will cause a bug -- if you bring up security image selection in HUD mode while
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
// HMD preview will stay off.
// TODO: Fix this unlikely bug
onVisibleChanged: {
if (visible) {
sendSignalToWallet({method: 'disableHmdPreview'});
} else {
sendSignalToWallet({method: 'maybeEnableHmdPreview'});
}
}
// Security Image
Item {

View file

@ -18,7 +18,7 @@ import "../../../styles-uit"
import "../../../controls-uit" as HifiControlsUit
import "../../../controls" as HifiControls
import "../common" as HifiCommerceCommon
import "./sendMoney"
import "../common/sendAsset"
Rectangle {
HifiConstants { id: hifi; }
@ -160,7 +160,9 @@ Rectangle {
lightboxPopup.bodyImageSource = titleBarSecurityImage.source;
lightboxPopup.bodyText = lightboxPopup.securityPicBodyText;
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
}
}
@ -341,7 +343,7 @@ Rectangle {
}
}
SendMoney {
SendAsset {
id: sendMoney;
z: 997;
visible: root.activeView === "sendMoney";
@ -350,7 +352,7 @@ Rectangle {
parentAppNavBarHeight: tabButtonsContainer.height;
Connections {
onSendSignalToWallet: {
onSendSignalToParent: {
sendToScript(msg);
}
}
@ -405,7 +407,7 @@ Rectangle {
//
Item {
id: tabButtonsContainer;
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange" && sendMoney.currentActiveView !== "sendMoneyStep";
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange" && sendMoney.currentActiveView !== "sendAssetStep";
property int numTabs: 5;
// Size
width: root.width;

View file

@ -206,9 +206,14 @@ Item {
"This step cannot be undone.";
lightboxPopup.button1color = hifi.buttons.red;
lightboxPopup.button1text = "YES, CREATE NEW WALLET";
lightboxPopup.button1method = "root.visible = false;proceed(true);";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
proceed(true);
}
lightboxPopup.button2text = "CANCEL";
lightboxPopup.button2method = "root.visible = false;"
lightboxPopup.button2method = function() {
lightboxPopup.visible = false;
};
lightboxPopup.buttonLayout = "topbottom";
lightboxPopup.visible = true;
}
@ -241,7 +246,9 @@ Item {
"If you'd prefer to create a new wallet (not recommended - you will lose your money and past " +
"purchases), click 'Create New Wallet'.";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
} else {
lightboxPopup.titleText = "You may have set up more than one wallet";
@ -251,7 +258,9 @@ Item {
"If you would prefer to use another wallet, click 'Locate Other Keys' to show us where " +
"you've stored the private keys for that wallet.";
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
}
}

View file

@ -76,7 +76,7 @@ Item {
UserActivityLogger.commerceWalletSetupProgress(timestamp, root.setupAttemptID,
Math.round((timestamp - root.startingTimestamp)/1000), currentStepNumber, root.setupStepNames[currentStepNumber - 1]);
if (root.activeView === "step_2" || root.activeView === "step_3") {
if (root.activeView === "step_3") {
sendSignalToWallet({method: 'disableHmdPreview'});
} else {
sendSignalToWallet({method: 'maybeEnableHmdPreview'});
@ -150,7 +150,9 @@ Item {
lightboxPopup.bodyImageSource = titleBarSecurityImage.source;
lightboxPopup.bodyText = lightboxPopup.securityPicBodyText;
lightboxPopup.button1text = "CLOSE";
lightboxPopup.button1method = "root.visible = false;"
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
}
}

View file

@ -344,5 +344,10 @@ QtObject {
readonly property string wand: "\ue02d"
readonly property string hat: "\ue02e"
readonly property string install: "\ue02f"
readonly property string certificate: "\ue030"
readonly property string gift: "\ue031"
readonly property string update: "\ue032"
readonly property string uninstall: "\ue033"
readonly property string verticalEllipsis: "\ue034"
}
}

View file

@ -1266,9 +1266,32 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Make sure the window is set to the correct size by processing the pending events
QCoreApplication::processEvents();
_glWidget->createContext();
_glWidget->makeCurrent();
// Create the main thread context, the GPU backend, and the display plugins
initializeGL();
qCDebug(interfaceapp, "Initialized Display.");
// Create the rendering engine. This can be slow on some machines due to lots of
// GPU pipeline creation.
initializeRenderEngine();
qCDebug(interfaceapp, "Initialized Render Engine.");
// Initialize the user interface and menu system
// Needs to happen AFTER the render engine initialization to access its configuration
initializeUi();
init();
qCDebug(interfaceapp, "init() complete.");
// create thread for parsing of octree data independent of the main network and rendering threads
_octreeProcessor.initialize(_enableProcessOctreeThread);
connect(&_octreeProcessor, &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
_entityEditSender.initialize(_enableProcessOctreeThread);
_idleLoopStdev.reset();
// update before the first render
update(0);
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
@ -2432,48 +2455,47 @@ void Application::initializeGL() {
_isGLInitialized = true;
}
// Build a shared canvas / context for the Chromium processes
_glWidget->makeCurrent();
glClearColor(0.2f, 0.2f, 0.2f, 1);
glClear(GL_COLOR_BUFFER_BIT);
_glWidget->swapBuffers();
#if !defined(DISABLE_QML)
// Chromium rendering uses some GL functions that prevent nSight from capturing
// frames, so we only create the shared context if nsight is NOT active.
if (!nsightActive()) {
_chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->qglContext());
_chromiumShareContext->makeCurrent();
if (!_chromiumShareContext->makeCurrent()) {
qCWarning(interfaceapp, "Unable to make chromium shared context current");
}
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
} else {
qCWarning(interfaceapp) << "nSIGHT detected, disabling chrome rendering";
// Build an offscreen GL context for the main thread.
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
#endif
_offscreenContext->doneCurrent();
_offscreenContext->setThreadContext();
// Build a shared canvas / context for the QML rendering
_glWidget->makeCurrent();
_qmlShareContext = new OffscreenGLCanvas();
_qmlShareContext->setObjectName("QmlShareContext");
_qmlShareContext->create(_glWidget->qglContext());
if (!_qmlShareContext->makeCurrent()) {
qCWarning(interfaceapp, "Unable to make QML shared context current");
// Move the GL widget context to the render event handler thread
_renderEventHandler = new RenderEventHandler(_glWidget->qglContext());
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
OffscreenQmlSurface::setSharedContext(_qmlShareContext->getContext());
_qmlShareContext->doneCurrent();
// Create the GPU backend
// Requires the window context, because that's what's used in the actual rendering
// and the GPU backend will make things like the VAO which cannot be shared across
// contexts
_glWidget->makeCurrent();
gpu::Context::init<gpu::gl::GLBackend>();
qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK,
QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram)));
_gpuContext = std::make_shared<gpu::Context>();
// The gpu context can make child contexts for transfers, so
// we need to restore primary rendering context
_glWidget->makeCurrent();
_gpuContext = std::make_shared<gpu::Context>();
initDisplay();
qCDebug(interfaceapp, "Initialized Display.");
// Restore the default main thread context
_offscreenContext->makeCurrent();
updateDisplayMode();
}
void Application::initializeRenderEngine() {
_offscreenContext->makeCurrent();
// FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
DeadlockWatchdogThread::withPause([&] {
@ -2490,66 +2512,44 @@ void Application::initializeGL() {
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
});
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
_offscreenContext->doneCurrent();
_offscreenContext->setThreadContext();
_renderEventHandler = new RenderEventHandler(_glWidget->qglContext());
// The UI can't be created until the primary OpenGL
// context is created, because it needs to share
// texture resources
// Needs to happen AFTER the render engine initialization to access its configuration
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
initializeUi();
qCDebug(interfaceapp, "Initialized Offscreen UI.");
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
init();
qCDebug(interfaceapp, "init() complete.");
// create thread for parsing of octree data independent of the main network and rendering threads
_octreeProcessor.initialize(_enableProcessOctreeThread);
connect(&_octreeProcessor, &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
_entityEditSender.initialize(_enableProcessOctreeThread);
_idleLoopStdev.reset();
// Restore the primary GL content for the main thread
if (!_offscreenContext->makeCurrent()) {
qFatal("Unable to make offscreen context current");
}
// update before the first render
update(0);
}
extern void setupPreferences();
void Application::initializeUi() {
// Build a shared canvas / context for the Chromium processes
#if !defined(DISABLE_QML)
// Chromium rendering uses some GL functions that prevent nSight from capturing
// frames, so we only create the shared context if nsight is NOT active.
if (!nsightActive()) {
_chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_offscreenContext->getContext());
if (!_chromiumShareContext->makeCurrent()) {
qCWarning(interfaceapp, "Unable to make chromium shared context current");
}
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
_chromiumShareContext->doneCurrent();
// Restore the GL widget context
_offscreenContext->makeCurrent();
} else {
qCWarning(interfaceapp) << "nSIGHT detected, disabling chrome rendering";
}
#endif
// Build a shared canvas / context for the QML rendering
_qmlShareContext = new OffscreenGLCanvas();
_qmlShareContext->setObjectName("QmlShareContext");
_qmlShareContext->create(_offscreenContext->getContext());
if (!_qmlShareContext->makeCurrent()) {
qCWarning(interfaceapp, "Unable to make QML shared context current");
}
OffscreenQmlSurface::setSharedContext(_qmlShareContext->getContext());
_qmlShareContext->doneCurrent();
// Restore the GL widget context
_offscreenContext->makeCurrent();
// Make sure all QML surfaces share the main thread GL context
OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext());
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "OverlayWindowTest.qml" },
[](QQmlContext* context) {
qDebug() << "Whitelist OverlayWindow worked";
context->setContextProperty("OverlayWindowTestString", "TestWorked");
});
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "hifi/audio/Audio.qml" },
[](QQmlContext* context) {
qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked";
});
AddressBarDialog::registerType();
ErrorDialog::registerType();
@ -2565,6 +2565,7 @@ void Application::initializeUi() {
QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" },
QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" },
QUrl{ "hifi/commerce/common/SortableListModel.qml" },
QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" },
QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" },
QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" },
QUrl{ "hifi/commerce/purchases/Purchases.qml" },
@ -2577,7 +2578,6 @@ void Application::initializeUi() {
QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" },
QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" },
QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" },
QUrl{ "hifi/commerce/wallet/sendMoney/SendMoney.qml" },
QUrl{ "hifi/commerce/wallet/Wallet.qml" },
QUrl{ "hifi/commerce/wallet/WalletHome.qml" },
QUrl{ "hifi/commerce/wallet/WalletSetup.qml" },
@ -2652,6 +2652,10 @@ void Application::initializeUi() {
auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1);
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
// Now that the menu is instantiated, ensure the display plugin menu is properly updated
updateDisplayMode();
flushMenuUpdates();
}
@ -3149,6 +3153,10 @@ void Application::loadServerlessDomain(QUrl domainURL) {
tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0);
}
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
nodeList->getDomainHandler().connectedToServerless(namedPaths);
_fullSceneReceivedCounter++;
}
@ -4616,11 +4624,8 @@ QVector<EntityItemID> Application::pasteEntities(float x, float y, float z) {
return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z);
}
void Application::initDisplay() {
}
void Application::init() {
_offscreenContext->makeCurrent();
// Make sure Login state is up to date
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
if (!DISABLE_DEFERRED) {
@ -4829,7 +4834,7 @@ void Application::updateThreads(float deltaTime) {
void Application::toggleOverlays() {
auto menu = Menu::getInstance();
menu->setIsOptionChecked(MenuOption::Overlays, menu->isOptionChecked(MenuOption::Overlays));
menu->setIsOptionChecked(MenuOption::Overlays, !menu->isOptionChecked(MenuOption::Overlays));
}
void Application::setOverlaysVisible(bool visible) {
@ -5316,52 +5321,56 @@ void Application::update(float deltaTime) {
});
}
{
PROFILE_RANGE(simulation_physics, "PostPhysics");
PerformanceTimer perfTimer("postPhysics");
if (_physicsEngine->hasOutgoingChanges()) {
// grab the collision events BEFORE handleOutgoingChanges() because at this point
// we have a better idea of which objects we own or should own.
auto& collisionEvents = _physicsEngine->getCollisionEvents();
{
PROFILE_RANGE(simulation_physics, "PostPhysics");
PerformanceTimer perfTimer("postPhysics");
// grab the collision events BEFORE handleChangedMotionStates() because at this point
// we have a better idea of which objects we own or should own.
auto& collisionEvents = _physicsEngine->getCollisionEvents();
getEntities()->getTree()->withWriteLock([&] {
PROFILE_RANGE(simulation_physics, "HandleChanges");
PerformanceTimer perfTimer("handleChanges");
getEntities()->getTree()->withWriteLock([&] {
PROFILE_RANGE(simulation_physics, "HandleChanges");
PerformanceTimer perfTimer("handleChanges");
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
_entitySimulation->handleChangedMotionStates(outgoingChanges);
avatarManager->handleChangedMotionStates(outgoingChanges);
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
_entitySimulation->handleChangedMotionStates(outgoingChanges);
avatarManager->handleChangedMotionStates(outgoingChanges);
const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates();
_entitySimulation->handleDeactivatedMotionStates(deactivations);
});
const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates();
_entitySimulation->handleDeactivatedMotionStates(deactivations);
});
if (!_aboutToQuit) {
// handleCollisionEvents() AFTER handleOutgoingChanges()
{
PROFILE_RANGE(simulation_physics, "CollisionEvents");
avatarManager->handleCollisionEvents(collisionEvents);
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
// deadlock.)
_entitySimulation->handleCollisionEvents(collisionEvents);
if (!_aboutToQuit) {
// handleCollisionEvents() AFTER handleChangedMotionStates()
{
PROFILE_RANGE(simulation_physics, "CollisionEvents");
avatarManager->handleCollisionEvents(collisionEvents);
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
// deadlock.)
_entitySimulation->handleCollisionEvents(collisionEvents);
}
}
{
PROFILE_RANGE(simulation_physics, "MyAvatar");
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
}
if (PerformanceTimer::isActive() &&
Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming)) {
_physicsEngine->harvestPerformanceStats();
}
// NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework
_physicsEngine->dumpStatsIfNecessary();
}
if (!_aboutToQuit) {
// NOTE: the getEntities()->update() call below will wait for lock
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
// and will provide non-physical entity motion
getEntities()->update(true); // update the models...
}
{
PROFILE_RANGE(simulation_physics, "MyAvatar");
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
}
if (PerformanceTimer::isActive() &&
Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
_physicsEngine->harvestPerformanceStats();
}
// NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework
_physicsEngine->dumpStatsIfNecessary();
}
}
} else {
@ -5917,6 +5926,9 @@ void Application::nodeActivated(SharedNodePointer node) {
}
getMyAvatar()->markIdentityDataChanged();
getMyAvatar()->resetLastSent();
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
getMyAvatar()->sendAvatarDataPacket(true);
}
}
@ -6022,9 +6034,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() {
bool result = true;
foreach (EntityItemPointer entity, entities) {
if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*");
qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName();
HIFI_FCDEBUG(interfaceapp(), "Physics disabled until entity loads: " << entity->getID() << entity->getName());
// don't break here because we want all the relevant entities to start their downloads
result = false;
}
@ -7515,21 +7525,34 @@ void Application::updateDisplayMode() {
qFatal("Attempted to switch display plugins from a non-main thread");
}
auto menu = Menu::getInstance();
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
// Once time initialization code
static std::once_flag once;
std::call_once(once, [&] {
bool first = true;
// first sort the plugins into groupings: standard, advanced, developer
DisplayPluginList standard;
DisplayPluginList advanced;
DisplayPluginList developer;
foreach(auto displayPlugin, displayPlugins) {
displayPlugin->setContext(_gpuContext);
auto grouping = displayPlugin->getGrouping();
switch (grouping) {
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged,
[this](const QSize& size) { resizeGL(); });
QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset);
}
});
// Once time initialization code that depends on the UI being available
auto menu = Menu::getInstance();
if (menu) {
static std::once_flag onceUi;
std::call_once(onceUi, [&] {
bool first = true;
// first sort the plugins into groupings: standard, advanced, developer
DisplayPluginList standard;
DisplayPluginList advanced;
DisplayPluginList developer;
foreach(auto displayPlugin, displayPlugins) {
displayPlugin->setContext(_gpuContext);
auto grouping = displayPlugin->getGrouping();
switch (grouping) {
case Plugin::ADVANCED:
advanced.push_back(displayPlugin);
break;
@ -7539,42 +7562,40 @@ void Application::updateDisplayMode() {
default:
standard.push_back(displayPlugin);
break;
}
}
}
// concatenate the groupings into a single list in the order: standard, advanced, developer
standard.insert(std::end(standard), std::begin(advanced), std::end(advanced));
standard.insert(std::end(standard), std::begin(developer), std::end(developer));
// concatenate the groupings into a single list in the order: standard, advanced, developer
standard.insert(std::end(standard), std::begin(advanced), std::end(advanced));
standard.insert(std::end(standard), std::begin(developer), std::end(developer));
foreach(auto displayPlugin, standard) {
addDisplayPluginToMenu(displayPlugin, first);
auto displayPluginName = displayPlugin->getName();
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) {
resizeGL();
});
QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset);
first = false;
}
foreach(auto displayPlugin, standard) {
addDisplayPluginToMenu(displayPlugin, first);
first = false;
}
// after all plugins have been added to the menu, add a separator to the menu
auto menu = Menu::getInstance();
auto parent = menu->getMenu(MenuOption::OutputMenu);
parent->addSeparator();
});
// after all plugins have been added to the menu, add a separator to the menu
auto parent = menu->getMenu(MenuOption::OutputMenu);
parent->addSeparator();
});
}
// Default to the first item on the list, in case none of the menu items match
DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0);
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
QString name = displayPlugin->getName();
QAction* action = menu->getActionForOption(name);
// Menu might have been removed if the display plugin lost
if (!action) {
continue;
}
if (action->isChecked()) {
newDisplayPlugin = displayPlugin;
break;
if (menu) {
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
QString name = displayPlugin->getName();
QAction* action = menu->getActionForOption(name);
// Menu might have been removed if the display plugin lost
if (!action) {
continue;
}
if (action->isChecked()) {
newDisplayPlugin = displayPlugin;
break;
}
}
}
@ -7582,8 +7603,13 @@ void Application::updateDisplayMode() {
return;
}
setDisplayPlugin(newDisplayPlugin);
}
void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto desktop = offscreenUi->getDesktop();
auto menu = Menu::getInstance();
// Make the switch atomic from the perspective of other threads
{
@ -7604,6 +7630,8 @@ void Application::updateDisplayMode() {
bool active = newDisplayPlugin->activate();
if (!active) {
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
// If the new plugin fails to activate, fallback to last display
qWarning() << "Failed to activate display: " << newDisplayPlugin->getName();
newDisplayPlugin = oldDisplayPlugin;
@ -7624,13 +7652,6 @@ void Application::updateDisplayMode() {
if (!active) {
qFatal("Failed to activate fallback plugin");
}
// We've changed the selection - it should be reflected in the menu
QAction* action = menu->getActionForOption(newDisplayPlugin->getName());
if (!action) {
qFatal("Failed to find activated plugin");
}
action->setChecked(true);
}
offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize()));
@ -7657,14 +7678,21 @@ void Application::updateDisplayMode() {
getMyAvatar()->reset(false);
// switch to first person if entering hmd and setting is checked
if (isHmd && menu->isOptionChecked(MenuOption::FirstPersonHMD)) {
menu->setIsOptionChecked(MenuOption::FirstPerson, true);
cameraMenuChanged();
}
if (menu) {
QAction* action = menu->getActionForOption(newDisplayPlugin->getName());
if (action) {
action->setChecked(true);
}
// Remove the mirror camera option from menu if in HMD mode
auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror);
mirrorAction->setVisible(!isHmd);
if (isHmd && menu->isOptionChecked(MenuOption::FirstPersonHMD)) {
menu->setIsOptionChecked(MenuOption::FirstPerson, true);
cameraMenuChanged();
}
// Remove the mirror camera option from menu if in HMD mode
auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror);
mirrorAction->setVisible(!isHmd);
}
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
}
@ -7740,15 +7768,18 @@ void Application::unresponsiveApplication() {
}
void Application::setActiveDisplayPlugin(const QString& pluginName) {
auto menu = Menu::getInstance();
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
DisplayPluginPointer newDisplayPlugin;
for (DisplayPluginPointer displayPlugin : PluginManager::getInstance()->getDisplayPlugins()) {
QString name = displayPlugin->getName();
QAction* action = menu->getActionForOption(name);
if (pluginName == name) {
action->setChecked(true);
newDisplayPlugin = displayPlugin;
break;
}
}
updateDisplayMode();
if (newDisplayPlugin) {
setDisplayPlugin(newDisplayPlugin);
}
}
void Application::handleLocalServerConnection() const {

View file

@ -147,6 +147,7 @@ public:
Q_INVOKABLE QString getUserAgent();
void initializeGL();
void initializeRenderEngine();
void initializeUi();
void updateCamera(RenderArgs& renderArgs, float deltaTime);
@ -442,6 +443,7 @@ private slots:
static void packetSent(quint64 length);
static void addingEntityWithCertificate(const QString& certificateID, const QString& placeName);
void updateDisplayMode();
void setDisplayPlugin(DisplayPluginPointer newPlugin);
void domainConnectionRefused(const QString& reasonMessage, int reason, const QString& extraInfo);
void addAssetToWorldCheckModelSize();
@ -454,7 +456,6 @@ private slots:
void switchDisplayMode();
private:
static void initDisplay();
void init();
bool handleKeyEventForFocusedEntityOrOverlay(QEvent* event);
bool handleFileOpenEvent(QFileOpenEvent* event);

View file

@ -87,10 +87,8 @@ EntityDynamicPointer InterfaceDynamicFactory::factoryBA(EntityItemPointer ownerE
if (dynamic) {
dynamic->deserialize(data);
if (dynamic->lifetimeIsOver()) {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex(".*factoryBA lifetimeIsOver during dynamic creation.*");
qDebug() << "InterfaceDynamicFactory::factoryBA lifetimeIsOver during dynamic creation --"
<< dynamic->getExpires() << "<" << usecTimestampNow();
HIFI_FDEBUG("InterfaceDynamicFactory::factoryBA lifetimeIsOver during dynamic creation --"
<< dynamic->getExpires() << "<" << usecTimestampNow());
return nullptr;
}
}

View file

@ -683,11 +683,12 @@ Menu::Menu() {
qApp, SLOT(enablePerfStats(bool)));
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandSimulationTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPhysicsTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPhysicsSimulationTiming, 0, false);
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer);
addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, qApp, SLOT(runTests()));

View file

@ -105,7 +105,8 @@ namespace MenuOption {
const QString ExpandMyAvatarTiming = "Expand /myAvatar";
const QString ExpandOtherAvatarTiming = "Expand /otherAvatar";
const QString ExpandPaintGLTiming = "Expand /paintGL";
const QString ExpandPhysicsSimulationTiming = "Expand /physics";
const QString ExpandSimulationTiming = "Expand /simulation";
const QString ExpandPhysicsTiming = "Expand /physics";
const QString ExpandUpdateTiming = "Expand /update";
const QString FirstPerson = "First Person";
const QString FirstPersonHMD = "Enter First Person Mode in HMD";

View file

@ -56,8 +56,8 @@ Handler(buy)
Handler(receiveAt)
Handler(balance)
Handler(inventory)
Handler(transferHfcToNode)
Handler(transferHfcToUsername)
Handler(transferAssetToNode)
Handler(transferAssetToUsername)
Handler(alreadyOwned)
Handler(availableUpdates)
Handler(updateItem)
@ -173,7 +173,8 @@ QString userLink(const QString& username, const QString& placename) {
QString transactionString(const QJsonObject& valueObject) {
int sentCerts = valueObject["sent_certs"].toInt();
int receivedCerts = valueObject["received_certs"].toInt();
int sent = valueObject["sent_money"].toInt();
int sentMoney = valueObject["sent_money"].toInt();
int receivedMoney = valueObject["received_money"].toInt();
int dateInteger = valueObject["created_at"].toInt();
QString message = valueObject["message"].toString();
QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC));
@ -181,7 +182,7 @@ QString transactionString(const QJsonObject& valueObject) {
if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
// this is an hfc transfer.
if (sent > 0) {
if (sentMoney > 0) {
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
result += QString("Money sent to %1").arg(recipient);
} else {
@ -191,6 +192,18 @@ QString transactionString(const QJsonObject& valueObject) {
if (!message.isEmpty()) {
result += QString("<br>with memo: <i>\"%1\"</i>").arg(message);
}
} else if (sentMoney <= 0 && receivedMoney <= 0 && (sentCerts > 0 || receivedCerts > 0) && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
// this is a non-HFC asset transfer.
if (sentCerts > 0) {
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
result += QString("Gift sent to %1").arg(recipient);
} else {
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
result += QString("Gift from %1").arg(sender);
}
if (!message.isEmpty()) {
result += QString("<br>with memo: <i>\"%1\"</i>").arg(message);
}
} else {
result += valueObject["message"].toString();
}
@ -354,27 +367,41 @@ void Ledger::certificateInfo(const QString& certificateId) {
send(endpoint, "certificateInfoSuccess", "certificateInfoFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::None, request);
}
void Ledger::transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage) {
void Ledger::transferAssetToNode(const QString& hfc_key, const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage) {
QJsonObject transaction;
transaction["public_key"] = hfc_key;
transaction["node_id"] = nodeID;
transaction["quantity"] = amount;
transaction["message"] = optionalMessage;
transaction["place_name"] = DependencyManager::get<AddressManager>()->getPlaceName();
if (!certificateID.isEmpty()) {
transaction["certificate_id"] = certificateID;
}
QJsonDocument transactionDoc{ transaction };
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferHfcToNodeSuccess", "transferHfcToNodeFailure");
if (certificateID.isEmpty()) {
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferAssetToNodeSuccess", "transferAssetToNodeFailure");
} else {
signedSend("transaction", transactionString, hfc_key, "transfer_asset_to_node", "transferAssetToNodeSuccess", "transferAssetToNodeFailure");
}
}
void Ledger::transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage) {
void Ledger::transferAssetToUsername(const QString& hfc_key, const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage) {
QJsonObject transaction;
transaction["public_key"] = hfc_key;
transaction["username"] = username;
transaction["quantity"] = amount;
transaction["message"] = optionalMessage;
if (!certificateID.isEmpty()) {
transaction["certificate_id"] = certificateID;
}
QJsonDocument transactionDoc{ transaction };
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_user", "transferHfcToUsernameSuccess", "transferHfcToUsernameFailure");
if (certificateID.isEmpty()) {
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_user", "transferAssetToUsernameSuccess", "transferAssetToUsernameFailure");
} else {
signedSend("transaction", transactionString, hfc_key, "transfer_asset_to_user", "transferAssetToUsernameSuccess", "transferAssetToUsernameFailure");
}
}
void Ledger::alreadyOwned(const QString& marketplaceId) {

View file

@ -33,8 +33,8 @@ public:
void account();
void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false);
void certificateInfo(const QString& certificateId);
void transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage);
void transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage);
void transferAssetToNode(const QString& hfc_key, const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage);
void transferAssetToUsername(const QString& hfc_key, const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage);
void alreadyOwned(const QString& marketplaceId);
void getAvailableUpdates(const QString& itemId = "");
void updateItem(const QString& hfc_key, const QString& certificate_id);
@ -56,8 +56,8 @@ signals:
void accountResult(QJsonObject result);
void locationUpdateResult(QJsonObject result);
void certificateInfoResult(QJsonObject result);
void transferHfcToNodeResult(QJsonObject result);
void transferHfcToUsernameResult(QJsonObject result);
void transferAssetToNodeResult(QJsonObject result);
void transferAssetToUsernameResult(QJsonObject result);
void alreadyOwnedResult(QJsonObject result);
void availableUpdatesResult(QJsonObject result);
void updateItemResult(QJsonObject result);
@ -81,10 +81,10 @@ public slots:
void updateLocationFailure(QNetworkReply& reply);
void certificateInfoSuccess(QNetworkReply& reply);
void certificateInfoFailure(QNetworkReply& reply);
void transferHfcToNodeSuccess(QNetworkReply& reply);
void transferHfcToNodeFailure(QNetworkReply& reply);
void transferHfcToUsernameSuccess(QNetworkReply& reply);
void transferHfcToUsernameFailure(QNetworkReply& reply);
void transferAssetToNodeSuccess(QNetworkReply& reply);
void transferAssetToNodeFailure(QNetworkReply& reply);
void transferAssetToUsernameSuccess(QNetworkReply& reply);
void transferAssetToUsernameFailure(QNetworkReply& reply);
void alreadyOwnedSuccess(QNetworkReply& reply);
void alreadyOwnedFailure(QNetworkReply& reply);
void availableUpdatesSuccess(QNetworkReply& reply);

View file

@ -36,8 +36,8 @@ QmlCommerce::QmlCommerce() {
connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult);
connect(ledger.data(), &Ledger::alreadyOwnedResult, this, &QmlCommerce::alreadyOwnedResult);
connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus);
connect(ledger.data(), &Ledger::transferHfcToNodeResult, this, &QmlCommerce::transferHfcToNodeResult);
connect(ledger.data(), &Ledger::transferHfcToUsernameResult, this, &QmlCommerce::transferHfcToUsernameResult);
connect(ledger.data(), &Ledger::transferAssetToNodeResult, this, &QmlCommerce::transferAssetToNodeResult);
connect(ledger.data(), &Ledger::transferAssetToUsernameResult, this, &QmlCommerce::transferAssetToUsernameResult);
connect(ledger.data(), &Ledger::availableUpdatesResult, this, &QmlCommerce::availableUpdatesResult);
connect(ledger.data(), &Ledger::updateItemResult, this, &QmlCommerce::updateItemResult);
@ -166,28 +166,28 @@ void QmlCommerce::certificateInfo(const QString& certificateId) {
ledger->certificateInfo(certificateId);
}
void QmlCommerce::transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage) {
void QmlCommerce::transferAssetToNode(const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage) {
auto ledger = DependencyManager::get<Ledger>();
auto wallet = DependencyManager::get<Wallet>();
QStringList keys = wallet->listPublicKeys();
if (keys.count() == 0) {
QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } };
return emit buyResult(result);
return emit transferAssetToNodeResult(result);
}
QString key = keys[0];
ledger->transferHfcToNode(key, nodeID, amount, optionalMessage);
ledger->transferAssetToNode(key, nodeID, certificateID, amount, optionalMessage);
}
void QmlCommerce::transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage) {
void QmlCommerce::transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage) {
auto ledger = DependencyManager::get<Ledger>();
auto wallet = DependencyManager::get<Wallet>();
QStringList keys = wallet->listPublicKeys();
if (keys.count() == 0) {
QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } };
return emit buyResult(result);
return emit transferAssetToUsernameResult(result);
}
QString key = keys[0];
ledger->transferHfcToUsername(key, username, amount, optionalMessage);
ledger->transferAssetToUsername(key, username, certificateID, amount, optionalMessage);
}
void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) {

View file

@ -48,8 +48,8 @@ signals:
void updateCertificateStatus(const QString& certID, uint certStatus);
void transferHfcToNodeResult(QJsonObject result);
void transferHfcToUsernameResult(QJsonObject result);
void transferAssetToNodeResult(QJsonObject result);
void transferAssetToUsernameResult(QJsonObject result);
void contentSetChanged(const QString& contentSetHref);
@ -81,8 +81,8 @@ protected:
Q_INVOKABLE void certificateInfo(const QString& certificateId);
Q_INVOKABLE void alreadyOwned(const QString& marketplaceId);
Q_INVOKABLE void transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage);
Q_INVOKABLE void transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage);
Q_INVOKABLE void transferAssetToNode(const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage);
Q_INVOKABLE void transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage);
Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID);

View file

@ -13,8 +13,9 @@
#include "Ledger.h"
#include "Wallet.h"
#include "Application.h"
#include "ui/ImageProvider.h"
#include "ui/SecurityImageProvider.h"
#include "scripting/HMDScriptingInterface.h"
#include <ui/TabletScriptingInterface.h>
#include <PathUtils.h>
#include <OffscreenUi.h>
@ -566,7 +567,6 @@ bool Wallet::generateKeyPair() {
}
QStringList Wallet::listPublicKeys() {
qCInfo(commerce) << "Enumerating public keys.";
return _publicKeys;
}
@ -607,11 +607,17 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
}
void Wallet::updateImageProvider() {
// inform the image provider. Note it doesn't matter which one you inform, as the
// images are statics
auto engine = DependencyManager::get<OffscreenUi>()->getSurfaceContext()->engine();
auto imageProvider = reinterpret_cast<ImageProvider*>(engine->imageProvider(ImageProvider::PROVIDER_NAME));
imageProvider->setSecurityImage(_securityImage);
SecurityImageProvider* securityImageProvider;
// inform offscreenUI security image provider
QQmlEngine* engine = DependencyManager::get<OffscreenUi>()->getSurfaceContext()->engine();
securityImageProvider = reinterpret_cast<SecurityImageProvider*>(engine->imageProvider(SecurityImageProvider::PROVIDER_NAME));
securityImageProvider->setSecurityImage(_securityImage);
// inform tablet security image provider
QQmlEngine* tabletEngine = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system")->getTabletSurface()->getSurfaceContext()->engine();
securityImageProvider = reinterpret_cast<SecurityImageProvider*>(tabletEngine->imageProvider(SecurityImageProvider::PROVIDER_NAME));
securityImageProvider->setSecurityImage(_securityImage);
}
void Wallet::chooseSecurityImage(const QString& filename) {
@ -651,6 +657,7 @@ bool Wallet::getSecurityImage() {
// if already decrypted, don't do it again
if (_securityImage) {
updateImageProvider();
emit securityImageResult(true);
return true;
}

View file

@ -61,7 +61,7 @@ bool Stats::includeTimingRecord(const QString& name) {
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
if (name.startsWith("/idle/update/")) {
if (name.startsWith("/idle/update/simulation/")) {
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming);
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandSimulationTiming);
} else if (name.startsWith("/idle/update/myAvatar/")) {
if (name.startsWith("/idle/update/myAvatar/simulate/")) {
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandMyAvatarSimulateTiming);
@ -76,7 +76,7 @@ bool Stats::includeTimingRecord(const QString& name) {
} else if (name.startsWith("/paintGL/")) {
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
} else if (name.startsWith("physics/")) {
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming);
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming);
}
return true;
}

View file

@ -39,9 +39,6 @@ AudioRingBufferTemplate<T>::AudioRingBufferTemplate(int numFrameSamples, int num
_nextOutput = _buffer;
_endOfLastWrite = _buffer;
}
static QString repeatedOverflowMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
static QString repeatedDroppedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG);
}
template <class T>
@ -154,6 +151,11 @@ int AudioRingBufferTemplate<T>::appendData(char *data, int maxSize) {
return numReadSamples * SampleSize;
}
namespace {
int repeatedOverflowMessageID = 0;
std::once_flag messageIDFlag;
}
template <class T>
int AudioRingBufferTemplate<T>::writeData(const char* data, int maxSize) {
// only copy up to the number of samples we have capacity for
@ -167,7 +169,9 @@ int AudioRingBufferTemplate<T>::writeData(const char* data, int maxSize) {
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
_overflowCount++;
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
std::call_once(messageIDFlag, [](int* id) { *id = LogHandler::getInstance().newRepeatedMessageID(); },
&repeatedOverflowMessageID);
HIFI_FCDEBUG_ID(audio(), repeatedOverflowMessageID, RING_BUFFER_OVERFLOW_DEBUG);
}
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
@ -224,7 +228,7 @@ int AudioRingBufferTemplate<T>::addSilentSamples(int silentSamples) {
if (numWriteSamples > samplesRoomFor) {
numWriteSamples = samplesRoomFor;
qCDebug(audio) << qPrintable(DROPPED_SILENT_DEBUG);
HIFI_FCDEBUG(audio(), DROPPED_SILENT_DEBUG);
}
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
@ -275,7 +279,10 @@ int AudioRingBufferTemplate<T>::writeSamples(ConstIterator source, int maxSample
int samplesToDelete = samplesToCopy - samplesRoomFor;
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
_overflowCount++;
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
std::call_once(messageIDFlag, [](int* id) { *id = LogHandler::getInstance().newRepeatedMessageID(); },
&repeatedOverflowMessageID);
HIFI_FCDEBUG_ID(audio(), repeatedOverflowMessageID, RING_BUFFER_OVERFLOW_DEBUG);
}
Sample* bufferLast = _buffer + _bufferLength - 1;
@ -297,7 +304,10 @@ int AudioRingBufferTemplate<T>::writeSamplesWithFade(ConstIterator source, int m
int samplesToDelete = samplesToCopy - samplesRoomFor;
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
_overflowCount++;
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
std::call_once(messageIDFlag, [](int* id) { *id = LogHandler::getInstance().newRepeatedMessageID(); },
&repeatedOverflowMessageID);
HIFI_FCDEBUG_ID(audio(), repeatedOverflowMessageID, RING_BUFFER_OVERFLOW_DEBUG);
}
Sample* bufferLast = _buffer + _bufferLength - 1;

View file

@ -16,6 +16,7 @@
#include <glm/detail/func_common.hpp>
#include <QtCore/QDataStream>
#include <QtCore/QLoggingCategory>
#include <LogHandler.h>
#include <Node.h>
@ -80,10 +81,7 @@ int PositionalAudioStream::parsePositionalData(const QByteArray& positionalByteA
// if the client sends us a bad position, flag it so that we don't consider this stream for mixing
if (glm::isnan(_position.x) || glm::isnan(_position.y) || glm::isnan(_position.z)) {
static const QString INVALID_POSITION_REGEX = "PositionalAudioStream unpacked invalid position for node";
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(INVALID_POSITION_REGEX);
qDebug() << "PositionalAudioStream unpacked invalid position for node" << uuidStringWithoutCurlyBraces(getNodeID());
HIFI_FDEBUG("PositionalAudioStream unpacked invalid position for node" << uuidStringWithoutCurlyBraces(getNodeID()) );
_hasValidPosition = false;
} else {

View file

@ -58,6 +58,13 @@ void SkeletonModel::initJointStates() {
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
_rig.initJointStates(geometry, modelOffset);
{
// initialize _jointData with proper values for default joints
QVector<JointData> defaultJointData;
_rig.copyJointsIntoJointData(defaultJointData);
_owningAvatar->setRawJointData(defaultJointData);
}
// Determine the default eye position for avatar scale = 1.0
int headJointIndex = geometry.headJointIndex;
if (0 > headJointIndex || headJointIndex >= _rig.getJointStateCount()) {

View file

@ -559,7 +559,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
const JointData& last = lastSentJointData[i];
if (!data.rotationIsDefaultPose) {
if (sendAll || last.rotationIsDefaultPose || last.rotation != data.rotation) {
bool mustSend = sendAll || last.rotationIsDefaultPose;
if (mustSend || last.rotation != data.rotation) {
bool largeEnoughRotation = true;
if (cullSmallChanges) {
@ -568,7 +569,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
largeEnoughRotation = fabsf(glm::dot(last.rotation, data.rotation)) < minRotationDOT;
}
if (sendAll || !cullSmallChanges || largeEnoughRotation) {
if (mustSend || !cullSmallChanges || largeEnoughRotation) {
validity |= (1 << validityBit);
#ifdef WANT_DEBUG
rotationSentCount++;
@ -608,10 +609,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
float maxTranslationDimension = 0.0;
for (int i = 0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i];
const JointData& last = lastSentJointData[i];
if (!data.translationIsDefaultPose) {
if (sendAll || lastSentJointData[i].translation != data.translation) {
if (sendAll || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
bool mustSend = sendAll || last.translationIsDefaultPose;
if (mustSend || last.translation != data.translation) {
if (mustSend || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
validity |= (1 << validityBit);
#ifdef WANT_DEBUG
translationSentCount++;
@ -669,6 +672,19 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
}
if (sentJointDataOut) {
// Mark default poses in lastSentJointData, so when they become non-default we send them.
for (int i = 0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i];
JointData& local = localSentJointDataOut[i];
if (data.rotationIsDefaultPose) {
local.rotationIsDefaultPose = true;
}
if (data.translationIsDefaultPose) {
local.translationIsDefaultPose = true;
}
}
// Push new sent joint data to sentJointDataOut
sentJointDataOut->swap(localSentJointDataOut);
}
@ -1816,13 +1832,13 @@ void AvatarData::setJointMappingsFromNetworkReply() {
networkReply->deleteLater();
}
void AvatarData::sendAvatarDataPacket() {
void AvatarData::sendAvatarDataPacket(bool sendAll) {
auto nodeList = DependencyManager::get<NodeList>();
// about 2% of the time, we send a full update (meaning, we transmit all the joint data), even if nothing has changed.
// this is to guard against a joint moving once, the packet getting lost, and the joint never moving again.
bool cullSmallData = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
bool cullSmallData = !sendAll && (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
auto dataDetail = cullSmallData ? SendAllData : CullSmallData;
QByteArray avatarByteArray = toByteArrayStateful(dataDetail);

View file

@ -256,6 +256,11 @@ namespace AvatarDataPacket {
SixByteQuat rotation[numValidRotations]; // encodeded and compressed by packOrientationQuatToSixBytes()
uint8_t translationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed translation follows.
SixByteTrans translation[numValidTranslations]; // encodeded and compressed by packFloatVec3ToSignedTwoByteFixed()
SixByteQuat leftHandControllerRotation;
SixByteTrans leftHandControllerTranslation;
SixByteQuat rightHandControllerRotation;
SixByteTrans rightHandControllerTranslation;
};
*/
size_t maxJointDataSize(size_t numJoints);
@ -707,11 +712,11 @@ signals:
void sessionUUIDChanged();
public slots:
void sendAvatarDataPacket();
void sendAvatarDataPacket(bool sendAll = false);
void sendIdentityPacket();
void setJointMappingsFromNetworkReply();
void setSessionUUID(const QUuid& sessionUUID) {
virtual void setSessionUUID(const QUuid& sessionUUID) {
if (sessionUUID != getID()) {
if (sessionUUID == QUuid()) {
setID(AVATAR_SELF_ID);

View file

@ -56,10 +56,8 @@ glm::mat4 StereoDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& basePr
static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
std::vector<QAction*> _screenActions;
bool StereoDisplayPlugin::internalActivate() {
auto screens = qApp->screens();
_screenActions.resize(screens.size());
for (int i = 0; i < screens.size(); ++i) {
auto screen = screens.at(i);
QString name = QString("Screen %1: %2").arg(i + 1).arg(screen->name());
@ -67,9 +65,9 @@ bool StereoDisplayPlugin::internalActivate() {
if (screen == qApp->primaryScreen()) {
checked = true;
}
auto action = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), name,
[this](bool clicked) { updateScreen(); }, true, checked, "Screens");
_screenActions[i] = action;
const uint32_t screenIndex = i;
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), name,
[=](bool clicked) { updateScreen(screenIndex); }, true, checked, "Screens");
}
_container->removeMenu(FRAMERATE);
@ -80,18 +78,12 @@ bool StereoDisplayPlugin::internalActivate() {
return Parent::internalActivate();
}
void StereoDisplayPlugin::updateScreen() {
for (uint32_t i = 0; i < _screenActions.size(); ++i) {
if (_screenActions[i]->isChecked()) {
_screen = qApp->screens().at(i);
_container->setFullscreen(_screen);
break;
}
}
void StereoDisplayPlugin::updateScreen(uint32_t i) {
_screen = qApp->screens().at(i);
_container->setFullscreen(_screen);
}
void StereoDisplayPlugin::internalDeactivate() {
_screenActions.clear();
_container->unsetFullscreen();
Parent::internalDeactivate();
}

View file

@ -31,7 +31,7 @@ public:
protected:
virtual bool internalActivate() override;
virtual void internalDeactivate() override;
void updateScreen();
void updateScreen(uint32_t i);
float _ipd{ 0.064f };
QScreen* _screen;

View file

@ -2193,10 +2193,8 @@ void EntityItem::deserializeActionsInternal() {
entity->addActionInternal(simulation, action);
updated << actionID;
} else {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex(".*action creation failed for.*");
qCDebug(entities) << "EntityItem::deserializeActionsInternal -- action creation failed for"
<< getID() << _name; // getName();
HIFI_FCDEBUG(entities(), "EntityItem::deserializeActionsInternal -- action creation failed for"
<< getID() << _name); // getName();
removeActionInternal(actionID, nullptr);
}
}

View file

@ -759,7 +759,7 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesByType(const QString entity
foreach(EntityItemPointer entity, entities) {
if (entity->getType() == type) {
result << entity->getEntityItemID();
result << entity->getEntityItemID().toString();
}
}
}

View file

@ -113,6 +113,11 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
resetClientEditStats();
clearDeletedEntities();
{
QWriteLocker locker(&_needsParentFixupLock);
_needsParentFixup.clear();
}
}
void EntityTree::readBitstreamToTree(const unsigned char* bitstream,
@ -1653,11 +1658,9 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
_recentlyDeletedEntityItemIDs.insert(usecTimestampNow(), entityItemID);
}
} else {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex("^Edit failed.*");
qCDebug(entities) << "Edit failed. [" << message.getType() <<"] " <<
HIFI_FCDEBUG(entities(), "Edit failed. [" << message.getType() <<"] " <<
"entity id:" << entityItemID <<
"existingEntity pointer:" << existingEntity.get();
"existingEntity pointer:" << existingEntity.get());
}
}
@ -2329,6 +2332,16 @@ bool EntityTree::readFromMap(QVariantMap& map) {
_persistDataVersion = map["DataVersion"].toInt();
}
_namedPaths.clear();
if (map.contains("Paths")) {
QVariantMap namedPathsMap = map["Paths"].toMap();
for(QVariantMap::const_iterator iter = namedPathsMap.begin(); iter != namedPathsMap.end(); ++iter) {
QString namedPathName = iter.key();
QString namedPathViewPoint = iter.value().toString();
_namedPaths[namedPathName] = namedPathViewPoint;
}
}
// map will have a top-level list keyed as "Entities". This will be extracted
// and iterated over. Each member of this list is converted to a QVariantMap, then
// to a QScriptValue, and then to EntityItemProperties. These properties are used

View file

@ -303,6 +303,8 @@ public:
static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName);
static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName);
std::map<QString, QString> getNamedPaths() const { return _namedPaths; }
signals:
void deletingEntity(const EntityItemID& entityID);
void deletingEntityPointer(EntityItem* entityID);
@ -421,6 +423,8 @@ private:
std::vector<int32_t> _staleProxies;
bool _serverlessDomain { false };
std::map<QString, QString> _namedPaths;
};
#endif // hifi_EntityTree_h

View file

@ -566,20 +566,20 @@ glm::vec3 FBXReader::normalizeDirForPacking(const glm::vec3& dir) {
}
void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*");
unsigned int totalSourceIndices = 0;
foreach(const FBXMeshPart& part, extractedMesh.parts) {
totalSourceIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size());
}
static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID();
if (!totalSourceIndices) {
qCDebug(modelformat) << "buildModelMesh failed -- no indices, url = " << url;
HIFI_FCDEBUG_ID(modelformat(), repeatMessageID, "buildModelMesh failed -- no indices, url = " << url);
return;
}
if (extractedMesh.vertices.size() == 0) {
qCDebug(modelformat) << "buildModelMesh failed -- no vertices, url = " << url;
HIFI_FCDEBUG_ID(modelformat(), repeatMessageID, "buildModelMesh failed -- no vertices, url = " << url);
return;
}

View file

@ -72,6 +72,10 @@ void GLWidget::createContext() {
_context->doneCurrent();
}
void GLWidget::swapBuffers() {
_context->swapBuffers();
}
bool GLWidget::makeCurrent() {
gl::Context::makeCurrent(_context->qglContext(), windowHandle());
return _context->makeCurrent();

View file

@ -32,6 +32,7 @@ public:
void createContext();
bool makeCurrent();
void doneCurrent();
void swapBuffers();
gl::Context* context() { return _context; }
QOpenGLContext* qglContext();

View file

@ -316,7 +316,17 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
_shareablePlaceName.clear();
setDomainInfo(lookupUrl, trigger);
emit lookupResultsFinished();
handlePath(DOMAIN_SPAWNING_POINT, LookupTrigger::Internal, false);
QString path = DOMAIN_SPAWNING_POINT;
QUrlQuery queryArgs(lookupUrl);
const QString LOCATION_QUERY_KEY = "location";
if (queryArgs.hasQueryItem(LOCATION_QUERY_KEY)) {
path = queryArgs.queryItemValue(LOCATION_QUERY_KEY);
} else {
path = DEFAULT_NAMED_PATH;
}
handlePath(path, LookupTrigger::Internal, false);
return true;
}
@ -433,7 +443,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
QUrl domainURL;
domainURL.setScheme(URL_SCHEME_HIFI);
domainURL.setHost(domainHostname);
domainURL.setPort(domainPort);
if (domainPort > 0) {
domainURL.setPort(domainPort);
}
emit possibleDomainChangeRequired(domainURL, domainID);
} else {
QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString();
@ -604,7 +616,9 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTri
QUrl domainURL;
domainURL.setScheme(URL_SCHEME_HIFI);
domainURL.setHost(domainIPString);
domainURL.setPort(domainPort);
if (domainPort > 0) {
domainURL.setPort(domainPort);
}
hostChanged = setDomainInfo(domainURL, trigger);
return true;
@ -625,7 +639,9 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTri
QUrl domainURL;
domainURL.setScheme(URL_SCHEME_HIFI);
domainURL.setHost(domainHostname);
domainURL.setPort(domainPort);
if (domainPort > 0) {
domainURL.setPort(domainPort);
}
hostChanged = setDomainInfo(domainURL, trigger);
return true;
@ -757,7 +773,9 @@ bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16
_domainURL = QUrl();
_domainURL.setScheme(URL_SCHEME_HIFI);
_domainURL.setHost(host);
_domainURL.setPort(port);
if (port > 0) {
_domainURL.setPort(port);
}
// any host change should clear the shareable place name
_shareablePlaceName.clear();

View file

@ -173,15 +173,15 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) {
QString previousHost = _domainURL.host();
_domainURL = domainURL;
if (domainURL.scheme() != URL_SCHEME_HIFI) {
setIsConnected(true);
} else if (previousHost != domainURL.host()) {
if (previousHost != domainURL.host()) {
qCDebug(networking) << "Updated domain hostname to" << domainURL.host();
if (!domainURL.host().isEmpty()) {
// re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname
qCDebug(networking, "Looking up DS hostname %s.", domainURL.host().toLocal8Bit().constData());
QHostInfo::lookupHost(domainURL.host(), this, SLOT(completedHostnameLookup(const QHostInfo&)));
if (domainURL.scheme() == URL_SCHEME_HIFI) {
// re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname
qCDebug(networking, "Looking up DS hostname %s.", domainURL.host().toLocal8Bit().constData());
QHostInfo::lookupHost(domainURL.host(), this, SLOT(completedHostnameLookup(const QHostInfo&)));
}
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(
LimitedNodeList::ConnectionStep::SetDomainHostname);
@ -250,6 +250,17 @@ void DomainHandler::activateICEPublicSocket() {
emit completedSocketDiscovery();
}
QString DomainHandler::getViewPointFromNamedPath(QString namedPath) {
auto lookup = _namedPaths.find(namedPath);
if (lookup != _namedPaths.end()) {
return lookup->second;
}
if (namedPath == DEFAULT_NAMED_PATH) {
return DOMAIN_SPAWNING_POINT;
}
return "";
}
void DomainHandler::completedHostnameLookup(const QHostInfo& hostInfo) {
for (int i = 0; i < hostInfo.addresses().size(); i++) {
if (hostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) {
@ -297,6 +308,11 @@ void DomainHandler::setIsConnected(bool isConnected) {
}
}
void DomainHandler::connectedToServerless(std::map<QString, QString> namedPaths) {
_namedPaths = namedPaths;
setIsConnected(true);
}
void DomainHandler::requestDomainSettings() {
qCDebug(networking) << "Requesting settings from domain server";

View file

@ -76,6 +76,10 @@ public:
void setIsConnected(bool isConnected);
bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_HIFI; }
void connectedToServerless(std::map<QString, QString> namedPaths);
QString getViewPointFromNamedPath(QString namedPath);
bool hasSettings() const { return !_settingsObject.isEmpty(); }
void requestDomainSettings();
const QJsonObject& getSettingsObject() const { return _settingsObject; }
@ -200,9 +204,11 @@ private:
int _checkInPacketsSinceLastReply { 0 };
QTimer _apiRefreshTimer;
std::map<QString, QString> _namedPaths;
};
const QString DOMAIN_SPAWNING_POINT { "/0, -10, 0" };
const QString DEFAULT_NAMED_PATH { "/" };
#endif // hifi_DomainHandler_h

View file

@ -277,13 +277,8 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
emit dataReceived(sendingNodeType, packet.getPayloadSize());
return true;
} else {
static const QString UNSOLICITED_REPLICATED_REGEX =
"Replicated packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unknown upstream";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(UNSOLICITED_REPLICATED_REGEX);
qCDebug(networking) << "Replicated packet of type" << headerType
<< "received from unknown upstream" << packet.getSenderSockAddr();
HIFI_FCDEBUG(networking(), "Replicated packet of type" << headerType
<< "received from unknown upstream" << packet.getSenderSockAddr());
return false;
}
@ -345,12 +340,8 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
return true;
} else {
static const QString UNKNOWN_REGEX = "Packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unknown node with UUID";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(UNKNOWN_REGEX);
qCDebug(networking) << "Packet of type" << headerType
<< "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID);
HIFI_FCDEBUG(networking(),
"Packet of type" << headerType << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID));
}
}

View file

@ -90,8 +90,8 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
// assume that we may need to send a new DS check in anytime a new keypair is generated
connect(accountManager.data(), &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn);
// clear out NodeList when login is finished
connect(accountManager.data(), SIGNAL(loginComplete(const QUrl&)) , this, SLOT(reset()));
// clear out NodeList when login is finished and we know our new username
connect(accountManager.data(), SIGNAL(usernameChanged(QString)) , this, SLOT(reset()));
// clear our NodeList when logout is requested
connect(accountManager.data(), SIGNAL(logoutComplete()) , this, SLOT(reset()));
@ -413,7 +413,16 @@ void NodeList::sendDomainServerCheckIn() {
}
void NodeList::handleDSPathQuery(const QString& newPath) {
if (_domainHandler.isSocketKnown()) {
if (_domainHandler.isServerless()) {
if (_domainHandler.isConnected()) {
auto viewpoint = _domainHandler.getViewPointFromNamedPath(newPath);
if (!newPath.isEmpty()) {
DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, newPath);
}
} else {
_domainHandler.setPendingPath(newPath);
}
} else if (_domainHandler.isSocketKnown()) {
// if we have a DS socket we assume it will get this packet and send if off right away
sendDSPathQuery(newPath);
} else {
@ -427,10 +436,17 @@ void NodeList::sendPendingDSPathQuery() {
QString pendingPath = _domainHandler.getPendingPath();
if (!pendingPath.isEmpty()) {
qCDebug(networking) << "Attempting to send pending query to DS for path" << pendingPath;
// this is a slot triggered if we just established a network link with a DS and want to send a path query
sendDSPathQuery(_domainHandler.getPendingPath());
if (_domainHandler.isServerless()) {
auto viewpoint = _domainHandler.getViewPointFromNamedPath(pendingPath);
if (!pendingPath.isEmpty()) {
DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, pendingPath);
}
} else {
qCDebug(networking) << "Attempting to send pending query to DS for path" << pendingPath;
// this is a slot triggered if we just established a network link with a DS and want to send a path query
sendDSPathQuery(_domainHandler.getPendingPath());
}
// clear whatever the pending path was
_domainHandler.clearPendingPath();
@ -498,7 +514,7 @@ void NodeList::processDomainServerPathResponse(QSharedPointer<ReceivedMessage> m
QString viewpoint = QString::fromUtf8(message->getRawMessage() + message->getPosition(), numViewpointBytes);
// Hand it off to the AddressManager so it can handle it as a relative viewpoint
if (DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, pathQuery)) {
if (!pathQuery.isEmpty() && DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, pathQuery)) {
qCDebug(networking) << "Going to viewpoint" << viewpoint << "which was the lookup result for path" << pathQuery;
} else {
qCDebug(networking) << "Could not go to viewpoint" << viewpoint

View file

@ -89,10 +89,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
} else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
arrivalInfo._status = Unreasonable;
static const QString UNREASONABLE_SEQUENCE_REGEX { "unreasonable sequence number: \\d+ previous: \\d+" };
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(UNREASONABLE_SEQUENCE_REGEX);
qCDebug(networking) << "unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence;
HIFI_FCDEBUG(networking(), "unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence);
_stats._unreasonable++;
@ -154,10 +151,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
arrivalInfo._status = Unreasonable;
static const QString UNREASONABLE_SEQUENCE_REGEX { "unreasonable sequence number: \\d+ \\(possible duplicate\\)" };
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(UNREASONABLE_SEQUENCE_REGEX);
qCDebug(networking) << "unreasonable sequence number:" << incoming << "(possible duplicate)";
HIFI_FCDEBUG(networking(), "unreasonable sequence number:" << incoming << "(possible duplicate)");
_stats._unreasonable++;

View file

@ -107,8 +107,7 @@ Packet::Packet(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& se
QString::number(getMessagePartNumber()));
}
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Unobfuscating packet .*");
qCDebug(networking) << qPrintable(debugString);
HIFI_FCDEBUG(networking(), debugString);
#endif
obfuscate(NoObfuscation); // Undo obfuscation

View file

@ -479,8 +479,7 @@ bool SendQueue::maybeResendPacket() {
debugString = debugString.arg(QString::number(resendPacket.getMessageNumber()),
QString::number(resendPacket.getMessagePartNumber()));
}
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Obfuscating packet .*");
qCritical() << qPrintable(debugString);
HIFI_FDEBUG(debugString);
#endif
// Create copy of the packet

View file

@ -229,11 +229,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc
if (bytesWritten < 0) {
// when saturating a link this isn't an uncommon message - suppress it so it doesn't bomb the debug
static const QString WRITE_ERROR_REGEX = "Socket::writeDatagram QAbstractSocket::NetworkError - Unable to send a message";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(WRITE_ERROR_REGEX);
qCDebug(networking) << "Socket::writeDatagram" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString());
HIFI_FCDEBUG(networking(), "Socket::writeDatagram" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString()) );
}
return bytesWritten;
@ -517,11 +513,7 @@ std::vector<HifiSockAddr> Socket::getConnectionSockAddrs() {
}
void Socket::handleSocketError(QAbstractSocket::SocketError socketError) {
static const QString SOCKET_REGEX = "udt::Socket error - ";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(SOCKET_REGEX);
qCDebug(networking) << "udt::Socket error - " << socketError << _udpSocket.errorString();
HIFI_FCDEBUG(networking(), "udt::Socket error - " << socketError << _udpSocket.errorString());
}
void Socket::handleStateChanged(QAbstractSocket::SocketState socketState) {

View file

@ -121,11 +121,7 @@ void Octree::recurseTreeWithPostOperation(const RecurseOctreeOperation& operatio
void Octree::recurseElementWithOperation(const OctreeElementPointer& element, const RecurseOctreeOperation& operation, void* extraData,
int recursionCount) {
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qCDebug(octree) << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
HIFI_FCDEBUG(octree(), "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
return;
}
@ -143,11 +139,7 @@ void Octree::recurseElementWithOperation(const OctreeElementPointer& element, co
void Octree::recurseElementWithPostOperation(const OctreeElementPointer& element, const RecurseOctreeOperation& operation,
void* extraData, int recursionCount) {
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithPostOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qCDebug(octree) << "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
HIFI_FCDEBUG(octree(), "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
return;
}
@ -173,11 +165,7 @@ void Octree::recurseElementWithOperationDistanceSorted(const OctreeElementPointe
const glm::vec3& point, void* extraData, int recursionCount) {
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithOperationDistanceSorted\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qCDebug(octree) << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
HIFI_FCDEBUG(octree(), "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
return;
}
@ -215,11 +203,7 @@ void Octree::recurseTreeWithOperator(RecurseOctreeOperator* operatorObject) {
bool Octree::recurseElementWithOperator(const OctreeElementPointer& element,
RecurseOctreeOperator* operatorObject, int recursionCount) {
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithOperator\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qCDebug(octree) << "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
HIFI_FCDEBUG(octree(), "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
return false;
}
@ -285,11 +269,7 @@ OctreeElementPointer Octree::createMissingElement(const OctreeElementPointer& la
const unsigned char* codeToReach, int recursionCount) {
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::createMissingElement\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qCDebug(octree) << "Octree::createMissingElement() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
HIFI_FCDEBUG(octree(), "Octree::createMissingElement() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
return lastParentElement;
}
int indexOfNewChild = branchIndexWithDescendant(lastParentElement->getOctalCode(), codeToReach);
@ -446,16 +426,9 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, uint64_t buffe
(unsigned char *)bitstreamAt, NULL);
int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes);
if (numberOfThreeBitSectionsInStream > UNREASONABLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
"numberOfThreeBitSectionsInStream: \\d+ This buffer is corrupt. Returning."
);
qCDebug(octree) << "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
HIFI_FCDEBUG(octree(), "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
"numberOfThreeBitSectionsInStream:" << numberOfThreeBitSectionsInStream <<
"This buffer is corrupt. Returning.";
"This buffer is corrupt. Returning.");
return;
}

View file

@ -401,11 +401,7 @@ OctreeElementPointer OctreeElement::addChildAtIndex(int childIndex) {
bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) {
bool deleteApproved = false;
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"OctreeElement::safeDeepDeleteChildAtIndex\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qCDebug(octree) << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
HIFI_FCDEBUG(octree(), "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
return deleteApproved;
}
OctreeElementPointer childToDelete = getChildAtIndex(childIndex);

View file

@ -636,12 +636,8 @@ void OctreeSceneStats::trackIncomingOctreePacket(ReceivedMessage& message, bool
const qint64 MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive
const qint64 MIN_RESONABLE_FLIGHT_TIME = -1 * (qint64)USECS_PER_SECOND; // more than 1 second of "reverse flight time" would be unreasonable
if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"ignoring unreasonable packet... flightTime: -?\\d+ nodeClockSkewUsec: -?\\d+ usecs");
qCDebug(octree) << "ignoring unreasonable packet... flightTime:" << flightTime
<< "nodeClockSkewUsec:" << nodeClockSkewUsec << "usecs";;
HIFI_FCDEBUG(octree(), "ignoring unreasonable packet... flightTime:" << flightTime
<< "nodeClockSkewUsec:" << nodeClockSkewUsec << "usecs");
return; // ignore any packets that are unreasonable
}

View file

@ -47,19 +47,22 @@ ObjectActionTractor::~ObjectActionTractor() {
bool ObjectActionTractor::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
glm::vec3& linearVelocity, glm::vec3& angularVelocity,
float& linearTimeScale, float& angularTimeScale) {
SpatiallyNestablePointer other = getOther();
bool success { true };
EntityItemPointer other = std::dynamic_pointer_cast<EntityItem>(getOther());
withReadLock([&]{
linearTimeScale = _linearTimeScale;
angularTimeScale = _angularTimeScale;
if (!_otherID.isNull()) {
if (other) {
if (other && other->isReadyToComputeShape()) {
rotation = _desiredRotationalTarget * other->getWorldOrientation();
position = other->getWorldOrientation() * _desiredPositionalTarget + other->getWorldPosition();
} else {
// we should have an "other" but can't find it, so disable the tractor.
// we should have an "other" but can't find it, or its collision shape isn't loaded,
// so disable the tractor.
linearTimeScale = FLT_MAX;
angularTimeScale = FLT_MAX;
success = false;
}
} else {
rotation = _desiredRotationalTarget;
@ -68,7 +71,7 @@ bool ObjectActionTractor::getTarget(float deltaTimeStep, glm::quat& rotation, gl
linearVelocity = glm::vec3();
angularVelocity = glm::vec3();
});
return true;
return success;
}
bool ObjectActionTractor::prepareForTractorUpdate(btScalar deltaTimeStep) {
@ -122,6 +125,8 @@ bool ObjectActionTractor::prepareForTractorUpdate(btScalar deltaTimeStep) {
linearTractorCount++;
position += positionForAction;
}
} else {
return false; // we don't have both entities loaded, so don't do anything
}
}

View file

@ -85,12 +85,11 @@ btTypedConstraint* ObjectConstraintBallSocket::getConstraint() {
return constraint;
}
static QString repeatedBallSocketNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
"ObjectConstraintBallSocket::getConstraint -- no rigidBody.*");
static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID();
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyA";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintBallSocket::getConstraint -- no rigidBodyA");
return nullptr;
}
@ -99,7 +98,7 @@ btTypedConstraint* ObjectConstraintBallSocket::getConstraint() {
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
if (!rigidBodyB) {
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyB";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintBallSocket::getConstraint -- no rigidBodyB");
return nullptr;
}

View file

@ -96,12 +96,11 @@ btTypedConstraint* ObjectConstraintConeTwist::getConstraint() {
return constraint;
}
static QString repeatedConeTwistNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
"ObjectConstraintConeTwist::getConstraint -- no rigidBody.*");
static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID();
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyA";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintConeTwist::getConstraint -- no rigidBodyA");
return nullptr;
}
@ -130,7 +129,7 @@ btTypedConstraint* ObjectConstraintConeTwist::getConstraint() {
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
if (!rigidBodyB) {
qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyB";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintConeTwist::getConstraint -- no rigidBodyB");
return nullptr;
}

View file

@ -94,13 +94,12 @@ btTypedConstraint* ObjectConstraintHinge::getConstraint() {
if (constraint) {
return constraint;
}
static QString repeatedHingeNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
"ObjectConstraintHinge::getConstraint -- no rigidBody.*");
static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID();
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
qCDebug(physics) << "ObjectConstraintHinge::getConstraint -- no rigidBodyA";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintHinge::getConstraint -- no rigidBodyA");
return nullptr;
}
@ -115,7 +114,7 @@ btTypedConstraint* ObjectConstraintHinge::getConstraint() {
// This hinge is between two entities... find the other rigid body.
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
if (!rigidBodyB) {
qCDebug(physics) << "ObjectConstraintHinge::getConstraint -- no rigidBodyB";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintHinge::getConstraint -- no rigidBodyB");
return nullptr;
}

View file

@ -87,12 +87,11 @@ btTypedConstraint* ObjectConstraintSlider::getConstraint() {
return constraint;
}
static QString repeatedSliderNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
"ObjectConstraintSlider::getConstraint -- no rigidBody.*");
static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID();
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyA";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintSlider::getConstraint -- no rigidBodyA");
return nullptr;
}
@ -121,7 +120,7 @@ btTypedConstraint* ObjectConstraintSlider::getConstraint() {
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
if (!rigidBodyB) {
qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyB";
HIFI_FCDEBUG_ID(physics(), repeatMessageID, "ObjectConstraintSlider::getConstraint -- no rigidBodyB");
return nullptr;
}

View file

@ -41,7 +41,7 @@ void PhysicalEntitySimulation::init(
// begin EntitySimulation overrides
void PhysicalEntitySimulation::updateEntitiesInternal(uint64_t now) {
// Do nothing here because the "internal" update the PhysicsEngine::stepSimualtion() which is done elsewhere.
// Do nothing here because the "internal" update the PhysicsEngine::stepSimulation() which is done elsewhere.
}
void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {

View file

@ -126,9 +126,6 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext,
if (defaultSkyboxAmbientTexture) {
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
} else {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
"Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step");
}
// fall through: render defaults skybox
} else {

View file

@ -142,15 +142,18 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
// Mask out haze on the tablet
PrepareStencil::testMask(*state);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), HazeEffect_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), HazeEffect_TransformBufferSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), HazeEffect_ColorMapSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("linearDepthMap"), HazeEffect_LinearDepthMapSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), HazeEffect_LightingMapSlot));
gpu::Shader::makeProgram(*program, slotBindings);
_hazePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
gpu::doInBatch("DrawHaze::build", args->_context, [program](gpu::Batch& batch) {
batch.runLambda([program]() {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), HazeEffect_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), HazeEffect_TransformBufferSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), HazeEffect_ColorMapSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("linearDepthMap"), HazeEffect_LinearDepthMapSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), HazeEffect_LightingMapSlot));
gpu::Shader::makeProgram(*program, slotBindings);
});
});
}
auto sourceFramebufferSize = glm::ivec2(inputBuffer->getDimensions());

View file

@ -311,9 +311,6 @@ void diffuseProfileGPU(gpu::TexturePointer& profileMap, RenderArgs* args) {
auto ps = subsurfaceScattering_makeProfile_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
makePipeline = gpu::Pipeline::create(program, state);
@ -342,26 +339,27 @@ void diffuseScatterGPU(const gpu::TexturePointer& profileMap, gpu::TexturePointe
int height = lut->getHeight();
gpu::PipelinePointer makePipeline;
{
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = subsurfaceScattering_makeLUT_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = subsurfaceScattering_makeLUT_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringProfile"), 0));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
makePipeline = gpu::Pipeline::create(program, state);
}
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
makePipeline = gpu::Pipeline::create(program, state);
auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("diffuseScatter"));
makeFramebuffer->setRenderBuffer(0, lut);
gpu::doInBatch("SubsurfaceScattering::diffuseScatterGPU", args->_context, [=](gpu::Batch& batch) {
batch.enableStereo(false);
batch.runLambda([program] (){
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringProfile"), 0));
gpu::Shader::makeProgram(*program, slotBindings);
});
batch.setViewportTransform(glm::ivec4(0, 0, width, height));
batch.setFramebuffer(makeFramebuffer);
@ -385,9 +383,6 @@ void computeSpecularBeckmannGPU(gpu::TexturePointer& beckmannMap, RenderArgs* ar
auto ps = subsurfaceScattering_makeSpecularBeckmann_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
makePipeline = gpu::Pipeline::create(program, state);
@ -495,7 +490,6 @@ gpu::PipelinePointer DebugSubsurfaceScattering::getShowLUTPipeline() {
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());

View file

@ -167,7 +167,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con
outputs.edit3() = halfLinearDepthTexture;
outputs.edit4() = halfNormalTexture;
auto linearDepthPipeline = getLinearDepthPipeline();
auto linearDepthPipeline = getLinearDepthPipeline(renderContext);
auto downsamplePipeline = getDownsamplePipeline();
auto depthViewport = args->_viewport;
@ -209,17 +209,12 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con
}
const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() {
const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline(const render::RenderContextPointer& renderContext) {
gpu::ShaderPointer program;
if (!_linearDepthPipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto ps = surfaceGeometry_makeLinearDepth_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DepthLinearPass_FrameTransformSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DepthLinearPass_DepthMapSlot));
gpu::Shader::makeProgram(*program, slotBindings);
program = gpu::Shader::createProgram(vs, ps);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
@ -230,8 +225,18 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() {
// Good to go add the brand new pipeline
_linearDepthPipeline = gpu::Pipeline::create(program, state);
gpu::doInBatch("LinearDepthPass::run", renderContext->args->_context, [program](gpu::Batch& batch) {
batch.runLambda([program]() {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DepthLinearPass_FrameTransformSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DepthLinearPass_DepthMapSlot));
gpu::Shader::makeProgram(*program, slotBindings);
});
});
}
return _linearDepthPipeline;
}
@ -455,7 +460,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext,
outputs.edit2() = curvatureFramebuffer;
outputs.edit3() = lowCurvatureFramebuffer;
auto curvaturePipeline = getCurvaturePipeline();
auto curvaturePipeline = getCurvaturePipeline(renderContext);
auto diffuseVPipeline = _diffusePass.getBlurVPipeline();
auto diffuseHPipeline = _diffusePass.getBlurHPipeline();
@ -536,21 +541,12 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext,
config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage());
}
const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() {
const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline(const render::RenderContextPointer& renderContext) {
if (!_curvaturePipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto ps = surfaceGeometry_makeCurvature_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), SurfaceGeometryPass_FrameTransformSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("surfaceGeometryParamsBuffer"), SurfaceGeometryPass_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), SurfaceGeometryPass_DepthMapSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), SurfaceGeometryPass_NormalMapSlot));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
#ifdef USE_STENCIL_TEST
@ -559,6 +555,17 @@ const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() {
#endif
// Good to go add the brand new pipeline
_curvaturePipeline = gpu::Pipeline::create(program, state);
gpu::doInBatch("SurfaceGeometryPass::CurvaturePipeline", renderContext->args->_context, [program](gpu::Batch& batch) {
batch.runLambda([program]() {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), SurfaceGeometryPass_FrameTransformSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("surfaceGeometryParamsBuffer"), SurfaceGeometryPass_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), SurfaceGeometryPass_DepthMapSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), SurfaceGeometryPass_NormalMapSlot));
gpu::Shader::makeProgram(*program, slotBindings);
});
});
}
return _curvaturePipeline;

View file

@ -81,7 +81,7 @@ private:
LinearDepthFramebufferPointer _linearDepthFramebuffer;
const gpu::PipelinePointer& getLinearDepthPipeline();
const gpu::PipelinePointer& getLinearDepthPipeline(const render::RenderContextPointer& renderContext);
gpu::PipelinePointer _linearDepthPipeline;
const gpu::PipelinePointer& getDownsamplePipeline();
@ -195,7 +195,7 @@ private:
SurfaceGeometryFramebufferPointer _surfaceGeometryFramebuffer;
const gpu::PipelinePointer& getCurvaturePipeline();
const gpu::PipelinePointer& getCurvaturePipeline(const render::RenderContextPointer& renderContext);
gpu::PipelinePointer _curvaturePipeline;

View file

@ -27,19 +27,24 @@ ToneMappingEffect::ToneMappingEffect() {
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
}
void ToneMappingEffect::init() {
void ToneMappingEffect::init(RenderArgs* args) {
auto blitPS = toneMapping_frag::getShader();
auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), ToneMappingEffect_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), ToneMappingEffect_LightingMapSlot));
gpu::Shader::makeProgram(*blitProgram, slotBindings);
auto blitState = std::make_shared<gpu::State>();
blitState->setColorWriteMask(true, true, true, true);
_blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
gpu::doInBatch("ToneMappingEffect::toneMapping", args->_context, [blitProgram](gpu::Batch& batch) {
batch.runLambda([blitProgram]() {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), ToneMappingEffect_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), ToneMappingEffect_LightingMapSlot));
gpu::Shader::makeProgram(*blitProgram, slotBindings);
});
});
}
void ToneMappingEffect::setExposure(float exposure) {
@ -59,7 +64,7 @@ void ToneMappingEffect::setToneCurve(ToneCurve curve) {
void ToneMappingEffect::render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, const gpu::FramebufferPointer& requestedDestinationFramebuffer) {
if (!_blitLightBuffer) {
init();
init(args);
}
auto destinationFramebuffer = requestedDestinationFramebuffer;

View file

@ -59,7 +59,7 @@ private:
typedef gpu::BufferView UniformBufferView;
gpu::BufferView _parametersBuffer;
void init();
void init(RenderArgs* args);
};
class ToneMappingConfig : public render::Job::Config {

View file

@ -41,6 +41,11 @@ void render::renderItems(const RenderContextPointer& renderContext, const ItemBo
}
}
namespace {
int repeatedInvalidKeyMessageID = 0;
std::once_flag messageIDFlag;
}
void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item, const ShapeKey& globalKey) {
assert(item.getKey().isShape());
auto key = item.getShapeKey() | globalKey;
@ -55,9 +60,9 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
} else if (key.hasOwnPipeline()) {
item.render(args);
} else {
qCDebug(renderlogging) << "Item could not be rendered with invalid key" << key;
static QString repeatedCouldNotBeRendered = LogHandler::getInstance().addRepeatedMessageRegex(
"Item could not be rendered with invalid key.*");
std::call_once(messageIDFlag, [](int* id) { *id = LogHandler::getInstance().newRepeatedMessageID(); },
&repeatedInvalidKeyMessageID);
HIFI_FCDEBUG_ID(renderlogging(), repeatedInvalidKeyMessageID, "Item could not be rendered with invalid key" << key);
}
args->_itemShapeKey = 0;
}
@ -108,9 +113,9 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
} else if (key.hasOwnPipeline()) {
ownPipelineBucket.push_back( std::make_tuple(item, key) );
} else {
static QString repeatedCouldNotBeRendered = LogHandler::getInstance().addRepeatedMessageRegex(
"Item could not be rendered with invalid key.*");
qCDebug(renderlogging) << "Item could not be rendered with invalid key" << key;
std::call_once(messageIDFlag, [](int* id) { *id = LogHandler::getInstance().newRepeatedMessageID(); },
&repeatedInvalidKeyMessageID);
HIFI_FCDEBUG_ID(renderlogging(), repeatedInvalidKeyMessageID, "Item could not be rendered with invalid key" << key);
}
}
}

View file

@ -25,7 +25,7 @@
#include <QtCore/QThread>
#include <QtCore/QTimer>
QMutex LogHandler::_mutex;
QMutex LogHandler::_mutex(QMutex::Recursive);
LogHandler& LogHandler::getInstance() {
static LogHandler staticInstance;
@ -36,6 +36,9 @@ LogHandler::LogHandler() {
// when the log handler is first setup we should print our timezone
QString timezoneString = "Time zone: " + QDateTime::currentDateTime().toString("t");
printMessage(LogMsgType::LogInfo, QMessageLogContext(), timezoneString);
// make sure we setup the repeated message flusher, but do it on the LogHandler thread
QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher");
}
LogHandler::~LogHandler() {
@ -91,58 +94,25 @@ void LogHandler::setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds) {
void LogHandler::flushRepeatedMessages() {
QMutexLocker lock(&_mutex);
for(auto& message: _repeatedMessages) {
if (message.messageCount > 1) {
QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"")
.arg(message.messageCount - 1)
.arg(message.regexp.pattern())
.arg(message.lastMessage);
QMessageLogContext emptyContext;
lock.unlock();
printMessage(LogSuppressed, emptyContext, repeatMessage);
lock.relock();
// New repeat-suppress scheme:
for (int m = 0; m < (int)_repeatedMessageRecords.size(); ++m) {
int repeatCount = _repeatedMessageRecords[m].repeatCount;
if (repeatCount > 1) {
QString repeatLogMessage = QString().setNum(repeatCount) + " repeated log entries - Last entry: \""
+ _repeatedMessageRecords[m].repeatString + "\"";
printMessage(LogSuppressed, QMessageLogContext(), repeatLogMessage);
_repeatedMessageRecords[m].repeatCount = 0;
_repeatedMessageRecords[m].repeatString = QString();
}
message.messageCount = 0;
}
}
QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
QMutexLocker lock(&_mutex);
if (message.isEmpty()) {
return QString();
}
if (type == LogDebug) {
// for debug messages, check if this matches any of our regexes for repeated log messages
for (auto& repeatRegex : _repeatedMessages) {
if (repeatRegex.regexp.indexIn(message) != -1) {
// If we've printed the first one then return out.
if (repeatRegex.messageCount++ == 0) {
break;
}
repeatRegex.lastMessage = message;
return QString();
}
}
}
if (type == LogDebug) {
// see if this message is one we should only print once
for (auto& onceOnly : _onetimeMessages) {
if (onceOnly.regexp.indexIn(message) != -1) {
if (onceOnly.messageCount++ == 0) {
// we have a match and haven't yet printed this message.
break;
} else {
// We've already printed this message, don't print it again.
return QString();
}
}
}
}
QMutexLocker lock(&_mutex);
// log prefix is in the following format
// [TIMESTAMP] [DEBUG] [PID] [TID] [TARGET] logged string
@ -199,21 +169,27 @@ void LogHandler::setupRepeatedMessageFlusher() {
});
}
const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) {
// make sure we setup the repeated message flusher, but do it on the LogHandler thread
QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher");
int LogHandler::newRepeatedMessageID() {
QMutexLocker lock(&_mutex);
RepeatedMessage repeatRecord;
repeatRecord.regexp = QRegExp(regexString);
_repeatedMessages.push_back(repeatRecord);
return regexString;
int newMessageId = _currentMessageID;
++_currentMessageID;
RepeatedMessageRecord newRecord { 0, QString() };
_repeatedMessageRecords.push_back(newRecord);
return newMessageId;
}
const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) {
void LogHandler::printRepeatedMessage(int messageID, LogMsgType type, const QMessageLogContext& context,
const QString& message) {
QMutexLocker lock(&_mutex);
OnceOnlyMessage onetimeMessage;
onetimeMessage.regexp = QRegExp(regexString);
_onetimeMessages.push_back(onetimeMessage);
return regexString;
if (messageID >= _currentMessageID) {
return;
}
if (_repeatedMessageRecords[messageID].repeatCount == 0) {
printMessage(type, context, message);
} else {
_repeatedMessageRecords[messageID].repeatString = message;
}
++_repeatedMessageRecords[messageID].repeatCount;
}

View file

@ -51,8 +51,8 @@ public:
/// prints various process, message type, and time information
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
const QString& addRepeatedMessageRegex(const QString& regexString);
const QString& addOnlyOnceMessageRegex(const QString& regexString);
int newRepeatedMessageID();
void printRepeatedMessage(int messageID, LogMsgType type, const QMessageLogContext& context, const QString &message);
private slots:
void setupRepeatedMessageFlusher();
@ -68,20 +68,40 @@ private:
bool _shouldOutputThreadID { false };
bool _shouldDisplayMilliseconds { false };
struct RepeatedMessage {
QRegExp regexp;
int messageCount { 0 };
QString lastMessage;
int _currentMessageID { 0 };
struct RepeatedMessageRecord {
int repeatCount;
QString repeatString;
};
std::vector<RepeatedMessage> _repeatedMessages;
struct OnceOnlyMessage {
QRegExp regexp;
int messageCount { 0 };
};
std::vector<OnceOnlyMessage> _onetimeMessages;
std::vector<RepeatedMessageRecord> _repeatedMessageRecords;
static QMutex _mutex;
};
#define HIFI_FCDEBUG(category, message) \
do { \
if (category.isDebugEnabled()) { \
static int repeatedMessageID_ = LogHandler::getInstance().newRepeatedMessageID(); \
QString logString_; \
QDebug debugStringReceiver_(&logString_); \
debugStringReceiver_ << message; \
LogHandler::getInstance().printRepeatedMessage(repeatedMessageID_, LogDebug, QMessageLogContext(__FILE__, \
__LINE__, __func__, category().categoryName()), logString_); \
} \
} while (false)
#define HIFI_FDEBUG(message) HIFI_FCDEBUG((*QLoggingCategory::defaultCategory()), message)
#define HIFI_FCDEBUG_ID(category, messageID, message) \
do { \
if (category.isDebugEnabled()) { \
QString logString_; \
QDebug debugStringReceiver_(&logString_); \
debugStringReceiver_ << message; \
LogHandler::getInstance().printRepeatedMessage(messageID, LogDebug, QMessageLogContext(__FILE__, \
__LINE__, __func__, category().categoryName()), logString_); \
} \
} while (false)
#define HIFI_FDEBUG_ID(messageID, message) HIFI_FCDEBUG_ID((*QLoggingCategory::defaultCategory()), messageID, message)
#endif // hifi_LogHandler_h

View file

@ -34,48 +34,140 @@ PluginContainer::~PluginContainer() {
INSTANCE = nullptr;
};
struct MenuCache {
QSet<QString> menus;
struct Item {
QString path;
std::function<void(bool)> onClicked;
bool checkable;
bool checked;
QString groupName;
};
QHash<QString, Item> items;
std::map<QString, QActionGroup*> _exclusiveGroups;
void addMenu(ui::Menu* menu, const QString& menuName) {
if (!menu) {
menus.insert(menuName);
return;
}
flushCache(menu);
menu->addMenu(menuName);
}
void removeMenu(ui::Menu* menu, const QString& menuName) {
if (!menu) {
menus.remove(menuName);
return;
}
flushCache(menu);
menu->removeMenu(menuName);
}
void addMenuItem(ui::Menu* menu, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
if (!menu) {
items[name] = Item{ path, onClicked, checkable, checked, groupName };
return;
}
flushCache(menu);
MenuWrapper* parentItem = menu->getMenu(path);
QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name);
if (!groupName.isEmpty()) {
QActionGroup* group{ nullptr };
if (!_exclusiveGroups.count(groupName)) {
group = _exclusiveGroups[groupName] = new QActionGroup(menu);
group->setExclusive(true);
} else {
group = _exclusiveGroups[groupName];
}
group->addAction(action);
}
QObject::connect(action, &QAction::triggered, [=] {
onClicked(action->isChecked());
});
action->setCheckable(checkable);
action->setChecked(checked);
}
void removeMenuItem(ui::Menu* menu, const QString& menuName, const QString& menuItemName) {
if (!menu) {
items.remove(menuItemName);
return;
}
flushCache(menu);
menu->removeMenuItem(menuName, menuItemName);
}
bool isOptionChecked(ui::Menu* menu, const QString& name) {
if (!menu) {
return items.contains(name) && items[name].checked;
}
flushCache(menu);
return menu->isOptionChecked(name);
}
void setIsOptionChecked(ui::Menu* menu, const QString& name, bool checked) {
if (!menu) {
if (items.contains(name)) {
items[name].checked = checked;
}
return;
}
flushCache(menu);
}
void flushCache(ui::Menu* menu) {
if (!menu) {
return;
}
static bool flushed = false;
if (flushed) {
return;
}
flushed = true;
for (const auto& menuName : menus) {
addMenu(menu, menuName);
}
menus.clear();
for (const auto& menuItemName : items.keys()) {
const auto menuItem = items[menuItemName];
addMenuItem(menu, menuItem.path, menuItemName, menuItem.onClicked, menuItem.checkable, menuItem.checked, menuItem.groupName);
}
items.clear();
}
};
static MenuCache& getMenuCache() {
static MenuCache cache;
return cache;
}
void PluginContainer::addMenu(const QString& menuName) {
getPrimaryMenu()->addMenu(menuName);
getMenuCache().addMenu(getPrimaryMenu(), menuName);
}
void PluginContainer::removeMenu(const QString& menuName) {
getPrimaryMenu()->removeMenu(menuName);
getMenuCache().removeMenu(getPrimaryMenu(), menuName);
}
QAction* PluginContainer::addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
auto menu = getPrimaryMenu();
MenuWrapper* parentItem = menu->getMenu(path);
QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name);
if (!groupName.isEmpty()) {
QActionGroup* group { nullptr };
if (!_exclusiveGroups.count(groupName)) {
group = _exclusiveGroups[groupName] = new QActionGroup(menu);
group->setExclusive(true);
} else {
group = _exclusiveGroups[groupName];
}
group->addAction(action);
}
QObject::connect(action, &QAction::triggered, [=] {
onClicked(action->isChecked());
});
action->setCheckable(checkable);
action->setChecked(checked);
void PluginContainer::addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
getMenuCache().addMenuItem(getPrimaryMenu(), path, name, onClicked, checkable, checked, groupName);
if (type == PluginType::DISPLAY_PLUGIN) {
_currentDisplayPluginActions.push_back({ path, name });
} else {
_currentInputPluginActions.push_back({ path, name });
}
return action;
}
void PluginContainer::removeMenuItem(const QString& menuName, const QString& menuItem) {
getPrimaryMenu()->removeMenuItem(menuName, menuItem);
getMenuCache().removeMenuItem(getPrimaryMenu(), menuName, menuItem);
}
bool PluginContainer::isOptionChecked(const QString& name) {
return getPrimaryMenu()->isOptionChecked(name);
return getMenuCache().isOptionChecked(getPrimaryMenu(), name);
}
void PluginContainer::setIsOptionChecked(const QString& path, bool checked) {
@ -161,3 +253,7 @@ void PluginContainer::setBoolSetting(const QString& settingName, bool value) {
Setting::Handle<bool> settingValue(settingName, value);
return settingValue.set(value);
}
void PluginContainer::flushMenuUpdates() {
getMenuCache().flushCache(getPrimaryMenu());
}

View file

@ -46,7 +46,7 @@ public:
void addMenu(const QString& menuName);
void removeMenu(const QString& menuName);
QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "");
void addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "");
void removeMenuItem(const QString& menuName, const QString& menuItem);
bool isOptionChecked(const QString& name);
void setIsOptionChecked(const QString& path, bool checked);
@ -77,9 +77,9 @@ public:
}
protected:
void flushMenuUpdates();
QVector<QPair<QString, QString>> _currentDisplayPluginActions;
QVector<QPair<QString, QString>> _currentInputPluginActions;
std::map<QString, QActionGroup*> _exclusiveGroups;
QRect _savedGeometry { 10, 120, 800, 600 };
};

View file

@ -1,59 +0,0 @@
//
// ImageProvider.cpp
// interface/src/ui
//
// Created by David Kelly on 8/23/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ImageProvider.h"
#include <QReadLocker>
#include <QWriteLocker>
const QString ImageProvider::PROVIDER_NAME = "security";
QReadWriteLock ImageProvider::_rwLock;
QPixmap* ImageProvider::_securityImage = nullptr;
ImageProvider::~ImageProvider() {
QWriteLocker lock(&_rwLock);
if (_securityImage) {
delete _securityImage;
_securityImage = nullptr;
}
}
void ImageProvider::setSecurityImage(const QPixmap* pixmap) {
// no need to delete old one, that is managed by the wallet
QWriteLocker lock(&_rwLock);
if (_securityImage) {
delete _securityImage;
}
if (pixmap) {
_securityImage = new QPixmap(*pixmap);
} else {
_securityImage = nullptr;
}
}
QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) {
// adjust the internal pixmap to have the requested size
QReadLocker lock(&_rwLock);
if (id == "securityImage" && _securityImage) {
*size = _securityImage->size();
if (requestedSize.width() > 0 && requestedSize.height() > 0) {
return _securityImage->scaled(requestedSize.width(), requestedSize.height(), Qt::KeepAspectRatio);
} else {
return _securityImage->copy();
}
}
// otherwise just return a grey pixmap. This avoids annoying error messages in qml we would get
// when sending a 'null' pixmap (QPixmap())
QPixmap greyPixmap(200, 200);
greyPixmap.fill(QColor("darkGrey"));
return greyPixmap;
}

View file

@ -48,7 +48,7 @@
#include <gl/Context.h>
#include <shared/ReadWriteLockable.h>
#include "ImageProvider.h"
#include "SecurityImageProvider.h"
#include "types/FileTypeProfile.h"
#include "types/HFWebEngineProfile.h"
#include "types/SoundEffect.h"
@ -233,8 +233,8 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) {
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
});
// register the pixmap image provider (used only for security image, for now)
engine->addImageProvider(ImageProvider::PROVIDER_NAME, new ImageProvider());
// Register the pixmap Security Image Provider
engine->addImageProvider(SecurityImageProvider::PROVIDER_NAME, new SecurityImageProvider());
engine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
auto importList = engine->importPathList();
@ -344,6 +344,7 @@ void OffscreenQmlSurface::onRootCreated() {
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", this);
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
getSurfaceContext()->engine()->addImageProvider(SecurityImageProvider::PROVIDER_NAME, new SecurityImageProvider());
}
QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection);
}

View file

@ -0,0 +1,52 @@
//
// SecurityImageProvider.cpp
// interface/src/ui
//
// Created by David Kelly on 8/23/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SecurityImageProvider.h"
#include <QReadLocker>
#include <QWriteLocker>
const QString SecurityImageProvider::PROVIDER_NAME = "security";
SecurityImageProvider::~SecurityImageProvider() {
}
void SecurityImageProvider::setSecurityImage(const QPixmap* pixmap) {
// no need to delete old one, that is managed by the wallet
QWriteLocker lock(&_rwLock);
if (pixmap) {
_securityImage = pixmap->copy();
} else {
QPixmap greyPixmap(200, 200);
greyPixmap.fill(QColor("darkGrey"));
_securityImage = greyPixmap.copy();
}
}
QPixmap SecurityImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) {
// adjust the internal pixmap to have the requested size
QReadLocker lock(&_rwLock);
if (id == "securityImage") {
*size = _securityImage.size();
if (requestedSize.width() > 0 && requestedSize.height() > 0) {
return _securityImage.scaled(requestedSize.width(), requestedSize.height(), Qt::KeepAspectRatio);
} else {
return _securityImage.copy();
}
}
// otherwise just return a grey pixmap. This avoids annoying error messages in qml we would get
// when sending a 'null' pixmap (QPixmap())
QPixmap greyPixmap(200, 200);
greyPixmap.fill(QColor("darkGrey"));
return greyPixmap;
}

View file

@ -1,5 +1,5 @@
//
// ImageProvider.h
// SecurityImageProvider.h
//
// Created by David Kelly on 2017/08/23
// Copyright 2017 High Fidelity, Inc.
@ -9,26 +9,25 @@
//
#pragma once
#ifndef hifi_ImageProvider_h
#define hifi_ImageProvider_h
#ifndef hifi_SecurityImageProvider_h
#define hifi_SecurityImageProvider_h
#include <QQuickImageProvider>
#include <QReadWriteLock>
class ImageProvider: public QQuickImageProvider {
class SecurityImageProvider: public QQuickImageProvider {
public:
static const QString PROVIDER_NAME;
ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {}
virtual ~ImageProvider();
SecurityImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {}
virtual ~SecurityImageProvider();
QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override;
void setSecurityImage(const QPixmap* pixmap);
protected:
static QReadWriteLock _rwLock;
static QPixmap* _securityImage;
QReadWriteLock _rwLock;
QPixmap _securityImage;
};
#endif //hifi_ImageProvider_h
#endif //hifi_SecurityImageProvider_h

View file

@ -18,8 +18,6 @@
var bubbleOverlayTimestamp;
// Used for rate limiting the bubble sound
var lastBubbleSoundTimestamp = 0;
// Used for flashing the HUD button upon activation
var bubbleButtonFlashState = false;
// Affects bubble height
var BUBBLE_HEIGHT_SCALE = 0.15;
// The bubble model itself
@ -36,18 +34,16 @@
var bubbleActivateSound = SoundCache.getSound(Script.resolvePath("assets/sounds/bubble.wav"));
// Is the update() function connected?
var updateConnected = false;
var bubbleFlashTimer = false;
var BUBBLE_VISIBLE_DURATION_MS = 3000;
var BUBBLE_RAISE_ANIMATION_DURATION_MS = 750;
var BUBBLE_SOUND_RATE_LIMIT_MS = 15000;
// Hides the bubble model overlay and resets the button flash state
// Hides the bubble model overlay
function hideOverlays() {
Overlays.editOverlay(bubbleOverlay, {
visible: false
});
bubbleButtonFlashState = false;
}
// Make the bubble overlay visible, set its position, and play the sound
@ -89,8 +85,6 @@
bubbleOverlayTimestamp = nowTimestamp;
Script.update.connect(update);
updateConnected = true;
writeButtonProperties(bubbleButtonFlashState);
bubbleButtonFlashState = !bubbleButtonFlashState;
}
// Called from the C++ scripting interface to show the bubble overlay
@ -110,7 +104,6 @@
var delay = (timestamp - bubbleOverlayTimestamp);
var overlayAlpha = 1.0 - (delay / BUBBLE_VISIBLE_DURATION_MS);
if (overlayAlpha > 0) {
if (delay < BUBBLE_RAISE_ANIMATION_DURATION_MS) {
Overlays.editOverlay(bubbleOverlay, {
dimensions: {
@ -158,11 +151,6 @@
Script.update.disconnect(update);
updateConnected = false;
}
if (bubbleFlashTimer) {
Script.clearTimeout(bubbleFlashTimer);
bubbleFlashTimer = false;
}
writeButtonProperties(Users.getIgnoreRadiusEnabled());
}
}
@ -170,10 +158,6 @@
// NOTE: the c++ calls this with just the first param -- we added a second
// just for not logging the initial state of the bubble when we startup.
function onBubbleToggled(enabled, doNotLog) {
if (bubbleFlashTimer) {
Script.clearTimeout(bubbleFlashTimer);
bubbleFlashTimer = false;
}
writeButtonProperties(enabled);
if (doNotLog !== true) {
UserActivityLogger.bubbleToggled(enabled);
@ -208,17 +192,12 @@
// Cleanup the tablet button and overlays when script is stopped
Script.scriptEnding.connect(function () {
button.clicked.disconnect(Users.toggleIgnoreRadius);
if (bubbleFlashTimer) {
Script.clearTimeout(bubbleFlashTimer);
bubbleFlashTimer = false;
}
if (tablet) {
tablet.removeButton(button);
}
Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled);
Users.enteredIgnoreRadius.disconnect(enteredIgnoreRadius);
Overlays.deleteOverlay(bubbleOverlay);
bubbleButtonFlashState = false;
if (updateConnected === true) {
Script.update.disconnect(update);
}

View file

@ -11,140 +11,16 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/*global XXX */
/* global getConnectionData */
(function () { // BEGIN LOCAL_SCOPE
Script.include("/~/system/libraries/accountUtils.js");
var request = Script.require('request').request;
Script.include("/~/system/libraries/connectionUtils.js");
var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
// Function Name: onButtonClicked()
//
// Description:
// -Fired when the app button is pressed.
//
// Relevant Variables:
// -WALLET_QML_SOURCE: The path to the Wallet QML
// -onWalletScreen: true/false depending on whether we're looking at the app.
var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml";
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml";
var onWalletScreen = false;
function onButtonClicked() {
if (!tablet) {
print("Warning in buttonClicked(): 'tablet' undefined!");
return;
}
if (onWalletScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
tablet.loadQMLSource(WALLET_QML_SOURCE);
}
}
// Function Name: sendToQml()
//
// Description:
// -Use this function to send a message to the QML (i.e. to change appearances). The "message" argument is what is sent to
// the QML in the format "{method, params}", like json-rpc. See also fromQml().
function sendToQml(message) {
tablet.sendToQml(message);
}
//***********************************************
//
// BEGIN Connection logic
//
//***********************************************
// Function Names:
// - requestJSON
// - getAvailableConnections
// - getInfoAboutUser
// - getConnectionData
//
// Description:
// - Update all the usernames that I am entitled to see, using my login but not dependent on canKick.
var METAVERSE_BASE = Account.metaverseServerURL;
function requestJSON(url, callback) { // callback(data) if successfull. Logs otherwise.
request({
uri: url
}, function (error, response) {
if (error || (response.status !== 'success')) {
print("Error: unable to get", url, error || response.status);
return;
}
callback(response.data);
});
}
function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successful. (Logs otherwise)
url = METAVERSE_BASE + '/api/v1/users?per_page=400&'
if (domain) {
url += 'status=' + domain.slice(1, -1); // without curly braces
} else {
url += 'filter=connections'; // regardless of whether online
}
requestJSON(url, function (connectionsData) {
callback(connectionsData.users);
});
}
function getInfoAboutUser(specificUsername, callback) {
url = METAVERSE_BASE + '/api/v1/users?filter=connections'
requestJSON(url, function (connectionsData) {
for (user in connectionsData.users) {
if (connectionsData.users[user].username === specificUsername) {
callback(connectionsData.users[user]);
return;
}
}
callback(false);
});
}
function getConnectionData(specificUsername, domain) {
function frob(user) { // get into the right format
var formattedSessionId = user.location.node_id || '';
if (formattedSessionId !== '' && formattedSessionId.indexOf("{") != 0) {
formattedSessionId = "{" + formattedSessionId + "}";
}
return {
sessionId: formattedSessionId,
userName: user.username,
connection: user.connection,
profileUrl: user.images.thumbnail,
placeName: (user.location.root || user.location.domain || {}).name || ''
};
}
if (specificUsername) {
getInfoAboutUser(specificUsername, function (user) {
if (user) {
updateUser(frob(user));
} else {
print('Error: Unable to find information about ' + specificUsername + ' in connectionsData!');
}
});
} else {
getAvailableConnections(domain, function (users) {
if (domain) {
users.forEach(function (user) {
updateUser(frob(user));
});
} else {
sendToQml({ method: 'updateConnections', connections: users.map(frob) });
}
});
}
}
//***********************************************
//
// END Connection logic
//
//***********************************************
//***********************************************
//
// BEGIN Avatar Selector logic
//
//***********************************************
// BEGIN AVATAR SELECTOR LOGIC
var UNSELECTED_TEXTURES = {
"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"),
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png")
@ -415,7 +291,7 @@
userName: ''
};
sendToQml(message);
ExtendedOverlay.some(function (overlay) {
var id = overlay.key;
var selected = ExtendedOverlay.isSelected(id);
@ -521,11 +397,40 @@
triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand));
triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand));
triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand));
//***********************************************
// END AVATAR SELECTOR LOGIC
// Function Name: onButtonClicked()
//
// END Avatar Selector logic
// Description:
// -Fired when the app button is pressed.
//
//***********************************************
// Relevant Variables:
// -WALLET_QML_SOURCE: The path to the Wallet QML
// -onWalletScreen: true/false depending on whether we're looking at the app.
var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml";
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml";
var onWalletScreen = false;
function onButtonClicked() {
if (!tablet) {
print("Warning in buttonClicked(): 'tablet' undefined!");
return;
}
if (onWalletScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
tablet.loadQMLSource(WALLET_QML_SOURCE);
}
}
// Function Name: sendToQml()
//
// Description:
// -Use this function to send a message to the QML (i.e. to change appearances). The "message" argument is what is sent to
// the QML in the format "{method, params}", like json-rpc. See also fromQml().
function sendToQml(message) {
tablet.sendToQml(message);
}
var sendMoneyRecipient;
var sendMoneyParticleEffectUpdateTimer;
@ -678,18 +583,23 @@
}
removeOverlays();
break;
case 'sendMoney_sendPublicly':
deleteSendMoneyParticleEffect();
sendMoneyRecipient = message.recipient;
var amount = message.amount;
var props = SEND_MONEY_PARTICLE_PROPERTIES;
props.parentID = MyAvatar.sessionUUID;
props.position = MyAvatar.position;
props.position.y += 0.2;
sendMoneyParticleEffect = Entities.addEntity(props, true);
particleEffectTimestamp = Date.now();
updateSendMoneyParticleEffect();
sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
case 'sendAsset_sendPublicly':
if (message.assetName === "") {
deleteSendMoneyParticleEffect();
sendMoneyRecipient = message.recipient;
var amount = message.amount;
var props = SEND_MONEY_PARTICLE_PROPERTIES;
props.parentID = MyAvatar.sessionUUID;
props.position = MyAvatar.position;
props.position.y += 0.2;
if (message.effectImage) {
props.textures = message.effectImage;
}
sendMoneyParticleEffect = Entities.addEntity(props, true);
particleEffectTimestamp = Date.now();
updateSendMoneyParticleEffect();
sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
}
break;
case 'transactionHistory_goToBank':
if (Account.metaverseServerURL.indexOf("staging") >= 0) {
@ -781,18 +691,19 @@
var isWired = false;
var isUpdateOverlaysWired = false;
function off() {
if (isWired) { // It is not ok to disconnect these twice, hence guard.
if (isWired) {
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
Controller.mousePressEvent.disconnect(handleMouseEvent);
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
triggerMapping.disable();
triggerPressMapping.disable();
isWired = false;
}
if (isUpdateOverlaysWired) {
Script.update.disconnect(updateOverlays);
isUpdateOverlaysWired = false;
}
triggerMapping.disable(); // It's ok if we disable twice.
triggerPressMapping.disable(); // see above
removeOverlays();
}
function shutdown() {

View file

@ -7,11 +7,12 @@
/* jslint bitwise: true */
/* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation,
/* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation,
controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true,
LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES,
getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, COLORS_GRAB_SEARCHING_HALF_SQUEEZE
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, TRIGGER_ON_VALUE, PointerManager
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, TRIGGER_ON_VALUE, PointerManager, print
Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE
*/
controllerDispatcherPlugins = {};
@ -123,6 +124,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
return getControllerWorldLocation(Controller.Standard.RightHand, true);
};
Selection.enableListHighlight(DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE);
Selection.enableListToScene(DISPATCHER_HOVERING_LIST);
this.updateTimings = function () {
_this.intervalCount++;
var thisInterval = Date.now();
@ -157,7 +161,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
this.update = function () {
try {
_this.updateInternal();
} catch (e) {
} catch (e) {
print(e);
}
Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS);
@ -477,6 +481,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Controller.disableMapping(MAPPING_NAME);
_this.pointerManager.removePointers();
Pointers.removePointer(this.mouseRayPick);
Selection.disableListHighlight(DISPATCHER_HOVERING_LIST);
};
}
function mouseReleaseOnOverlay(overlayID, event) {

View file

@ -10,7 +10,7 @@
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid, unhighlightTargetEntity
*/
Script.include("/~/system/libraries/Xform.js");
@ -483,7 +483,13 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.dropGestureReset();
this.clearEquipHaptics();
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
unhighlightTargetEntity(this.targetEntityID);
var message = {
hand: this.hand,
entityID: this.targetEntityID
};
Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message));
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID);
// if an object is "equipped" and has a predefined offset, use it.

View file

@ -14,7 +14,7 @@
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI
Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection
Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -103,6 +103,7 @@ Script.include("/~/system/libraries/Xform.js");
this.contextOverlayTimer = false;
this.previousCollisionStatus = false;
this.locked = false;
this.highlightedEntity = null;
this.reticleMinX = MARGIN;
this.reticleMaxX;
this.reticleMinY = MARGIN;
@ -402,6 +403,9 @@ Script.include("/~/system/libraries/Xform.js");
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE ||
this.notPointingAtEntity(controllerData) || this.targetIsNull()) {
this.endNearGrabAction();
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
return makeRunningValues(false, [], []);
}
this.intersectionDistance = controllerData.rayPicks[this.hand].distance;
@ -450,7 +454,9 @@ Script.include("/~/system/libraries/Xform.js");
if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) {
if (controllerData.triggerClicks[this.hand]) {
var entityID = rayPickInfo.objectID;
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
var targetProps = Entities.getEntityProperties(entityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
@ -498,38 +504,62 @@ Script.include("/~/system/libraries/Xform.js");
this.startFarGrabAction(controllerData, targetProps);
}
}
} else if (!this.entityWithContextOverlay) {
var _this = this;
} else {
var targetEntityID = rayPickInfo.objectID;
if (this.highlightedEntity !== targetEntityID) {
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) {
if (_this.contextOverlayTimer) {
Script.clearTimeout(_this.contextOverlayTimer);
var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps);
selectionTargetObject.parentProps = getEntityParents(selectionTargetProps);
var selectionTargetEntity = selectionTargetObject.getTargetEntity();
if (entityIsGrabbable(selectionTargetEntity.props) ||
entityIsGrabbable(selectionTargetObject.entityProps)) {
Selection.addToSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", rayPickInfo.objectID);
}
_this.contextOverlayTimer = false;
_this.potentialEntityWithContextOverlay = rayPickInfo.objectID;
this.highlightedEntity = rayPickInfo.objectID;
}
if (!_this.contextOverlayTimer) {
_this.contextOverlayTimer = Script.setTimeout(function () {
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var props = Entities.getEntityProperties(rayPickInfo.objectID);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse
pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, rayPickInfo.intersection, props),
pos3D: rayPickInfo.intersection,
normal: rayPickInfo.surfaceNormal,
direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal),
button: "Secondary"
};
if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) {
_this.entityWithContextOverlay = rayPickInfo.objectID;
}
if (!this.entityWithContextOverlay) {
var _this = this;
if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) {
if (_this.contextOverlayTimer) {
Script.clearTimeout(_this.contextOverlayTimer);
}
_this.contextOverlayTimer = false;
}, 500);
_this.potentialEntityWithContextOverlay = rayPickInfo.objectID;
}
if (!_this.contextOverlayTimer) {
_this.contextOverlayTimer = Script.setTimeout(function () {
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var props = Entities.getEntityProperties(rayPickInfo.objectID);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse
pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, rayPickInfo.intersection, props),
pos3D: rayPickInfo.intersection,
normal: rayPickInfo.surfaceNormal,
direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal),
button: "Secondary"
};
if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) {
_this.entityWithContextOverlay = rayPickInfo.objectID;
}
}
_this.contextOverlayTimer = false;
}, 500);
}
}
}
} else if (this.distanceRotating) {
@ -545,6 +575,9 @@ Script.include("/~/system/libraries/Xform.js");
if (disableModule) {
if (disableModule.disableModules) {
this.endNearGrabAction();
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
return makeRunningValues(false, [], []);
}
}

View file

@ -0,0 +1,148 @@
//
// highlightNearbyEntities.js
//
// Created by Dante Ruiz 2018-4-10
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset,
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData, makeLaserParams, entityIsCloneable, Messages, print
*/
"use strict";
(function () {
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
Script.include("/~/system/libraries/cloneEntityUtils.js");
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
function differenceInArrays(firstArray, secondArray) {
var differenceArray = firstArray.filter(function(element) {
return secondArray.indexOf(element) < 0;
});
return differenceArray;
}
function HighlightNearbyEntities(hand) {
this.hand = hand;
this.otherHand = hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND :
dispatcherUtils.RIGHT_HAND;
this.highlightedEntities = [];
this.parameters = dispatcherUtils.makeDispatcherModuleParameters(
480,
this.hand === dispatcherUtils.RIGHT_HAND ? ["rightHand"] : ["leftHand"],
[],
100);
this.isGrabable = function(controllerData, props) {
var canGrabEntity = false;
if (dispatcherUtils.entityIsGrabbable(props) || entityIsCloneable(props)) {
// if we've attempted to grab a child, roll up to the root of the tree
var groupRootProps = dispatcherUtils.findGroupParent(controllerData, props);
canGrabEntity = true;
if (!dispatcherUtils.entityIsGrabbable(groupRootProps)) {
canGrabEntity = false;
}
}
return canGrabEntity;
};
this.hasHyperLink = function(props) {
return (props.href !== "" && props.href !== undefined);
};
this.removeEntityFromHighlightList = function(entityID) {
var index = this.highlightedEntities.indexOf(entityID);
if (index > -1) {
this.highlightedEntities.splice(index, 1);
}
};
this.getOtherModule = function() {
var otherModule = this.hand === dispatcherUtils.RIGHT_HAND ? leftHighlightNearbyEntities :
rightHighlightNearbyEntities;
return otherModule;
};
this.getOtherHandHighlightedEntities = function() {
return this.getOtherModule().highlightedEntities;
};
this.highlightEntities = function(controllerData) {
var nearbyEntitiesProperties = controllerData.nearbyEntityProperties[this.hand];
var otherHandHighlightedEntities = this.getOtherHandHighlightedEntities();
var newHighlightedEntities = [];
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
for (var i = 0; i < nearbyEntitiesProperties.length; i++) {
var props = nearbyEntitiesProperties[i];
if (props.distance > dispatcherUtils.NEAR_GRAB_RADIUS * sensorScaleFactor) {
continue;
}
if (this.isGrabable(controllerData, props) || this.hasHyperLink(props)) {
dispatcherUtils.highlightTargetEntity(props.id);
newHighlightedEntities.push(props.id);
}
}
var unhighlightEntities = differenceInArrays(this.highlightedEntities, newHighlightedEntities);
unhighlightEntities.forEach(function(entityID) {
if (otherHandHighlightedEntities.indexOf(entityID) < 0 ) {
dispatcherUtils.unhighlightTargetEntity(entityID);
}
});
this.highlightedEntities = newHighlightedEntities;
};
this.isReady = function(controllerData) {
this.highlightEntities(controllerData);
return dispatcherUtils.makeRunningValues(false, [], []);
};
this.run = function(controllerData) {
return this.isReady(controllerData);
};
}
var handleMessage = function(channel, message, sender) {
var data;
if (sender === MyAvatar.sessionUUID) {
if (channel === 'Hifi-unhighlight-entity') {
try {
data = JSON.parse(message);
var hand = data.hand;
if (hand === dispatcherUtils.LEFT_HAND) {
leftHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID);
} else if (hand === dispatcherUtils.RIGHT_HAND) {
rightHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID);
}
} catch (e) {
print("Failed to parse message");
}
}
}
};
var leftHighlightNearbyEntities = new HighlightNearbyEntities(dispatcherUtils.LEFT_HAND);
var rightHighlightNearbyEntities = new HighlightNearbyEntities(dispatcherUtils.RIGHT_HAND);
dispatcherUtils.enableDispatcherModule("LeftHighlightNearbyEntities", leftHighlightNearbyEntities);
dispatcherUtils.enableDispatcherModule("RightHighlightNearbyEntities", rightHighlightNearbyEntities);
function cleanup() {
dispatcherUtils.disableDispatcherModule("LeftHighlightNearbyEntities");
dispatcherUtils.disableDispatcherModule("RightHighlightNearbyEntities");
}
Messages.subscribe('Hifi-unhighlight-entity');
Messages.messageReceived.connect(handleMessage);
Script.scriptEnding.connect(cleanup);
}());

View file

@ -0,0 +1,77 @@
//
// mouseHighlightEntities.js
//
// scripts/system/controllers/controllerModules/
//
// Created by Dante Ruiz 2018-4-11
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* jslint bitwise: true */
/* global Script, print, Entities, Picks, HMD */
(function() {
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
function MouseHighlightEntities() {
this.highlightedEntity = null;
this.parameters = dispatcherUtils.makeDispatcherModuleParameters(
5,
["mouse"],
[],
100);
this.isReady = function(controllerData) {
if (HMD.active) {
if (this.highlightedEntity) {
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
}
} else {
var pickResult = controllerData.mouseRayPick;
if (pickResult.type === Picks.INTERSECTED_ENTITY) {
var targetEntityID = pickResult.objectID;
if (this.highlightedEntity !== targetEntityID) {
var targetProps = Entities.getEntityProperties(targetEntityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
if (this.highlightedEntity) {
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
}
if (dispatcherUtils.entityIsGrabbable(targetProps)) {
// highlight entity
dispatcherUtils.highlightTargetEntity(targetEntityID);
this.highlightedEntity = targetEntityID;
}
}
}
}
return dispatcherUtils.makeRunningValues(false, [], []);
};
this.run = function(controllerData) {
return this.isReady(controllerData);
};
}
var mouseHighlightEntities = new MouseHighlightEntities();
dispatcherUtils.enableDispatcherModule("MouseHighlightEntities", mouseHighlightEntities);
function cleanup() {
dispatcherUtils.disableDispatcherModule("MouseHighlightEntities");
}
Script.scriptEnding.connect(cleanup);
})();

Some files were not shown because too many files have changed in this diff Show more