diff --git a/.gitignore b/.gitignore
index 072e6001da..4b6949e268 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,6 +64,7 @@ gvr-interface/libs/*
# ignore files for various dev environments
TAGS
*.sw[po]
+*.qmlc
# ignore node files for the console
node_modules
diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp
index fa9c73b12d..995a5bad27 100644
--- a/assignment-client/src/entities/EntityServer.cpp
+++ b/assignment-client/src/entities/EntityServer.cpp
@@ -41,8 +41,15 @@ EntityServer::EntityServer(ReceivedMessage& message) :
DependencyManager::set();
auto& packetReceiver = DependencyManager::get()->getPacketReceiver();
- packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityEdit, PacketType::EntityErase, PacketType::EntityPhysics, PacketType::ChallengeOwnership },
- this, "handleEntityPacket");
+ packetReceiver.registerListenerForTypes({ PacketType::EntityAdd,
+ PacketType::EntityEdit,
+ PacketType::EntityErase,
+ PacketType::EntityPhysics,
+ PacketType::ChallengeOwnership,
+ PacketType::ChallengeOwnershipRequest,
+ PacketType::ChallengeOwnershipReply },
+ this,
+ "handleEntityPacket");
connect(&_dynamicDomainVerificationTimer, &QTimer::timeout, this, &EntityServer::startDynamicDomainVerification);
_dynamicDomainVerificationTimer.setSingleShot(true);
@@ -459,7 +466,7 @@ void EntityServer::startDynamicDomainVerification() {
EntityItemPointer entity = tree->findEntityByEntityItemID(i.value());
if (entity) {
- if (!entity->verifyStaticCertificateProperties()) {
+ if (!entity->getProperties().verifyStaticCertificateProperties()) {
qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed"
<< "static certificate verification.";
// Delete the entity if it doesn't pass static certificate verification
diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp
index 03014bae6a..11e4d533fb 100644
--- a/assignment-client/src/entities/EntityTreeSendThread.cpp
+++ b/assignment-client/src/entities/EntityTreeSendThread.cpp
@@ -175,7 +175,7 @@ bool EntityTreeSendThread::addAncestorsToExtraFlaggedEntities(const QUuid& filte
return parentWasNew || ancestorsWereNew;
}
- // since we didn't have a parent niether of our parents or ancestors could be new additions
+ // since we didn't have a parent, neither of our parents or ancestors could be new additions
return false;
}
@@ -204,7 +204,9 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil
return hasNewChild || hasNewDescendants;
}
-void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) {
+void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset,
+ bool usesViewFrustum) {
+
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesViewFrustum);
// there are three types of traversal:
//
@@ -423,12 +425,19 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
uint64_t sendTime = usecTimestampNow();
auto nodeData = static_cast(params.nodeData);
nodeData->stats.encodeStarted();
+ auto entityNode = _node.toStrongRef();
+ auto entityNodeData = static_cast(entityNode->getLinkedData());
while(!_sendQueue.empty()) {
PrioritizedEntity queuedItem = _sendQueue.top();
EntityItemPointer entity = queuedItem.getEntity();
if (entity) {
// Only send entities that match the jsonFilters, but keep track of everything we've tried to send so we don't try to send it again
- if (entity->matchesJSONFilters(jsonFilters)) {
+ bool entityMatchesFilters = entity->matchesJSONFilters(jsonFilters);
+ if (entityMatchesFilters || entityNodeData->isEntityFlaggedAsExtra(entity->getID())) {
+ if (!jsonFilters.isEmpty() && entityMatchesFilters) {
+ // Record explicitly filtered-in entity so that extra entities can be flagged.
+ entityNodeData->insertSentFilteredEntity(entity->getID());
+ }
OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData);
if (appendEntityState != OctreeElement::COMPLETED) {
diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h
index 49901491ff..a96a18494d 100644
--- a/assignment-client/src/entities/EntityTreeSendThread.h
+++ b/assignment-client/src/entities/EntityTreeSendThread.h
@@ -38,7 +38,8 @@ private:
bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
- void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum);
+ void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset,
+ bool usesViewFrustum);
bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override;
void preDistributionProcessing() override;
diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp
index 3f835678ac..bce6e7fe44 100644
--- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp
+++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp
@@ -96,6 +96,14 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer
_myServer->getOctree()->withWriteLock([&] {
_myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode);
});
+ } else if (packetType == PacketType::ChallengeOwnershipRequest) {
+ _myServer->getOctree()->withWriteLock([&] {
+ _myServer->getOctree()->processChallengeOwnershipRequestPacket(*message, sendingNode);
+ });
+ } else if (packetType == PacketType::ChallengeOwnershipReply) {
+ _myServer->getOctree()->withWriteLock([&] {
+ _myServer->getOctree()->processChallengeOwnershipReplyPacket(*message, sendingNode);
+ });
} else if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket);
_receivedPacketCount++;
diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp
index 89e3d403fc..3ae653307f 100644
--- a/assignment-client/src/octree/OctreeSendThread.cpp
+++ b/assignment-client/src/octree/OctreeSendThread.cpp
@@ -82,8 +82,12 @@ bool OctreeSendThread::process() {
if (auto node = _node.lock()) {
OctreeQueryNode* nodeData = static_cast(node->getLinkedData());
- // Sometimes the node data has not yet been linked, in which case we can't really do anything
- if (nodeData && !nodeData->isShuttingDown()) {
+ // If we don't have the OctreeQueryNode at all
+ // or it's uninitialized because we haven't received a query yet from the client
+ // or we don't know where we should send packets for this node
+ // or we're shutting down
+ // then we can't send an entity data packet
+ if (nodeData && nodeData->hasReceivedFirstQuery() && node->getActiveSocket() && !nodeData->isShuttingDown()) {
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
packetDistributor(node, nodeData, viewFrustumChanged);
}
diff --git a/cmake/externals/hifiAudioCodec/CMakeLists.txt b/cmake/externals/hifiAudioCodec/CMakeLists.txt
index a30396c6fd..e3ba36a440 100644
--- a/cmake/externals/hifiAudioCodec/CMakeLists.txt
+++ b/cmake/externals/hifiAudioCodec/CMakeLists.txt
@@ -5,43 +5,41 @@ set(EXTERNAL_NAME hifiAudioCodec)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
-if (NOT ANDROID)
-
- if (WIN32 OR APPLE)
- ExternalProject_Add(
- ${EXTERNAL_NAME}
- URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
- URL_MD5 23ec3fe51eaa155ea159a4971856fc13
- CONFIGURE_COMMAND ""
- BUILD_COMMAND ""
- INSTALL_COMMAND ""
- LOG_DOWNLOAD 1
- )
- else ()
- ExternalProject_Add(
- ${EXTERNAL_NAME}
- URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
- URL_MD5 7d37914a18aa4de971d2f45dd3043bde
- CONFIGURE_COMMAND ""
- BUILD_COMMAND ""
- INSTALL_COMMAND ""
- LOG_DOWNLOAD 1
- )
- endif()
-
- # Hide this external target (for ide users)
- set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
-
- ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
-
- set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
-
- if (WIN32)
- set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
- elseif(APPLE)
- set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
- elseif(NOT ANDROID)
- set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
- endif()
-
+if (WIN32)
+ set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-win-2.0.zip)
+ set(DOWNLOAD_MD5 9199d4dbd6b16bed736b235efe980e67)
+elseif (APPLE)
+ set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-mac-2.0.zip)
+ set(DOWNLOAD_MD5 21649881e7d5dc94f922179be96f76ba)
+elseif (ANDROID)
+ set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-android-2.0.zip)
+ set(DOWNLOAD_MD5 aef2a852600d498d58aa586668191683)
+elseif (UNIX)
+ set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip)
+ set(DOWNLOAD_MD5 67fb7755f9bcafb98a9fceea53bc7481)
+else()
+ return()
+endif()
+
+ExternalProject_Add(
+ ${EXTERNAL_NAME}
+ URL ${DOWNLOAD_URL}
+ URL_MD5 ${DOWNLOAD_MD5}
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ LOG_DOWNLOAD 1
+)
+
+# Hide this external target (for ide users)
+set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
+
+ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
+
+set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
+
+if (WIN32)
+ set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
+else()
+ set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
endif()
diff --git a/cmake/externals/wasapi/CMakeLists.txt b/cmake/externals/wasapi/CMakeLists.txt
index 4437024962..4c0ffaf88f 100644
--- a/cmake/externals/wasapi/CMakeLists.txt
+++ b/cmake/externals/wasapi/CMakeLists.txt
@@ -6,8 +6,8 @@ if (WIN32)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
- URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi9.zip
- URL_MD5 94f4765bdbcd53cd099f349ae031e769
+ URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi10.zip
+ URL_MD5 4f40e49715a420fb67b45b9cee19052c
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake
index 338dee7bc8..0619c4d587 100644
--- a/cmake/modules/FindOpenSSL.cmake
+++ b/cmake/modules/FindOpenSSL.cmake
@@ -60,7 +60,7 @@ if (WIN32 AND NOT CYGWIN)
select_library_configurations(LIB_EAY)
select_library_configurations(SSL_EAY)
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
- find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
+ find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} NO_DEFAULT_PATH)
endif()
else()
diff --git a/domain-server/resources/web/content/index.shtml b/domain-server/resources/web/content/index.shtml
index e1ba5499b6..0e48c1eff8 100644
--- a/domain-server/resources/web/content/index.shtml
+++ b/domain-server/resources/web/content/index.shtml
@@ -19,12 +19,13 @@
Upload an entities file (e.g.: models.json.gz) to replace the content of this domain.
Note: Your domain's content will be replaced by the content you upload , but the backup files of your domain's content will not immediately be changed.
-
- If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:
-
C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
- /Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
- /home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz
-
+ If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:
+ Windows
+ C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
+ OSX
+ /Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
+ Linux
+ /home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz
diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml
index 5358ad1adc..37c3c2adab 100644
--- a/interface/resources/qml/hifi/AssetServer.qml
+++ b/interface/resources/qml/hifi/AssetServer.qml
@@ -16,10 +16,10 @@ import Qt.labs.settings 1.0
import "../styles-uit"
import "../controls-uit" as HifiControls
-import "../windows"
+import "../windows" as Windows
import "../dialogs"
-ScrollingWindow {
+Windows.ScrollingWindow {
id: root
objectName: "AssetServer"
title: "Asset Browser"
diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml
index fcfff02b72..775bae7969 100644
--- a/interface/resources/qml/hifi/NameCard.qml
+++ b/interface/resources/qml/hifi/NameCard.qml
@@ -432,7 +432,8 @@ Item {
anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter
x: 240
onClicked: {
- AddressManager.goToUser(thisNameCard.userName);
+ console.log("Vist user button clicked."); // Remove after debugging.
+ AddressManager.goToUser(thisNameCard.userName, false);
UserActivityLogger.palAction("go_to_user", thisNameCard.userName);
}
}
@@ -594,7 +595,10 @@ Item {
// the avatar goes into fly mode rather than falling. However, that is not exposed to Javascript right now.
// FIXME: it would be nice if this used the same teleport steps and smoothing as in the teleport.js script.
// Note, however, that this script allows teleporting to a person in the air, while teleport.js is going to a grounded target.
+ // Position avatar 2 metres from the target in the direction that target avatar was facing.
MyAvatar.position = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.orientation, {x: 0, y: 0, z: -2}));
- MyAvatar.orientation = Quat.multiply(avatar.orientation, {y: 1});
+
+ // Rotate avatar on Y axis to face target avatar and cancel out any inherited roll and pitch.
+ MyAvatar.orientation = Quat.cancelOutRollAndPitch(Quat.multiply(avatar.orientation, {y: 1}));
}
}
diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml
index 89f18e5ce2..efcf6ccfcf 100644
--- a/interface/resources/qml/hifi/Pal.qml
+++ b/interface/resources/qml/hifi/Pal.qml
@@ -827,7 +827,7 @@ Rectangle {
hoverEnabled: enabled
enabled: connectionsNameCard.selected && pal.activeTab == "connectionsTab"
onClicked: {
- AddressManager.goToUser(model.userName);
+ AddressManager.goToUser(model.userName, false);
UserActivityLogger.palAction("go_to_user", model.userName);
}
onEntered: connectionsLocationData.color = hifi.colors.blueHighlight;
diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml
index 12c2ec1835..87ddce49ca 100644
--- a/interface/resources/qml/hifi/audio/Audio.qml
+++ b/interface/resources/qml/hifi/audio/Audio.qml
@@ -213,8 +213,8 @@ Rectangle {
anchors.right: parent.right
peak: model.peak;
anchors.verticalCenter: parent.verticalCenter
- visible: (bar.currentIndex === 1 && selectedHMD && isVR) ||
- (bar.currentIndex === 0 && selectedDesktop && !isVR) &&
+ visible: ((bar.currentIndex === 1 && isVR) ||
+ (bar.currentIndex === 0 && !isVR)) &&
Audio.devices.input.peakValuesAvailable;
}
}
diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
index aa1372494f..b6c29a1fad 100644
--- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
+++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
@@ -33,6 +33,7 @@ Rectangle {
property string dateOfPurchase: "--";
property bool isLightbox: false;
property bool isMyCert: false;
+ property bool isCertificateInvalid: false;
// Style
color: hifi.colors.faintGray;
Hifi.QmlCommerce {
@@ -44,10 +45,11 @@ Rectangle {
} else {
root.marketplaceUrl = result.data.marketplace_item_url;
root.isMyCert = result.isMyCert ? result.isMyCert : false;
- root.itemOwner = root.isMyCert ? Account.username :
- "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
- root.itemEdition = result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run);
- root.dateOfPurchase = getFormattedDate(result.data.transfer_created_at * 1000);
+ root.itemOwner = root.isCertificateInvalid ? "--" : (root.isMyCert ? Account.username :
+ "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022");
+ root.itemEdition = root.isCertificateInvalid ? "Uncertified Copy" :
+ (result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run));
+ root.dateOfPurchase = root.isCertificateInvalid ? "" : getFormattedDate(result.data.transfer_created_at * 1000);
root.itemName = result.data.marketplace_item_name;
if (result.data.invalid_reason || result.data.transfer_status[0] === "failed") {
@@ -65,6 +67,44 @@ Rectangle {
}
}
}
+
+ onUpdateCertificateStatus: {
+ if (certStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS
+ // NOP
+ } else if (certStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT
+ root.isCertificateInvalid = true;
+ errorText.text = "Verification of this certificate timed out.";
+ errorText.color = hifi.colors.redHighlight;
+ } else if (certStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED
+ root.isCertificateInvalid = true;
+ titleBarText.text = "Invalid Certificate";
+ titleBarText.color = hifi.colors.redHighlight;
+
+ popText.text = "";
+ root.itemOwner = "";
+ dateOfPurchaseHeader.text = "";
+ root.dateOfPurchase = "";
+ root.itemEdition = "Uncertified Copy";
+
+ errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item.";
+ errorText.color = hifi.colors.baseGray;
+ } else if (certStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
+ root.isCertificateInvalid = true;
+ titleBarText.text = "Invalid Certificate";
+ titleBarText.color = hifi.colors.redHighlight;
+
+ popText.text = "";
+ root.itemOwner = "";
+ dateOfPurchaseHeader.text = "";
+ root.dateOfPurchase = "";
+ root.itemEdition = "Uncertified Copy";
+
+ errorText.text = "The avatar who rezzed this item doesn't own it.";
+ errorText.color = hifi.colors.baseGray;
+ } else {
+ console.log("Unknown certificate status received from ledger signal!");
+ }
+ }
}
onCertificateIdChanged: {
@@ -216,7 +256,7 @@ Rectangle {
}
AnonymousProRegular {
id: isMyCertText;
- visible: root.isMyCert;
+ visible: root.isMyCert && !root.isCertificateInvalid;
text: "(Private)";
size: 18;
// Anchors
diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml
index 1fe0dcc58b..fd7ce0fdfd 100644
--- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml
@@ -196,7 +196,38 @@ Item {
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
- anchors.rightMargin: 24;
+
+ Item {
+ visible: transactionHistoryModel.count === 0 && root.historyReceived;
+ anchors.centerIn: parent;
+ width: parent.width - 12;
+ height: parent.height;
+
+ HifiControlsUit.Separator {
+ colorScheme: 1;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ anchors.top: parent.top;
+ }
+
+ RalewayRegular {
+ id: noActivityText;
+ text: "The Wallet app is in closed Beta. To request entry and receive free HFC , please contact " +
+ "info@highfidelity.com with your High Fidelity account username and the email address registered to that account.";
+ // Text size
+ size: 24;
+ // Style
+ color: hifi.colors.blueAccent;
+ anchors.left: parent.left;
+ anchors.leftMargin: 12;
+ anchors.right: parent.right;
+ anchors.rightMargin: 12;
+ anchors.verticalCenter: parent.verticalCenter;
+ height: paintedHeight;
+ wrapMode: Text.WordWrap;
+ horizontalAlignment: Text.AlignHCenter;
+ }
+ }
ListView {
id: transactionHistory;
@@ -294,17 +325,6 @@ Item {
}
}
}
-
- // This should never be visible (since you immediately get 100 HFC)
- FiraSansRegular {
- id: emptyTransationHistory;
- size: 24;
- visible: !transactionHistory.visible && root.historyReceived;
- text: "Recent Activity Unavailable";
- anchors.fill: parent;
- horizontalAlignment: Text.AlignHCenter;
- verticalAlignment: Text.AlignVCenter;
- }
}
}
@@ -350,7 +370,9 @@ Item {
}
root.pendingCount = pendingCount;
- transactionHistoryModel.insert(0, {"transaction_type": "pendingCount"});
+ if (pendingCount > 0) {
+ transactionHistoryModel.insert(0, {"transaction_type": "pendingCount"});
+ }
}
//
diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml
index 47d28486a9..3debc8b9e7 100644
--- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml
+++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml
@@ -11,8 +11,11 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
+import QtQuick.Dialogs 1.2 as OriginalDialogs
+
import "../../styles-uit"
import "../../controls-uit"
+import "../dialogs"
Rectangle {
id: newModelDialog
@@ -25,6 +28,15 @@ Rectangle {
property bool punctuationMode: false
property bool keyboardRasied: false
+ function errorMessageBox(message) {
+ return desktop.messageBox({
+ icon: hifi.icons.warning,
+ defaultButton: OriginalDialogs.StandardButton.Ok,
+ title: "Error",
+ text: message
+ });
+ }
+
Item {
id: column1
anchors.rightMargin: 10
@@ -98,7 +110,6 @@ Rectangle {
CheckBox {
id: dynamic
text: qsTr("Dynamic")
-
}
Row {
@@ -117,6 +128,7 @@ Rectangle {
Text {
id: text2
width: 160
+ x: dynamic.width / 2
color: "#ffffff"
text: qsTr("Models with automatic collisions set to 'Exact' cannot be dynamic, and should not be used as floors")
wrapMode: Text.WordWrap
@@ -139,15 +151,40 @@ Rectangle {
ComboBox {
id: collisionType
+
+ property int priorIndex: 0
+ property string staticMeshCollisionText: "Exact - All polygons"
+ property var collisionArray: ["No Collision",
+ "Basic - Whole model",
+ "Good - Sub-meshes",
+ staticMeshCollisionText,
+ "Box",
+ "Sphere"]
+
width: 200
z: 100
transformOrigin: Item.Center
- model: ["No Collision",
- "Basic - Whole model",
- "Good - Sub-meshes",
- "Exact - All polygons",
- "Box",
- "Sphere"]
+ model: collisionArray
+
+ onCurrentIndexChanged: {
+ if (collisionArray[currentIndex] === staticMeshCollisionText) {
+
+ if (dynamic.checked) {
+ currentIndex = priorIndex;
+
+ errorMessageBox("Models with Automatic Collisions set to \""
+ + staticMeshCollisionText + "\" cannot be dynamic.");
+ //--EARLY EXIT--( Can't have a static mesh model that's dynamic )
+ return;
+ }
+
+ dynamic.enabled = false;
+ } else {
+ dynamic.enabled = true;
+ }
+
+ priorIndex = currentIndex;
+ }
}
Row {
@@ -155,10 +192,10 @@ Rectangle {
width: 200
height: 400
spacing: 5
-
- anchors {
- rightMargin: 15
- }
+
+ anchors.horizontalCenter: column3.horizontalCenter
+ anchors.horizontalCenterOffset: -20
+
Button {
id: button1
text: qsTr("Add")
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 4f051697ad..4b99d50761 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -1825,6 +1825,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Preload Tablet sounds
DependencyManager::get()->preloadSounds();
+ _pendingIdleEvent = false;
+ _pendingRenderEvent = false;
+
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
}
@@ -2693,7 +2696,7 @@ bool Application::importFromZIP(const QString& filePath) {
qDebug() << "A zip file has been dropped in: " << filePath;
QUrl empty;
// handle Blocks download from Marketplace
- if (filePath.contains("vr.google.com/downloads")) {
+ if (filePath.contains("poly.google.com/downloads")) {
addAssetToWorldFromURL(filePath);
} else {
qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true, false);
@@ -4441,7 +4444,7 @@ void Application::cameraModeChanged() {
void Application::cameraMenuChanged() {
auto menu = Menu::getInstance();
if (menu->isOptionChecked(MenuOption::FullscreenMirror)) {
- if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
+ if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
_myCamera.setMode(CAMERA_MODE_MIRROR);
getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers
}
@@ -6235,7 +6238,7 @@ void Application::addAssetToWorldFromURL(QString url) {
if (url.contains("filename")) {
filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL.
}
- if (url.contains("vr.google.com/downloads")) {
+ if (url.contains("poly.google.com/downloads")) {
filename = url.section('/', -1);
if (url.contains("noDownload")) {
filename.remove(".zip?noDownload=false");
@@ -6270,7 +6273,7 @@ void Application::addAssetToWorldFromURLRequestFinished() {
if (url.contains("filename")) {
filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL.
}
- if (url.contains("vr.google.com/downloads")) {
+ if (url.contains("poly.google.com/downloads")) {
filename = url.section('/', -1);
if (url.contains("noDownload")) {
filename.remove(".zip?noDownload=false");
@@ -7271,6 +7274,10 @@ void Application::updateDisplayMode() {
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");
}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index fbfb3979be..19a6dfdac1 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -708,7 +708,7 @@ private:
friend class RenderEventHandler;
- std::atomic _pendingIdleEvent { false };
- std::atomic _pendingRenderEvent { false };
+ std::atomic _pendingIdleEvent { true };
+ std::atomic _pendingRenderEvent { true };
};
#endif // hifi_Application_h
diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp
index d3c8746e16..01ccbd0d9a 100644
--- a/interface/src/LODManager.cpp
+++ b/interface/src/LODManager.cpp
@@ -54,7 +54,9 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta
float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET;
float maxTime = glm::max(renderTime, engineRunTime);
const float BLEND_TIMESCALE = 0.3f; // sec
- float blend = BLEND_TIMESCALE / deltaTimeSec;
+ const float MIN_DELTA_TIME = 0.001f;
+ const float safeDeltaTime = glm::max(deltaTimeSec, MIN_DELTA_TIME);
+ float blend = BLEND_TIMESCALE / safeDeltaTime;
if (blend > 1.0f) {
blend = 1.0f;
}
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 0fceba82f0..0dfcf93a65 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -135,7 +135,7 @@ MyAvatar::MyAvatar(QThread* thread) :
connect(&domainHandler, &DomainHandler::settingsReceived, this, &MyAvatar::restrictScaleFromDomainSettings);
// when we leave a domain we lift whatever restrictions that domain may have placed on our scale
- connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &MyAvatar::clearScaleRestriction);
+ connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &MyAvatar::leaveDomain);
_bodySensorMatrix = deriveBodyFromHMDSensor();
@@ -2189,6 +2189,7 @@ void MyAvatar::clampScaleChangeToDomainLimits(float desiredScale) {
setTargetScale(clampedTargetScale);
qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
+ emit(scaleChanged());
}
float MyAvatar::getDomainMinScale() {
@@ -2278,6 +2279,18 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings
settings.endGroup();
}
+void MyAvatar::leaveDomain() {
+ clearScaleRestriction();
+ saveAvatarScale();
+}
+
+void MyAvatar::saveAvatarScale() {
+ Settings settings;
+ settings.beginGroup("Avatar");
+ settings.setValue("scale", _targetScale);
+ settings.endGroup();
+}
+
void MyAvatar::clearScaleRestriction() {
_domainMinimumScale = MIN_AVATAR_SCALE;
_domainMaximumScale = MAX_AVATAR_SCALE;
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 303a395a47..e4e8f8d02c 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -620,6 +620,10 @@ signals:
void dominantHandChanged(const QString& hand);
void sensorToWorldScaleChanged(float sensorToWorldScale);
void attachmentsChanged();
+ void scaleChanged();
+
+private slots:
+ void leaveDomain();
private:
@@ -637,6 +641,8 @@ private:
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
virtual glm::vec3 getSkeletonPosition() const override;
+ void saveAvatarScale();
+
glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; }
float getScriptedMotorTimescale() const { return _scriptedMotorTimescale; }
QString getScriptedMotorFrame() const;
diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h
index ae001010f0..42eb0ffc49 100644
--- a/interface/src/commerce/Ledger.h
+++ b/interface/src/commerce/Ledger.h
@@ -35,6 +35,14 @@ public:
void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false);
void certificateInfo(const QString& certificateId);
+ enum CertificateStatus {
+ CERTIFICATE_STATUS_UNKNOWN = 0,
+ CERTIFICATE_STATUS_VERIFICATION_SUCCESS,
+ CERTIFICATE_STATUS_VERIFICATION_TIMEOUT,
+ CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED,
+ CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED,
+ };
+
signals:
void buyResult(QJsonObject result);
void receiveAtResult(QJsonObject result);
@@ -45,6 +53,8 @@ signals:
void locationUpdateResult(QJsonObject result);
void certificateInfoResult(QJsonObject result);
+ void updateCertificateStatus(const QString& certID, uint certStatus);
+
public slots:
void buySuccess(QNetworkReply& reply);
void buyFailure(QNetworkReply& reply);
diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp
index 803264fa9f..f29e46d843 100644
--- a/interface/src/commerce/QmlCommerce.cpp
+++ b/interface/src/commerce/QmlCommerce.cpp
@@ -30,6 +30,12 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult);
connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult);
connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult);
+ connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus);
+
+ auto accountManager = DependencyManager::get();
+ connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() {
+ setPassphrase("");
+ });
}
void QmlCommerce::getWalletStatus() {
diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h
index ae63133425..d4f4aa35d2 100644
--- a/interface/src/commerce/QmlCommerce.h
+++ b/interface/src/commerce/QmlCommerce.h
@@ -45,6 +45,8 @@ signals:
void accountResult(QJsonObject result);
void certificateInfoResult(QJsonObject result);
+ void updateCertificateStatus(const QString& certID, uint certStatus);
+
protected:
Q_INVOKABLE void getWalletStatus();
diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp
index c7c09d8b03..85632ff8f1 100644
--- a/interface/src/commerce/Wallet.cpp
+++ b/interface/src/commerce/Wallet.cpp
@@ -319,6 +319,7 @@ Wallet::Wallet() {
auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
+ packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket");
connect(ledger.data(), &Ledger::accountResult, this, [&]() {
auto wallet = DependencyManager::get();
@@ -717,50 +718,86 @@ bool Wallet::changePassphrase(const QString& newPassphrase) {
}
void Wallet::handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode) {
+ auto nodeList = DependencyManager::get();
+
+ bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest;
unsigned char decryptedText[64];
int certIDByteArraySize;
int encryptedTextByteArraySize;
+ int challengingNodeUUIDByteArraySize;
packet->readPrimitive(&certIDByteArraySize);
packet->readPrimitive(&encryptedTextByteArraySize);
+ if (challengeOriginatedFromClient) {
+ packet->readPrimitive(&challengingNodeUUIDByteArraySize);
+ }
QByteArray certID = packet->read(certIDByteArraySize);
QByteArray encryptedText = packet->read(encryptedTextByteArraySize);
+ QByteArray challengingNodeUUID;
+ if (challengeOriginatedFromClient) {
+ challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize);
+ }
RSA* rsa = readKeys(keyFilePath().toStdString().c_str());
+ int decryptionStatus = -1;
if (rsa) {
- const int decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize,
+ ERR_clear_error();
+ decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize,
reinterpret_cast(encryptedText.constData()),
decryptedText,
rsa,
RSA_PKCS1_OAEP_PADDING);
RSA_free(rsa);
-
- if (decryptionStatus != -1) {
- auto nodeList = DependencyManager::get();
-
- QByteArray decryptedTextByteArray = QByteArray(reinterpret_cast(decryptedText), decryptionStatus);
- int decryptedTextByteArraySize = decryptedTextByteArray.size();
- int certIDSize = certID.size();
- // setup the packet
- auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + decryptedTextByteArraySize + 2 * sizeof(int), true);
-
- decryptedTextPacket->writePrimitive(certIDSize);
- decryptedTextPacket->writePrimitive(decryptedTextByteArraySize);
- decryptedTextPacket->write(certID);
- decryptedTextPacket->write(decryptedTextByteArray);
-
- qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
-
- nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
- } else {
- qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed.";
- }
} else {
qCDebug(commerce) << "During entity ownership challenge, creating the RSA object failed.";
}
+
+ QByteArray decryptedTextByteArray;
+ if (decryptionStatus > -1) {
+ decryptedTextByteArray = QByteArray(reinterpret_cast(decryptedText), decryptionStatus);
+ }
+ int decryptedTextByteArraySize = decryptedTextByteArray.size();
+ int certIDSize = certID.size();
+ // setup the packet
+ if (challengeOriginatedFromClient) {
+ auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnershipReply,
+ certIDSize + decryptedTextByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int),
+ true);
+
+ decryptedTextPacket->writePrimitive(certIDSize);
+ decryptedTextPacket->writePrimitive(decryptedTextByteArraySize);
+ decryptedTextPacket->writePrimitive(challengingNodeUUIDByteArraySize);
+ decryptedTextPacket->write(certID);
+ decryptedTextPacket->write(decryptedTextByteArray);
+ decryptedTextPacket->write(challengingNodeUUID);
+
+ qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
+
+ nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
+ } else {
+ auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + decryptedTextByteArraySize + 2 * sizeof(int), true);
+
+ decryptedTextPacket->writePrimitive(certIDSize);
+ decryptedTextPacket->writePrimitive(decryptedTextByteArraySize);
+ decryptedTextPacket->write(certID);
+ decryptedTextPacket->write(decryptedTextByteArray);
+
+ qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
+
+ nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
+ }
+
+ if (decryptionStatus == -1) {
+ qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed.";
+ long error = ERR_get_error();
+ if (error != 0) {
+ const char* error_str = ERR_error_string(error, NULL);
+ qCWarning(entities) << "RSA error:" << error_str;
+ }
+ }
}
void Wallet::account() {
diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp
index 75b43a251b..32dd74279b 100644
--- a/interface/src/raypick/LaserPointer.cpp
+++ b/interface/src/raypick/LaserPointer.cpp
@@ -25,7 +25,6 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
_distanceScaleEnd(distanceScaleEnd),
_rayPickUID(DependencyManager::get()->createRayPick(rayProps))
{
-
for (auto& state : _renderStates) {
if (!enabled || state.first != _currentRenderState) {
@@ -119,23 +118,25 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
qApp->getOverlays().editOverlay(renderState.getStartID(), startProps);
}
glm::vec3 endVec;
- if (((defaultState || !_lockEnd) && _objectLockEnd.first.isNull()) || type == IntersectionType::HUD) {
+ if (((defaultState || !_lockEnd) && _lockEndObject.id.isNull()) || type == IntersectionType::HUD) {
endVec = pickRay.origin + pickRay.direction * distance;
} else {
- if (!_objectLockEnd.first.isNull()) {
+ if (!_lockEndObject.id.isNull()) {
glm::vec3 pos;
glm::quat rot;
glm::vec3 dim;
glm::vec3 registrationPoint;
- if (_objectLockEnd.second) {
- pos = vec3FromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "position").value);
- rot = quatFromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "rotation").value);
- dim = vec3FromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "dimensions").value);
+ if (_lockEndObject.isOverlay) {
+ pos = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "position").value);
+ rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value);
+ dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value);
registrationPoint = glm::vec3(0.5f);
} else {
- EntityItemProperties props = DependencyManager::get()->getEntityProperties(_objectLockEnd.first);
- pos = props.getPosition();
- rot = props.getRotation();
+ EntityItemProperties props = DependencyManager::get()->getEntityProperties(_lockEndObject.id);
+ glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition());
+ glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat;
+ pos = extractTranslation(finalPosAndRotMat);
+ rot = glmExtractRotation(finalPosAndRotMat);
dim = props.getDimensions();
registrationPoint = props.getRegistrationPoint();
}
@@ -209,7 +210,7 @@ void LaserPointer::update() {
withReadLock([&] {
RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID);
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
- (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
+ (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_lockEndObject.id.isNull())) {
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
disableRenderState(_defaultRenderStates[_currentRenderState].second);
@@ -233,9 +234,11 @@ void LaserPointer::setLaserLength(const float laserLength) {
});
}
-void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) {
+void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay, const glm::mat4& offsetMat) {
withWriteLock([&] {
- _objectLockEnd = std::pair(objectID, isOverlay);
+ _lockEndObject.id = objectID;
+ _lockEndObject.isOverlay = isOverlay;
+ _lockEndObject.offsetMat = offsetMat;
});
}
diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h
index f2350c7199..896752a96e 100644
--- a/interface/src/raypick/LaserPointer.h
+++ b/interface/src/raypick/LaserPointer.h
@@ -21,6 +21,12 @@
class RayPickResult;
+struct LockEndObject {
+ QUuid id { QUuid() };
+ bool isOverlay { false };
+ glm::mat4 offsetMat { glm::mat4() };
+};
+
class RenderState {
public:
@@ -74,7 +80,7 @@ public:
void setPrecisionPicking(const bool precisionPicking);
void setLaserLength(const float laserLength);
- void setLockEndUUID(QUuid objectID, const bool isOverlay);
+ void setLockEndUUID(QUuid objectID, const bool isOverlay, const glm::mat4& offsetMat = glm::mat4());
void setIgnoreItems(const QVector& ignoreItems) const;
void setIncludeItems(const QVector& includeItems) const;
@@ -91,7 +97,7 @@ private:
bool _centerEndY;
bool _lockEnd;
bool _distanceScaleEnd;
- std::pair _objectLockEnd { std::pair(QUuid(), false)};
+ LockEndObject _lockEndObject;
const QUuid _rayPickUID;
diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp
index 9d58cc2587..45420d1488 100644
--- a/interface/src/raypick/LaserPointerManager.cpp
+++ b/interface/src/raypick/LaserPointerManager.cpp
@@ -113,9 +113,9 @@ void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector
}
}
-void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const {
+void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat) const {
auto laserPointer = find(uid);
if (laserPointer) {
- laserPointer->setLockEndUUID(objectID, isOverlay);
+ laserPointer->setLockEndUUID(objectID, isOverlay, offsetMat);
}
}
diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h
index e302318483..25089a291a 100644
--- a/interface/src/raypick/LaserPointerManager.h
+++ b/interface/src/raypick/LaserPointerManager.h
@@ -39,7 +39,7 @@ public:
void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const;
void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const;
- void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const;
+ void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const;
void update();
diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h
index 19262e6e5d..986c53e24f 100644
--- a/interface/src/raypick/LaserPointerScriptingInterface.h
+++ b/interface/src/raypick/LaserPointerScriptingInterface.h
@@ -35,7 +35,7 @@ public slots:
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const;
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const;
- Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); }
+ Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay, offsetMat); }
private:
static RenderState buildRenderState(const QVariantMap& propMap);
diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp
index 808396c901..1adf5650dd 100644
--- a/interface/src/scripting/SelectionScriptingInterface.cpp
+++ b/interface/src/scripting/SelectionScriptingInterface.cpp
@@ -71,6 +71,12 @@ bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& lis
return false;
}
+bool SelectionScriptingInterface::clearSelectedItemsList(const QString& listName) {
+ _selectedItemsListMap.insert(listName, GameplayObjects());
+ emit selectedItemsListChanged(listName);
+ return true;
+}
+
template bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
currentList.addToGameplayObjects(idToAdd);
diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h
index d1a372c5c4..d9003c2c32 100644
--- a/interface/src/scripting/SelectionScriptingInterface.h
+++ b/interface/src/scripting/SelectionScriptingInterface.h
@@ -56,11 +56,45 @@ public:
GameplayObjects getList(const QString& listName);
+ /**jsdoc
+ * Prints out the list of avatars, entities and overlays stored in a particular selection.
+ * @function Selection.printList
+ * @param listName {string} name of the selection
+ */
Q_INVOKABLE void printList(const QString& listName);
+ /**jsdoc
+ * Removes a named selection from the list of selections.
+ * @function Selection.removeListFromMap
+ * @param listName {string} name of the selection
+ * @returns {bool} true if the selection existed and was successfully removed.
+ */
Q_INVOKABLE bool removeListFromMap(const QString& listName);
+ /**jsdoc
+ * Add an item in a selection.
+ * @function Selection.addToSelectedItemsList
+ * @param listName {string} name of the selection
+ * @param itemType {string} the type of the item (one of "avatar", "entity" or "overlay")
+ * @param id {EntityID} the Id of the item to add to the selection
+ * @returns {bool} true if the item was successfully added.
+ */
Q_INVOKABLE bool addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id);
+ /**jsdoc
+ * Remove an item from a selection.
+ * @function Selection.removeFromSelectedItemsList
+ * @param listName {string} name of the selection
+ * @param itemType {string} the type of the item (one of "avatar", "entity" or "overlay")
+ * @param id {EntityID} the Id of the item to remove
+ * @returns {bool} true if the item was successfully removed.
+ */
Q_INVOKABLE bool removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id);
+ /**jsdoc
+ * Remove all items from a selection.
+ * @function Selection.clearSelectedItemsList
+ * @param listName {string} name of the selection
+ * @returns {bool} true if the item was successfully cleared.
+ */
+ Q_INVOKABLE bool clearSelectedItemsList(const QString& listName);
signals:
void selectedItemsListChanged(const QString& listName);
diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp
index 42425932df..d157e29959 100644
--- a/interface/src/ui/overlays/Base3DOverlay.cpp
+++ b/interface/src/ui/overlays/Base3DOverlay.cpp
@@ -265,7 +265,7 @@ void Base3DOverlay::locationChanged(bool tellPhysics) {
SpatiallyNestable::locationChanged(tellPhysics);
// Force the actual update of the render transform through the notify call
- notifyRenderTransformChange();
+ notifyRenderVariableChange();
}
void Base3DOverlay::parentDeleted() {
@@ -275,18 +275,21 @@ void Base3DOverlay::parentDeleted() {
void Base3DOverlay::update(float duration) {
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
// then the correct transform used for rendering is computed in the update transaction and assigned.
- if (_renderTransformDirty) {
+ if (_renderVariableDirty) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
// Capture the render transform value in game loop before
auto latestTransform = evalRenderTransform();
- _renderTransformDirty = false;
+ bool latestVisible = getVisible();
+ _renderVariableDirty = false;
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
- transaction.updateItem(itemID, [latestTransform](Overlay& data) {
+ transaction.updateItem(itemID, [latestTransform, latestVisible](Overlay& data) {
auto overlay3D = dynamic_cast(&data);
if (overlay3D) {
+ // TODO: overlays need to communicate all relavent render properties through transactions
overlay3D->setRenderTransform(latestTransform);
+ overlay3D->setRenderVisible(latestVisible);
}
});
scene->enqueueTransaction(transaction);
@@ -294,8 +297,8 @@ void Base3DOverlay::update(float duration) {
}
}
-void Base3DOverlay::notifyRenderTransformChange() const {
- _renderTransformDirty = true;
+void Base3DOverlay::notifyRenderVariableChange() const {
+ _renderVariableDirty = true;
}
Transform Base3DOverlay::evalRenderTransform() {
@@ -306,8 +309,17 @@ void Base3DOverlay::setRenderTransform(const Transform& transform) {
_renderTransform = transform;
}
+void Base3DOverlay::setRenderVisible(bool visible) {
+ _renderVisible = visible;
+}
+
SpatialParentTree* Base3DOverlay::getParentTree() const {
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
return entityTree.get();
}
+
+void Base3DOverlay::setVisible(bool visible) {
+ Parent::setVisible(visible);
+ notifyRenderVariableChange();
+}
\ No newline at end of file
diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h
index 436cfbf97b..83c5873260 100644
--- a/interface/src/ui/overlays/Base3DOverlay.h
+++ b/interface/src/ui/overlays/Base3DOverlay.h
@@ -18,11 +18,14 @@
class Base3DOverlay : public Overlay, public SpatiallyNestable {
Q_OBJECT
+ using Parent = Overlay;
public:
Base3DOverlay();
Base3DOverlay(const Base3DOverlay* base3DOverlay);
+ void setVisible(bool visible) override;
+
virtual OverlayID getOverlayID() const override { return OverlayID(getID().toString()); }
void setOverlayID(OverlayID overlayID) override { setID(overlayID); }
@@ -56,7 +59,7 @@ public:
void update(float deltatime) override;
- void notifyRenderTransformChange() const;
+ void notifyRenderVariableChange() const;
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
@@ -76,8 +79,10 @@ protected:
virtual void parentDeleted() override;
mutable Transform _renderTransform;
+ mutable bool _renderVisible;
virtual Transform evalRenderTransform();
virtual void setRenderTransform(const Transform& transform);
+ void setRenderVisible(bool visible);
const Transform& getRenderTransform() const { return _renderTransform; }
float _lineWidth;
@@ -87,7 +92,7 @@ protected:
bool _drawInFront;
bool _drawHUDLayer;
bool _isGrabbable { false };
- mutable bool _renderTransformDirty{ true };
+ mutable bool _renderVariableDirty { true };
QString _name;
};
diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp
index 536b2c764f..69ce331c99 100644
--- a/interface/src/ui/overlays/Circle3DOverlay.cpp
+++ b/interface/src/ui/overlays/Circle3DOverlay.cpp
@@ -59,7 +59,7 @@ Circle3DOverlay::~Circle3DOverlay() {
}
}
void Circle3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
@@ -259,7 +259,7 @@ void Circle3DOverlay::render(RenderArgs* args) {
}
const render::ShapeKey Circle3DOverlay::getShapeKey() {
- auto builder = render::ShapeKey::Builder().withoutCullFace().withUnlit();
+ auto builder = render::ShapeKey::Builder().withoutCullFace();
if (isTransparent()) {
builder.withTranslucent();
}
diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp
index 70b75a0b17..d40c0972e9 100644
--- a/interface/src/ui/overlays/ContextOverlayInterface.cpp
+++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp
@@ -14,6 +14,10 @@
#include
#include
+#include
+#include
+#include
+#include
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -34,14 +38,14 @@ ContextOverlayInterface::ContextOverlayInterface() {
_tabletScriptingInterface = DependencyManager::get();
_selectionScriptingInterface = DependencyManager::get();
- _selectionToSceneHandler.initialize("contextOverlayHighlightList");
-
_entityPropertyFlags += PROP_POSITION;
_entityPropertyFlags += PROP_ROTATION;
_entityPropertyFlags += PROP_MARKETPLACE_ID;
_entityPropertyFlags += PROP_DIMENSIONS;
_entityPropertyFlags += PROP_REGISTRATION_POINT;
_entityPropertyFlags += PROP_CERTIFICATE_ID;
+ _entityPropertyFlags += PROP_CLIENT_ONLY;
+ _entityPropertyFlags += PROP_OWNING_AVATAR_ID;
auto entityScriptingInterface = DependencyManager::get().data();
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay);
@@ -60,12 +64,31 @@ ContextOverlayInterface::ContextOverlayInterface() {
}
});
connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity);
-
connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay);
connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay);
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
- connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged);
+ {
+ render::Transaction transaction;
+ initializeSelectionToSceneHandler(_selectionToSceneHandlers[0], "contextOverlayHighlightList", transaction);
+ for (auto i = 1; i < MAX_SELECTION_COUNT; i++) {
+ auto selectionName = QString("highlightList") + QString::number(i);
+ initializeSelectionToSceneHandler(_selectionToSceneHandlers[i], selectionName, transaction);
+ }
+ const render::ScenePointer& scene = qApp->getMain3DScene();
+ scene->enqueueTransaction(transaction);
+ }
+
+ auto nodeList = DependencyManager::get();
+ auto& packetReceiver = nodeList->getPacketReceiver();
+ packetReceiver.registerListener(PacketType::ChallengeOwnershipReply, this, "handleChallengeOwnershipReplyPacket");
+ _challengeOwnershipTimeoutTimer.setSingleShot(true);
+}
+
+void ContextOverlayInterface::initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction) {
+ handler.initialize(selectionName);
+ connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &handler, &SelectionToSceneHandler::selectedItemsListChanged);
+ transaction.resetSelectionHighlight(selectionName.toStdString());
}
static const uint32_t MOUSE_HW_ID = 0;
@@ -260,6 +283,89 @@ void ContextOverlayInterface::openInspectionCertificate() {
auto tablet = dynamic_cast(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH);
_hmdScriptingInterface->openTablet();
+
+ setLastInspectedEntity(_currentEntityWithContextOverlay);
+
+ EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
+
+ auto nodeList = DependencyManager::get();
+
+ if (entityProperties.getClientOnly()) {
+ if (entityProperties.verifyStaticCertificateProperties()) {
+ SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
+
+ if (entityServer) {
+ QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
+ QNetworkRequest networkRequest;
+ networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+ networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
+ requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
+ QJsonObject request;
+ request["certificate_id"] = entityProperties.getCertificateID();
+ networkRequest.setUrl(requestURL);
+
+ QNetworkReply* networkReply = NULL;
+ networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
+
+ connect(networkReply, &QNetworkReply::finished, [=]() {
+ QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
+ jsonObject = jsonObject["data"].toObject();
+
+ if (networkReply->error() == QNetworkReply::NoError) {
+ if (!jsonObject["invalid_reason"].toString().isEmpty()) {
+ qCDebug(entities) << "invalid_reason not empty";
+ } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
+ qCDebug(entities) << "'transfer_status' is 'failed'";
+ } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
+ qCDebug(entities) << "'transfer_status' is 'pending'";
+ } else {
+ QString ownerKey = jsonObject["transfer_recipient_key"].toString();
+
+ QByteArray certID = entityProperties.getCertificateID().toUtf8();
+ QByteArray encryptedText = DependencyManager::get()->getTree()->computeEncryptedNonce(certID, ownerKey);
+ QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
+
+ int certIDByteArraySize = certID.length();
+ int encryptedTextByteArraySize = encryptedText.length();
+ int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
+
+ auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
+ certIDByteArraySize + encryptedTextByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
+ true);
+ challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
+ challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize);
+ challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
+ challengeOwnershipPacket->write(certID);
+ challengeOwnershipPacket->write(encryptedText);
+ challengeOwnershipPacket->write(nodeToChallengeByteArray);
+ nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
+
+ // Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
+ if (thread() != QThread::currentThread()) {
+ QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
+ return;
+ } else {
+ startChallengeOwnershipTimer();
+ }
+ }
+ } else {
+ qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
+ "More info:" << networkReply->readAll();
+ }
+
+ networkReply->deleteLater();
+ });
+ } else {
+ qCWarning(context_overlay) << "Couldn't get Entity Server!";
+ }
+ } else {
+ auto ledger = DependencyManager::get();
+ _challengeOwnershipTimeoutTimer.stop();
+ emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
+ qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
+ }
+ }
}
}
@@ -293,3 +399,39 @@ void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) {
destroyContextOverlay(_currentEntityWithContextOverlay, PointerEvent());
}
}
+
+void ContextOverlayInterface::startChallengeOwnershipTimer() {
+ auto ledger = DependencyManager::get();
+ EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
+
+ connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
+ qCDebug(entities) << "Ownership challenge timed out for" << _lastInspectedEntity;
+ emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT));
+ });
+
+ _challengeOwnershipTimeoutTimer.start(5000);
+}
+
+void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode) {
+ auto ledger = DependencyManager::get();
+
+ _challengeOwnershipTimeoutTimer.stop();
+
+ int certIDByteArraySize;
+ int decryptedTextByteArraySize;
+
+ packet->readPrimitive(&certIDByteArraySize);
+ packet->readPrimitive(&decryptedTextByteArraySize);
+
+ QString certID(packet->read(certIDByteArraySize));
+ QString decryptedText(packet->read(decryptedTextByteArraySize));
+
+ EntityItemID id;
+ bool verificationSuccess = DependencyManager::get()->getTree()->verifyDecryptedNonce(certID, decryptedText, id);
+
+ if (verificationSuccess) {
+ emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
+ } else {
+ emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED));
+ }
+}
diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h
index b4d3ddc0c2..81e398e15d 100644
--- a/interface/src/ui/overlays/ContextOverlayInterface.h
+++ b/interface/src/ui/overlays/ContextOverlayInterface.h
@@ -47,10 +47,12 @@ class ContextOverlayInterface : public QObject, public Dependency {
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
std::shared_ptr _contextOverlay { nullptr };
public:
+
ContextOverlayInterface();
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
+ void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); _lastInspectedEntity = entityID; }
void setEnabled(bool enabled);
bool getEnabled() { return _enabled; }
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
@@ -70,10 +72,19 @@ public slots:
void contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event);
bool contextOverlayFilterPassed(const EntityItemID& entityItemID);
+private slots:
+ void handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode);
+
private:
+
+ enum {
+ MAX_SELECTION_COUNT = 16
+ };
+
bool _verboseLogging { true };
bool _enabled { true };
- QUuid _currentEntityWithContextOverlay{};
+ EntityItemID _currentEntityWithContextOverlay{};
+ EntityItemID _lastInspectedEntity{};
QString _entityMarketplaceID;
bool _contextOverlayJustClicked { false };
@@ -85,8 +96,12 @@ private:
void disableEntityHighlight(const EntityItemID& entityItemID);
void deletingEntity(const EntityItemID& entityItemID);
+ void initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction);
- SelectionToSceneHandler _selectionToSceneHandler;
+ SelectionToSceneHandler _selectionToSceneHandlers[MAX_SELECTION_COUNT];
+
+ Q_INVOKABLE void startChallengeOwnershipTimer();
+ QTimer _challengeOwnershipTimeoutTimer;
};
#endif // hifi_ContextOverlayInterface_h
diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp
index b6df1dbc31..caa9a1b397 100644
--- a/interface/src/ui/overlays/Cube3DOverlay.cpp
+++ b/interface/src/ui/overlays/Cube3DOverlay.cpp
@@ -44,7 +44,7 @@ Cube3DOverlay::~Cube3DOverlay() {
}
void Cube3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp
index ca275368cb..6fd132b531 100644
--- a/interface/src/ui/overlays/Grid3DOverlay.cpp
+++ b/interface/src/ui/overlays/Grid3DOverlay.cpp
@@ -53,7 +53,7 @@ AABox Grid3DOverlay::getBounds() const {
}
void Grid3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp
index 313d71fc40..a8ae293c83 100644
--- a/interface/src/ui/overlays/Image3DOverlay.cpp
+++ b/interface/src/ui/overlays/Image3DOverlay.cpp
@@ -60,7 +60,7 @@ void Image3DOverlay::update(float deltatime) {
}
void Image3DOverlay::render(RenderArgs* args) {
- if (!_visible || !getParentVisible() || !_texture || !_texture->isLoaded()) {
+ if (!_renderVisible || !getParentVisible() || !_texture || !_texture->isLoaded()) {
return;
}
diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp
index bdb35d4f49..5ef820b2e0 100644
--- a/interface/src/ui/overlays/Line3DOverlay.cpp
+++ b/interface/src/ui/overlays/Line3DOverlay.cpp
@@ -96,7 +96,7 @@ void Line3DOverlay::setEnd(const glm::vec3& end) {
} else {
_direction = glm::vec3(0.0f);
}
- notifyRenderTransformChange();
+ notifyRenderVariableChange();
}
void Line3DOverlay::setLocalEnd(const glm::vec3& localEnd) {
@@ -123,7 +123,7 @@ AABox Line3DOverlay::getBounds() const {
}
void Line3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp
index ac3fe66ddc..a9f0bfe2f1 100644
--- a/interface/src/ui/overlays/Planar3DOverlay.cpp
+++ b/interface/src/ui/overlays/Planar3DOverlay.cpp
@@ -37,7 +37,7 @@ AABox Planar3DOverlay::getBounds() const {
void Planar3DOverlay::setDimensions(const glm::vec2& value) {
_dimensions = value;
- notifyRenderTransformChange();
+ notifyRenderVariableChange();
}
void Planar3DOverlay::setProperties(const QVariantMap& properties) {
diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.cpp b/interface/src/ui/overlays/Rectangle3DOverlay.cpp
index 47d47b76a5..f2e324206d 100644
--- a/interface/src/ui/overlays/Rectangle3DOverlay.cpp
+++ b/interface/src/ui/overlays/Rectangle3DOverlay.cpp
@@ -23,7 +23,6 @@ Rectangle3DOverlay::Rectangle3DOverlay() :
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
_rectGeometryIds[i] = geometryCache->allocateID();
}
- qDebug() << "Building rect3d overlay";
}
Rectangle3DOverlay::Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOverlay) :
@@ -34,11 +33,9 @@ Rectangle3DOverlay::Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOver
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
_rectGeometryIds[i] = geometryCache->allocateID();
}
- qDebug() << "Building rect3d overlay";
}
Rectangle3DOverlay::~Rectangle3DOverlay() {
- qDebug() << "Destryoing rect3d overlay";
auto geometryCache = DependencyManager::get();
if (geometryCache) {
geometryCache->releaseID(_geometryCacheID);
@@ -49,7 +46,7 @@ Rectangle3DOverlay::~Rectangle3DOverlay() {
}
void Rectangle3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
@@ -58,18 +55,11 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
const float MAX_COLOR = 255.0f;
glm::vec4 rectangleColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
- glm::vec3 position = getPosition();
- glm::vec2 dimensions = getDimensions();
- glm::vec2 halfDimensions = dimensions * 0.5f;
- glm::quat rotation = getRotation();
-
auto batch = args->_batch;
-
if (batch) {
- // FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
- Transform transform;
- transform.setTranslation(position);
- transform.setRotation(rotation);
+ Transform transform = getRenderTransform();
+ glm::vec2 halfDimensions = transform.getScale() * 0.5f;
+ transform.setScale(1.0f);
batch->setModelTransform(transform);
auto geometryCache = DependencyManager::get();
@@ -124,8 +114,3 @@ void Rectangle3DOverlay::setProperties(const QVariantMap& properties) {
Rectangle3DOverlay* Rectangle3DOverlay::createClone() const {
return new Rectangle3DOverlay(this);
}
-
-Transform Rectangle3DOverlay::evalRenderTransform() {
- return getTransform();
-}
-
diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.h b/interface/src/ui/overlays/Rectangle3DOverlay.h
index a26ed524fc..645553ed38 100644
--- a/interface/src/ui/overlays/Rectangle3DOverlay.h
+++ b/interface/src/ui/overlays/Rectangle3DOverlay.h
@@ -29,9 +29,6 @@ public:
virtual Rectangle3DOverlay* createClone() const override;
-protected:
- Transform evalRenderTransform() override;
-
private:
int _geometryCacheID;
std::array _rectGeometryIds;
diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp
index a3b51d40bf..bd8e6a9728 100644
--- a/interface/src/ui/overlays/Shape3DOverlay.cpp
+++ b/interface/src/ui/overlays/Shape3DOverlay.cpp
@@ -24,7 +24,7 @@ Shape3DOverlay::Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay) :
}
void Shape3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp
index c9fc25b252..2013e5689a 100644
--- a/interface/src/ui/overlays/Sphere3DOverlay.cpp
+++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp
@@ -27,7 +27,7 @@ Sphere3DOverlay::Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay) :
}
void Sphere3DOverlay::render(RenderArgs* args) {
- if (!_visible) {
+ if (!_renderVisible) {
return; // do nothing if we're not visible
}
diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp
index d8188cf6dc..1cbc73304b 100644
--- a/interface/src/ui/overlays/Text3DOverlay.cpp
+++ b/interface/src/ui/overlays/Text3DOverlay.cpp
@@ -92,7 +92,7 @@ void Text3DOverlay::update(float deltatime) {
}
void Text3DOverlay::render(RenderArgs* args) {
- if (!_visible || !getParentVisible()) {
+ if (!_renderVisible || !getParentVisible()) {
return; // do nothing if we're not visible
}
diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp
index 8aa8490937..e5a418cce5 100644
--- a/interface/src/ui/overlays/Volume3DOverlay.cpp
+++ b/interface/src/ui/overlays/Volume3DOverlay.cpp
@@ -28,7 +28,7 @@ AABox Volume3DOverlay::getBounds() const {
void Volume3DOverlay::setDimensions(const glm::vec3& value) {
_localBoundingBox.setBox(-value / 2.0f, value);
- notifyRenderTransformChange();
+ notifyRenderVariableChange();
}
void Volume3DOverlay::setProperties(const QVariantMap& properties) {
diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp
index 42d0ea0f12..d418a79fbf 100644
--- a/interface/src/ui/overlays/Web3DOverlay.cpp
+++ b/interface/src/ui/overlays/Web3DOverlay.cpp
@@ -268,7 +268,7 @@ Q_INVOKABLE int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) {
}
void Web3DOverlay::render(RenderArgs* args) {
- if (!_visible || !getParentVisible()) {
+ if (!_renderVisible || !getParentVisible()) {
return;
}
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 0f2bce5ca4..78aa1f4ba8 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -39,7 +39,12 @@ static std::mutex rigRegistryMutex;
static bool isEqual(const glm::vec3& u, const glm::vec3& v) {
const float EPSILON = 0.0001f;
- return glm::length(u - v) / glm::length(u) <= EPSILON;
+ float uLen = glm::length(u);
+ if (uLen == 0.0f) {
+ return glm::length(v) <= EPSILON;
+ } else {
+ return (glm::length(u - v) / uLen) <= EPSILON;
+ }
}
static bool isEqual(const glm::quat& p, const glm::quat& q) {
@@ -152,6 +157,7 @@ void Rig::overrideRoleAnimation(const QString& role, const QString& url, float f
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
auto clipNode = std::make_shared(role, url, firstFrame, lastFrame, timeScale, loop, false);
+ _roleAnimStates[role] = { role, url, fps, loop, firstFrame, lastFrame };
AnimNode::Pointer parent = node->getParent();
parent->replaceChild(node, clipNode);
} else {
@@ -173,6 +179,11 @@ void Rig::restoreRoleAnimation(const QString& role) {
} else {
qCWarning(animation) << "Rig::restoreRoleAnimation could not find role " << role;
}
+
+ auto statesIter = _roleAnimStates.find(role);
+ if (statesIter != _roleAnimStates.end()) {
+ _roleAnimStates.erase(statesIter);
+ }
}
} else {
qCWarning(animation) << "Rig::overrideRoleAnimation avatar not ready yet";
@@ -302,7 +313,9 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) {
_rigToGeometryTransform = glm::inverse(_geometryToRigTransform);
// rebuild cached default poses
- buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
+ if (_animSkeleton) {
+ buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
+ }
}
}
@@ -1638,6 +1651,11 @@ void Rig::initAnimGraph(const QUrl& url) {
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
}
+ // restore the role animations we had before reset.
+ for (auto& roleAnimState : _roleAnimStates) {
+ auto roleState = roleAnimState.second;
+ overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame);
+ }
_animLoading = false;
emit onLoadComplete();
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 18d49c5f1e..e9cc444bd4 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -335,8 +335,22 @@ protected:
float firstFrame;
float lastFrame;
};
+
+ struct RoleAnimState {
+ RoleAnimState() {}
+ RoleAnimState(const QString& roleId, const QString& urlIn, float fpsIn, bool loopIn, float firstFrameIn, float lastFrameIn) :
+ role(roleId), url(urlIn), fps(fpsIn), loop(loopIn), firstFrame(firstFrameIn), lastFrame(lastFrameIn) {}
+
+ QString role;
+ QString url;
+ float fps;
+ bool loop;
+ float firstFrame;
+ float lastFrame;
+ };
UserAnimState _userAnimState;
+ std::map _roleAnimStates;
float _leftHandOverlayAlpha { 0.0f };
float _rightHandOverlayAlpha { 0.0f };
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index 142e57c9e5..49d2431098 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -453,7 +453,9 @@ void Avatar::applyPositionDelta(const glm::vec3& delta) {
void Avatar::measureMotionDerivatives(float deltaTime) {
PerformanceTimer perfTimer("derivatives");
// linear
- float invDeltaTime = 1.0f / deltaTime;
+ const float MIN_DELTA_TIME = 0.001f;
+ const float safeDeltaTime = glm::max(deltaTime, MIN_DELTA_TIME);
+ float invDeltaTime = 1.0f / safeDeltaTime;
// Floating point error prevents us from computing velocity in a naive way
// (e.g. vel = (pos - oldPos) / dt) so instead we use _positionOffsetAccumulator.
glm::vec3 velocity = _positionDeltaAccumulator * invDeltaTime;
@@ -728,19 +730,19 @@ void Avatar::simulateAttachments(float deltaTime) {
glm::quat jointRotation;
if (attachment.isSoft) {
// soft attachments do not have transform offsets
- model->setTranslation(getPosition());
- model->setRotation(getOrientation() * Quaternions::Y_180);
+ model->setTransformNoUpdateRenderItems(Transform(getOrientation() * Quaternions::Y_180, glm::vec3(1.0), getPosition()));
model->simulate(deltaTime);
+ model->updateRenderItems();
} else {
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) &&
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) {
- model->setTranslation(jointPosition + jointRotation * attachment.translation * getModelScale());
- model->setRotation(jointRotation * attachment.rotation);
+ model->setTransformNoUpdateRenderItems(Transform(jointRotation * attachment.rotation, glm::vec3(1.0), jointPosition + jointRotation * attachment.translation * getModelScale()));
float scale = getModelScale() * attachment.scale;
model->setScaleToFit(true, model->getNaturalDimensions() * scale, true); // hack to force rescale
model->setSnapModelToCenter(false); // hack to force resnap
model->setSnapModelToCenter(true);
model->simulate(deltaTime);
+ model->updateRenderItems();
}
}
}
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index 877bcd9353..bd313ac133 100644
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -2223,11 +2223,13 @@ glm::vec3 variantToVec3(const QVariant& var) {
return result;
}
-void AttachmentData::fromVariant(const QVariant& variant) {
+bool AttachmentData::fromVariant(const QVariant& variant) {
+ bool isValid = false;
auto map = variant.toMap();
if (map.contains("modelUrl")) {
auto urlString = map["modelUrl"].toString();
modelURL = urlString;
+ isValid = true;
}
if (map.contains("jointName")) {
jointName = map["jointName"].toString();
@@ -2244,6 +2246,7 @@ void AttachmentData::fromVariant(const QVariant& variant) {
if (map.contains("soft")) {
isSoft = map["soft"].toBool();
}
+ return isValid;
}
QVariantList AvatarData::getAttachmentsVariant() const {
@@ -2259,8 +2262,7 @@ void AvatarData::setAttachmentsVariant(const QVariantList& variant) {
newAttachments.reserve(variant.size());
for (const auto& attachmentVar : variant) {
AttachmentData attachment;
- attachment.fromVariant(attachmentVar);
- if (!attachment.modelURL.isEmpty()) {
+ if (attachment.fromVariant(attachmentVar)) {
newAttachments.append(attachment);
}
}
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 89fe270af1..4dabbb3ff5 100644
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -15,21 +15,7 @@
#include
#include
#include
-
-/* VS2010 defines stdint.h, but not inttypes.h */
-#if defined(_MSC_VER)
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long quint64;
-#define PRId64 "I64d"
-#else
#include
-#endif
#include
#include
@@ -903,7 +889,7 @@ public:
void fromJson(const QJsonObject& json);
QVariant toVariant() const;
- void fromVariant(const QVariant& variant);
+ bool fromVariant(const QVariant& variant);
};
QDataStream& operator<<(QDataStream& out, const AttachmentData& attachment);
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index 0235f1b7a3..7c96f00ede 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -342,23 +342,23 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity)
haze->setHazeActive(hazeMode == COMPONENT_MODE_ENABLED);
haze->setAltitudeBased(_hazeProperties.getHazeAltitudeEffect());
- haze->setHazeRangeFactor(model::convertHazeRangeToHazeRangeFactor(_hazeProperties.getHazeRange()));
+ haze->setHazeRangeFactor(model::Haze::convertHazeRangeToHazeRangeFactor(_hazeProperties.getHazeRange()));
xColor hazeColor = _hazeProperties.getHazeColor();
haze->setHazeColor(glm::vec3(hazeColor.red / 255.0, hazeColor.green / 255.0, hazeColor.blue / 255.0));
xColor hazeGlareColor = _hazeProperties.getHazeGlareColor();
- haze->setDirectionalLightColor(glm::vec3(hazeGlareColor.red / 255.0, hazeGlareColor.green / 255.0, hazeGlareColor.blue / 255.0));
+ haze->setHazeGlareColor(glm::vec3(hazeGlareColor.red / 255.0, hazeGlareColor.green / 255.0, hazeGlareColor.blue / 255.0));
haze->setHazeEnableGlare(_hazeProperties.getHazeEnableGlare());
- haze->setDirectionalLightBlend(model::convertDirectionalLightAngleToPower(_hazeProperties.getHazeGlareAngle()));
+ haze->setHazeGlareBlend(model::Haze::convertGlareAngleToPower(_hazeProperties.getHazeGlareAngle()));
float hazeAltitude = _hazeProperties.getHazeCeiling() - _hazeProperties.getHazeBaseRef();
- haze->setHazeAltitudeFactor(model::convertHazeAltitudeToHazeAltitudeFactor(hazeAltitude));
+ haze->setHazeAltitudeFactor(model::Haze::convertHazeAltitudeToHazeAltitudeFactor(hazeAltitude));
haze->setHazeBaseReference(_hazeProperties.getHazeBaseRef());
- haze->setHazeBackgroundBlendValue(_hazeProperties.getHazeBackgroundBlend());
+ haze->setHazeBackgroundBlend(_hazeProperties.getHazeBackgroundBlend());
haze->setHazeAttenuateKeyLight(_hazeProperties.getHazeAttenuateKeyLight());
- haze->setHazeKeyLightRangeFactor(model::convertHazeRangeToHazeRangeFactor(_hazeProperties.getHazeKeyLightRange()));
- haze->setHazeKeyLightAltitudeFactor(model::convertHazeAltitudeToHazeAltitudeFactor(_hazeProperties.getHazeKeyLightAltitude()));
+ haze->setHazeKeyLightRangeFactor(model::Haze::convertHazeRangeToHazeRangeFactor(_hazeProperties.getHazeKeyLightRange()));
+ haze->setHazeKeyLightAltitudeFactor(model::Haze::convertHazeAltitudeToHazeAltitudeFactor(_hazeProperties.getHazeKeyLightAltitude()));
haze->setZoneTransform(entity->getTransform().getMatrix());
}
diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt
index 322d69da16..c23740654e 100644
--- a/libraries/entities/CMakeLists.txt
+++ b/libraries/entities/CMakeLists.txt
@@ -1,4 +1,4 @@
set(TARGET_NAME entities)
setup_hifi_library(Network Script)
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
-link_hifi_libraries(shared networking octree avatars)
+link_hifi_libraries(shared networking octree avatars model)
diff --git a/libraries/entities/src/DiffTraversal.cpp b/libraries/entities/src/DiffTraversal.cpp
index 2f9423daa3..764c420197 100644
--- a/libraries/entities/src/DiffTraversal.cpp
+++ b/libraries/entities/src/DiffTraversal.cpp
@@ -142,7 +142,8 @@ DiffTraversal::DiffTraversal() {
_path.reserve(MIN_PATH_DEPTH);
}
-DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) {
+DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root,
+ int32_t lodLevelOffset, bool usesViewFrustum) {
assert(root);
// there are three types of traversal:
//
diff --git a/libraries/entities/src/DiffTraversal.h b/libraries/entities/src/DiffTraversal.h
index c26e48ae5f..eb7168356e 100644
--- a/libraries/entities/src/DiffTraversal.h
+++ b/libraries/entities/src/DiffTraversal.h
@@ -57,7 +57,8 @@ public:
DiffTraversal();
- Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum);
+ Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset,
+ bool usesViewFrustum);
const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; }
const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; }
diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp
index e82ed82093..168b0cd446 100644
--- a/libraries/entities/src/EntityEditPacketSender.cpp
+++ b/libraries/entities/src/EntityEditPacketSender.cpp
@@ -93,27 +93,41 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
QByteArray bufferOut(NLPacket::maxPayloadSize(type), 0);
- bool success;
+ OctreeElement::AppendState encodeResult = OctreeElement::PARTIAL; // start the loop assuming there's more to send
auto nodeList = DependencyManager::get();
+
+ EntityPropertyFlags didntFitProperties;
+ EntityItemProperties propertiesCopy = properties;
+
if (properties.parentIDChanged() && properties.getParentID() == AVATAR_SELF_ID) {
- EntityItemProperties propertiesCopy = properties;
const QUuid myNodeID = nodeList->getSessionUUID();
propertiesCopy.setParentID(myNodeID);
- success = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, propertiesCopy, bufferOut);
- } else {
- success = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, properties, bufferOut);
}
- if (success) {
- #ifdef WANT_DEBUG
- qCDebug(entities) << "calling queueOctreeEditMessage()...";
- qCDebug(entities) << " id:" << entityItemID;
- qCDebug(entities) << " properties:" << properties;
- #endif
- queueOctreeEditMessage(type, bufferOut);
- if (type == PacketType::EntityAdd && !properties.getCertificateID().isEmpty()) {
- emit addingEntityWithCertificate(properties.getCertificateID(), DependencyManager::get()->getPlaceName());
+ EntityPropertyFlags requestedProperties = propertiesCopy.getChangedProperties();
+
+ while (encodeResult == OctreeElement::PARTIAL) {
+ encodeResult = EntityItemProperties::encodeEntityEditPacket(type, entityItemID, propertiesCopy, bufferOut, requestedProperties, didntFitProperties);
+
+ if (encodeResult != OctreeElement::NONE) {
+ #ifdef WANT_DEBUG
+ qCDebug(entities) << "calling queueOctreeEditMessage()...";
+ qCDebug(entities) << " id:" << entityItemID;
+ qCDebug(entities) << " properties:" << properties;
+ #endif
+ queueOctreeEditMessage(type, bufferOut);
+ if (type == PacketType::EntityAdd && !properties.getCertificateID().isEmpty()) {
+ emit addingEntityWithCertificate(properties.getCertificateID(), DependencyManager::get()->getPlaceName());
+ }
}
+
+ // if we still have properties to send, switch the message type to edit, and request only the packets that didn't fit
+ if (encodeResult != OctreeElement::COMPLETED) {
+ type = PacketType::EntityEdit;
+ requestedProperties = didntFitProperties;
+ }
+
+ bufferOut.resize(NLPacket::maxPayloadSize(type)); // resize our output buffer for the next packet
}
}
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 4f5db991c8..3f054e1ccb 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -14,10 +14,6 @@
#include
#include
#include
-#include
-#include
-#include
-#include
#include
#include
#include
@@ -87,7 +83,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_ANGULAR_VELOCITY;
requestedProperties += PROP_ACCELERATION;
- requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete
+ requestedProperties += PROP_DIMENSIONS;
requestedProperties += PROP_DENSITY;
requestedProperties += PROP_GRAVITY;
requestedProperties += PROP_DAMPING;
@@ -245,7 +241,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getLocalAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration());
- APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); // NOTE: PROP_RADIUS obsolete
+ APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity());
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity());
APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping());
@@ -1575,116 +1571,6 @@ float EntityItem::getRadius() const {
return 0.5f * glm::length(getDimensions());
}
-// Checking Certifiable Properties
-#define ADD_STRING_PROPERTY(n, N) if (!propertySet.get##N().isEmpty()) json[#n] = propertySet.get##N()
-#define ADD_ENUM_PROPERTY(n, N) json[#n] = propertySet.get##N##AsString()
-#define ADD_INT_PROPERTY(n, N) if (propertySet.get##N() != 0) json[#n] = (propertySet.get##N() == (quint32) -1) ? -1.0 : ((double) propertySet.get##N())
-QByteArray EntityItem::getStaticCertificateJSON() const {
- // Produce a compact json of every non-default static certificate property, with the property names in alphabetical order.
- // The static certificate properties include all an only those properties that cannot be changed without altering the identity
- // of the entity as reviewed during the certification submission.
-
- QJsonObject json;
- EntityItemProperties propertySet = getProperties(); // Note: neither EntityItem nor EntityitemProperties "properties" are QObject "properties"!
- // It is important that this be reproducible in the same order each time. Since we also generate these on the server, we do it alphabetically
- // to help maintainence in two different code bases.
- if (!propertySet.getAnimation().getURL().isEmpty()) {
- json["animationURL"] = propertySet.getAnimation().getURL();
- }
- ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL);
- ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL);
- ADD_INT_PROPERTY(editionNumber, EditionNumber);
- ADD_INT_PROPERTY(instanceNumber, EntityInstanceNumber);
- ADD_STRING_PROPERTY(itemArtist, ItemArtist);
- ADD_STRING_PROPERTY(itemCategories, ItemCategories);
- ADD_STRING_PROPERTY(itemDescription, ItemDescription);
- ADD_STRING_PROPERTY(itemLicenseUrl, ItemLicense);
- ADD_STRING_PROPERTY(itemName, ItemName);
- ADD_INT_PROPERTY(limitedRun, LimitedRun);
- ADD_STRING_PROPERTY(marketplaceID, MarketplaceID);
- ADD_STRING_PROPERTY(modelURL, ModelURL);
- ADD_STRING_PROPERTY(script, Script);
- ADD_ENUM_PROPERTY(shapeType, ShapeType);
- json["type"] = EntityTypes::getEntityTypeName(propertySet.getType());
-
- return QJsonDocument(json).toJson(QJsonDocument::Compact);
-}
-QByteArray EntityItem::getStaticCertificateHash() const {
- return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256);
-}
-
-bool EntityItem::verifyStaticCertificateProperties() {
- // True IIF a non-empty certificateID matches the static certificate json.
- // I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash.
-
- if (getCertificateID().isEmpty()) {
- return false;
- }
-
- const QByteArray marketplacePublicKeyByteArray = EntityItem::_marketplacePublicKey.toUtf8();
- const unsigned char* marketplacePublicKey = reinterpret_cast(marketplacePublicKeyByteArray.constData());
- int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length();
-
- BIO *bio = BIO_new_mem_buf((void*)marketplacePublicKey, marketplacePublicKeyLength);
- EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
- if (evp_key) {
- RSA* rsa = EVP_PKEY_get1_RSA(evp_key);
- if (rsa) {
- const QByteArray digestByteArray = getStaticCertificateHash();
- const unsigned char* digest = reinterpret_cast(digestByteArray.constData());
- int digestLength = digestByteArray.length();
-
- const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8());
- const unsigned char* signature = reinterpret_cast(signatureByteArray.constData());
- int signatureLength = signatureByteArray.length();
-
- ERR_clear_error();
- bool answer = RSA_verify(NID_sha256,
- digest,
- digestLength,
- signature,
- signatureLength,
- rsa);
- long error = ERR_get_error();
- if (error != 0) {
- const char* error_str = ERR_error_string(error, NULL);
- qCWarning(entities) << "ERROR while verifying static certificate properties! RSA error:" << error_str
- << "\nStatic Cert JSON:" << getStaticCertificateJSON()
- << "\nKey:" << EntityItem::_marketplacePublicKey << "\nKey Length:" << marketplacePublicKeyLength
- << "\nDigest:" << digest << "\nDigest Length:" << digestLength
- << "\nSignature:" << signature << "\nSignature Length:" << signatureLength;
- }
- RSA_free(rsa);
- if (bio) {
- BIO_free(bio);
- }
- if (evp_key) {
- EVP_PKEY_free(evp_key);
- }
- return answer;
- } else {
- if (bio) {
- BIO_free(bio);
- }
- if (evp_key) {
- EVP_PKEY_free(evp_key);
- }
- long error = ERR_get_error();
- const char* error_str = ERR_error_string(error, NULL);
- qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str;
- return false;
- }
- } else {
- if (bio) {
- BIO_free(bio);
- }
- long error = ERR_get_error();
- const char* error_str = ERR_error_string(error, NULL);
- qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str;
- return false;
- }
-}
-
void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
glm::mat4 scale = glm::scale(getDimensions());
@@ -1769,7 +1655,6 @@ void EntityItem::updateDimensions(const glm::vec3& value) {
setDimensions(value);
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
_queryAACubeSet = false;
- dimensionsChanged();
}
}
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 79862b9bd2..76a5205960 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -328,9 +328,6 @@ public:
void setEntityInstanceNumber(const quint32&);
QString getCertificateID() const;
void setCertificateID(const QString& value);
- QByteArray getStaticCertificateJSON() const;
- QByteArray getStaticCertificateHash() const;
- bool verifyStaticCertificateProperties();
// TODO: get rid of users of getRadius()...
float getRadius() const;
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 3bbd6ce8e6..108fc14e30 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -14,6 +14,15 @@
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#include
#include
#include
@@ -1212,8 +1221,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
//
// TODO: Implement support for script and visible properties.
//
-bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
- QByteArray& buffer) {
+OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
+ QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties) {
+
OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too.
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
@@ -1255,17 +1265,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
QByteArray encodedUpdateDelta = updateDeltaCoder;
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
- EntityPropertyFlags requestedProperties = properties.getChangedProperties();
EntityPropertyFlags propertiesDidntFit = requestedProperties;
- // TODO: we need to handle the multi-pass form of this, similar to how we handle entity data
- //
- // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
- // then our modelTreeElementExtraEncodeData should include data about which properties we need to append.
- //if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) {
- // requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID());
- //}
-
LevelDetails entityLevel = packetData->startLevel();
// Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this
@@ -1293,7 +1294,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
int propertyCount = 0;
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
- && successLastUpdatedFits && successPropertyFlagsFits;
+ && successLastUpdatedFits && successPropertyFlagsFits;
int startOfEntityItemData = packetData->getUncompressedByteOffset();
@@ -1307,7 +1308,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, properties._simulationOwner.toByteArray());
APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition());
- APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete
+ APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions());
APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, properties.getVelocity());
@@ -1463,6 +1464,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
properties.getType() == EntityTypes::Sphere) {
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
}
+
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
@@ -1513,12 +1515,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
// If any part of the model items didn't fit, then the element is considered partial
if (appendState != OctreeElement::COMPLETED) {
- // TODO: handle mechanism for handling partial fitting data!
- // add this item into our list for the next appendElementData() pass
- //modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit);
-
- // for now, if it's not complete, it's not successful
- success = false;
+ didntFitProperties = propertiesDidntFit;
}
}
@@ -1534,11 +1531,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
} else {
qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer.";
success = false;
+ appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
+ // maybe we should assert!!!
}
} else {
packetData->discardSubTree();
}
- return success;
+
+
+ return appendState;
}
QByteArray EntityItemProperties::getPackedNormals() const {
@@ -1664,7 +1665,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATION_OWNER, QByteArray, setSimulationOwner);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition);
- READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity);
@@ -2471,3 +2472,110 @@ bool EntityItemProperties::parentRelatedPropertyChanged() const {
bool EntityItemProperties::queryAACubeRelatedPropertyChanged() const {
return parentRelatedPropertyChanged() || dimensionsChanged();
}
+
+// Checking Certifiable Properties
+#define ADD_STRING_PROPERTY(n, N) if (!get##N().isEmpty()) json[#n] = get##N()
+#define ADD_ENUM_PROPERTY(n, N) json[#n] = get##N##AsString()
+#define ADD_INT_PROPERTY(n, N) if (get##N() != 0) json[#n] = (get##N() == (quint32) -1) ? -1.0 : ((double) get##N())
+QByteArray EntityItemProperties::getStaticCertificateJSON() const {
+ // Produce a compact json of every non-default static certificate property, with the property names in alphabetical order.
+ // The static certificate properties include all an only those properties that cannot be changed without altering the identity
+ // of the entity as reviewed during the certification submission.
+
+ QJsonObject json;
+ if (!getAnimation().getURL().isEmpty()) {
+ json["animationURL"] = getAnimation().getURL();
+ }
+ ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL);
+ ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL);
+ ADD_INT_PROPERTY(editionNumber, EditionNumber);
+ ADD_INT_PROPERTY(instanceNumber, EntityInstanceNumber);
+ ADD_STRING_PROPERTY(itemArtist, ItemArtist);
+ ADD_STRING_PROPERTY(itemCategories, ItemCategories);
+ ADD_STRING_PROPERTY(itemDescription, ItemDescription);
+ ADD_STRING_PROPERTY(itemLicenseUrl, ItemLicense);
+ ADD_STRING_PROPERTY(itemName, ItemName);
+ ADD_INT_PROPERTY(limitedRun, LimitedRun);
+ ADD_STRING_PROPERTY(marketplaceID, MarketplaceID);
+ ADD_STRING_PROPERTY(modelURL, ModelURL);
+ ADD_STRING_PROPERTY(script, Script);
+ ADD_ENUM_PROPERTY(shapeType, ShapeType);
+ json["type"] = EntityTypes::getEntityTypeName(getType());
+
+ return QJsonDocument(json).toJson(QJsonDocument::Compact);
+}
+QByteArray EntityItemProperties::getStaticCertificateHash() const {
+ return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256);
+}
+
+bool EntityItemProperties::verifyStaticCertificateProperties() {
+ // True IIF a non-empty certificateID matches the static certificate json.
+ // I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash.
+
+ if (getCertificateID().isEmpty()) {
+ return false;
+ }
+
+ const QByteArray marketplacePublicKeyByteArray = EntityItem::_marketplacePublicKey.toUtf8();
+ const unsigned char* marketplacePublicKey = reinterpret_cast(marketplacePublicKeyByteArray.constData());
+ int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length();
+
+ BIO *bio = BIO_new_mem_buf((void*)marketplacePublicKey, marketplacePublicKeyLength);
+ EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+ if (evp_key) {
+ RSA* rsa = EVP_PKEY_get1_RSA(evp_key);
+ if (rsa) {
+ const QByteArray digestByteArray = getStaticCertificateHash();
+ const unsigned char* digest = reinterpret_cast(digestByteArray.constData());
+ int digestLength = digestByteArray.length();
+
+ const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8());
+ const unsigned char* signature = reinterpret_cast(signatureByteArray.constData());
+ int signatureLength = signatureByteArray.length();
+
+ ERR_clear_error();
+ bool answer = RSA_verify(NID_sha256,
+ digest,
+ digestLength,
+ signature,
+ signatureLength,
+ rsa);
+ long error = ERR_get_error();
+ if (error != 0) {
+ const char* error_str = ERR_error_string(error, NULL);
+ qCWarning(entities) << "ERROR while verifying static certificate properties! RSA error:" << error_str
+ << "\nStatic Cert JSON:" << getStaticCertificateJSON()
+ << "\nKey:" << EntityItem::_marketplacePublicKey << "\nKey Length:" << marketplacePublicKeyLength
+ << "\nDigest:" << digest << "\nDigest Length:" << digestLength
+ << "\nSignature:" << signature << "\nSignature Length:" << signatureLength;
+ }
+ RSA_free(rsa);
+ if (bio) {
+ BIO_free(bio);
+ }
+ if (evp_key) {
+ EVP_PKEY_free(evp_key);
+ }
+ return answer;
+ } else {
+ if (bio) {
+ BIO_free(bio);
+ }
+ if (evp_key) {
+ EVP_PKEY_free(evp_key);
+ }
+ long error = ERR_get_error();
+ const char* error_str = ERR_error_string(error, NULL);
+ qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str;
+ return false;
+ }
+ } else {
+ if (bio) {
+ BIO_free(bio);
+ }
+ long error = ERR_get_error();
+ const char* error_str = ERR_error_string(error, NULL);
+ qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str;
+ return false;
+ }
+}
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 6547026e5c..732dbdf69f 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -262,8 +262,8 @@ public:
float getLocalRenderAlpha() const { return _localRenderAlpha; }
void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; }
- static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
- QByteArray& buffer);
+ static OctreeElement::AppendState encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
+ QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties);
static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer);
@@ -336,6 +336,10 @@ public:
QByteArray getPackedStrokeColors() const;
QByteArray packStrokeColors(const QVector& strokeColors) const;
+ QByteArray getStaticCertificateJSON() const;
+ QByteArray getStaticCertificateHash() const;
+ bool verifyStaticCertificateProperties();
+
protected:
QString getCollisionMaskAsString() const;
void setCollisionMaskFromString(const QString& maskString);
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index f0f22b0091..35d40b669a 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -21,8 +21,7 @@ enum EntityPropertyList {
// these properties are supported by the EntityItem base class
PROP_VISIBLE,
PROP_POSITION,
- PROP_RADIUS, // NOTE: PROP_RADIUS is obsolete and only included in old format streams
- PROP_DIMENSIONS = PROP_RADIUS,
+ PROP_DIMENSIONS,
PROP_ROTATION,
PROP_DENSITY,
PROP_VELOCITY,
@@ -47,13 +46,13 @@ enum EntityPropertyList {
PROP_ANGULAR_VELOCITY,
PROP_ANGULAR_DAMPING,
PROP_COLLISIONLESS,
- PROP_DYNAMIC,
+ PROP_DYNAMIC, // 24
// property used by Light entity
PROP_IS_SPOTLIGHT,
PROP_DIFFUSE_COLOR,
- PROP_AMBIENT_COLOR_UNUSED,
- PROP_SPECULAR_COLOR_UNUSED,
+ PROP_AMBIENT_COLOR_UNUSED, // FIXME - No longer used, can remove and bump protocol
+ PROP_SPECULAR_COLOR_UNUSED, // FIXME - No longer used, can remove and bump protocol
PROP_INTENSITY, // Previously PROP_CONSTANT_ATTENUATION
PROP_LINEAR_ATTENUATION_UNUSED,
PROP_QUADRATIC_ATTENUATION_UNUSED,
@@ -61,30 +60,30 @@ enum EntityPropertyList {
PROP_CUTOFF,
// available to all entities
- PROP_LOCKED,
+ PROP_LOCKED, // 34
PROP_TEXTURES, // used by Model entities
- PROP_ANIMATION_SETTINGS, // used by Model entities
- PROP_USER_DATA, // all entities
+ PROP_ANIMATION_SETTINGS_UNUSED, // FIXME - No longer used, can remove and bump protocol
+ PROP_USER_DATA, // all entities -- 37
PROP_SHAPE_TYPE, // used by Model + zones entities
// used by ParticleEffect entities
- PROP_MAX_PARTICLES,
- PROP_LIFESPAN,
+ PROP_MAX_PARTICLES, // 39
+ PROP_LIFESPAN, // 40 -- used by all entities
PROP_EMIT_RATE,
PROP_EMIT_SPEED,
PROP_EMIT_STRENGTH,
- PROP_EMIT_ACCELERATION,
- PROP_PARTICLE_RADIUS,
+ PROP_EMIT_ACCELERATION, // FIXME - doesn't seem to get set in mark all changed????
+ PROP_PARTICLE_RADIUS, // 45!!
PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities
PROP_MARKETPLACE_ID, // all entities
PROP_ACCELERATION, // all entities
PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID
- PROP_NAME, // all entities
+ PROP_NAME, // all entities -- 50
PROP_COLLISION_SOUND_URL,
PROP_RESTITUTION,
- PROP_FRICTION,
+ PROP_FRICTION, // 53
PROP_VOXEL_VOLUME_SIZE,
PROP_VOXEL_DATA,
@@ -96,7 +95,7 @@ enum EntityPropertyList {
// used by hyperlinks
PROP_HREF,
- PROP_DESCRIPTION,
+ PROP_DESCRIPTION, // 61
PROP_FACE_CAMERA,
PROP_SCRIPT_TIMESTAMP,
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index c83a5f60a1..998a2d4dfe 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -1827,7 +1827,7 @@ bool EntityScriptingInterface::verifyStaticCertificateProperties(const QUuid& en
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
if (entity) {
- result = entity->verifyStaticCertificateProperties();
+ result = entity->getProperties().verifyStaticCertificateProperties();
}
});
}
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 9397f38cdd..333a514377 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -1195,7 +1195,6 @@ QByteArray EntityTree::computeEncryptedNonce(const QString& certID, const QStrin
QWriteLocker locker(&_certNonceMapLock);
_certNonceMap.insert(certID, nonce);
- qCDebug(entities) << "Challenging ownership of Cert ID" << certID << "by encrypting and sending nonce" << nonce << "to owner.";
return encryptedText;
} else {
@@ -1206,9 +1205,7 @@ QByteArray EntityTree::computeEncryptedNonce(const QString& certID, const QStrin
}
}
-bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce) {
-
- EntityItemID id;
+bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce, EntityItemID& id) {
{
QReadLocker certIdMapLocker(&_entityCertificateIDMapLock);
id = _entityCertificateIDMap.value(certID);
@@ -1221,19 +1218,116 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr
}
bool verificationSuccess = (actualNonce == decryptedNonce);
- if (!verificationSuccess) {
- if (!id.isNull()) {
- qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed; deleting entity" << id
- << "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce;
- deleteEntity(id, true);
- }
+
+ if (verificationSuccess) {
+ qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded.";
} else {
- qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded; keeping entity" << id;
+ qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed."
+ << "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce;
}
return verificationSuccess;
}
+void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
+ int certIDByteArraySize;
+ int encryptedTextByteArraySize;
+ int nodeToChallengeByteArraySize;
+
+ message.readPrimitive(&certIDByteArraySize);
+ message.readPrimitive(&encryptedTextByteArraySize);
+ message.readPrimitive(&nodeToChallengeByteArraySize);
+
+ QByteArray certID(message.read(certIDByteArraySize));
+ QByteArray encryptedText(message.read(encryptedTextByteArraySize));
+ QByteArray nodeToChallenge(message.read(nodeToChallengeByteArraySize));
+
+ sendChallengeOwnershipRequestPacket(certID, encryptedText, nodeToChallenge, sourceNode);
+}
+
+void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
+ auto nodeList = DependencyManager::get();
+
+ int certIDByteArraySize;
+ int decryptedTextByteArraySize;
+ int challengingNodeUUIDByteArraySize;
+
+ message.readPrimitive(&certIDByteArraySize);
+ message.readPrimitive(&decryptedTextByteArraySize);
+ message.readPrimitive(&challengingNodeUUIDByteArraySize);
+
+ QByteArray certID(message.read(certIDByteArraySize));
+ QByteArray decryptedText(message.read(decryptedTextByteArraySize));
+ QUuid challengingNode = QUuid::fromRfc4122(message.read(challengingNodeUUIDByteArraySize));
+
+ auto challengeOwnershipReplyPacket = NLPacket::create(PacketType::ChallengeOwnershipReply,
+ certIDByteArraySize + decryptedText.length() + 2 * sizeof(int),
+ true);
+ challengeOwnershipReplyPacket->writePrimitive(certIDByteArraySize);
+ challengeOwnershipReplyPacket->writePrimitive(decryptedText.length());
+ challengeOwnershipReplyPacket->write(certID);
+ challengeOwnershipReplyPacket->write(decryptedText);
+
+ nodeList->sendPacket(std::move(challengeOwnershipReplyPacket), *(nodeList->nodeWithUUID(challengingNode)));
+}
+
+void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode) {
+ // 1. Encrypt a nonce with the owner's public key
+ auto nodeList = DependencyManager::get();
+
+ QByteArray encryptedText = computeEncryptedNonce(certID, ownerKey);
+
+ if (encryptedText == "") {
+ qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce. Deleting entity...";
+ deleteEntity(entityItemID, true);
+ } else {
+ qCDebug(entities) << "Challenging ownership of Cert ID" << certID;
+ // 2. Send the encrypted text to the rezzing avatar's node
+ QByteArray certIDByteArray = certID.toUtf8();
+ int certIDByteArraySize = certIDByteArray.size();
+ auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership,
+ certIDByteArraySize + encryptedText.length() + 2 * sizeof(int),
+ true);
+ challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
+ challengeOwnershipPacket->writePrimitive(encryptedText.length());
+ challengeOwnershipPacket->write(certIDByteArray);
+ challengeOwnershipPacket->write(encryptedText);
+ nodeList->sendPacket(std::move(challengeOwnershipPacket), *senderNode);
+
+ // 3. Kickoff a 10-second timeout timer that deletes the entity if we don't get an ownership response in time
+ if (thread() != QThread::currentThread()) {
+ QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer", Q_ARG(const EntityItemID&, entityItemID));
+ return;
+ } else {
+ startChallengeOwnershipTimer(entityItemID);
+ }
+ }
+}
+
+void EntityTree::sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& encryptedText, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode) {
+ auto nodeList = DependencyManager::get();
+
+ // In this case, Client A is challenging Client B. Client A is inspecting a certified entity that it wants
+ // to make sure belongs to Avatar B.
+ QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122();
+
+ int certIDByteArraySize = certID.length();
+ int encryptedTextByteArraySize = encryptedText.length();
+ int senderNodeUUIDSize = senderNodeUUID.length();
+
+ auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
+ certIDByteArraySize + encryptedTextByteArraySize + senderNodeUUIDSize + 3 * sizeof(int),
+ true);
+ challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
+ challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize);
+ challengeOwnershipPacket->writePrimitive(senderNodeUUIDSize);
+ challengeOwnershipPacket->write(certID);
+ challengeOwnershipPacket->write(encryptedText);
+ challengeOwnershipPacket->write(senderNodeUUID);
+
+ nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(QUuid::fromRfc4122(nodeToChallenge))));
+}
+
void EntityTree::validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation) {
// Start owner verification.
auto nodeList = DependencyManager::get();
@@ -1279,33 +1373,11 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
}
} else {
// Second, challenge ownership of the PoP cert
- // 1. Encrypt a nonce with the owner's public key
- QByteArray encryptedText = computeEncryptedNonce(certID, jsonObject["transfer_recipient_key"].toString());
+ sendChallengeOwnershipPacket(certID,
+ jsonObject["transfer_recipient_key"].toString(),
+ entityItemID,
+ senderNode);
- if (encryptedText == "") {
- qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce. Deleting entity...";
- deleteEntity(entityItemID, true);
- } else {
- // 2. Send the encrypted text to the rezzing avatar's node
- QByteArray certIDByteArray = certID.toUtf8();
- int certIDByteArraySize = certIDByteArray.size();
- auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership,
- certIDByteArraySize + encryptedText.length() + 2 * sizeof(int),
- true);
- challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
- challengeOwnershipPacket->writePrimitive(encryptedText.length());
- challengeOwnershipPacket->write(certIDByteArray);
- challengeOwnershipPacket->write(encryptedText);
- nodeList->sendPacket(std::move(challengeOwnershipPacket), *senderNode);
-
- // 3. Kickoff a 10-second timeout timer that deletes the entity if we don't get an ownership response in time
- if (thread() != QThread::currentThread()) {
- QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer", Q_ARG(const EntityItemID&, entityItemID));
- return;
- } else {
- startChallengeOwnershipTimer(entityItemID);
- }
- }
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityItemID
@@ -1329,7 +1401,12 @@ void EntityTree::processChallengeOwnershipPacket(ReceivedMessage& message, const
emit killChallengeOwnershipTimeoutTimer(certID);
- verifyDecryptedNonce(certID, decryptedText);
+ EntityItemID id;
+ if (!verifyDecryptedNonce(certID, decryptedText, id)) {
+ if (!id.isNull()) {
+ deleteEntity(id, true);
+ }
+ }
}
int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
@@ -1528,7 +1605,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
_totalCreates++;
if (newEntity && isCertified && getIsServer()) {
- if (!newEntity->verifyStaticCertificateProperties()) {
+ if (!properties.verifyStaticCertificateProperties()) {
qCDebug(entities) << "User" << senderNode->getUUID()
<< "attempted to add a certified entity with ID" << entityItemID << "which failed"
<< "static certificate verification.";
diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h
index 518cde9a59..86bfe984f6 100644
--- a/libraries/entities/src/EntityTree.h
+++ b/libraries/entities/src/EntityTree.h
@@ -93,6 +93,8 @@ public:
void fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties);
virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
const SharedNodePointer& senderNode) override;
+ virtual void processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
+ virtual void processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@@ -273,6 +275,9 @@ public:
static const float DEFAULT_MAX_TMP_ENTITY_LIFETIME;
+ QByteArray computeEncryptedNonce(const QString& certID, const QString ownerKey);
+ bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce, EntityItemID& id);
+
signals:
void deletingEntity(const EntityItemID& entityID);
void deletingEntityPointer(EntityItem* entityID);
@@ -375,8 +380,8 @@ protected:
Q_INVOKABLE void startPendingTransferStatusTimer(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode);
private:
- QByteArray computeEncryptedNonce(const QString& certID, const QString ownerKey);
- bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce);
+ void sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode);
+ void sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& encryptedText, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode);
void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation);
};
diff --git a/libraries/entities/src/HazePropertyGroup.cpp b/libraries/entities/src/HazePropertyGroup.cpp
index 996d2e0cd3..f137fca5ce 100644
--- a/libraries/entities/src/HazePropertyGroup.cpp
+++ b/libraries/entities/src/HazePropertyGroup.cpp
@@ -15,19 +15,6 @@
#include "EntityItemProperties.h"
#include "EntityItemPropertiesMacros.h"
-const float HazePropertyGroup::DEFAULT_HAZE_RANGE{ 1000.0f };
-const xColor HazePropertyGroup::DEFAULT_HAZE_COLOR{ 128, 154, 179 }; // Bluish
-const xColor HazePropertyGroup::DEFAULT_HAZE_GLARE_COLOR{ 255, 229, 179 }; // Yellowish
-const float HazePropertyGroup::DEFAULT_HAZE_GLARE_ANGLE{ 20.0 };
-
-const float HazePropertyGroup::DEFAULT_HAZE_CEILING{ 200.0f };
-const float HazePropertyGroup::DEFAULT_HAZE_BASE_REF{ 0.0f };
-
-const float HazePropertyGroup::DEFAULT_HAZE_BACKGROUND_BLEND{ 0.0f };
-
-const float HazePropertyGroup::DEFAULT_HAZE_KEYLIGHT_RANGE{ 1000.0 };
-const float HazePropertyGroup::DEFAULT_HAZE_KEYLIGHT_ALTITUDE{ 200.0f };
-
void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_RANGE, Haze, haze, HazeRange, hazeRange);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_COLOR, Haze, haze, HazeColor, hazeColor);
@@ -306,6 +293,7 @@ EntityPropertyFlags HazePropertyGroup::getEntityProperties(EncodeBitstreamParams
requestedProperties += PROP_HAZE_ENABLE_GLARE;
requestedProperties += PROP_HAZE_GLARE_ANGLE;
+ requestedProperties += PROP_HAZE_ALTITUDE_EFFECT;
requestedProperties += PROP_HAZE_CEILING;
requestedProperties += PROP_HAZE_BASE_REF;
diff --git a/libraries/entities/src/HazePropertyGroup.h b/libraries/entities/src/HazePropertyGroup.h
index cdd36ff7ef..939391caf9 100644
--- a/libraries/entities/src/HazePropertyGroup.h
+++ b/libraries/entities/src/HazePropertyGroup.h
@@ -27,6 +27,19 @@ class OctreePacketData;
class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams;
+static const float INITIAL_HAZE_RANGE{ 1000.0f };
+static const xColor initialHazeGlareColorXcolor{ 255, 229, 179 };
+static const xColor initialHazeColorXcolor{ 128, 154, 179 };
+static const float INITIAL_HAZE_GLARE_ANGLE{ 20.0f };
+
+static const float INITIAL_HAZE_BASE_REFERENCE{ 0.0f };
+static const float INITIAL_HAZE_HEIGHT{ 200.0f };
+
+static const float INITIAL_HAZE_BACKGROUND_BLEND{ 0.0f };
+
+static const float INITIAL_KEY_LIGHT_RANGE{ 1000.0f };
+static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f };
+
class HazePropertyGroup : public PropertyGroup {
public:
// EntityItemProperty related helpers
@@ -74,38 +87,25 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
- static const float DEFAULT_HAZE_RANGE;
- static const xColor DEFAULT_HAZE_COLOR;
- static const xColor DEFAULT_HAZE_GLARE_COLOR;
- static const float DEFAULT_HAZE_GLARE_ANGLE;
-
- static const float DEFAULT_HAZE_CEILING;
- static const float DEFAULT_HAZE_BASE_REF;
-
- static const float DEFAULT_HAZE_BACKGROUND_BLEND;
-
- static const float DEFAULT_HAZE_KEYLIGHT_RANGE;
- static const float DEFAULT_HAZE_KEYLIGHT_ALTITUDE;
-
// Range only parameters
- DEFINE_PROPERTY(PROP_HAZE_RANGE, HazeRange, hazeRange, float, DEFAULT_HAZE_RANGE);
- DEFINE_PROPERTY_REF(PROP_HAZE_COLOR, HazeColor, hazeColor, xColor, DEFAULT_HAZE_COLOR);
- DEFINE_PROPERTY_REF(PROP_HAZE_GLARE_COLOR, HazeGlareColor, hazeGlareColor, xColor, DEFAULT_HAZE_GLARE_COLOR);
+ DEFINE_PROPERTY(PROP_HAZE_RANGE, HazeRange, hazeRange, float, INITIAL_HAZE_RANGE);
+ DEFINE_PROPERTY_REF(PROP_HAZE_COLOR, HazeColor, hazeColor, xColor, initialHazeColorXcolor);
+ DEFINE_PROPERTY_REF(PROP_HAZE_GLARE_COLOR, HazeGlareColor, hazeGlareColor, xColor, initialHazeGlareColorXcolor);
DEFINE_PROPERTY(PROP_HAZE_ENABLE_GLARE, HazeEnableGlare, hazeEnableGlare, bool, false);
- DEFINE_PROPERTY_REF(PROP_HAZE_GLARE_ANGLE, HazeGlareAngle, hazeGlareAngle, float, DEFAULT_HAZE_GLARE_ANGLE);
+ DEFINE_PROPERTY_REF(PROP_HAZE_GLARE_ANGLE, HazeGlareAngle, hazeGlareAngle, float, INITIAL_HAZE_GLARE_ANGLE);
// Altitude parameters
DEFINE_PROPERTY(PROP_HAZE_ALTITUDE_EFFECT, HazeAltitudeEffect, hazeAltitudeEffect, bool, false);
- DEFINE_PROPERTY_REF(PROP_HAZE_CEILING, HazeCeiling, hazeCeiling, float, DEFAULT_HAZE_CEILING);
- DEFINE_PROPERTY_REF(PROP_HAZE_BASE_REF, HazeBaseRef, hazeBaseRef, float, DEFAULT_HAZE_BASE_REF);
+ DEFINE_PROPERTY_REF(PROP_HAZE_CEILING, HazeCeiling, hazeCeiling, float, INITIAL_HAZE_BASE_REFERENCE + INITIAL_HAZE_HEIGHT);
+ DEFINE_PROPERTY_REF(PROP_HAZE_BASE_REF, HazeBaseRef, hazeBaseRef, float, INITIAL_HAZE_BASE_REFERENCE);
// Background (skybox) blend value
- DEFINE_PROPERTY_REF(PROP_HAZE_BACKGROUND_BLEND, HazeBackgroundBlend, hazeBackgroundBlend, float, DEFAULT_HAZE_BACKGROUND_BLEND);
+ DEFINE_PROPERTY_REF(PROP_HAZE_BACKGROUND_BLEND, HazeBackgroundBlend, hazeBackgroundBlend, float, INITIAL_HAZE_BACKGROUND_BLEND);
// hazeDirectional light attenuation
DEFINE_PROPERTY(PROP_HAZE_ATTENUATE_KEYLIGHT, HazeAttenuateKeyLight, hazeAttenuateKeyLight, bool, false);
- DEFINE_PROPERTY_REF(PROP_HAZE_KEYLIGHT_RANGE, HazeKeyLightRange, hazeKeyLightRange, float, DEFAULT_HAZE_KEYLIGHT_RANGE);
- DEFINE_PROPERTY_REF(PROP_HAZE_KEYLIGHT_ALTITUDE, HazeKeyLightAltitude, hazeKeyLightAltitude, float, DEFAULT_HAZE_KEYLIGHT_ALTITUDE);
+ DEFINE_PROPERTY_REF(PROP_HAZE_KEYLIGHT_RANGE, HazeKeyLightRange, hazeKeyLightRange, float, INITIAL_KEY_LIGHT_RANGE);
+ DEFINE_PROPERTY_REF(PROP_HAZE_KEYLIGHT_ALTITUDE, HazeKeyLightAltitude, hazeKeyLightAltitude, float, INITIAL_KEY_LIGHT_ALTITUDE);
};
#endif // hifi_HazePropertyGroup_h
diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp
index 9a1a500a54..4115a606df 100644
--- a/libraries/entities/src/ShapeEntityItem.cpp
+++ b/libraries/entities/src/ShapeEntityItem.cpp
@@ -51,12 +51,12 @@ namespace entity {
}
}
-// shapeCalculator is a hook for external code that knows how to configure a ShapeInfo
+// hullShapeCalculator is a hook for external code that knows how to configure a ShapeInfo
// for given entity::Shape and dimensions
-ShapeEntityItem::ShapeInfoCalculator shapeCalculator = nullptr;
+ShapeEntityItem::ShapeInfoCalculator hullShapeCalculator = nullptr;
void ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator callback) {
- shapeCalculator = callback;
+ hullShapeCalculator = callback;
}
ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@@ -104,6 +104,14 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) {
case entity::Shape::Sphere:
_type = EntityTypes::Sphere;
break;
+ case entity::Shape::Circle:
+ // Circle is implicitly flat so we enforce flat dimensions
+ setDimensions(getDimensions());
+ break;
+ case entity::Shape::Quad:
+ // Quad is implicitly flat so we enforce flat dimensions
+ setDimensions(getDimensions());
+ break;
default:
_type = EntityTypes::Shape;
break;
@@ -196,6 +204,18 @@ void ShapeEntityItem::setColor(const QColor& value) {
setAlpha(value.alpha());
}
+void ShapeEntityItem::setDimensions(const glm::vec3& value) {
+ const float MAX_FLAT_DIMENSION = 0.0001f;
+ if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
+ // enforce flatness in Y
+ glm::vec3 newDimensions = value;
+ newDimensions.y = MAX_FLAT_DIMENSION;
+ EntityItem::setDimensions(newDimensions);
+ } else {
+ EntityItem::setDimensions(value);
+ }
+}
+
bool ShapeEntityItem::supportsDetailedRayIntersection() const {
return _shape == entity::Sphere;
}
@@ -249,19 +269,13 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
const glm::vec3 entityDimensions = getDimensions();
switch (_shape){
- case entity::Shape::Quad: {
- // Not in GeometryCache::buildShapes, unsupported.
- _collisionShapeType = SHAPE_TYPE_ELLIPSOID;
- //TODO WL21389: Add a SHAPE_TYPE_QUAD ShapeType and treat
- // as a special box (later if desired support)
- }
- break;
+ case entity::Shape::Quad:
+ // Quads collide like flat Cubes
case entity::Shape::Cube: {
_collisionShapeType = SHAPE_TYPE_BOX;
}
break;
case entity::Shape::Sphere: {
-
float diameter = entityDimensions.x;
const float MIN_DIAMETER = 0.001f;
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
@@ -275,25 +289,28 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
}
}
break;
- case entity::Shape::Circle: {
- _collisionShapeType = SHAPE_TYPE_CIRCLE;
- }
- break;
+ case entity::Shape::Circle:
+ // Circles collide like flat Cylinders
case entity::Shape::Cylinder: {
- _collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
- // TODO WL21389: determine if rotation is axis-aligned
- //const Transform::Quat & rot = _transform.getRotation();
-
- // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and
- // hull ( or dimensions, need circular cross section)
- // Should allow for minor variance along axes?
-
+ float diameter = entityDimensions.x;
+ const float MIN_DIAMETER = 0.001f;
+ const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
+ if (diameter > MIN_DIAMETER
+ && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
+ _collisionShapeType = SHAPE_TYPE_SPHERE;
+ } else if (hullShapeCalculator) {
+ hullShapeCalculator(this, info);
+ _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
+ } else {
+ // woops, someone forgot to hook up the hullShapeCalculator()!
+ // final fallback is ellipsoid
+ _collisionShapeType = SHAPE_TYPE_ELLIPSOID;
+ }
}
break;
case entity::Shape::Cone: {
- if (shapeCalculator) {
- shapeCalculator(this, info);
- // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
+ if (hullShapeCalculator) {
+ hullShapeCalculator(this, info);
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
@@ -304,9 +321,8 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
case entity::Shape::Triangle:
case entity::Shape::Hexagon:
case entity::Shape::Octagon: {
- if (shapeCalculator) {
- shapeCalculator(this, info);
- // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
+ if (hullShapeCalculator) {
+ hullShapeCalculator(this, info);
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
@@ -318,9 +334,8 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
case entity::Shape::Octahedron:
case entity::Shape::Dodecahedron:
case entity::Shape::Icosahedron: {
- if ( shapeCalculator ) {
- shapeCalculator(this, info);
- // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
+ if ( hullShapeCalculator ) {
+ hullShapeCalculator(this, info);
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
@@ -330,7 +345,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
case entity::Shape::Torus: {
// Not in GeometryCache::buildShapes, unsupported.
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
- //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support)
+ //TODO handle this shape more correctly
}
break;
default: {
diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h
index a88a2098e9..20e36c88e6 100644
--- a/libraries/entities/src/ShapeEntityItem.h
+++ b/libraries/entities/src/ShapeEntityItem.h
@@ -80,6 +80,8 @@ public:
const rgbColor& getColor() const { return _color; }
void setColor(const rgbColor& value);
+ void setDimensions(const glm::vec3& value) override;
+
xColor getXColor() const;
void setColor(const xColor& value);
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 588c1f9386..8b3d22daaf 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -330,103 +330,3 @@ void ZoneEntityItem::setHazeMode(const uint32_t value) {
uint32_t ZoneEntityItem::getHazeMode() const {
return _hazeMode;
}
-
-void ZoneEntityItem::setHazeRange(const float hazeRange) {
- _hazeRange = hazeRange;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeRange() const {
- return _hazeRange;
-}
-
-void ZoneEntityItem::setHazeColor(const xColor hazeColor) {
- _hazeColor = hazeColor;
- _hazePropertiesChanged = true;
-}
-
-xColor ZoneEntityItem::getHazeColor() const {
- return _hazeColor;
-}
-
-void ZoneEntityItem::setHazeGlareColor(const xColor hazeGlareColor) {
- _hazeGlareColor = hazeGlareColor;
- _hazePropertiesChanged = true;
-}
-
-xColor ZoneEntityItem::getHazeGlareColor()const {
- return _hazeGlareColor;
-}
-
-void ZoneEntityItem::setHazeEnableGlare(const bool hazeEnableGlare) {
- _hazeEnableGlare = hazeEnableGlare;
- _hazePropertiesChanged = true;
-}
-
-bool ZoneEntityItem::getHazeEnableGlare()const {
- return _hazeEnableGlare;
-}
-
-void ZoneEntityItem::setHazeGlareAngle(const float hazeGlareAngle) {
- _hazeGlareAngle = hazeGlareAngle;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeGlareAngle() const {
- return _hazeGlareAngle;
-}
-
-void ZoneEntityItem::setHazeCeiling(const float hazeCeiling) {
- _hazeCeiling = hazeCeiling;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeCeiling() const {
- return _hazeCeiling;
-}
-
-void ZoneEntityItem::setHazeBaseRef(const float hazeBaseRef) {
- _hazeBaseRef = hazeBaseRef;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeBaseRef() const {
- return _hazeBaseRef;
-}
-
-void ZoneEntityItem::setHazeBackgroundBlend(const float hazeBackgroundBlend) {
- _hazeBackgroundBlend = hazeBackgroundBlend;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeBackgroundBlend() const {
- return _hazeBackgroundBlend;
-}
-
-void ZoneEntityItem::setHazeAttenuateKeyLight(const bool hazeAttenuateKeyLight) {
- _hazeAttenuateKeyLight = hazeAttenuateKeyLight;
- _hazePropertiesChanged = true;
-}
-
-bool ZoneEntityItem::getHazeAttenuateKeyLight() const {
- return _hazeAttenuateKeyLight;
-}
-
-void ZoneEntityItem::setHazeKeyLightRange(const float hazeKeyLightRange) {
- _hazeKeyLightRange = hazeKeyLightRange;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeKeyLightRange() const {
- return _hazeKeyLightRange;
-}
-
-void ZoneEntityItem::setHazeKeyLightAltitude(const float hazeKeyLightAltitude) {
- _hazeKeyLightAltitude = hazeKeyLightAltitude;
- _hazePropertiesChanged = true;
-}
-
-float ZoneEntityItem::getHazeKeyLightAltitude() const {
- return _hazeKeyLightAltitude;
-}
-
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index ddbb2ed914..46e8a00c24 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -73,32 +73,6 @@ public:
void setHazeMode(const uint32_t value);
uint32_t getHazeMode() const;
- void setHazeRange(const float hazeRange);
- float getHazeRange() const;
- void setHazeColor(const xColor hazeColor);
- xColor getHazeColor() const;
- void setHazeGlareColor(const xColor hazeGlareColor);
- xColor getHazeGlareColor() const;
- void setHazeEnableGlare(const bool hazeEnableGlare);
- bool getHazeEnableGlare() const;
- void setHazeGlareAngle(const float hazeGlareAngle);
- float getHazeGlareAngle() const;
-
- void setHazeCeiling(const float hazeCeiling);
- float getHazeCeiling() const;
- void setHazeBaseRef(const float hazeBaseRef);
- float getHazeBaseRef() const;
-
- void setHazeBackgroundBlend(const float hazeBackgroundBlend);
- float getHazeBackgroundBlend() const;
-
- void setHazeAttenuateKeyLight(const bool hazeAttenuateKeyLight);
- bool getHazeAttenuateKeyLight() const;
- void setHazeKeyLightRange(const float hazeKeyLightRange);
- float getHazeKeyLightRange() const;
- void setHazeKeyLightAltitude(const float hazeKeyLightAltitude);
- float getHazeKeyLightAltitude() const;
-
SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock([&] { return _skyboxProperties; }); }
const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; }
@@ -150,21 +124,6 @@ protected:
uint32_t _hazeMode{ DEFAULT_HAZE_MODE };
- float _hazeRange{ HazePropertyGroup::DEFAULT_HAZE_RANGE };
- xColor _hazeColor{ HazePropertyGroup::DEFAULT_HAZE_COLOR };
- xColor _hazeGlareColor{ HazePropertyGroup::DEFAULT_HAZE_GLARE_COLOR };
- bool _hazeEnableGlare{ false };
- float _hazeGlareAngle{ HazePropertyGroup::DEFAULT_HAZE_GLARE_ANGLE };
-
- float _hazeCeiling{ HazePropertyGroup::DEFAULT_HAZE_CEILING };
- float _hazeBaseRef{ HazePropertyGroup::DEFAULT_HAZE_BASE_REF };
-
- float _hazeBackgroundBlend{ HazePropertyGroup::DEFAULT_HAZE_BACKGROUND_BLEND };
-
- bool _hazeAttenuateKeyLight{ false };
- float _hazeKeyLightRange{ HazePropertyGroup::DEFAULT_HAZE_KEYLIGHT_RANGE };
- float _hazeKeyLightAltitude{ HazePropertyGroup::DEFAULT_HAZE_KEYLIGHT_ALTITUDE };
-
SkyboxPropertyGroup _skyboxProperties;
HazePropertyGroup _hazeProperties;
StagePropertyGroup _stageProperties;
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.h b/libraries/gpu-gl/src/gpu/gl/GLShared.h
index 1b898e5c22..a1cf27afa6 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShared.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLShared.h
@@ -110,6 +110,7 @@ static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = {
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
+ GL_UNSIGNED_BYTE,
GL_UNSIGNED_BYTE
};
diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp
index 192a82dafc..528a2b524b 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp
@@ -212,6 +212,9 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
case gpu::NUINT8:
result = GL_RGBA8;
break;
+ case gpu::NUINT2:
+ result = GL_RGBA2;
+ break;
case gpu::NINT8:
result = GL_RGBA8_SNORM;
break;
@@ -498,6 +501,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
break;
}
case gpu::COMPRESSED:
+ case gpu::NUINT2:
case gpu::NUM_TYPES: { // quiet compiler
Q_UNREACHABLE();
}
@@ -548,6 +552,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
break;
}
case gpu::COMPRESSED:
+ case gpu::NUINT2:
case gpu::NUM_TYPES: { // quiet compiler
Q_UNREACHABLE();
}
@@ -660,6 +665,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.format = GL_RGBA;
texel.internalFormat = GL_RGBA8_SNORM;
break;
+ case gpu::NUINT2:
+ texel.format = GL_RGBA;
+ texel.internalFormat = GL_RGBA2;
+ break;
case gpu::NUINT32:
case gpu::NINT32:
case gpu::COMPRESSED:
diff --git a/libraries/gpu/src/gpu/Format.cpp b/libraries/gpu/src/gpu/Format.cpp
index 7efe4d3ed6..3b153097cf 100644
--- a/libraries/gpu/src/gpu/Format.cpp
+++ b/libraries/gpu/src/gpu/Format.cpp
@@ -19,6 +19,8 @@ const Element Element::COLOR_SRGBA_32{ VEC4, NUINT8, SRGBA };
const Element Element::COLOR_BGRA_32{ VEC4, NUINT8, BGRA };
const Element Element::COLOR_SBGRA_32{ VEC4, NUINT8, SBGRA };
+const Element Element::COLOR_RGBA_2{ VEC4, NUINT2, RGBA };
+
const Element Element::COLOR_COMPRESSED_RED{ TILE4x4, COMPRESSED, COMPRESSED_BC4_RED };
const Element Element::COLOR_COMPRESSED_SRGB { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGB };
const Element Element::COLOR_COMPRESSED_SRGBA_MASK { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGBA };
diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h
index 0654b23581..9d5d2fc49d 100644
--- a/libraries/gpu/src/gpu/Format.h
+++ b/libraries/gpu/src/gpu/Format.h
@@ -38,6 +38,7 @@ enum Type : uint8_t {
NUINT16,
NINT8,
NUINT8,
+ NUINT2,
COMPRESSED,
@@ -309,6 +310,7 @@ public:
static const Element COLOR_SRGBA_32;
static const Element COLOR_BGRA_32;
static const Element COLOR_SBGRA_32;
+ static const Element COLOR_RGBA_2;
static const Element COLOR_R11G11B10;
static const Element COLOR_RGB9E5;
static const Element COLOR_COMPRESSED_RED;
diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp
index f1257e7c83..4fcc9ab0f9 100755
--- a/libraries/gpu/src/gpu/Framebuffer.cpp
+++ b/libraries/gpu/src/gpu/Framebuffer.cpp
@@ -220,7 +220,7 @@ uint32 Framebuffer::getRenderBufferSubresource(uint32 slot) const {
}
}
-bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) {
+bool Framebuffer::assignDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) {
if (isSwapchain()) {
return false;
}
@@ -244,20 +244,59 @@ bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const For
// assign the new one
_depthStencilBuffer = TextureView(texture, subresource, format);
- _bufferMask = ( _bufferMask & ~BUFFER_DEPTHSTENCIL);
- if (texture) {
- if (format.getSemantic() == gpu::DEPTH) {
- _bufferMask |= BUFFER_DEPTH;
- } else if (format.getSemantic() == gpu::STENCIL) {
- _bufferMask |= BUFFER_STENCIL;
- } else if (format.getSemantic() == gpu::DEPTH_STENCIL) {
- _bufferMask |= BUFFER_DEPTHSTENCIL;
- }
- }
-
return true;
}
+bool Framebuffer::setDepthBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) {
+ if (assignDepthStencilBuffer(texture, format, subresource)) {
+ _bufferMask = (_bufferMask & ~BUFFER_DEPTHSTENCIL);
+ if (texture) {
+ if (format.getSemantic() == gpu::DEPTH || format.getSemantic() == gpu::DEPTH_STENCIL) {
+ _bufferMask |= BUFFER_DEPTH;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool Framebuffer::setStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) {
+ if (assignDepthStencilBuffer(texture, format, subresource)) {
+ _bufferMask = (_bufferMask & ~BUFFER_DEPTHSTENCIL);
+ if (texture) {
+ if (format.getSemantic() == gpu::STENCIL || format.getSemantic() == gpu::DEPTH_STENCIL) {
+ _bufferMask |= BUFFER_STENCIL;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) {
+ if (assignDepthStencilBuffer(texture, format, subresource)) {
+ _bufferMask = (_bufferMask & ~BUFFER_DEPTHSTENCIL);
+ if (texture) {
+ if (format.getSemantic() == gpu::DEPTH) {
+ _bufferMask |= BUFFER_DEPTH;
+ } else if (format.getSemantic() == gpu::STENCIL) {
+ _bufferMask |= BUFFER_STENCIL;
+ } else if (format.getSemantic() == gpu::DEPTH_STENCIL) {
+ _bufferMask |= BUFFER_DEPTHSTENCIL;
+ }
+ }
+
+ return true;
+ }
+ return false;
+}
+
TexturePointer Framebuffer::getDepthStencilBuffer() const {
if (isSwapchain()) {
return TexturePointer();
diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h
index b3a500d68f..b3cf0fbba3 100755
--- a/libraries/gpu/src/gpu/Framebuffer.h
+++ b/libraries/gpu/src/gpu/Framebuffer.h
@@ -107,6 +107,8 @@ public:
TexturePointer getRenderBuffer(uint32 slot) const;
uint32 getRenderBufferSubresource(uint32 slot) const;
+ bool setDepthBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
+ bool setStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
bool setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
TexturePointer getDepthStencilBuffer() const;
uint32 getDepthStencilBufferSubresource() const;
@@ -168,6 +170,7 @@ protected:
uint16 _numSamples = 0;
void updateSize(const TexturePointer& texture);
+ bool assignDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource);
// Non exposed
Framebuffer(const Framebuffer& framebuffer) = delete;
diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh
index 9feca4a3c9..b9b8544601 100644
--- a/libraries/gpu/src/gpu/Transform.slh
+++ b/libraries/gpu/src/gpu/Transform.slh
@@ -193,13 +193,17 @@ TransformObject getTransformObject() {
}
<@endfunc@>
-<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@>
- { // transformModelToClipPos
+<@func transformModelToMonoClipPos(cameraTransform, objectTransform, modelPos, clipPos)@>
+ { // transformModelToMonoClipPos
vec4 eyeWAPos;
<$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$>
-
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos;
-
+ }
+<@endfunc@>
+
+<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@>
+ { // transformModelToClipPos
+ <$transformModelToMonoClipPos($cameraTransform$, $objectTransform$, $modelPos$, $clipPos$)$>
<$transformStereoClipsSpace($cameraTransform$, $clipPos$)$>
}
<@endfunc@>
diff --git a/libraries/model/src/model/Haze.cpp b/libraries/model/src/model/Haze.cpp
index 679d4ad3d1..c9c73bcee9 100644
--- a/libraries/model/src/model/Haze.cpp
+++ b/libraries/model/src/model/Haze.cpp
@@ -9,12 +9,30 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include
-#include
#include "Haze.h"
using namespace model;
+const float Haze::INITIAL_HAZE_RANGE{ 1000.0f };
+const float Haze::INITIAL_HAZE_HEIGHT{ 200.0f };
+
+const float Haze::INITIAL_KEY_LIGHT_RANGE{ 1000.0f };
+const float Haze::INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f };
+
+const float Haze::INITIAL_HAZE_BACKGROUND_BLEND{ 0.0f };
+
+const glm::vec3 Haze::INITIAL_HAZE_COLOR{ 0.5f, 0.6f, 0.7f }; // Bluish
+
+const float Haze::INITIAL_HAZE_GLARE_ANGLE{ 20.0f };
+
+const glm::vec3 Haze::INITIAL_HAZE_GLARE_COLOR{ 1.0f, 0.9f, 0.7f };
+
+const float Haze::INITIAL_HAZE_BASE_REFERENCE{ 0.0f };
+
+const float Haze::LOG_P_005{ logf(0.05f)};
+const float Haze::LOG_P_05{ logf(0.5f) };
+
Haze::Haze() {
Parameters parameters;
_hazeParametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters));
@@ -23,7 +41,7 @@ Haze::Haze() {
enum HazeModes {
HAZE_MODE_IS_ACTIVE = 1 << 0,
HAZE_MODE_IS_ALTITUDE_BASED = 1 << 1,
- HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED = 1 << 2,
+ HAZE_MODE_IS_KEYLIGHT_ATTENUATED = 1 << 2,
HAZE_MODE_IS_MODULATE_COLOR = 1 << 3,
HAZE_MODE_IS_ENABLE_LIGHT_BLEND = 1 << 4
};
@@ -55,25 +73,25 @@ void Haze::setHazeEnableGlare(const bool isHazeEnableGlare) {
}
}
-void Haze::setDirectionalLightBlend(const float hazeDirectionalLightBlend) {
+void Haze::setHazeGlareBlend(const float hazeGlareBlend) {
auto& params = _hazeParametersBuffer.get();
- if (params.directionalLightBlend != hazeDirectionalLightBlend) {
- _hazeParametersBuffer.edit().directionalLightBlend = hazeDirectionalLightBlend;
+ if (params.hazeGlareBlend != hazeGlareBlend) {
+ _hazeParametersBuffer.edit().hazeGlareBlend = hazeGlareBlend;
}
}
-void Haze::setDirectionalLightColor(const glm::vec3 hazeDirectionalLightColor) {
+void Haze::setHazeGlareColor(const glm::vec3 hazeGlareColor) {
auto& params = _hazeParametersBuffer.get();
- if (params.directionalLightColor.r != hazeDirectionalLightColor.r) {
- _hazeParametersBuffer.edit().directionalLightColor.r = hazeDirectionalLightColor.r;
+ if (params.hazeGlareColor.r != hazeGlareColor.r) {
+ _hazeParametersBuffer.edit().hazeGlareColor.r = hazeGlareColor.r;
}
- if (params.directionalLightColor.g != hazeDirectionalLightColor.g) {
- _hazeParametersBuffer.edit().directionalLightColor.g = hazeDirectionalLightColor.g;
+ if (params.hazeGlareColor.g != hazeGlareColor.g) {
+ _hazeParametersBuffer.edit().hazeGlareColor.g = hazeGlareColor.g;
}
- if (params.directionalLightColor.b != hazeDirectionalLightColor.b) {
- _hazeParametersBuffer.edit().directionalLightColor.b = hazeDirectionalLightColor.b;
+ if (params.hazeGlareColor.b != hazeGlareColor.b) {
+ _hazeParametersBuffer.edit().hazeGlareColor.b = hazeGlareColor.b;
}
}
void Haze::setHazeActive(const bool isHazeActive) {
@@ -99,10 +117,10 @@ void Haze::setAltitudeBased(const bool isAltitudeBased) {
void Haze::setHazeAttenuateKeyLight(const bool isHazeAttenuateKeyLight) {
auto& params = _hazeParametersBuffer.get();
- if (((params.hazeMode & HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED) == HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED ) && !isHazeAttenuateKeyLight) {
- _hazeParametersBuffer.edit().hazeMode &= ~HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED;
- } else if (((params.hazeMode & HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED) != HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED) && isHazeAttenuateKeyLight) {
- _hazeParametersBuffer.edit().hazeMode |= HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED;
+ if (((params.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) && !isHazeAttenuateKeyLight) {
+ _hazeParametersBuffer.edit().hazeMode &= ~HAZE_MODE_IS_KEYLIGHT_ATTENUATED;
+ } else if (((params.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) != HAZE_MODE_IS_KEYLIGHT_ATTENUATED) && isHazeAttenuateKeyLight) {
+ _hazeParametersBuffer.edit().hazeMode |= HAZE_MODE_IS_KEYLIGHT_ATTENUATED;
}
}
@@ -124,11 +142,11 @@ void Haze::setHazeRangeFactor(const float hazeRangeFactor) {
}
}
-void Haze::setHazeAltitudeFactor(const float hazeAltitudeFactor) {
+void Haze::setHazeAltitudeFactor(const float hazeHeightFactor) {
auto& params = _hazeParametersBuffer.get();
- if (params.hazeAltitudeFactor != hazeAltitudeFactor) {
- _hazeParametersBuffer.edit().hazeAltitudeFactor = hazeAltitudeFactor;
+ if (params.hazeHeightFactor != hazeHeightFactor) {
+ _hazeParametersBuffer.edit().hazeHeightFactor = hazeHeightFactor;
}
}
@@ -156,11 +174,11 @@ void Haze::setHazeBaseReference(const float hazeBaseReference) {
}
}
-void Haze::setHazeBackgroundBlendValue(const float hazeBackgroundBlendValue) {
+void Haze::setHazeBackgroundBlend(const float hazeBackgroundBlend) {
auto& params = _hazeParametersBuffer.get();
- if (params.hazeBackgroundBlendValue != hazeBackgroundBlendValue) {
- _hazeParametersBuffer.edit().hazeBackgroundBlendValue = hazeBackgroundBlendValue;
+ if (params.hazeBackgroundBlend != hazeBackgroundBlend) {
+ _hazeParametersBuffer.edit().hazeBackgroundBlend = hazeBackgroundBlend;
}
}
diff --git a/libraries/model/src/model/Haze.h b/libraries/model/src/model/Haze.h
index fe606bf083..a0cc7c3bc7 100644
--- a/libraries/model/src/model/Haze.h
+++ b/libraries/model/src/model/Haze.h
@@ -12,71 +12,70 @@
#define hifi_model_Haze_h
#include
+#include
+
#include "Transform.h"
#include "NumericalConstants.h"
namespace model {
- const float LOG_P_005 = (float)log(0.05);
- const float LOG_P_05 = (float)log(0.5);
-
- // Derivation (d is distance, b is haze coefficient, f is attenuation, solve for f = 0.05
- // f = exp(-d * b)
- // ln(f) = -d * b
- // b = -ln(f)/d
- inline glm::vec3 convertHazeRangeToHazeRangeFactor(const glm::vec3 hazeRange_m) {
- return glm::vec3(
- -LOG_P_005 / hazeRange_m.x,
- -LOG_P_005 / hazeRange_m.y,
- -LOG_P_005 / hazeRange_m.z);
- }
-
- inline float convertHazeRangeToHazeRangeFactor(const float hazeRange_m) { return (-LOG_P_005 / hazeRange_m); }
-
- inline float convertHazeAltitudeToHazeAltitudeFactor(const float hazeAltitude_m) {
- return -LOG_P_005 / hazeAltitude_m;
- }
-
- // Derivation (s is the proportion of sun blend, a is the angle at which the blend is 50%, solve for m = 0.5
- // s = dot(lookAngle, sunAngle) = cos(a)
- // m = pow(s, p)
- // log(m) = p * log(s)
- // p = log(m) / log(s)
- inline float convertDirectionalLightAngleToPower(const float directionalLightAngle) {
- return LOG_P_05 / (float)log(cos(RADIANS_PER_DEGREE * directionalLightAngle));
- }
-
- const glm::vec3 initialHazeColor{ 0.5f, 0.6f, 0.7f };
- const float initialDirectionalLightAngle_degs{ 30.0f };
-
- const glm::vec3 initialDirectionalLightColor{ 1.0f, 0.9f, 0.7f };
- const float initialHazeBaseReference{ 0.0f };
-
// Haze range is defined here as the range the visibility is reduced by 95%
// Haze altitude is defined here as the altitude (above 0) that the haze is reduced by 95%
- const float initialHazeRange_m{ 150.0f };
- const float initialHazeAltitude_m{ 150.0f };
-
- const float initialHazeKeyLightRange_m{ 150.0f };
- const float initialHazeKeyLightAltitude_m{ 150.0f };
-
- const float initialHazeBackgroundBlendValue{ 0.0f };
-
- const glm::vec3 initialColorModulationFactor{
- convertHazeRangeToHazeRangeFactor(initialHazeRange_m),
- convertHazeRangeToHazeRangeFactor(initialHazeRange_m),
- convertHazeRangeToHazeRangeFactor(initialHazeRange_m)
- };
class Haze {
public:
- using UniformBufferView = gpu::BufferView;
+ // Initial values
+ static const float INITIAL_HAZE_RANGE;
+ static const float INITIAL_HAZE_HEIGHT;
+
+ static const float INITIAL_KEY_LIGHT_RANGE;
+ static const float INITIAL_KEY_LIGHT_ALTITUDE;
+
+ static const float INITIAL_HAZE_BACKGROUND_BLEND;
+
+ static const glm::vec3 INITIAL_HAZE_COLOR;
+
+ static const float INITIAL_HAZE_GLARE_ANGLE;
+
+ static const glm::vec3 INITIAL_HAZE_GLARE_COLOR;
+
+ static const float INITIAL_HAZE_BASE_REFERENCE;
+
+ static const float LOG_P_005;
+ static const float LOG_P_05;
+
+ // Derivation (d is distance, b is haze coefficient, f is attenuation, solve for f = 0.05
+ // f = exp(-d * b)
+ // ln(f) = -d * b
+ // b = -ln(f)/d
+ static inline glm::vec3 convertHazeRangeToHazeRangeFactor(const glm::vec3 hazeRange) {
+ return glm::vec3(
+ -LOG_P_005 / hazeRange.x,
+ -LOG_P_005 / hazeRange.y,
+ -LOG_P_005 / hazeRange.z);
+ }
+
+ // limit range and altitude to no less than 1.0 metres
+ static inline float convertHazeRangeToHazeRangeFactor(const float hazeRange) { return -LOG_P_005 / glm::max(hazeRange, 1.0f); }
+
+ static inline float convertHazeAltitudeToHazeAltitudeFactor(const float hazeHeight) { return -LOG_P_005 / glm::max(hazeHeight, 1.0f); }
+
+ // Derivation (s is the proportion of sun blend, a is the angle at which the blend is 50%, solve for m = 0.5
+ // s = dot(lookAngle, sunAngle) = cos(a)
+ // m = pow(s, p)
+ // log(m) = p * log(s)
+ // p = log(m) / log(s)
+ // limit to 0.1 degrees
+ static inline float convertGlareAngleToPower(const float hazeGlareAngle) {
+ const float GLARE_ANGLE_LIMIT = 0.1f;
+ return LOG_P_05 / logf(cosf(RADIANS_PER_DEGREE * glm::max(GLARE_ANGLE_LIMIT, hazeGlareAngle)));
+ }
Haze();
void setHazeColor(const glm::vec3 hazeColor);
- void setDirectionalLightBlend(const float directionalLightBlend);
+ void setHazeGlareBlend(const float hazeGlareBlend);
- void setDirectionalLightColor(const glm::vec3 directionalLightColor);
+ void setHazeGlareColor(const glm::vec3 hazeGlareColor);
void setHazeBaseReference(const float hazeBaseReference);
void setHazeActive(const bool isHazeActive);
@@ -91,23 +90,24 @@ namespace model {
void setHazeKeyLightRangeFactor(const float hazeKeyLightRange);
void setHazeKeyLightAltitudeFactor(const float hazeKeyLightAltitude);
- void setHazeBackgroundBlendValue(const float hazeBackgroundBlendValue);
+ void setHazeBackgroundBlend(const float hazeBackgroundBlend);
void setZoneTransform(const glm::mat4& zoneTransform);
+ using UniformBufferView = gpu::BufferView;
UniformBufferView getHazeParametersBuffer() const { return _hazeParametersBuffer; }
protected:
class Parameters {
public:
// DO NOT CHANGE ORDER HERE WITHOUT UNDERSTANDING THE std140 LAYOUT
- glm::vec3 hazeColor{ initialHazeColor };
- float directionalLightBlend{ convertDirectionalLightAngleToPower(initialDirectionalLightAngle_degs) };
+ glm::vec3 hazeColor{ INITIAL_HAZE_COLOR };
+ float hazeGlareBlend{ convertGlareAngleToPower(INITIAL_HAZE_GLARE_ANGLE) };
- glm::vec3 directionalLightColor{ initialDirectionalLightColor };
- float hazeBaseReference{ initialHazeBaseReference };
+ glm::vec3 hazeGlareColor{ INITIAL_HAZE_GLARE_COLOR };
+ float hazeBaseReference{ INITIAL_HAZE_BASE_REFERENCE };
- glm::vec3 colorModulationFactor{ initialColorModulationFactor };
+ glm::vec3 colorModulationFactor;
int hazeMode{ 0 }; // bit 0 - set to activate haze attenuation of fragment color
// bit 1 - set to add the effect of altitude to the haze attenuation
// bit 2 - set to activate directional light attenuation mode
@@ -116,14 +116,14 @@ namespace model {
glm::mat4 zoneTransform;
// Amount of background (skybox) to display, overriding the haze effect for the background
- float hazeBackgroundBlendValue{ initialHazeBackgroundBlendValue };
+ float hazeBackgroundBlend{ INITIAL_HAZE_BACKGROUND_BLEND };
// The haze attenuation exponents used by both fragment and directional light attenuation
- float hazeRangeFactor{ convertHazeRangeToHazeRangeFactor(initialHazeRange_m) };
- float hazeAltitudeFactor{ convertHazeAltitudeToHazeAltitudeFactor(initialHazeAltitude_m) };
+ float hazeRangeFactor{ convertHazeRangeToHazeRangeFactor(INITIAL_HAZE_RANGE) };
+ float hazeHeightFactor{ convertHazeAltitudeToHazeAltitudeFactor(INITIAL_HAZE_HEIGHT) };
- float hazeKeyLightRangeFactor{ convertHazeRangeToHazeRangeFactor(initialHazeKeyLightRange_m) };
- float hazeKeyLightAltitudeFactor{ convertHazeAltitudeToHazeAltitudeFactor(initialHazeKeyLightAltitude_m) };
+ float hazeKeyLightRangeFactor{ convertHazeRangeToHazeRangeFactor(INITIAL_KEY_LIGHT_RANGE) };
+ float hazeKeyLightAltitudeFactor{ convertHazeAltitudeToHazeAltitudeFactor(INITIAL_KEY_LIGHT_ALTITUDE) };
Parameters() {}
};
diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp
index cd2312122c..5854162cfa 100644
--- a/libraries/model/src/model/Stage.cpp
+++ b/libraries/model/src/model/Stage.cpp
@@ -256,10 +256,3 @@ void SunSkyStage::setSkybox(const SkyboxPointer& skybox) {
_skybox = skybox;
invalidate();
}
-
-void SunSkyStage::setHazeMode(uint32_t hazeMode) {
- if (hazeMode < COMPONENT_MODE_ITEM_COUNT) {
- _hazeMode = hazeMode;
- invalidate();
- }
-}
diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h
index e009684c62..5f48824568 100644
--- a/libraries/model/src/model/Stage.h
+++ b/libraries/model/src/model/Stage.h
@@ -15,7 +15,6 @@
#include "Light.h"
#include "Skybox.h"
-#include "Haze.h"
namespace model {
@@ -175,65 +174,8 @@ public:
void setSkybox(const SkyboxPointer& skybox);
const SkyboxPointer& getSkybox() const { valid(); return _skybox; }
- // Haze
- enum HazeMode {
- HAZE_OFF,
- HAZE_ON,
-
- NUM_HAZE_MODES
- };
-
- void setHazeMode(uint32_t mode);
- uint32_t getHazeMode() const { return _hazeMode; }
-
- void setHazeRange(float hazeRange) { _hazeRange = hazeRange; }
- float getHazeRange() const { return _hazeRange; }
- void setHazeColor(const xColor hazeColor) { _hazeColor = hazeColor; }
- xColor getHazeColor() { return _hazeColor; }
- void setHazeGlareColor(const xColor hazeGlareColor) { _hazeGlareColor = hazeGlareColor; }
- xColor getHazeGlareColor() const { return _hazeGlareColor; }
- void setHazeEnableGlare(bool hazeEnableGlare) { _hazeEnableGlare = hazeEnableGlare; }
- bool getHazeEnableGlare() const { return _hazeEnableGlare; }
- void setHazeGlareAngle(float hazeGlareAngle) { _hazeGlareAngle = hazeGlareAngle; }
- float getHazeGlareAngle() const { return _hazeGlareAngle; }
-
- void setHazeAltitudeEffect(bool hazeAltitudeEffect) { _hazeAltitudeEffect = hazeAltitudeEffect; }
- bool getHazeAltitudeEffect() const { return _hazeAltitudeEffect; }
- void setHazeCeiling(float hazeCeiling) { _hazeCeiling = hazeCeiling; }
- float getHazeCeiling() const { return _hazeCeiling; }
- void setHazeBaseRef(float hazeBaseRef) { _hazeBaseRef = hazeBaseRef; }
- float getHazeBaseRef() const { return _hazeBaseRef; }
-
- void setHazeBackgroundBlend(float hazeBackgroundBlend) { _hazeBackgroundBlend = hazeBackgroundBlend; }
- float getHazeBackgroundBlend() const { return _hazeBackgroundBlend; }
-
- void setHazeAttenuateKeyLight(bool hazeAttenuateKeyLight) { _hazeAttenuateKeyLight = hazeAttenuateKeyLight; }
- bool getHazeAttenuateKeyLight() const { return _hazeAttenuateKeyLight; }
- void setHazeKeyLightRange(float hazeKeyLightRange) { _hazeKeyLightRange = hazeKeyLightRange; }
- float getHazeKeyLightRange() const { return _hazeKeyLightRange; }
- void setHazeKeyLightAltitude(float hazeKeyLightAltitude) { _hazeKeyLightAltitude = hazeKeyLightAltitude; }
- float getHazeKeyLightAltitude() const { return _hazeKeyLightAltitude; }
-
protected:
BackgroundMode _backgroundMode = SKY_DEFAULT;
-
- uint8_t _hazeMode = (uint8_t)HAZE_OFF;
-
- float _hazeRange;
- xColor _hazeColor;
- xColor _hazeGlareColor;
- bool _hazeEnableGlare;
- float _hazeGlareAngle;
-
- bool _hazeAltitudeEffect;
- float _hazeCeiling;
- float _hazeBaseRef;
-
- float _hazeBackgroundBlend;
-
- bool _hazeAttenuateKeyLight;
- float _hazeKeyLightRange;
- float _hazeKeyLightAltitude;
LightPointer _sunLight;
mutable SkyboxPointer _skybox;
diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp
index 1a51440e91..b884dcba17 100644
--- a/libraries/networking/src/AddressManager.cpp
+++ b/libraries/networking/src/AddressManager.cpp
@@ -667,8 +667,11 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
qCDebug(networking) << "Orientation parsed from lookup string is invalid. Will not use for location change.";
}
}
-
- emit locationChangeRequired(newPosition, orientationChanged, newOrientation, shouldFace);
+
+ emit locationChangeRequired(newPosition, orientationChanged,
+ LookupTrigger::VisitUserFromPAL ? cancelOutRollAndPitch(newOrientation): newOrientation,
+ shouldFace
+ );
} else {
qCDebug(networking) << "Could not jump to position from lookup string because it has an invalid value.";
@@ -732,13 +735,14 @@ bool AddressManager::setDomainInfo(const QString& hostname, quint16 port, Lookup
return hostChanged;
}
-void AddressManager::goToUser(const QString& username) {
+void AddressManager::goToUser(const QString& username, bool shouldMatchOrientation) {
QString formattedUsername = QUrl::toPercentEncoding(username);
- // for history storage handling we remember how this lookup was trigged - for a username it's always user input
+ // for history storage handling we remember how this lookup was triggered - for a username it's always user input
QVariantMap requestParams;
- requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast(LookupTrigger::UserInput));
-
+ requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast(
+ shouldMatchOrientation ? LookupTrigger::UserInput : LookupTrigger::VisitUserFromPAL
+ ));
// this is a username - pull the captured name and lookup that user's location
DependencyManager::get()->sendRequest(GET_USER_LOCATION.arg(formattedUsername),
AccountManagerAuth::Optional,
@@ -840,8 +844,8 @@ void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
// and do not but it into the back stack
_forwardStack.push(currentAddress());
} else {
- if (trigger == LookupTrigger::UserInput) {
- // anyime the user has manually looked up an address we know we should clear the forward stack
+ if (trigger == LookupTrigger::UserInput || trigger == LookupTrigger::VisitUserFromPAL) {
+ // anyime the user has actively triggered an address we know we should clear the forward stack
_forwardStack.clear();
emit goForwardPossible(false);
diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h
index 366fc5dfab..2f3d896509 100644
--- a/libraries/networking/src/AddressManager.h
+++ b/libraries/networking/src/AddressManager.h
@@ -54,7 +54,8 @@ public:
DomainPathResponse,
Internal,
AttemptedRefresh,
- Suggestions
+ Suggestions,
+ VisitUserFromPAL
};
bool isConnected();
@@ -93,7 +94,7 @@ public slots:
void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger); }
void goToEntry(LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(DEFAULT_HIFI_ADDRESS, trigger); }
- void goToUser(const QString& username);
+ void goToUser(const QString& username, bool shouldMatchOrientation = true);
void refreshPreviousLookup();
diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h
index 0bb0cee5d2..0c210e4360 100644
--- a/libraries/networking/src/NetworkingConstants.h
+++ b/libraries/networking/src/NetworkingConstants.h
@@ -16,8 +16,8 @@
namespace NetworkingConstants {
// If you want to use STAGING instead of STABLE,
- // don't forget to ALSO change the Domain Server Metaverse Server URL, which is at the top of:
- // \domain-server\resources\web\settings\js\settings.js
+ // don't forget to ALSO change the Domain Server Metaverse Server URL inside of:
+ // \domain-server\resources\web\js\shared.js
const QUrl METAVERSE_SERVER_URL_STABLE("https://metaverse.highfidelity.com");
const QUrl METAVERSE_SERVER_URL_STAGING("https://staging.highfidelity.com");
const QUrl METAVERSE_SERVER_URL = METAVERSE_SERVER_URL_STABLE;
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index e00b4139c3..21b4ae8878 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -124,6 +124,8 @@ public:
OctreeFileReplacementFromUrl,
ChallengeOwnership,
EntityScriptCallMethod,
+ ChallengeOwnershipRequest,
+ ChallengeOwnershipReply,
NUM_PACKET_TYPE
};
diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h
index 2761dffb1b..ec6a0e810d 100644
--- a/libraries/octree/src/Octree.h
+++ b/libraries/octree/src/Octree.h
@@ -212,6 +212,8 @@ public:
virtual bool handlesEditPacketType(PacketType packetType) const { return false; }
virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
const SharedNodePointer& sourceNode) { return 0; }
+ virtual void processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; }
+ virtual void processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; }
virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; }
virtual bool recurseChildrenWithData() const { return true; }
diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp
index 493dfdcff5..b5b4a161ef 100644
--- a/libraries/octree/src/OctreePacketData.cpp
+++ b/libraries/octree/src/OctreePacketData.cpp
@@ -68,8 +68,8 @@ bool OctreePacketData::append(const unsigned char* data, int length) {
_dirty = true;
}
- const bool wantDebug = false;
- if (wantDebug && !success) {
+ #ifdef WANT_DEBUG
+ if (!success) {
qCDebug(octree) << "OctreePacketData::append(const unsigned char* data, int length) FAILING....";
qCDebug(octree) << " length=" << length;
qCDebug(octree) << " _bytesAvailable=" << _bytesAvailable;
@@ -77,6 +77,7 @@ bool OctreePacketData::append(const unsigned char* data, int length) {
qCDebug(octree) << " _targetSize=" << _targetSize;
qCDebug(octree) << " _bytesReserved=" << _bytesReserved;
}
+ #endif
return success;
}
@@ -647,6 +648,13 @@ void OctreePacketData::debugContent() {
printf("\n");
}
+void OctreePacketData::debugBytes() {
+ qCDebug(octree) << " _bytesAvailable=" << _bytesAvailable;
+ qCDebug(octree) << " _bytesInUse=" << _bytesInUse;
+ qCDebug(octree) << " _targetSize=" << _targetSize;
+ qCDebug(octree) << " _bytesReserved=" << _bytesReserved;
+}
+
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QString& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));
diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h
index ed6a49941b..37c171504b 100644
--- a/libraries/octree/src/OctreePacketData.h
+++ b/libraries/octree/src/OctreePacketData.h
@@ -240,6 +240,7 @@ public:
/// displays contents for debugging
void debugContent();
+ void debugBytes();
static quint64 getCompressContentTime() { return _compressContentTime; } /// total time spent compressing content
static quint64 getCompressContentCalls() { return _compressContentCalls; } /// total calls to compress content
diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h
index 81a63a696c..bbd0350baf 100644
--- a/libraries/octree/src/OctreeQuery.h
+++ b/libraries/octree/src/OctreeQuery.h
@@ -12,21 +12,7 @@
#ifndef hifi_OctreeQuery_h
#define hifi_OctreeQuery_h
-/* VS2010 defines stdint.h, but not inttypes.h */
-#if defined(_MSC_VER)
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long quint64;
-#define PRId64 "I64d"
-#else
#include
-#endif
-
#include
#include
@@ -45,7 +31,7 @@ public:
virtual ~OctreeQuery() {}
int getBroadcastData(unsigned char* destinationBuffer);
- int parseData(ReceivedMessage& message) override;
+ virtual int parseData(ReceivedMessage& message) override;
// getters for camera details
const glm::vec3& getCameraPosition() const { return _cameraPosition; }
diff --git a/libraries/octree/src/OctreeQueryNode.cpp b/libraries/octree/src/OctreeQueryNode.cpp
index c26b4ce77b..941bb6b536 100644
--- a/libraries/octree/src/OctreeQueryNode.cpp
+++ b/libraries/octree/src/OctreeQueryNode.cpp
@@ -18,6 +18,12 @@
#include
#include
+int OctreeQueryNode::parseData(ReceivedMessage& message) {
+ // set our flag to indicate that we've parsed for this query at least once
+ _hasReceivedFirstQuery = true;
+
+ return OctreeQuery::parseData(message);
+}
void OctreeQueryNode::nodeKilled() {
_isShuttingDown = true;
diff --git a/libraries/octree/src/OctreeQueryNode.h b/libraries/octree/src/OctreeQueryNode.h
index fd89a89949..fac118c628 100644
--- a/libraries/octree/src/OctreeQueryNode.h
+++ b/libraries/octree/src/OctreeQueryNode.h
@@ -35,6 +35,8 @@ public:
void init(); // called after creation to set up some virtual items
virtual PacketType getMyPacketType() const = 0;
+ virtual int parseData(ReceivedMessage& message) override;
+
void resetOctreePacket(); // resets octree packet to after "V" header
void writeToPacket(const unsigned char* buffer, unsigned int bytes); // writes to end of packet
@@ -106,6 +108,8 @@ public:
bool shouldForceFullScene() const { return _shouldForceFullScene; }
void setShouldForceFullScene(bool shouldForceFullScene) { _shouldForceFullScene = shouldForceFullScene; }
+ bool hasReceivedFirstQuery() const { return _hasReceivedFirstQuery; }
+
private:
OctreeQueryNode(const OctreeQueryNode &);
OctreeQueryNode& operator= (const OctreeQueryNode&);
@@ -153,6 +157,8 @@ private:
QJsonObject _lastCheckJSONParameters;
bool _shouldForceFullScene { false };
+
+ bool _hasReceivedFirstQuery { false };
};
#endif // hifi_OctreeQueryNode_h
diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp
index cd0fba848a..f484f32fdf 100644
--- a/libraries/physics/src/ShapeFactory.cpp
+++ b/libraries/physics/src/ShapeFactory.cpp
@@ -16,6 +16,40 @@
#include "ShapeFactory.h"
#include "BulletUtil.h"
+
+class StaticMeshShape : public btBvhTriangleMeshShape {
+public:
+ StaticMeshShape() = delete;
+
+ StaticMeshShape(btTriangleIndexVertexArray* dataArray)
+ : btBvhTriangleMeshShape(dataArray, true), _dataArray(dataArray) {
+ assert(_dataArray);
+ }
+
+ ~StaticMeshShape() {
+ assert(_dataArray);
+ IndexedMeshArray& meshes = _dataArray->getIndexedMeshArray();
+ for (int32_t i = 0; i < meshes.size(); ++i) {
+ btIndexedMesh mesh = meshes[i];
+ mesh.m_numTriangles = 0;
+ delete [] mesh.m_triangleIndexBase;
+ mesh.m_triangleIndexBase = nullptr;
+ mesh.m_numVertices = 0;
+ delete [] mesh.m_vertexBase;
+ mesh.m_vertexBase = nullptr;
+ }
+ meshes.clear();
+ delete _dataArray;
+ _dataArray = nullptr;
+ }
+
+private:
+ // the StaticMeshShape owns its vertex/index data
+ btTriangleIndexVertexArray* _dataArray;
+};
+
+// the dataArray must be created before we create the StaticMeshShape
+
// These are the same normalized directions used by the btShapeHull class.
// 12 points for the face centers of a dodecahedron plus another 30 points
// for the midpoints the edges, for a total of 42.
@@ -230,23 +264,6 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) {
return dataArray;
}
-// util method
-void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) {
- assert(dataArray);
- IndexedMeshArray& meshes = dataArray->getIndexedMeshArray();
- for (int32_t i = 0; i < meshes.size(); ++i) {
- btIndexedMesh mesh = meshes[i];
- mesh.m_numTriangles = 0;
- delete [] mesh.m_triangleIndexBase;
- mesh.m_triangleIndexBase = nullptr;
- mesh.m_numVertices = 0;
- delete [] mesh.m_vertexBase;
- mesh.m_vertexBase = nullptr;
- }
- meshes.clear();
- delete dataArray;
-}
-
const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
btCollisionShape* shape = NULL;
int type = info.getType();
@@ -431,7 +448,6 @@ void ShapeFactory::deleteShape(const btCollisionShape* shape) {
assert(shape);
// ShapeFactory is responsible for deleting all shapes, even the const ones that are stored
// in the ShapeManager, so we must cast to non-const here when deleting.
- // so we cast to non-const here when deleting memory.
btCollisionShape* nonConstShape = const_cast(shape);
if (nonConstShape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) {
btCompoundShape* compoundShape = static_cast(nonConstShape);
@@ -448,14 +464,3 @@ void ShapeFactory::deleteShape(const btCollisionShape* shape) {
}
delete nonConstShape;
}
-
-// the dataArray must be created before we create the StaticMeshShape
-ShapeFactory::StaticMeshShape::StaticMeshShape(btTriangleIndexVertexArray* dataArray)
-: btBvhTriangleMeshShape(dataArray, true), _dataArray(dataArray) {
- assert(dataArray);
-}
-
-ShapeFactory::StaticMeshShape::~StaticMeshShape() {
- deleteStaticMeshArray(_dataArray);
- _dataArray = nullptr;
-}
diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h
index 2bf79f390c..704a7804b3 100644
--- a/libraries/physics/src/ShapeFactory.h
+++ b/libraries/physics/src/ShapeFactory.h
@@ -17,25 +17,11 @@
#include
-// translates between ShapeInfo and btShape
+// The ShapeFactory assembles and correctly disassembles btCollisionShapes.
namespace ShapeFactory {
const btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
void deleteShape(const btCollisionShape* shape);
-
- //btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info);
- //void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray);
-
- class StaticMeshShape : public btBvhTriangleMeshShape {
- public:
- StaticMeshShape() = delete;
- StaticMeshShape(btTriangleIndexVertexArray* dataArray);
- ~StaticMeshShape();
-
- private:
- // the StaticMeshShape owns its vertex/index data
- btTriangleIndexVertexArray* _dataArray;
- };
};
#endif // hifi_ShapeFactory_h
diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp
index 77716f671b..97b9e5dab1 100644
--- a/libraries/physics/src/ShapeManager.cpp
+++ b/libraries/physics/src/ShapeManager.cpp
@@ -32,7 +32,7 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
if (info.getType() == SHAPE_TYPE_NONE) {
return nullptr;
}
- DoubleHashKey key = info.getHash();
+ HashKey key = info.getHash();
ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef) {
shapeRef->refCount++;
@@ -50,7 +50,7 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
}
// private helper method
-bool ShapeManager::releaseShapeByKey(const DoubleHashKey& key) {
+bool ShapeManager::releaseShapeByKey(const HashKey& key) {
ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef) {
if (shapeRef->refCount > 0) {
@@ -88,7 +88,7 @@ bool ShapeManager::releaseShape(const btCollisionShape* shape) {
void ShapeManager::collectGarbage() {
int numShapes = _pendingGarbage.size();
for (int i = 0; i < numShapes; ++i) {
- DoubleHashKey& key = _pendingGarbage[i];
+ HashKey& key = _pendingGarbage[i];
ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef && shapeRef->refCount == 0) {
ShapeFactory::deleteShape(shapeRef->shape);
@@ -99,7 +99,7 @@ void ShapeManager::collectGarbage() {
}
int ShapeManager::getNumReferences(const ShapeInfo& info) const {
- DoubleHashKey key = info.getHash();
+ HashKey key = info.getHash();
const ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef) {
return shapeRef->refCount;
diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h
index ed81b5e8f8..d75bb1dc4a 100644
--- a/libraries/physics/src/ShapeManager.h
+++ b/libraries/physics/src/ShapeManager.h
@@ -17,7 +17,29 @@
#include
-#include "DoubleHashKey.h"
+#include "HashKey.h"
+
+// The ShapeManager handles the ref-counting on shared shapes:
+//
+// Each object added to the physics simulation gets a corresponding btRigidBody.
+// The body has a btCollisionShape that represents the contours of its collision
+// surface. Multiple bodies may have the same shape. Rather than create a unique
+// btCollisionShape instance for every body with a particular shape we can instead
+// use a single shape instance for all of the bodies. This is called "shape
+// sharing".
+//
+// When body needs a new shape a description of ths shape (ShapeInfo) is assembled
+// and a request is sent to the ShapeManager for a corresponding btCollisionShape
+// pointer. The ShapeManager will compute a hash of the ShapeInfo's data and use
+// that to find the shape in its map. If it finds one it increments the ref-count
+// and returns the pointer. If not it asks the ShapeFactory to create it, adds an
+// entry in the map with a ref-count of 1, and returns the pointer.
+//
+// When a body stops using a shape the ShapeManager must be informed so it can
+// decrement its ref-count. When a ref-count drops to zero the ShapeManager
+// doesn't delete it right away. Instead it puts the shape's key on a list delete
+// later. When that list grows big enough the ShapeManager will remove any matching
+// entries that still have zero ref-count.
class ShapeManager {
public:
@@ -41,18 +63,19 @@ public:
bool hasShape(const btCollisionShape* shape) const;
private:
- bool releaseShapeByKey(const DoubleHashKey& key);
+ bool releaseShapeByKey(const HashKey& key);
class ShapeReference {
public:
int refCount;
const btCollisionShape* shape;
- DoubleHashKey key;
+ HashKey key;
ShapeReference() : refCount(0), shape(nullptr) {}
};
- btHashMap _shapeMap;
- btAlignedObjectArray _pendingGarbage;
+ // btHashMap is required because it supports memory alignment of the btCollisionShapes
+ btHashMap _shapeMap;
+ btAlignedObjectArray _pendingGarbage;
};
#endif // hifi_ShapeManager_h
diff --git a/libraries/render-utils/src/BackgroundStage.cpp b/libraries/render-utils/src/BackgroundStage.cpp
index 2ea3683c4a..2d2c0ed150 100644
--- a/libraries/render-utils/src/BackgroundStage.cpp
+++ b/libraries/render-utils/src/BackgroundStage.cpp
@@ -14,6 +14,7 @@
#include
std::string BackgroundStage::_stageName { "BACKGROUND_STAGE"};
+const BackgroundStage::Index BackgroundStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const {
auto found = _backgroundMap.find(background);
diff --git a/libraries/render-utils/src/BackgroundStage.h b/libraries/render-utils/src/BackgroundStage.h
index eab7c94f0d..4e0e09db5b 100644
--- a/libraries/render-utils/src/BackgroundStage.h
+++ b/libraries/render-utils/src/BackgroundStage.h
@@ -27,7 +27,7 @@ public:
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
- static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
+ static const Index INVALID_INDEX;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using BackgroundPointer = model::SunSkyStagePointer;
diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp
index 07628904f1..3bb2aa2ef9 100644
--- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp
+++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp
@@ -20,11 +20,22 @@ using namespace render;
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
-void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(
- const Transform& renderTransform,
- const gpu::BufferPointer& buffer) {
+void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterMatrices, const std::vector& cauterizedClusterMatrices) {
+ ModelMeshPartPayload::updateClusterBuffer(clusterMatrices);
+
+ if (cauterizedClusterMatrices.size() > 1) {
+ if (!_cauterizedClusterBuffer) {
+ _cauterizedClusterBuffer = std::make_shared(cauterizedClusterMatrices.size() * sizeof(glm::mat4),
+ (const gpu::Byte*) cauterizedClusterMatrices.data());
+ } else {
+ _cauterizedClusterBuffer->setSubData(0, cauterizedClusterMatrices.size() * sizeof(glm::mat4),
+ (const gpu::Byte*) cauterizedClusterMatrices.data());
+ }
+ }
+}
+
+void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) {
_cauterizedTransform = renderTransform;
- _cauterizedClusterBuffer = buffer;
}
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h
index 5e3135ea84..1c98f5abf3 100644
--- a/libraries/render-utils/src/CauterizedMeshPartPayload.h
+++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h
@@ -15,7 +15,9 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload {
public:
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
- void updateTransformForCauterizedMesh(const Transform& renderTransform, const gpu::BufferPointer& buffer);
+ void updateClusterBuffer(const std::vector& clusterMatrices, const std::vector& cauterizedClusterMatrices);
+
+ void updateTransformForCauterizedMesh(const Transform& renderTransform);
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index 47ada457a0..30121a232d 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -48,7 +48,7 @@ void CauterizedModel::createVisibleRenderItemSet() {
const auto& meshes = _renderGeometry->getMeshes();
// all of our mesh vectors must match in size
- if ((int)meshes.size() != _meshStates.size()) {
+ if (meshes.size() != _meshStates.size()) {
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
return;
}
@@ -57,6 +57,7 @@ void CauterizedModel::createVisibleRenderItemSet() {
Q_ASSERT(_modelMeshRenderItems.isEmpty());
_modelMeshRenderItems.clear();
+ _modelMeshRenderItemShapes.clear();
Transform transform;
transform.setTranslation(_translation);
@@ -80,6 +81,7 @@ void CauterizedModel::createVisibleRenderItemSet() {
for (int partIndex = 0; partIndex < numParts; partIndex++) {
auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset);
_modelMeshRenderItems << std::static_pointer_cast(ptr);
+ _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++;
}
}
@@ -102,7 +104,7 @@ void CauterizedModel::updateClusterMatrices() {
_needsUpdateClusterMatrices = false;
const FBXGeometry& geometry = getFBXGeometry();
- for (int i = 0; i < _meshStates.size(); i++) {
+ for (int i = 0; i < (int)_meshStates.size(); i++) {
Model::MeshState& state = _meshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) {
@@ -110,17 +112,6 @@ void CauterizedModel::updateClusterMatrices() {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
}
-
- // Once computed the cluster matrices, update the buffer(s)
- if (mesh.clusters.size() > 1) {
- if (!state.clusterBuffer) {
- state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4),
- (const gpu::Byte*) state.clusterMatrices.constData());
- } else {
- state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4),
- (const gpu::Byte*) state.clusterMatrices.constData());
- }
- }
}
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
@@ -143,17 +134,6 @@ void CauterizedModel::updateClusterMatrices() {
}
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
}
-
- if (!_cauterizeBoneSet.empty() && (state.clusterMatrices.size() > 1)) {
- if (!state.clusterBuffer) {
- state.clusterBuffer =
- std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4),
- (const gpu::Byte*) state.clusterMatrices.constData());
- } else {
- state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4),
- (const gpu::Byte*) state.clusterMatrices.constData());
- }
- }
}
}
@@ -181,11 +161,11 @@ void CauterizedModel::updateRenderItems() {
// queue up this work for later processing, at the end of update and just before rendering.
// the application will ensure only the last lambda is actually invoked.
void* key = (void*)this;
- std::weak_ptr weakSelf = shared_from_this();
- AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() {
+ std::weak_ptr weakSelf = std::dynamic_pointer_cast(shared_from_this());
+ AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() {
// do nothing, if the model has already been destroyed.
auto self = weakSelf.lock();
- if (!self) {
+ if (!self || !self->isLoaded()) {
return;
}
@@ -198,37 +178,28 @@ void CauterizedModel::updateRenderItems() {
modelTransform.setTranslation(self->getTranslation());
modelTransform.setRotation(self->getRotation());
- Transform scaledModelTransform(modelTransform);
- scaledModelTransform.setScale(scale);
-
- uint32_t deleteGeometryCounter = self->getGeometryCounter();
-
render::Transaction transaction;
- QList keys = self->getRenderItems().keys();
- foreach (auto itemID, keys) {
- transaction.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) {
- ModelPointer model = data._model.lock();
- if (model && model->isLoaded()) {
- // Ensure the model geometry was not reset between frames
- if (deleteGeometryCounter == model->getGeometryCounter()) {
- // this stuff identical to what happens in regular Model
- const Model::MeshState& state = model->getMeshState(data._meshIndex);
- Transform renderTransform = modelTransform;
- if (state.clusterMatrices.size() == 1) {
- renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0]));
- }
- data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer);
+ for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) {
- // this stuff for cauterized mesh
- CauterizedModel* cModel = static_cast(model.get());
- const Model::MeshState& cState = cModel->getCauterizeMeshState(data._meshIndex);
- renderTransform = modelTransform;
- if (cState.clusterMatrices.size() == 1) {
- renderTransform = modelTransform.worldTransform(Transform(cState.clusterMatrices[0]));
- }
- data.updateTransformForCauterizedMesh(renderTransform, cState.clusterBuffer);
- }
+ auto itemID = self->_modelMeshRenderItemIDs[i];
+ auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
+ auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
+ auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices);
+
+ transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized](CauterizedMeshPartPayload& data) {
+ data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized);
+
+ Transform renderTransform = modelTransform;
+ if (clusterMatrices.size() == 1) {
+ renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
}
+ data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
+
+ renderTransform = modelTransform;
+ if (clusterMatricesCauterized.size() == 1) {
+ renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0]));
+ }
+ data.updateTransformForCauterizedMesh(renderTransform);
});
}
diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh
index cc20f6335e..f70daf1e77 100644
--- a/libraries/render-utils/src/DeferredGlobalLight.slh
+++ b/libraries/render-utils/src/DeferredGlobalLight.slh
@@ -134,7 +134,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
color += directionalSpecular;
// Attenuate the light if haze effect selected
- if ((hazeParams.hazeMode & HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED) == HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED) {
+ if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) {
// Directional light attenuation is simulated by assuming the light source is at a fixed height above the
// fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height
//
@@ -147,8 +147,8 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
// Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen)
float height_95p = 2000.0;
- if (hazeParams.hazeAltitudeFactorKeyLight > 0.0f) {
- height_95p = -log(0.05) / hazeParams.hazeAltitudeFactorKeyLight;
+ if (hazeParams.hazeKeyLightAltitudeFactor > 0.0f) {
+ height_95p = -log(0.05) / hazeParams.hazeKeyLightAltitudeFactor;
}
// Note that the sine will always be positive
@@ -168,8 +168,8 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
// Integration is from the fragment towards the light source
// Note that the haze base reference affects only the haze density as function of altitude
float hazeDensityDistribution =
- hazeParams.hazeRangeFactorKeyLight *
- exp(-hazeParams.hazeAltitudeFactorKeyLight * (worldFragPos.y - hazeParams.hazeBaseReference));
+ hazeParams.hazeKeyLightRangeFactor *
+ exp(-hazeParams.hazeKeyLightAltitudeFactor * (worldFragPos.y - hazeParams.hazeBaseReference));
float hazeIntegral = hazeDensityDistribution * distance;
diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp
index bf254ce80e..f694a93033 100644
--- a/libraries/render-utils/src/DrawHaze.cpp
+++ b/libraries/render-utils/src/DrawHaze.cpp
@@ -21,32 +21,16 @@
#include "Haze_frag.h"
-void HazeConfig::setHazeColorR(const float value) {
- hazeColorR = value;
+void HazeConfig::setHazeColor(const glm::vec3 value) {
+ hazeColor = value;
}
-void HazeConfig::setHazeColorG(const float value) {
- hazeColorG = value;
+void HazeConfig::setHazeGlareAngle(const float value) {
+ hazeGlareAngle = value;
}
-void HazeConfig::setHazeColorB(const float value) {
- hazeColorB = value;
-}
-
-void HazeConfig::setDirectionalLightAngle_degs(const float value) {
- hazeDirectionalLightAngle_degs = value;
-}
-
-void HazeConfig::setDirectionalLightColorR(const float value) {
- hazeDirectionalLightColorR = value;
-}
-
-void HazeConfig::setDirectionalLightColorG(const float value) {
- hazeDirectionalLightColorG = value;
-}
-
-void HazeConfig::setDirectionalLightColorB(const float value) {
- hazeDirectionalLightColorB = value;
+void HazeConfig::setHazeGlareColor(const glm::vec3 value) {
+ hazeGlareColor = value;
}
void HazeConfig::setHazeBaseReference(const float value) {
@@ -73,24 +57,24 @@ void HazeConfig::setHazeEnableGlare(const bool active) {
isHazeEnableGlare = active;
}
-void HazeConfig::setHazeRange_m(const float value) {
- hazeRange_m = value;
+void HazeConfig::setHazeRange(const float value) {
+ hazeRange = value;
}
-void HazeConfig::setHazeAltitude_m(const float value) {
- hazeAltitude_m = value;
+void HazeConfig::setHazeAltitude(const float value) {
+ hazeHeight = value;
}
-void HazeConfig::setHazeKeyLightRange_m(const float value) {
- hazeKeyLightRange_m = value;
+void HazeConfig::setHazeKeyLightRange(const float value) {
+ hazeKeyLightRange = value;
}
-void HazeConfig::setHazeKeyLightAltitude_m(const float value) {
- hazeKeyLightAltitude_m = value;
+void HazeConfig::setHazeKeyLightAltitude(const float value) {
+ hazeKeyLightAltitude = value;
}
-void HazeConfig::setHazeBackgroundBlendValue(const float value) {
- hazeBackgroundBlendValue = value;
+void HazeConfig::setHazeBackgroundBlend(const float value) {
+ hazeBackgroundBlend = value;
}
MakeHaze::MakeHaze() {
@@ -98,10 +82,10 @@ MakeHaze::MakeHaze() {
}
void MakeHaze::configure(const Config& config) {
- _haze->setHazeColor(glm::vec3(config.hazeColorR, config.hazeColorG, config.hazeColorB));
- _haze->setDirectionalLightBlend(model::convertDirectionalLightAngleToPower(config.hazeDirectionalLightAngle_degs));
+ _haze->setHazeColor(config.hazeColor);
+ _haze->setHazeGlareBlend(model::Haze::convertGlareAngleToPower(config.hazeGlareAngle));
- _haze->setDirectionalLightColor(glm::vec3(config.hazeDirectionalLightColorR, config.hazeDirectionalLightColorG, config.hazeDirectionalLightColorB));
+ _haze->setHazeGlareColor(config.hazeGlareColor);
_haze->setHazeBaseReference(config.hazeBaseReference);
_haze->setHazeActive(config.isHazeActive);
@@ -110,13 +94,13 @@ void MakeHaze::configure(const Config& config) {
_haze->setModulateColorActive(config.isModulateColorActive);
_haze->setHazeEnableGlare(config.isHazeEnableGlare);
- _haze->setHazeRangeFactor(model::convertHazeRangeToHazeRangeFactor(config.hazeRange_m));
- _haze->setHazeAltitudeFactor(model::convertHazeAltitudeToHazeAltitudeFactor(config.hazeAltitude_m));
+ _haze->setHazeRangeFactor(model::Haze::convertHazeRangeToHazeRangeFactor(config.hazeRange));
+ _haze->setHazeAltitudeFactor(model::Haze::convertHazeAltitudeToHazeAltitudeFactor(config.hazeHeight));
- _haze->setHazeKeyLightRangeFactor(model::convertHazeRangeToHazeRangeFactor(config.hazeKeyLightRange_m));
- _haze->setHazeKeyLightAltitudeFactor(model::convertHazeAltitudeToHazeAltitudeFactor(config.hazeKeyLightAltitude_m));
+ _haze->setHazeKeyLightRangeFactor(model::Haze::convertHazeRangeToHazeRangeFactor(config.hazeKeyLightRange));
+ _haze->setHazeKeyLightAltitudeFactor(model::Haze::convertHazeAltitudeToHazeAltitudeFactor(config.hazeKeyLightAltitude));
- _haze->setHazeBackgroundBlendValue(config.hazeBackgroundBlendValue);
+ _haze->setHazeBackgroundBlend(config.hazeBackgroundBlend);
}
void MakeHaze::run(const render::RenderContextPointer& renderContext, model::HazePointer& haze) {
@@ -156,7 +140,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
// Mask out haze on the tablet
- PrepareStencil::testNoAA(*state);
+ PrepareStencil::testMask(*state);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), HazeEffect_ParamsSlot));
diff --git a/libraries/render-utils/src/DrawHaze.h b/libraries/render-utils/src/DrawHaze.h
index 4a7b2135bd..f158daa0c6 100644
--- a/libraries/render-utils/src/DrawHaze.h
+++ b/libraries/render-utils/src/DrawHaze.h
@@ -19,24 +19,19 @@
#include
#include
#include
+#include
#include "SurfaceGeometryPass.h"
-#include "model/Haze.h"
-
using LinearDepthFramebufferPointer = std::shared_ptr;
class MakeHazeConfig : public render::Job::Config {
Q_OBJECT
- Q_PROPERTY(float hazeColorR MEMBER hazeColorR WRITE setHazeColorR NOTIFY dirty);
- Q_PROPERTY(float hazeColorG MEMBER hazeColorG WRITE setHazeColorG NOTIFY dirty);
- Q_PROPERTY(float hazeColorB MEMBER hazeColorB WRITE setHazeColorB NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightAngle_degs MEMBER hazeDirectionalLightAngle_degs WRITE setDirectionalLightAngle_degs NOTIFY dirty);
+ Q_PROPERTY(glm::vec3 hazeColor MEMBER hazeColor WRITE setHazeColor NOTIFY dirty);
+ Q_PROPERTY(float hazeGlareAngle MEMBER hazeGlareAngle WRITE setHazeGlareAngle NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightColorR MEMBER hazeDirectionalLightColorR WRITE setDirectionalLightColorR NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightColorG MEMBER hazeDirectionalLightColorG WRITE setDirectionalLightColorG NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightColorB MEMBER hazeDirectionalLightColorB WRITE setDirectionalLightColorB NOTIFY dirty);
+ Q_PROPERTY(glm::vec3 hazeGlareColor MEMBER hazeGlareColor WRITE setHazeGlareColor NOTIFY dirty);
Q_PROPERTY(float hazeBaseReference MEMBER hazeBaseReference WRITE setHazeBaseReference NOTIFY dirty);
Q_PROPERTY(bool isHazeActive MEMBER isHazeActive WRITE setHazeActive NOTIFY dirty);
@@ -45,26 +40,22 @@ class MakeHazeConfig : public render::Job::Config {
Q_PROPERTY(bool isModulateColorActive MEMBER isModulateColorActive WRITE setModulateColorActive NOTIFY dirty);
Q_PROPERTY(bool isHazeEnableGlare MEMBER isHazeEnableGlare WRITE setHazeEnableGlare NOTIFY dirty);
- Q_PROPERTY(float hazeRange_m MEMBER hazeRange_m WRITE setHazeRange_m NOTIFY dirty);
- Q_PROPERTY(float hazeAltitude_m MEMBER hazeAltitude_m WRITE setHazeAltitude_m NOTIFY dirty);
+ Q_PROPERTY(float hazeRange MEMBER hazeRange WRITE setHazeRange NOTIFY dirty);
+ Q_PROPERTY(float hazeHeight MEMBER hazeHeight WRITE setHazeAltitude NOTIFY dirty);
- Q_PROPERTY(float hazeKeyLightRange_m MEMBER hazeKeyLightRange_m WRITE setHazeKeyLightRange_m NOTIFY dirty);
- Q_PROPERTY(float hazeKeyLightAltitude_m MEMBER hazeKeyLightAltitude_m WRITE setHazeKeyLightAltitude_m NOTIFY dirty);
+ Q_PROPERTY(float hazeKeyLightRange MEMBER hazeKeyLightRange WRITE setHazeKeyLightRange NOTIFY dirty);
+ Q_PROPERTY(float hazeKeyLightAltitude MEMBER hazeKeyLightAltitude WRITE setHazeKeyLightAltitude NOTIFY dirty);
- Q_PROPERTY(float hazeBackgroundBlendValue MEMBER hazeBackgroundBlendValue WRITE setHazeBackgroundBlendValue NOTIFY dirty);
+ Q_PROPERTY(float hazeBackgroundBlend MEMBER hazeBackgroundBlend WRITE setHazeBackgroundBlend NOTIFY dirty);
public:
MakeHazeConfig() : render::Job::Config() {}
- float hazeColorR{ model::initialHazeColor.r };
- float hazeColorG{ model::initialHazeColor.g };
- float hazeColorB{ model::initialHazeColor.b };
- float hazeDirectionalLightAngle_degs{ model::initialDirectionalLightAngle_degs };
+ glm::vec3 hazeColor{ model::Haze::INITIAL_HAZE_COLOR };
+ float hazeGlareAngle{ model::Haze::INITIAL_HAZE_GLARE_ANGLE };
- float hazeDirectionalLightColorR{ model::initialDirectionalLightColor.r };
- float hazeDirectionalLightColorG{ model::initialDirectionalLightColor.g };
- float hazeDirectionalLightColorB{ model::initialDirectionalLightColor.b };
- float hazeBaseReference{ model::initialHazeBaseReference };
+ glm::vec3 hazeGlareColor{ model::Haze::INITIAL_HAZE_GLARE_COLOR };
+ float hazeBaseReference{ model::Haze::INITIAL_HAZE_BASE_REFERENCE };
bool isHazeActive{ false };
bool isAltitudeBased{ false };
@@ -72,23 +63,19 @@ public:
bool isModulateColorActive{ false };
bool isHazeEnableGlare{ false };
- float hazeRange_m{ model::initialHazeRange_m };
- float hazeAltitude_m{ model::initialHazeAltitude_m };
+ float hazeRange{ model::Haze::INITIAL_HAZE_RANGE };
+ float hazeHeight{ model::Haze::INITIAL_HAZE_HEIGHT };
- float hazeKeyLightRange_m{ model::initialHazeKeyLightRange_m };
- float hazeKeyLightAltitude_m{ model::initialHazeKeyLightAltitude_m };
+ float hazeKeyLightRange{ model::Haze::INITIAL_KEY_LIGHT_RANGE };
+ float hazeKeyLightAltitude{ model::Haze::INITIAL_KEY_LIGHT_ALTITUDE };
- float hazeBackgroundBlendValue{ model::initialHazeBackgroundBlendValue };
+ float hazeBackgroundBlend{ model::Haze::INITIAL_HAZE_BACKGROUND_BLEND };
public slots:
- void setHazeColorR(const float value) { hazeColorR = value; emit dirty(); }
- void setHazeColorG(const float value) { hazeColorG = value; emit dirty(); }
- void setHazeColorB(const float value) { hazeColorB = value; emit dirty(); }
- void setDirectionalLightAngle_degs(const float value) { hazeDirectionalLightAngle_degs = value; emit dirty(); }
+ void setHazeColor(const glm::vec3 value) { hazeColor = value; emit dirty(); }
+ void setHazeGlareAngle(const float value) { hazeGlareAngle = value; emit dirty(); }
- void setDirectionalLightColorR(const float value) { hazeDirectionalLightColorR = value; emit dirty(); }
- void setDirectionalLightColorG(const float value) { hazeDirectionalLightColorG = value; emit dirty(); }
- void setDirectionalLightColorB(const float value) { hazeDirectionalLightColorB = value; emit dirty(); }
+ void setHazeGlareColor(const glm::vec3 value) { hazeGlareColor = value; emit dirty(); }
void setHazeBaseReference(const float value) { hazeBaseReference = value; ; emit dirty(); }
void setHazeActive(const bool active) { isHazeActive = active; emit dirty(); }
@@ -97,13 +84,13 @@ public slots:
void setModulateColorActive(const bool active) { isModulateColorActive = active; emit dirty(); }
void setHazeEnableGlare(const bool active) { isHazeEnableGlare = active; emit dirty(); }
- void setHazeRange_m(const float value) { hazeRange_m = value; emit dirty(); }
- void setHazeAltitude_m(const float value) { hazeAltitude_m = value; emit dirty(); }
+ void setHazeRange(const float value) { hazeRange = value; emit dirty(); }
+ void setHazeAltitude(const float value) { hazeHeight = value; emit dirty(); }
- void setHazeKeyLightRange_m(const float value) { hazeKeyLightRange_m = value; emit dirty(); }
- void setHazeKeyLightAltitude_m(const float value) { hazeKeyLightAltitude_m = value; emit dirty(); }
+ void setHazeKeyLightRange(const float value) { hazeKeyLightRange = value; emit dirty(); }
+ void setHazeKeyLightAltitude(const float value) { hazeKeyLightAltitude = value; emit dirty(); }
- void setHazeBackgroundBlendValue(const float value) { hazeBackgroundBlendValue = value; ; emit dirty(); }
+ void setHazeBackgroundBlend(const float value) { hazeBackgroundBlend = value; ; emit dirty(); }
signals:
void dirty();
@@ -128,15 +115,11 @@ public:
HazeConfig() : render::Job::Config(true) {}
// attributes
- float hazeColorR{ model::initialHazeColor.r };
- float hazeColorG{ model::initialHazeColor.g };
- float hazeColorB{ model::initialHazeColor.b };
- float hazeDirectionalLightAngle_degs{ model::initialDirectionalLightAngle_degs };
+ glm::vec3 hazeColor{ model::Haze::INITIAL_HAZE_COLOR };
+ float hazeGlareAngle{ model::Haze::INITIAL_HAZE_GLARE_ANGLE };
- float hazeDirectionalLightColorR{ model::initialDirectionalLightColor.r };
- float hazeDirectionalLightColorG{ model::initialDirectionalLightColor.g };
- float hazeDirectionalLightColorB{ model::initialDirectionalLightColor.b };
- float hazeBaseReference{ model::initialHazeBaseReference };
+ glm::vec3 hazeGlareColor{ model::Haze::INITIAL_HAZE_GLARE_COLOR };
+ float hazeBaseReference{ model::Haze::INITIAL_HAZE_BASE_REFERENCE };
bool isHazeActive{ false }; // Setting this to true will set haze to on
bool isAltitudeBased{ false };
@@ -144,23 +127,19 @@ public:
bool isModulateColorActive{ false };
bool isHazeEnableGlare{ false };
- float hazeRange_m{ model::initialHazeRange_m };
- float hazeAltitude_m{ model::initialHazeAltitude_m };
+ float hazeRange{ model::Haze::INITIAL_HAZE_RANGE };
+ float hazeHeight{ model::Haze::INITIAL_HAZE_HEIGHT };
- float hazeKeyLightRange_m{ model::initialHazeKeyLightRange_m };
- float hazeKeyLightAltitude_m{ model::initialHazeKeyLightAltitude_m };
+ float hazeKeyLightRange{ model::Haze::INITIAL_KEY_LIGHT_RANGE };
+ float hazeKeyLightAltitude{ model::Haze::INITIAL_KEY_LIGHT_ALTITUDE };
- float hazeBackgroundBlendValue{ model::initialHazeBackgroundBlendValue };
+ float hazeBackgroundBlend{ model::Haze::INITIAL_HAZE_BACKGROUND_BLEND };
// methods
- void setHazeColorR(const float value);
- void setHazeColorG(const float value);
- void setHazeColorB(const float value);
- void setDirectionalLightAngle_degs(const float value);
+ void setHazeColor(const glm::vec3 value);
+ void setHazeGlareAngle(const float value);
- void setDirectionalLightColorR(const float value);
- void setDirectionalLightColorG(const float value);
- void setDirectionalLightColorB(const float value);
+ void setHazeGlareColor(const glm::vec3 value);
void setHazeBaseReference(const float value);
void setHazeActive(const bool active);
@@ -169,13 +148,13 @@ public:
void setModulateColorActive(const bool active);
void setHazeEnableGlare(const bool active);
- void setHazeRange_m(const float value);
- void setHazeAltitude_m(const float value);
+ void setHazeRange(const float value);
+ void setHazeAltitude(const float value);
- void setHazeKeyLightRange_m(const float value);
- void setHazeKeyLightAltitude_m(const float value);
+ void setHazeKeyLightRange(const float value);
+ void setHazeKeyLightAltitude(const float value);
- void setHazeBackgroundBlendValue(const float value);
+ void setHazeBackgroundBlend(const float value);
};
class DrawHaze {
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index f35fb9f830..fa00737e3c 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -482,8 +482,10 @@ void GeometryCache::buildShapes() {
using namespace geometry;
auto vertexBuffer = std::make_shared();
auto indexBuffer = std::make_shared();
- // Cube
+ // Cube
setupFlatShape(_shapes[Cube], geometry::cube(), _shapeVertices, _shapeIndices);
+ //Quad renders as flat Cube
+ setupFlatShape(_shapes[Quad], geometry::cube(), _shapeVertices, _shapeIndices);
// Tetrahedron
setupFlatShape(_shapes[Tetrahedron], geometry::tetrahedron(), _shapeVertices, _shapeIndices);
// Icosahedron
@@ -524,12 +526,10 @@ void GeometryCache::buildShapes() {
extrudePolygon<64>(_shapes[Cylinder], _shapeVertices, _shapeIndices);
//Cone,
extrudePolygon<64>(_shapes[Cone], _shapeVertices, _shapeIndices, true);
- //Circle
- drawCircle(_shapes[Circle], _shapeVertices, _shapeIndices);
+ // Circle renders as flat Cylinder
+ extrudePolygon<64>(_shapes[Circle], _shapeVertices, _shapeIndices);
// Not implemented yet:
- //Quad,
- //Torus,
-
+ //Torus,
}
const GeometryCache::ShapeData * GeometryCache::getShapeData(const Shape shape) const {
diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf
index 77c820e093..b366e6d639 100644
--- a/libraries/render-utils/src/Haze.slf
+++ b/libraries/render-utils/src/Haze.slf
@@ -60,15 +60,15 @@ void main(void) {
Light light = getLight();
vec3 lightDirection = getLightDirection(light);
- float directionalLightComponent = max(0.0, dot(eyeFragDir, -lightDirection));
- float power = min(1.0, pow(directionalLightComponent, hazeParams.directionalLightBlend));
+ float glareComponent = max(0.0, dot(eyeFragDir, -lightDirection));
+ float power = min(1.0, pow(glareComponent, hazeParams.hazeGlareBlend));
- vec4 directionalLightColor = vec4(hazeParams.directionalLightColor, 1.0);
+ vec4 glareColor = vec4(hazeParams.hazeGlareColor, 1.0);
- // Use the haze colour for the belnd-out colour, if blend is not enabled
+ // Use the haze colour for the glare colour, if blend is not enabled
vec4 blendedHazeColor;
if ((hazeParams.hazeMode & HAZE_MODE_IS_ENABLE_LIGHT_BLEND) == HAZE_MODE_IS_ENABLE_LIGHT_BLEND) {
- blendedHazeColor = mix(hazeColor, directionalLightColor, power);
+ blendedHazeColor = mix(hazeColor, glareColor, power);
} else {
blendedHazeColor = hazeColor;
}
@@ -86,14 +86,14 @@ void main(void) {
// Note that the haze base reference affects only the haze density as function of altitude
vec3 hazeDensityDistribution =
hazeParams.colorModulationFactor *
- exp(-hazeParams.hazeAltitudeFactor * (worldEyePos.y - hazeParams.hazeBaseReference));
+ exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference));
vec3 hazeIntegral = hazeDensityDistribution * distance;
const float slopeThreshold = 0.01;
float deltaHeight = worldFragPos.y - worldEyePos.y;
if (abs(deltaHeight) > slopeThreshold) {
- float t = hazeParams.hazeAltitudeFactor * deltaHeight;
+ float t = hazeParams.hazeHeightFactor * deltaHeight;
hazeIntegral *= (1.0 - exp (-t)) / t;
}
@@ -117,14 +117,14 @@ void main(void) {
// Note that the haze base reference affects only the haze density as function of altitude
float hazeDensityDistribution =
hazeParams.hazeRangeFactor *
- exp(-hazeParams.hazeAltitudeFactor * (worldEyePos.y - hazeParams.hazeBaseReference));
+ exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference));
float hazeIntegral = hazeDensityDistribution * distance;
const float slopeThreshold = 0.01;
float deltaHeight = worldFragPos.y - worldEyePos.y;
if (abs(deltaHeight) > slopeThreshold) {
- float t = hazeParams.hazeAltitudeFactor * deltaHeight;
+ float t = hazeParams.hazeHeightFactor * deltaHeight;
// Protect from wild values
if (abs(t) > 0.0000001) {
hazeIntegral *= (1.0 - exp (-t)) / t;
@@ -140,7 +140,7 @@ void main(void) {
// Mix with background at far range
const float BLEND_DISTANCE = 27000.0;
if (distance > BLEND_DISTANCE) {
- outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlendValue);
+ outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend);
} else {
outFragColor = potentialFragColor;
}
diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh
index 614431dce7..de7f0ac246 100644
--- a/libraries/render-utils/src/Haze.slh
+++ b/libraries/render-utils/src/Haze.slh
@@ -12,28 +12,28 @@
const int HAZE_MODE_IS_ACTIVE = 1 << 0;
const int HAZE_MODE_IS_ALTITUDE_BASED = 1 << 1;
-const int HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED = 1 << 2;
+const int HAZE_MODE_IS_KEYLIGHT_ATTENUATED = 1 << 2;
const int HAZE_MODE_IS_MODULATE_COLOR = 1 << 3;
const int HAZE_MODE_IS_ENABLE_LIGHT_BLEND = 1 << 4;
struct HazeParams {
vec3 hazeColor;
- float directionalLightBlend;
+ float hazeGlareBlend;
- vec3 directionalLightColor;
+ vec3 hazeGlareColor;
float hazeBaseReference;
vec3 colorModulationFactor;
int hazeMode;
mat4 zoneTransform;
- float backgroundBlendValue;
+ float backgroundBlend;
float hazeRangeFactor;
- float hazeAltitudeFactor;
+ float hazeHeightFactor;
- float hazeRangeFactorKeyLight;
- float hazeAltitudeFactorKeyLight;
+ float hazeKeyLightRangeFactor;
+ float hazeKeyLightAltitudeFactor;
};
layout(std140) uniform hazeBuffer {
diff --git a/libraries/render-utils/src/HazeStage.cpp b/libraries/render-utils/src/HazeStage.cpp
index aa7a7f554c..016282d16f 100644
--- a/libraries/render-utils/src/HazeStage.cpp
+++ b/libraries/render-utils/src/HazeStage.cpp
@@ -14,16 +14,17 @@
#include
std::string HazeStage::_stageName { "HAZE_STAGE"};
+const HazeStage::Index HazeStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
FetchHazeStage::FetchHazeStage() {
_haze = std::make_shared();
}
void FetchHazeStage::configure(const Config& config) {
- _haze->setHazeColor(glm::vec3(config.hazeColorR, config.hazeColorG, config.hazeColorB));
- _haze->setDirectionalLightBlend(model::convertDirectionalLightAngleToPower(config.hazeDirectionalLightAngle_degs));
+ _haze->setHazeColor(config.hazeColor);
+ _haze->setHazeGlareBlend(model::Haze::convertGlareAngleToPower(config.hazeGlareAngle));
- _haze->setDirectionalLightColor(glm::vec3(config.hazeDirectionalLightColorR, config.hazeDirectionalLightColorG, config.hazeDirectionalLightColorB));
+ _haze->setHazeGlareColor(config.hazeGlareColor);
_haze->setHazeBaseReference(config.hazeBaseReference);
_haze->setHazeActive(config.isHazeActive);
@@ -32,13 +33,13 @@ void FetchHazeStage::configure(const Config& config) {
_haze->setModulateColorActive(config.isModulateColorActive);
_haze->setHazeEnableGlare(config.isHazeEnableGlare);
- _haze->setHazeRangeFactor(model::convertHazeRangeToHazeRangeFactor(config.hazeRange_m));
- _haze->setHazeAltitudeFactor(model::convertHazeAltitudeToHazeAltitudeFactor(config.hazeAltitude_m));
+ _haze->setHazeRangeFactor(model::Haze::convertHazeRangeToHazeRangeFactor(config.hazeRange));
+ _haze->setHazeAltitudeFactor(model::Haze::convertHazeAltitudeToHazeAltitudeFactor(config.hazeHeight));
- _haze->setHazeKeyLightRangeFactor(model::convertHazeRangeToHazeRangeFactor(config.hazeKeyLightRange_m));
- _haze->setHazeKeyLightAltitudeFactor(model::convertHazeAltitudeToHazeAltitudeFactor(config.hazeKeyLightAltitude_m));
+ _haze->setHazeKeyLightRangeFactor(model::Haze::convertHazeRangeToHazeRangeFactor(config.hazeKeyLightRange));
+ _haze->setHazeKeyLightAltitudeFactor(model::Haze::convertHazeAltitudeToHazeAltitudeFactor(config.hazeKeyLightAltitude));
- _haze->setHazeBackgroundBlendValue(config.hazeBackgroundBlendValue);
+ _haze->setHazeBackgroundBlend(config.hazeBackgroundBlend);
}
HazeStage::Index HazeStage::findHaze(const HazePointer& haze) const {
diff --git a/libraries/render-utils/src/HazeStage.h b/libraries/render-utils/src/HazeStage.h
index 7cc0c659b0..c355f06644 100644
--- a/libraries/render-utils/src/HazeStage.h
+++ b/libraries/render-utils/src/HazeStage.h
@@ -19,7 +19,7 @@
#include
#include
-#include "model/Haze.h"
+#include
// Haze stage to set up haze-related rendering tasks
class HazeStage : public render::Stage {
@@ -28,7 +28,7 @@ public:
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
- static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
+ static const Index INVALID_INDEX;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using HazePointer = model::HazePointer;
@@ -83,14 +83,10 @@ protected:
class FetchHazeConfig : public render::Job::Config {
Q_OBJECT
- Q_PROPERTY(float hazeColorR MEMBER hazeColorR WRITE setHazeColorR NOTIFY dirty);
- Q_PROPERTY(float hazeColorG MEMBER hazeColorG WRITE setHazeColorG NOTIFY dirty);
- Q_PROPERTY(float hazeColorB MEMBER hazeColorB WRITE setHazeColorB NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightAngle_degs MEMBER hazeDirectionalLightAngle_degs WRITE setDirectionalLightAngle_degs NOTIFY dirty);
+ Q_PROPERTY(glm::vec3 hazeColor MEMBER hazeColor WRITE setHazeColor NOTIFY dirty);
+ Q_PROPERTY(float hazeGlareAngle MEMBER hazeGlareAngle WRITE setHazeGlareAngle NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightColorR MEMBER hazeDirectionalLightColorR WRITE setDirectionalLightColorR NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightColorG MEMBER hazeDirectionalLightColorG WRITE setDirectionalLightColorG NOTIFY dirty);
- Q_PROPERTY(float hazeDirectionalLightColorB MEMBER hazeDirectionalLightColorB WRITE setDirectionalLightColorB NOTIFY dirty);
+ Q_PROPERTY(glm::vec3 hazeGlareColor MEMBER hazeGlareColor WRITE setHazeGlareColor NOTIFY dirty);
Q_PROPERTY(float hazeBaseReference MEMBER hazeBaseReference WRITE setHazeBaseReference NOTIFY dirty);
Q_PROPERTY(bool isHazeActive MEMBER isHazeActive WRITE setHazeActive NOTIFY dirty);
@@ -99,26 +95,22 @@ class FetchHazeConfig : public render::Job::Config {
Q_PROPERTY(bool isModulateColorActive MEMBER isModulateColorActive WRITE setModulateColorActive NOTIFY dirty);
Q_PROPERTY(bool isHazeEnableGlare MEMBER isHazeEnableGlare WRITE setHazeEnableGlare NOTIFY dirty);
- Q_PROPERTY(float hazeRange_m MEMBER hazeRange_m WRITE setHazeRange_m NOTIFY dirty);
- Q_PROPERTY(float hazeAltitude_m MEMBER hazeAltitude_m WRITE setHazeAltitude_m NOTIFY dirty);
+ Q_PROPERTY(float hazeRange MEMBER hazeRange WRITE setHazeRange NOTIFY dirty);
+ Q_PROPERTY(float hazeHeight MEMBER hazeHeight WRITE setHazeAltitude NOTIFY dirty);
- Q_PROPERTY(float hazeKeyLightRange_m MEMBER hazeKeyLightRange_m WRITE setHazeKeyLightRange_m NOTIFY dirty);
- Q_PROPERTY(float hazeKeyLightAltitude_m MEMBER hazeKeyLightAltitude_m WRITE setHazeKeyLightAltitude_m NOTIFY dirty);
+ Q_PROPERTY(float hazeKeyLightRange MEMBER hazeKeyLightRange WRITE setHazeKeyLightRange NOTIFY dirty);
+ Q_PROPERTY(float hazeKeyLightAltitude MEMBER hazeKeyLightAltitude WRITE setHazeKeyLightAltitude NOTIFY dirty);
- Q_PROPERTY(float hazeBackgroundBlendValue MEMBER hazeBackgroundBlendValue WRITE setHazeBackgroundBlendValue NOTIFY dirty);
+ Q_PROPERTY(float hazeBackgroundBlend MEMBER hazeBackgroundBlend WRITE setHazeBackgroundBlend NOTIFY dirty);
public:
FetchHazeConfig() : render::Job::Config() {}
- float hazeColorR{ model::initialHazeColor.r };
- float hazeColorG{ model::initialHazeColor.g };
- float hazeColorB{ model::initialHazeColor.b };
- float hazeDirectionalLightAngle_degs{ model::initialDirectionalLightAngle_degs };
+ glm::vec3 hazeColor{ model::Haze::INITIAL_HAZE_COLOR };
+ float hazeGlareAngle{ model::Haze::INITIAL_HAZE_GLARE_ANGLE };
- float hazeDirectionalLightColorR{ model::initialDirectionalLightColor.r };
- float hazeDirectionalLightColorG{ model::initialDirectionalLightColor.g };
- float hazeDirectionalLightColorB{ model::initialDirectionalLightColor.b };
- float hazeBaseReference{ model::initialHazeBaseReference };
+ glm::vec3 hazeGlareColor{ model::Haze::INITIAL_HAZE_GLARE_COLOR };
+ float hazeBaseReference{ model::Haze::INITIAL_HAZE_BASE_REFERENCE };
bool isHazeActive{ false };
bool isAltitudeBased{ false };
@@ -126,23 +118,19 @@ public:
bool isModulateColorActive{ false };
bool isHazeEnableGlare{ false };
- float hazeRange_m{ model::initialHazeRange_m };
- float hazeAltitude_m{ model::initialHazeAltitude_m };
+ float hazeRange{ model::Haze::INITIAL_HAZE_RANGE };
+ float hazeHeight{ model::Haze::INITIAL_HAZE_HEIGHT };
- float hazeKeyLightRange_m{ model::initialHazeKeyLightRange_m };
- float hazeKeyLightAltitude_m{ model::initialHazeKeyLightAltitude_m };
+ float hazeKeyLightRange{ model::Haze::INITIAL_KEY_LIGHT_RANGE };
+ float hazeKeyLightAltitude{ model::Haze::INITIAL_KEY_LIGHT_ALTITUDE };
- float hazeBackgroundBlendValue{ model::initialHazeBackgroundBlendValue };
+ float hazeBackgroundBlend{ model::Haze::INITIAL_HAZE_BACKGROUND_BLEND };
public slots:
- void setHazeColorR(const float value) { hazeColorR = value; emit dirty(); }
- void setHazeColorG(const float value) { hazeColorG = value; emit dirty(); }
- void setHazeColorB(const float value) { hazeColorB = value; emit dirty(); }
- void setDirectionalLightAngle_degs(const float value) { hazeDirectionalLightAngle_degs = value; emit dirty(); }
+ void setHazeColor(const glm::vec3 value) { hazeColor = value; emit dirty(); }
+ void setHazeGlareAngle(const float value) { hazeGlareAngle = value; emit dirty(); }
- void setDirectionalLightColorR(const float value) { hazeDirectionalLightColorR = value; emit dirty(); }
- void setDirectionalLightColorG(const float value) { hazeDirectionalLightColorG = value; emit dirty(); }
- void setDirectionalLightColorB(const float value) { hazeDirectionalLightColorB = value; emit dirty(); }
+ void setHazeGlareColor(const glm::vec3 value) { hazeGlareColor = value; emit dirty(); }
void setHazeBaseReference(const float value) { hazeBaseReference = value; ; emit dirty(); }
void setHazeActive(const bool active) { isHazeActive = active; emit dirty(); }
@@ -151,13 +139,13 @@ public slots:
void setModulateColorActive(const bool active) { isModulateColorActive = active; emit dirty(); }
void setHazeEnableGlare(const bool active) { isHazeEnableGlare = active; emit dirty(); }
- void setHazeRange_m(const float value) { hazeRange_m = value; emit dirty(); }
- void setHazeAltitude_m(const float value) { hazeAltitude_m = value; emit dirty(); }
+ void setHazeRange(const float value) { hazeRange = value; emit dirty(); }
+ void setHazeAltitude(const float value) { hazeHeight = value; emit dirty(); }
- void setHazeKeyLightRange_m(const float value) { hazeKeyLightRange_m = value; emit dirty(); }
- void setHazeKeyLightAltitude_m(const float value) { hazeKeyLightAltitude_m = value; emit dirty(); }
+ void setHazeKeyLightRange(const float value) { hazeKeyLightRange = value; emit dirty(); }
+ void setHazeKeyLightAltitude(const float value) { hazeKeyLightAltitude = value; emit dirty(); }
- void setHazeBackgroundBlendValue(const float value) { hazeBackgroundBlendValue = value; ; emit dirty(); }
+ void setHazeBackgroundBlend(const float value) { hazeBackgroundBlend = value; ; emit dirty(); }
signals:
void dirty();
diff --git a/libraries/render-utils/src/Outline.slf b/libraries/render-utils/src/Highlight.slf
similarity index 72%
rename from libraries/render-utils/src/Outline.slf
rename to libraries/render-utils/src/Highlight.slf
index 68ef870cba..bf65f92613 100644
--- a/libraries/render-utils/src/Outline.slf
+++ b/libraries/render-utils/src/Highlight.slf
@@ -1,5 +1,5 @@
-// Outline.slf
-// Add outline effect based on two zbuffers : one containing the total scene z and another
+// Highlight.slf
+// Add highlight effect based on two zbuffers : one containing the total scene z and another
// with the z of only the objects to be outlined.
// This is the version without the fill effect inside the silhouette.
//
@@ -9,5 +9,5 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-<@include Outline.slh@>
+<@include Highlight.slh@>
<$main(0)$>
diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Highlight.slh
similarity index 67%
rename from libraries/render-utils/src/Outline.slh
rename to libraries/render-utils/src/Highlight.slh
index ac56e4c95c..2faa10682e 100644
--- a/libraries/render-utils/src/Outline.slh
+++ b/libraries/render-utils/src/Highlight.slh
@@ -1,7 +1,7 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
<$declareDeferredFrameTransform()$>
-<@include Outline_shared.slh@>
+<@include Highlight_shared.slh@>
-uniform outlineParamsBuffer {
- OutlineParameters params;
+uniform highlightParamsBuffer {
+ HighlightParameters params;
};
uniform sampler2D sceneDepthMap;
-uniform sampler2D outlinedDepthMap;
+uniform sampler2D highlightedDepthMap;
in vec2 varTexCoord0;
out vec4 outFragColor;
@@ -35,30 +35,26 @@ void main(void) {
// We offset by half a texel to be centered on the depth sample. If we don't do this
// the blur will have a different width between the left / right sides and top / bottom
// sides of the silhouette
- vec2 halfTexel = getInvWidthHeight() / 2;
- vec2 texCoord0 = varTexCoord0+halfTexel;
- float outlinedDepth = texture(outlinedDepthMap, texCoord0).x;
+ float highlightedDepth = texture(highlightedDepthMap, varTexCoord0).x;
float intensity = 0.0;
- if (outlinedDepth < FAR_Z) {
- // We're not on the far plane so we are on the outlined object, thus no outline to do!
+ if (highlightedDepth < FAR_Z) {
+ // We're not on the far plane so we are on the highlighted object, thus no outline to do!
<@if IS_FILLED@>
// But we need to fill the interior
- float sceneDepth = texture(sceneDepthMap, texCoord0).x;
+ float sceneDepth = texture(sceneDepthMap, varTexCoord0).x;
// Transform to linear depth for better precision
- outlinedDepth = -evalZeyeFromZdb(outlinedDepth);
+ highlightedDepth = -evalZeyeFromZdb(highlightedDepth);
sceneDepth = -evalZeyeFromZdb(sceneDepth);
// Are we occluded?
- if (sceneDepth < (outlinedDepth-LINEAR_DEPTH_BIAS)) {
- intensity = params._fillOpacityOccluded;
- } else {
- intensity = params._fillOpacityUnoccluded;
- }
+ intensity = sceneDepth < (highlightedDepth-LINEAR_DEPTH_BIAS) ? params._occludedFillOpacity : params._unoccludedFillOpacity;
<@else@>
discard;
<@endif@>
} else {
+ vec2 halfTexel = getInvWidthHeight() / 2;
+ vec2 texCoord0 = varTexCoord0+halfTexel;
float weight = 0.0;
vec2 deltaUv = params._size / params._blurKernelSize;
vec2 lineStartUv = texCoord0 - params._size / 2.0;
@@ -74,9 +70,9 @@ void main(void) {
for (x=0 ; x=0.0 && uv.x<=1.0)
{
- outlinedDepth = texture(outlinedDepthMap, uv).x;
- intensity += (outlinedDepth < FAR_Z) ? 1.0 : 0.0;
- weight += 1.f;
+ highlightedDepth = texture(highlightedDepthMap, uv).x;
+ intensity += (highlightedDepth < FAR_Z) ? 1.0 : 0.0;
+ weight += 1.0;
}
uv.x += deltaUv.x;
}
diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp
new file mode 100644
index 0000000000..7c58e5ba66
--- /dev/null
+++ b/libraries/render-utils/src/HighlightEffect.cpp
@@ -0,0 +1,562 @@
+//
+// HighlightEffect.cpp
+// render-utils/src/
+//
+// Created by Olivier Prat on 08/08/17.
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#include "HighlightEffect.h"
+
+#include "GeometryCache.h"
+
+#include "CubeProjectedPolygon.h"
+
+#include
+#include
+
+#include "gpu/Context.h"
+#include "gpu/StandardShaderLib.h"
+
+#include
+
+#include "surfaceGeometry_copyDepth_frag.h"
+#include "debug_deferred_buffer_vert.h"
+#include "debug_deferred_buffer_frag.h"
+#include "Highlight_frag.h"
+#include "Highlight_filled_frag.h"
+#include "Highlight_aabox_vert.h"
+#include "nop_frag.h"
+
+using namespace render;
+
+#define OUTLINE_STENCIL_MASK 1
+
+HighlightRessources::HighlightRessources() {
+}
+
+void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) {
+ auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize());
+
+ // If the buffer size changed, we need to delete our FBOs and recreate them at the
+ // new correct dimensions.
+ if (_frameSize != newFrameSize) {
+ _frameSize = newFrameSize;
+ allocateDepthBuffer(primaryFrameBuffer);
+ allocateColorBuffer(primaryFrameBuffer);
+ } else {
+ if (!_depthFrameBuffer) {
+ allocateDepthBuffer(primaryFrameBuffer);
+ }
+ if (!_colorFrameBuffer) {
+ allocateColorBuffer(primaryFrameBuffer);
+ }
+ }
+}
+
+void HighlightRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
+ _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil"));
+ _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0));
+ _colorFrameBuffer->setStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat());
+}
+
+void HighlightRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
+ auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL);
+ _depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y));
+ _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("highlightDepth"));
+ _depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat);
+}
+
+gpu::FramebufferPointer HighlightRessources::getDepthFramebuffer() {
+ assert(_depthFrameBuffer);
+ return _depthFrameBuffer;
+}
+
+gpu::TexturePointer HighlightRessources::getDepthTexture() {
+ return _depthStencilTexture;
+}
+
+gpu::FramebufferPointer HighlightRessources::getColorFramebuffer() {
+ assert(_colorFrameBuffer);
+ return _colorFrameBuffer;
+}
+
+HighlightSharedParameters::HighlightSharedParameters() {
+ _highlightIds.fill(render::HighlightStage::INVALID_INDEX);
+}
+
+float HighlightSharedParameters::getBlurPixelWidth(const render::HighlightStyle& style, int frameBufferHeight) {
+ return ceilf(style.outlineWidth * frameBufferHeight / 400.0f);
+}
+
+PrepareDrawHighlight::PrepareDrawHighlight() {
+ _ressources = std::make_shared();
+}
+
+void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
+ auto destinationFrameBuffer = inputs;
+
+ _ressources->update(destinationFrameBuffer);
+ outputs = _ressources;
+}
+
+gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline;
+gpu::PipelinePointer DrawHighlightMask::_stencilMaskFillPipeline;
+
+DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex,
+ render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters) :
+ _highlightPassIndex{ highlightIndex },
+ _shapePlumber { shapePlumber },
+ _sharedParameters{ parameters } {
+}
+
+void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
+ assert(renderContext->args);
+ assert(renderContext->args->hasViewFrustum());
+ auto& inShapes = inputs.get0();
+
+ if (!_stencilMaskPipeline || !_stencilMaskFillPipeline) {
+ gpu::StatePointer state = gpu::StatePointer(new gpu::State());
+ state->setDepthTest(true, false, gpu::LESS_EQUAL);
+ state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO, gpu::State::STENCIL_OP_REPLACE));
+ state->setColorWriteMask(false, false, false, false);
+ state->setCullMode(gpu::State::CULL_FRONT);
+
+ gpu::StatePointer fillState = gpu::StatePointer(new gpu::State());
+ fillState->setDepthTest(false, false, gpu::LESS_EQUAL);
+ fillState->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE));
+ fillState->setColorWriteMask(false, false, false, false);
+ fillState->setCullMode(gpu::State::CULL_FRONT);
+
+ auto vs = gpu::Shader::createVertex(std::string(Highlight_aabox_vert));
+ auto ps = gpu::Shader::createPixel(std::string(nop_frag));
+ gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
+
+ gpu::Shader::BindingSet slotBindings;
+ gpu::Shader::makeProgram(*program, slotBindings);
+
+ _stencilMaskPipeline = gpu::Pipeline::create(program, state);
+ _stencilMaskFillPipeline = gpu::Pipeline::create(program, fillState);
+ }
+
+ if (!_boundsBuffer) {
+ _boundsBuffer = std::make_shared(sizeof(render::ItemBound));
+ }
+
+ auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName());
+ auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex];
+
+ if (!inShapes.empty() && !render::HighlightStage::isIndexInvalid(highlightId)) {
+ auto ressources = inputs.get1();
+ auto& highlight = highlightStage->getHighlight(highlightId);
+
+ RenderArgs* args = renderContext->args;
+ ShapeKey::Builder defaultKeyBuilder;
+
+ // Render full screen
+ outputs = args->_viewport;
+
+ // Clear the framebuffer without stereo
+ // Needs to be distinct from the other batch because using the clear call
+ // while stereo is enabled triggers a warning
+ gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
+ batch.enableStereo(false);
+ batch.setFramebuffer(ressources->getDepthFramebuffer());
+ batch.clearDepthStencilFramebuffer(1.0f, 0);
+ });
+
+ glm::mat4 projMat;
+ Transform viewMat;
+ args->getViewFrustum().evalProjectionMatrix(projMat);
+ args->getViewFrustum().evalViewTransform(viewMat);
+
+ render::ItemBounds itemBounds;
+
+ gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
+ args->_batch = &batch;
+
+ auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
+ auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
+
+ // Setup camera, projection and viewport for all items
+ batch.setViewportTransform(args->_viewport);
+ batch.setProjectionTransform(projMat);
+ batch.setViewTransform(viewMat);
+
+ std::vector skinnedShapeKeys{};
+
+ // Iterate through all inShapes and render the unskinned
+ args->_shapePipeline = maskPipeline;
+ batch.setPipeline(maskPipeline->pipeline);
+ for (const auto& items : inShapes) {
+ itemBounds.insert(itemBounds.end(), items.second.begin(), items.second.end());
+ if (items.first.isSkinned()) {
+ skinnedShapeKeys.push_back(items.first);
+ } else {
+ renderItems(renderContext, items.second);
+ }
+ }
+
+ // Reiterate to render the skinned
+ args->_shapePipeline = maskSkinnedPipeline;
+ batch.setPipeline(maskSkinnedPipeline->pipeline);
+ for (const auto& key : skinnedShapeKeys) {
+ renderItems(renderContext, inShapes.at(key));
+ }
+
+ args->_shapePipeline = nullptr;
+ args->_batch = nullptr;
+ });
+
+ _boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
+
+ gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
+ // Setup camera, projection and viewport for all items
+ batch.setViewportTransform(args->_viewport);
+ batch.setProjectionTransform(projMat);
+ batch.setViewTransform(viewMat);
+
+ // Draw stencil mask with object bounding boxes
+ const auto highlightWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth");
+ const auto securityMargin = 2.0f;
+ const float blurPixelWidth = 2.0f * securityMargin * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w);
+ const auto framebufferSize = ressources->getSourceFrameSize();
+
+ auto stencilPipeline = highlight._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline;
+ batch.setPipeline(stencilPipeline);
+ batch.setResourceBuffer(0, _boundsBuffer);
+ batch._glUniform2f(highlightWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y);
+ static const int NUM_VERTICES_PER_CUBE = 36;
+ batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_CUBE * (gpu::uint32) itemBounds.size(), 0);
+ });
+ } else {
+ // Highlight rect should be null as there are no highlighted shapes
+ outputs = glm::ivec4(0, 0, 0, 0);
+ }
+}
+
+gpu::PipelinePointer DrawHighlight::_pipeline;
+gpu::PipelinePointer DrawHighlight::_pipelineFilled;
+
+DrawHighlight::DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters) :
+ _highlightPassIndex{ highlightIndex },
+ _sharedParameters{ parameters } {
+}
+
+void DrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
+ auto highlightFrameBuffer = inputs.get1();
+ auto highlightRect = inputs.get3();
+
+ if (highlightFrameBuffer && highlightRect.z>0 && highlightRect.w>0) {
+ auto sceneDepthBuffer = inputs.get2();
+ const auto frameTransform = inputs.get0();
+ auto highlightedDepthTexture = highlightFrameBuffer->getDepthTexture();
+ auto destinationFrameBuffer = highlightFrameBuffer->getColorFramebuffer();
+ auto framebufferSize = glm::ivec2(highlightedDepthTexture->getDimensions());
+
+ if (sceneDepthBuffer) {
+ auto args = renderContext->args;
+
+ auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName());
+ auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex];
+ if (!render::HighlightStage::isIndexInvalid(highlightId)) {
+ auto& highlight = highlightStage->getHighlight(highlightId);
+ auto pipeline = getPipeline(highlight._style);
+ {
+ auto& shaderParameters = _configuration.edit();
+
+ shaderParameters._color = highlight._style.color;
+ shaderParameters._intensity = highlight._style.outlineIntensity * (highlight._style.isOutlineSmooth ? 2.0f : 1.0f);
+ shaderParameters._unoccludedFillOpacity = highlight._style.unoccludedFillOpacity;
+ shaderParameters._occludedFillOpacity = highlight._style.occludedFillOpacity;
+ shaderParameters._threshold = highlight._style.isOutlineSmooth ? 1.0f : 1e-3f;
+ shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(highlight._style.outlineWidth * 3 + 0.5f)));
+ // Size is in normalized screen height. We decide that for highlight width = 1, this is equal to 1/400.
+ auto size = highlight._style.outlineWidth / 400.0f;
+ shaderParameters._size.x = (size * framebufferSize.y) / framebufferSize.x;
+ shaderParameters._size.y = size;
+ }
+
+ gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
+ batch.enableStereo(false);
+ batch.setFramebuffer(destinationFrameBuffer);
+
+ batch.setViewportTransform(args->_viewport);
+ batch.setProjectionTransform(glm::mat4());
+ batch.resetViewTransform();
+ batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
+ batch.setPipeline(pipeline);
+
+ batch.setUniformBuffer(HIGHLIGHT_PARAMS_SLOT, _configuration);
+ batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
+ batch.setResourceTexture(SCENE_DEPTH_MAP_SLOT, sceneDepthBuffer->getPrimaryDepthTexture());
+ batch.setResourceTexture(HIGHLIGHTED_DEPTH_MAP_SLOT, highlightedDepthTexture);
+ batch.draw(gpu::TRIANGLE_STRIP, 4);
+ });
+ }
+ }
+ }
+}
+
+const gpu::PipelinePointer& DrawHighlight::getPipeline(const render::HighlightStyle& style) {
+ if (!_pipeline) {
+ gpu::StatePointer state = gpu::StatePointer(new gpu::State());
+ state->setDepthTest(gpu::State::DepthTest(false, false));
+ state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
+ state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL));
+
+ auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
+ auto ps = gpu::Shader::createPixel(std::string(Highlight_frag));
+ gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
+
+ gpu::Shader::BindingSet slotBindings;
+ slotBindings.insert(gpu::Shader::Binding("highlightParamsBuffer", HIGHLIGHT_PARAMS_SLOT));
+ slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT));
+ slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_MAP_SLOT));
+ slotBindings.insert(gpu::Shader::Binding("highlightedDepthMap", HIGHLIGHTED_DEPTH_MAP_SLOT));
+ gpu::Shader::makeProgram(*program, slotBindings);
+
+ _pipeline = gpu::Pipeline::create(program, state);
+
+ ps = gpu::Shader::createPixel(std::string(Highlight_filled_frag));
+ program = gpu::Shader::createProgram(vs, ps);
+ gpu::Shader::makeProgram(*program, slotBindings);
+ _pipelineFilled = gpu::Pipeline::create(program, state);
+ }
+ return style.isFilled() ? _pipelineFilled : _pipeline;
+}
+
+DebugHighlight::DebugHighlight() {
+ _geometryDepthId = DependencyManager::get()->allocateID();
+}
+
+DebugHighlight::~DebugHighlight() {
+ auto geometryCache = DependencyManager::get();
+ if (geometryCache) {
+ geometryCache->releaseID(_geometryDepthId);
+ }
+}
+
+void DebugHighlight::configure(const Config& config) {
+ _isDisplayEnabled = config.viewMask;
+}
+
+void DebugHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& input) {
+ const auto highlightRessources = input.get0();
+ const auto highlightRect = input.get1();
+
+ if (_isDisplayEnabled && highlightRessources && highlightRect.z>0 && highlightRect.w>0) {
+ assert(renderContext->args);
+ assert(renderContext->args->hasViewFrustum());
+ RenderArgs* args = renderContext->args;
+
+ gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
+ batch.setViewportTransform(args->_viewport);
+ batch.setFramebuffer(highlightRessources->getColorFramebuffer());
+
+ const auto geometryBuffer = DependencyManager::get();
+
+ glm::mat4 projMat;
+ Transform viewMat;
+ args->getViewFrustum().evalProjectionMatrix(projMat);
+ args->getViewFrustum().evalViewTransform(viewMat);
+ batch.setProjectionTransform(projMat);
+ batch.setViewTransform(viewMat, true);
+ batch.setModelTransform(Transform());
+
+ const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
+
+ batch.setPipeline(getDepthPipeline());
+ batch.setResourceTexture(0, highlightRessources->getDepthTexture());
+ const glm::vec2 bottomLeft(-1.0f, -1.0f);
+ const glm::vec2 topRight(1.0f, 1.0f);
+ geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId);
+
+ batch.setResourceTexture(0, nullptr);
+ });
+ }
+}
+
+void DebugHighlight::initializePipelines() {
+ static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert };
+ static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag };
+ static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" };
+ static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER);
+ Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO,
+ "Could not find source placeholder");
+
+ auto state = std::make_shared();
+ state->setDepthTest(gpu::State::DepthTest(false, false));
+ state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL));
+
+ const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
+
+ // Depth shader
+ {
+ static const std::string DEPTH_SHADER{
+ "vec4 getFragmentColor() {"
+ " float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x;"
+ " Zdb = 1.0-(1.0-Zdb)*100;"
+ " return vec4(Zdb, Zdb, Zdb, 1.0); "
+ "}"
+ };
+
+ auto fragmentShader = FRAGMENT_SHADER;
+ fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEPTH_SHADER);
+
+ const auto ps = gpu::Shader::createPixel(fragmentShader);
+ const auto program = gpu::Shader::createProgram(vs, ps);
+
+ gpu::Shader::BindingSet slotBindings;
+ slotBindings.insert(gpu::Shader::Binding("depthMap", 0));
+ gpu::Shader::makeProgram(*program, slotBindings);
+
+ _depthPipeline = gpu::Pipeline::create(program, state);
+ }
+}
+
+const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() {
+ if (!_depthPipeline) {
+ initializePipelines();
+ }
+
+ return _depthPipeline;
+}
+
+void SelectionToHighlight::run(const render::RenderContextPointer& renderContext, Outputs& outputs) {
+ auto scene = renderContext->_scene;
+ auto highlightStage = scene->getStage(render::HighlightStage::getName());
+
+ outputs.clear();
+ _sharedParameters->_highlightIds.fill(render::HighlightStage::INVALID_INDEX);
+
+ for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) {
+ std::ostringstream stream;
+ if (i > 0) {
+ stream << "highlightList" << i;
+ } else {
+ stream << "contextOverlayHighlightList";
+ }
+ auto selectionName = stream.str();
+ if (!scene->isSelectionEmpty(selectionName)) {
+ auto highlightId = highlightStage->getHighlightIdBySelection(selectionName);
+ if (!render::HighlightStage::isIndexInvalid(highlightId)) {
+ _sharedParameters->_highlightIds[outputs.size()] = highlightId;
+ outputs.emplace_back(selectionName);
+ }
+ }
+ }
+}
+
+void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
+ if (_highlightPassIndex < inputs.size()) {
+ outputs = inputs[_highlightPassIndex];
+ } else {
+ outputs.clear();
+ }
+}
+
+DrawHighlightTask::DrawHighlightTask() {
+
+}
+
+void DrawHighlightTask::configure(const Config& config) {
+
+}
+
+void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
+ const auto items = inputs.getN(0).get();
+ const auto sceneFrameBuffer = inputs.getN(1);
+ const auto primaryFramebuffer = inputs.getN(2);
+ const auto deferredFrameTransform = inputs.getN(3);
+
+ // Prepare the ShapePipeline
+ auto shapePlumber = std::make_shared();
+ {
+ auto state = std::make_shared();
+ state->setDepthTest(true, true, gpu::LESS_EQUAL);
+ state->setColorWriteMask(false, false, false, false);
+
+ initMaskPipelines(*shapePlumber, state);
+ }
+ auto sharedParameters = std::make_shared();
+
+ const auto highlightSelectionNames = task.addJob("SelectionToHighlight", sharedParameters);
+
+ // Prepare for highlight group rendering.
+ const auto highlightRessources = task.addJob("PrepareHighlight", primaryFramebuffer);
+ render::Varying highlight0Rect;
+
+ for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) {
+ const auto selectionName = task.addJob("ExtractSelectionName", highlightSelectionNames, i);
+ const auto groupItems = addSelectItemJobs(task, selectionName, items);
+ const auto highlightedItemIDs = task.addJob("HighlightMetaToSubItemIDs", groupItems);
+ const auto highlightedItems = task.addJob("HighlightMetaToSubItems", highlightedItemIDs);
+
+ // Sort
+ const auto sortedPipelines = task.addJob("HighlightPipelineSort", highlightedItems);
+ const auto sortedBounds = task.addJob("HighlightDepthSort", sortedPipelines);
+
+ // Draw depth of highlighted objects in separate buffer
+ std::string name;
+ {
+ std::ostringstream stream;
+ stream << "HighlightMask" << i;
+ name = stream.str();
+ }
+ const auto drawMaskInputs = DrawHighlightMask::Inputs(sortedBounds, highlightRessources).asVarying();
+ const auto highlightedRect = task.addJob(name, drawMaskInputs, i, shapePlumber, sharedParameters);
+ if (i == 0) {
+ highlight0Rect = highlightedRect;
+ }
+
+ // Draw highlight
+ {
+ std::ostringstream stream;
+ stream << "HighlightEffect" << i;
+ name = stream.str();
+ }
+ const auto drawHighlightInputs = DrawHighlight::Inputs(deferredFrameTransform, highlightRessources, sceneFrameBuffer, highlightedRect).asVarying();
+ task.addJob(name, drawHighlightInputs, i, sharedParameters);
+ }
+
+ // Debug highlight
+ const auto debugInputs = DebugHighlight::Inputs(highlightRessources, const_cast(highlight0Rect)).asVarying();
+ task.addJob("HighlightDebug", debugInputs);
+}
+
+const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const render::Varying& selectionName,
+ const RenderFetchCullSortTask::BucketList& items) {
+ const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
+ const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
+ const auto& metas = items[RenderFetchCullSortTask::META];
+
+ const auto selectMetaInput = SelectItems::Inputs(metas, Varying(), selectionName).asVarying();
+ const auto selectedMetas = task.addJob("MetaSelection", selectMetaInput);
+ const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas, selectionName).asVarying();
+ const auto selectedMetasAndOpaques = task.addJob("OpaqueSelection", selectMetaAndOpaqueInput);
+ const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques, selectionName).asVarying();
+ return task.addJob("TransparentSelection", selectItemInput);
+}
+
+#include "model_shadow_vert.h"
+#include "skin_model_shadow_vert.h"
+
+#include "model_shadow_frag.h"
+
+void DrawHighlightTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) {
+ auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
+ auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
+ gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel);
+ shapePlumber.addPipeline(
+ ShapeKey::Filter::Builder().withoutSkinned(),
+ modelProgram, state);
+
+ auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
+ gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, modelPixel);
+ shapePlumber.addPipeline(
+ ShapeKey::Filter::Builder().withSkinned(),
+ skinProgram, state);
+}
diff --git a/libraries/render-utils/src/HighlightEffect.h b/libraries/render-utils/src/HighlightEffect.h
new file mode 100644
index 0000000000..90a8e730ce
--- /dev/null
+++ b/libraries/render-utils/src/HighlightEffect.h
@@ -0,0 +1,226 @@
+//
+// HighlightEffect.h
+// render-utils/src/
+//
+// Created by Olivier Prat on 08/08/17.
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_render_utils_HighlightEffect_h
+#define hifi_render_utils_HighlightEffect_h
+
+#include
+#include
+#include
+
+#include "DeferredFramebuffer.h"
+#include "DeferredFrameTransform.h"
+
+class HighlightRessources {
+public:
+ HighlightRessources();
+
+ gpu::FramebufferPointer getDepthFramebuffer();
+ gpu::TexturePointer getDepthTexture();
+
+ gpu::FramebufferPointer getColorFramebuffer();
+
+ // Update the source framebuffer size which will drive the allocation of all the other resources.
+ void update(const gpu::FramebufferPointer& primaryFrameBuffer);
+ const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
+
+protected:
+
+ gpu::FramebufferPointer _depthFrameBuffer;
+ gpu::FramebufferPointer _colorFrameBuffer;
+ gpu::TexturePointer _depthStencilTexture;
+
+ glm::ivec2 _frameSize;
+
+ void allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer);
+ void allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer);
+};
+
+using HighlightRessourcesPointer = std::shared_ptr;
+
+class HighlightSharedParameters {
+public:
+
+ enum {
+ MAX_PASS_COUNT = 8
+ };
+
+ HighlightSharedParameters();
+
+ std::array _highlightIds;
+
+ static float getBlurPixelWidth(const render::HighlightStyle& style, int frameBufferHeight);
+};
+
+using HighlightSharedParametersPointer = std::shared_ptr;
+
+class PrepareDrawHighlight {
+public:
+ using Inputs = gpu::FramebufferPointer;
+ using Outputs = HighlightRessourcesPointer;
+ using JobModel = render::Job::ModelIO;
+
+ PrepareDrawHighlight();
+
+ void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
+
+private:
+
+ HighlightRessourcesPointer _ressources;
+
+};
+
+class SelectionToHighlight {
+public:
+
+ using Outputs = std::vector;
+ using JobModel = render::Job::ModelO;
+
+ SelectionToHighlight(HighlightSharedParametersPointer parameters) : _sharedParameters{ parameters } {}
+
+ void run(const render::RenderContextPointer& renderContext, Outputs& outputs);
+
+private:
+
+ HighlightSharedParametersPointer _sharedParameters;
+};
+
+class ExtractSelectionName {
+public:
+
+ using Inputs = SelectionToHighlight::Outputs;
+ using Outputs = std::string;
+ using JobModel = render::Job::ModelIO;
+
+ ExtractSelectionName(unsigned int highlightIndex) : _highlightPassIndex{ highlightIndex } {}
+
+ void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
+
+private:
+
+ unsigned int _highlightPassIndex;
+
+};
+
+class DrawHighlightMask {
+public:
+
+ using Inputs = render::VaryingSet2;
+ using Outputs = glm::ivec4;
+ using JobModel = render::Job::ModelIO;
+
+ DrawHighlightMask(unsigned int highlightIndex, render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters);
+
+ void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
+
+protected:
+
+ unsigned int _highlightPassIndex;
+ render::ShapePlumberPointer _shapePlumber;
+ HighlightSharedParametersPointer _sharedParameters;
+ gpu::BufferPointer _boundsBuffer;
+
+ static gpu::PipelinePointer _stencilMaskPipeline;
+ static gpu::PipelinePointer _stencilMaskFillPipeline;
+};
+
+class DrawHighlight {
+public:
+
+ using Inputs = render::VaryingSet4;
+ using Config = render::Job::Config;
+ using JobModel = render::Job::ModelI;
+
+ DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters);
+
+ void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
+
+private:
+
+#include "Highlight_shared.slh"
+
+ enum {
+ SCENE_DEPTH_MAP_SLOT = 0,
+ HIGHLIGHTED_DEPTH_MAP_SLOT,
+
+ HIGHLIGHT_PARAMS_SLOT = 0,
+ FRAME_TRANSFORM_SLOT,
+ };
+
+ using HighlightConfigurationBuffer = gpu::StructBuffer;
+
+ static const gpu::PipelinePointer& getPipeline(const render::HighlightStyle& style);
+
+ static gpu::PipelinePointer _pipeline;
+ static gpu::PipelinePointer _pipelineFilled;
+
+ unsigned int _highlightPassIndex;
+ HighlightParameters _parameters;
+ HighlightSharedParametersPointer _sharedParameters;
+ HighlightConfigurationBuffer _configuration;
+};
+
+class DebugHighlightConfig : public render::Job::Config {
+ Q_OBJECT
+ Q_PROPERTY(bool viewMask MEMBER viewMask NOTIFY dirty)
+
+public:
+
+ bool viewMask{ false };
+
+signals:
+ void dirty();
+};
+
+class DebugHighlight {
+public:
+ using Inputs = render::VaryingSet2;
+ using Config = DebugHighlightConfig;
+ using JobModel = render::Job::ModelI;
+
+ DebugHighlight();
+ ~DebugHighlight();
+
+ void configure(const Config& config);
+ void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
+
+private:
+
+ gpu::PipelinePointer _depthPipeline;
+ int _geometryDepthId{ 0 };
+ bool _isDisplayEnabled{ false };
+
+ const gpu::PipelinePointer& getDepthPipeline();
+ void initializePipelines();
+};
+
+class DrawHighlightTask {
+public:
+
+ using Inputs = render::VaryingSet4;
+ using Config = render::Task::Config;
+ using JobModel = render::Task::ModelI;
+
+ DrawHighlightTask();
+
+ void configure(const Config& config);
+ void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
+
+private:
+
+ static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state);
+ static const render::Varying addSelectItemJobs(JobModel& task, const render::Varying& selectionName, const RenderFetchCullSortTask::BucketList& items);
+
+};
+
+#endif // hifi_render_utils_HighlightEffect_h
+
+
diff --git a/libraries/render-utils/src/Highlight_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv
new file mode 100644
index 0000000000..4927db9610
--- /dev/null
+++ b/libraries/render-utils/src/Highlight_aabox.slv
@@ -0,0 +1,104 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+// Generated on <$_SCRIBE_DATE$>
+//
+// Draw and transform the fed vertex position with the standard MVP stack
+// and offset the vertices by a certain amount in the vertex direction
+//
+// Created by Olivier Prat on 11/02/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 gpu/Transform.slh@>
+
+<$declareStandardTransform()$>
+
+struct ItemBound {
+ vec4 id_boundPos;
+ vec4 boundDim_s;
+};
+
+#if defined(GPU_GL410)
+uniform samplerBuffer ssbo0Buffer;
+ItemBound getItemBound(int i) {
+ int offset = 2 * i;
+ ItemBound bound;
+ bound.id_boundPos = texelFetch(ssbo0Buffer, offset);
+ bound.boundDim_s = texelFetch(ssbo0Buffer, offset + 1);
+ return bound;
+}
+#else
+layout(std140) buffer ssbo0Buffer {
+ ItemBound bounds[];
+};
+ItemBound getItemBound(int i) {
+ ItemBound bound = bounds[i];
+ return bound;
+}
+#endif
+
+uniform vec2 outlineWidth;
+
+void main(void) {
+ const vec3 UNIT_BOX_VERTICES[8] = vec3[8](
+ vec3(0.0, 1.0, 0.0),
+ vec3(1.0, 1.0, 0.0),
+ vec3(1.0, 0.0, 0.0),
+ vec3(0.0, 0.0, 0.0),
+ vec3(0.0, 1.0, 1.0),
+ vec3(1.0, 1.0, 1.0),
+ vec3(1.0, 0.0, 1.0),
+ vec3(0.0, 0.0, 1.0)
+ );
+ const vec3 UNIT_BOX_NORMALS[8] = vec3[8](
+ vec3(-1.0, 1.0, -1.0),
+ vec3(1.0, 1.0, -1.0),
+ vec3(1.0, -1.0, -1.0),
+ vec3(-1.0, -1.0, -1.0),
+ vec3(-1.0, 1.0, 1.0),
+ vec3(1.0, 1.0, 1.0),
+ vec3(1.0, -1.0, 1.0),
+ vec3(-1.0, -1.0, 1.0)
+ );
+ const int NUM_VERTICES_PER_CUBE = 36;
+ const int UNIT_BOX_TRIANGLE_INDICES[NUM_VERTICES_PER_CUBE] = int[NUM_VERTICES_PER_CUBE](
+ 0, 1, 2,
+ 0, 2, 3,
+ 3, 2, 6,
+ 3, 6, 7,
+ 7, 6, 5,
+ 7, 5, 4,
+ 4, 5, 1,
+ 4, 1, 0,
+ 1, 5, 6,
+ 1, 6, 2,
+ 4, 0, 3,
+ 4, 3, 7
+ );
+
+ int boundID = gl_VertexID / NUM_VERTICES_PER_CUBE;
+ int vertexID = gl_VertexID - boundID * NUM_VERTICES_PER_CUBE;
+ int triangleIndex = UNIT_BOX_TRIANGLE_INDICES[vertexID];
+ vec3 cubeVec = UNIT_BOX_VERTICES[triangleIndex];
+
+ ItemBound bound = getItemBound(boundID);
+ vec3 boundPos = bound.id_boundPos.yzw;
+ vec3 boundDim = bound.boundDim_s.xyz;
+
+ vec4 pos = vec4(boundPos + boundDim * cubeVec.xyz, 1.0);
+
+ // standard transform
+ TransformCamera cam = getTransformCamera();
+ TransformObject obj = getTransformObject();
+ <$transformModelToMonoClipPos(cam, obj, pos, gl_Position)$>
+
+ // Offset the vertex to take into account the outline width
+ pos.xyz += UNIT_BOX_NORMALS[triangleIndex];
+ vec4 offsetPosition;
+ <$transformModelToMonoClipPos(cam, obj, pos, offsetPosition)$>
+ gl_Position.xy += normalize(offsetPosition.xy-gl_Position.xy) * outlineWidth * gl_Position.w;
+ <$transformStereoClipsSpace(cam, gl_Position)$>
+}
diff --git a/libraries/render-utils/src/Outline_filled.slf b/libraries/render-utils/src/Highlight_filled.slf
similarity index 71%
rename from libraries/render-utils/src/Outline_filled.slf
rename to libraries/render-utils/src/Highlight_filled.slf
index aaa3396bac..53530746f0 100644
--- a/libraries/render-utils/src/Outline_filled.slf
+++ b/libraries/render-utils/src/Highlight_filled.slf
@@ -1,5 +1,5 @@
-// Outline_filled.slf
-// Add outline effect based on two zbuffers : one containing the total scene z and another
+// Highlight_filled.slf
+// Add highlight effect based on two zbuffers : one containing the total scene z and another
// with the z of only the objects to be outlined.
// This is the version with the fill effect inside the silhouette.
//
@@ -9,5 +9,5 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-<@include Outline.slh@>
+<@include Highlight.slh@>
<$main(1)$>
diff --git a/libraries/render-utils/src/Highlight_shared.slh b/libraries/render-utils/src/Highlight_shared.slh
new file mode 100644
index 0000000000..5efbde4d52
--- /dev/null
+++ b/libraries/render-utils/src/Highlight_shared.slh
@@ -0,0 +1,30 @@
+// glsl / C++ compatible source as interface for highlight
+#ifdef __cplusplus
+# define TVEC2 glm::vec2
+# define TVEC3 glm::vec3
+# define TVEC4 glm::vec4
+#else
+# define TVEC2 vec2
+# define TVEC3 vec3
+# define TVEC4 vec4
+#endif
+
+struct HighlightParameters
+{
+ TVEC3 _color;
+ float _intensity;
+
+ TVEC2 _size;
+ float _unoccludedFillOpacity;
+ float _occludedFillOpacity;
+
+ float _threshold;
+ int _blurKernelSize;
+ float padding2;
+ float padding3;
+};
+
+// <@if 1@>
+// Trigger Scribe include
+// <@endif@>
+//
diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp
index 079c63f367..c280abfeaf 100644
--- a/libraries/render-utils/src/LightStage.cpp
+++ b/libraries/render-utils/src/LightStage.cpp
@@ -14,6 +14,7 @@
#include "LightStage.h"
std::string LightStage::_stageName { "LIGHT_STAGE"};
+const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
LightStage::LightStage() {
}
diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h
index 66d73c9a6e..c26f504658 100644
--- a/libraries/render-utils/src/LightStage.h
+++ b/libraries/render-utils/src/LightStage.h
@@ -32,7 +32,7 @@ public:
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
- static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
+ static const Index INVALID_INDEX;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using LightPointer = model::LightPointer;
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index 8b65c9f7ce..1ea3e1a705 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -337,7 +337,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
if (state.clusterMatrices.size() == 1) {
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
}
- updateTransformForSkinnedMesh(renderTransform, transform, state.clusterBuffer);
+ updateTransformForSkinnedMesh(renderTransform, transform);
initCache();
}
@@ -367,12 +367,25 @@ void ModelMeshPartPayload::notifyLocationChanged() {
}
-void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform,
- const gpu::BufferPointer& buffer) {
+
+void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterMatrices) {
+ // Once computed the cluster matrices, update the buffer(s)
+ if (clusterMatrices.size() > 1) {
+ if (!_clusterBuffer) {
+ _clusterBuffer = std::make_shared(clusterMatrices.size() * sizeof(glm::mat4),
+ (const gpu::Byte*) clusterMatrices.data());
+ }
+ else {
+ _clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4),
+ (const gpu::Byte*) clusterMatrices.data());
+ }
+ }
+}
+
+void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
_transform = renderTransform;
_worldBound = _adjustedLocalBound;
_worldBound.transform(boundTransform);
- _clusterBuffer = buffer;
}
ItemKey ModelMeshPartPayload::getKey() const {
@@ -416,7 +429,6 @@ int ModelMeshPartPayload::getLayer() const {
}
ShapeKey ModelMeshPartPayload::getShapeKey() const {
-
// guard against partially loaded meshes
ModelPointer model = _model.lock();
if (!model || !model->isLoaded() || !model->getGeometry()) {
@@ -582,11 +594,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
}
-void ModelMeshPartPayload::computeAdjustedLocalBound(const QVector& clusterMatrices) {
+void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterMatrices) {
_adjustedLocalBound = _localBound;
if (clusterMatrices.size() > 0) {
_adjustedLocalBound.transform(clusterMatrices[0]);
- for (int i = 1; i < clusterMatrices.size(); ++i) {
+ for (int i = 1; i < (int)clusterMatrices.size(); ++i) {
AABox clusterBound = _localBound;
clusterBound.transform(clusterMatrices[i]);
_adjustedLocalBound += clusterBound;
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index 99c14510b5..971c6fe90b 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -87,9 +87,8 @@ public:
typedef Payload::DataPointer Pointer;
void notifyLocationChanged() override;
- void updateTransformForSkinnedMesh(const Transform& renderTransform,
- const Transform& boundTransform,
- const gpu::BufferPointer& buffer);
+ void updateClusterBuffer(const std::vector& clusterMatrices);
+ void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface
render::ItemKey getKey() const override;
@@ -103,7 +102,7 @@ public:
void initCache();
- void computeAdjustedLocalBound(const QVector& clusterMatrices);
+ void computeAdjustedLocalBound(const std::vector& clusterMatrices);
gpu::BufferPointer _clusterBuffer;
ModelWeakPointer _model;
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 97f62a3ce0..428fcc7a54 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -226,7 +226,7 @@ void Model::updateRenderItems() {
// do nothing, if the model has already been destroyed.
auto self = weakSelf.lock();
- if (!self) {
+ if (!self || !self->isLoaded()) {
return;
}
@@ -237,24 +237,20 @@ void Model::updateRenderItems() {
Transform modelTransform = self->getTransform();
modelTransform.setScale(glm::vec3(1.0f));
- uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
-
render::Transaction transaction;
- foreach (auto itemID, self->_modelMeshRenderItemsMap.keys()) {
- transaction.updateItem(itemID, [deleteGeometryCounter, modelTransform](ModelMeshPartPayload& data) {
- ModelPointer model = data._model.lock();
- if (model && model->isLoaded()) {
- // Ensure the model geometry was not reset between frames
- if (deleteGeometryCounter == model->_deleteGeometryCounter) {
+ for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
- const Model::MeshState& state = model->getMeshState(data._meshIndex);
- Transform renderTransform = modelTransform;
- if (state.clusterMatrices.size() == 1) {
- renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0]));
- }
- data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer);
- }
+ auto itemID = self->_modelMeshRenderItemIDs[i];
+ auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
+ auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
+
+ transaction.updateItem(itemID, [modelTransform, clusterMatrices](ModelMeshPartPayload& data) {
+ data.updateClusterBuffer(clusterMatrices);
+ Transform renderTransform = modelTransform;
+ if (clusterMatrices.size() == 1) {
+ renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
}
+ data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
});
}
@@ -311,7 +307,7 @@ bool Model::updateGeometry() {
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());
- _meshStates.append(state);
+ _meshStates.push_back(state);
// Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index
// later in ModelMeshPayload, however the vast majority of meshes will not have them.
@@ -686,6 +682,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti
_modelMeshRenderItemIDs.clear();
_modelMeshRenderItemsMap.clear();
_modelMeshRenderItems.clear();
+ _modelMeshRenderItemShapes.clear();
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.removeItem(item);
@@ -1127,7 +1124,7 @@ void Model::updateClusterMatrices() {
}
_needsUpdateClusterMatrices = false;
const FBXGeometry& geometry = getFBXGeometry();
- for (int i = 0; i < _meshStates.size(); i++) {
+ for (int i = 0; i < (int) _meshStates.size(); i++) {
MeshState& state = _meshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) {
@@ -1135,17 +1132,6 @@ void Model::updateClusterMatrices() {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
}
-
- // Once computed the cluster matrices, update the buffer(s)
- if (mesh.clusters.size() > 1) {
- if (!state.clusterBuffer) {
- state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4),
- (const gpu::Byte*) state.clusterMatrices.constData());
- } else {
- state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4),
- (const gpu::Byte*) state.clusterMatrices.constData());
- }
- }
}
// post the blender if we're not currently waiting for one to finish
@@ -1255,7 +1241,7 @@ void Model::createVisibleRenderItemSet() {
const auto& meshes = _renderGeometry->getMeshes();
// all of our mesh vectors must match in size
- if ((int)meshes.size() != _meshStates.size()) {
+ if (meshes.size() != _meshStates.size()) {
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
return;
}
@@ -1264,6 +1250,7 @@ void Model::createVisibleRenderItemSet() {
Q_ASSERT(_modelMeshRenderItems.isEmpty());
_modelMeshRenderItems.clear();
+ _modelMeshRenderItemShapes.clear();
Transform transform;
transform.setTranslation(_translation);
@@ -1286,6 +1273,7 @@ void Model::createVisibleRenderItemSet() {
int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) {
_modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset);
+ _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++;
}
}
@@ -1327,7 +1315,7 @@ void Model::createCollisionRenderItemSet() {
}
bool Model::isRenderable() const {
- return !_meshStates.isEmpty() || (isLoaded() && _renderGeometry->getMeshes().empty());
+ return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
}
class CollisionRenderGeometry : public Geometry {
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 3abf7e2758..c537a928b3 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -246,8 +246,7 @@ public:
class MeshState {
public:
- QVector clusterMatrices;
- gpu::BufferPointer clusterBuffer;
+ std::vector clusterMatrices;
};
const MeshState& getMeshState(int index) { return _meshStates.at(index); }
@@ -317,7 +316,7 @@ protected:
bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point
glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to
- QVector _meshStates;
+ std::vector _meshStates;
virtual void initJointStates();
@@ -388,8 +387,9 @@ protected:
QVector> _modelMeshRenderItems;
QMap _modelMeshRenderItemsMap;
-
render::ItemIDs _modelMeshRenderItemIDs;
+ using ShapeInfo = struct { int meshIndex; };
+ std::vector _modelMeshRenderItemShapes;
bool _addedToScene { false }; // has been added to scene
bool _needsFixupInScene { true }; // needs to be removed/re-added to scene
diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp
deleted file mode 100644
index d5b3b1c3bb..0000000000
--- a/libraries/render-utils/src/OutlineEffect.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-//
-// OutlineEffect.cpp
-// render-utils/src/
-//
-// Created by Olivier Prat on 08/08/17.
-// Copyright 2017 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-#include "OutlineEffect.h"
-
-#include "GeometryCache.h"
-
-#include
-#include
-
-#include "gpu/Context.h"
-#include "gpu/StandardShaderLib.h"
-
-
-#include "surfaceGeometry_copyDepth_frag.h"
-#include "debug_deferred_buffer_vert.h"
-#include "debug_deferred_buffer_frag.h"
-#include "Outline_frag.h"
-#include "Outline_filled_frag.h"
-
-using namespace render;
-
-extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state);
-
-OutlineFramebuffer::OutlineFramebuffer() {
-}
-
-void OutlineFramebuffer::update(const gpu::TexturePointer& colorBuffer) {
- // If the depth buffer or size changed, we need to delete our FBOs and recreate them at the
- // new correct dimensions.
- if (_depthTexture) {
- auto newFrameSize = glm::ivec2(colorBuffer->getDimensions());
- if (_frameSize != newFrameSize) {
- _frameSize = newFrameSize;
- clear();
- }
- }
-}
-
-void OutlineFramebuffer::clear() {
- _depthFramebuffer.reset();
- _depthTexture.reset();
-}
-
-void OutlineFramebuffer::allocate() {
-
- auto width = _frameSize.x;
- auto height = _frameSize.y;
- auto format = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
-
- _depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(format, width, height));
- _depthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth"));
- _depthFramebuffer->setDepthStencilBuffer(_depthTexture, format);
-}
-
-gpu::FramebufferPointer OutlineFramebuffer::getDepthFramebuffer() {
- if (!_depthFramebuffer) {
- allocate();
- }
- return _depthFramebuffer;
-}
-
-gpu::TexturePointer OutlineFramebuffer::getDepthTexture() {
- if (!_depthTexture) {
- allocate();
- }
- return _depthTexture;
-}
-
-void DrawOutlineDepth::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) {
- assert(renderContext->args);
- assert(renderContext->args->hasViewFrustum());
- auto& inShapes = inputs.get0();
- auto& deferredFrameBuffer = inputs.get1();
-
- if (!inShapes.empty()) {
- RenderArgs* args = renderContext->args;
- ShapeKey::Builder defaultKeyBuilder;
-
- if (!_outlineFramebuffer) {
- _outlineFramebuffer = std::make_shared();
- }
- _outlineFramebuffer->update(deferredFrameBuffer->getDeferredColorTexture());
-
- gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
- args->_batch = &batch;
-
- batch.setFramebuffer(_outlineFramebuffer->getDepthFramebuffer());
- // Clear it
- batch.clearFramebuffer(
- gpu::Framebuffer::BUFFER_DEPTH,
- vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, false);
-
- // Setup camera, projection and viewport for all items
- batch.setViewportTransform(args->_viewport);
- batch.setStateScissorRect(args->_viewport);
-
- glm::mat4 projMat;
- Transform viewMat;
- args->getViewFrustum().evalProjectionMatrix(projMat);
- args->getViewFrustum().evalViewTransform(viewMat);
-
- batch.setProjectionTransform(projMat);
- batch.setViewTransform(viewMat);
-
- auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
- auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
-
- std::vector skinnedShapeKeys{};
-
- // Iterate through all inShapes and render the unskinned
- args->_shapePipeline = shadowPipeline;
- batch.setPipeline(shadowPipeline->pipeline);
- for (auto items : inShapes) {
- if (items.first.isSkinned()) {
- skinnedShapeKeys.push_back(items.first);
- }
- else {
- renderItems(renderContext, items.second);
- }
- }
-
- // Reiterate to render the skinned
- args->_shapePipeline = shadowSkinnedPipeline;
- batch.setPipeline(shadowSkinnedPipeline->pipeline);
- for (const auto& key : skinnedShapeKeys) {
- renderItems(renderContext, inShapes.at(key));
- }
-
- args->_shapePipeline = nullptr;
- args->_batch = nullptr;
- });
-
- output = _outlineFramebuffer;
- } else {
- output = nullptr;
- }
-}
-
-DrawOutline::DrawOutline() {
-}
-
-void DrawOutline::configure(const Config& config) {
- _color = config.color;
- _blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width*2 + 0.5f)));
- // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400.
- _size = config.width / 400.f;
- _fillOpacityUnoccluded = config.fillOpacityUnoccluded;
- _fillOpacityOccluded = config.fillOpacityOccluded;
- _threshold = config.glow ? 1.f : 1e-3f;
- _intensity = config.intensity * (config.glow ? 2.f : 1.f);
-}
-
-void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
- auto outlineFrameBuffer = inputs.get1();
-
- if (outlineFrameBuffer) {
- auto sceneDepthBuffer = inputs.get2();
- const auto frameTransform = inputs.get0();
- auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture();
- auto destinationFrameBuffer = inputs.get3();
- auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions());
-
- if (!_primaryWithoutDepthBuffer || framebufferSize!=_frameBufferSize) {
- // Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac
- _primaryWithoutDepthBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth"));
- _primaryWithoutDepthBuffer->setRenderBuffer(0, destinationFrameBuffer->getRenderBuffer(0));
- _frameBufferSize = framebufferSize;
- }
-
- if (sceneDepthBuffer) {
- const auto OPACITY_EPSILON = 5e-3f;
- auto pipeline = getPipeline(_fillOpacityUnoccluded>OPACITY_EPSILON || _fillOpacityOccluded>OPACITY_EPSILON);
- auto args = renderContext->args;
- {
- auto& configuration = _configuration.edit();
- configuration._color = _color;
- configuration._intensity = _intensity;
- configuration._fillOpacityUnoccluded = _fillOpacityUnoccluded;
- configuration._fillOpacityOccluded = _fillOpacityOccluded;
- configuration._threshold = _threshold;
- configuration._blurKernelSize = _blurKernelSize;
- configuration._size.x = _size * _frameBufferSize.y / _frameBufferSize.x;
- configuration._size.y = _size;
- }
-
- gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
- batch.enableStereo(false);
- batch.setFramebuffer(_primaryWithoutDepthBuffer);
-
- batch.setViewportTransform(args->_viewport);
- batch.setProjectionTransform(glm::mat4());
- batch.resetViewTransform();
- batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_frameBufferSize, args->_viewport));
- batch.setPipeline(pipeline);
-
- batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
- batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
- batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture());
- batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture);
- batch.draw(gpu::TRIANGLE_STRIP, 4);
-
- // Restore previous frame buffer
- batch.setFramebuffer(destinationFrameBuffer);
- });
- }
- }
-}
-
-const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) {
- if (!_pipeline) {
- auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
- auto ps = gpu::Shader::createPixel(std::string(Outline_frag));
- gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
-
- gpu::Shader::BindingSet slotBindings;
- slotBindings.insert(gpu::Shader::Binding("outlineParamsBuffer", OUTLINE_PARAMS_SLOT));
- slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT));
- slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT));
- slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT));
- gpu::Shader::makeProgram(*program, slotBindings);
-
- gpu::StatePointer state = gpu::StatePointer(new gpu::State());
- state->setDepthTest(gpu::State::DepthTest(false, false));
- state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
- _pipeline = gpu::Pipeline::create(program, state);
-
- ps = gpu::Shader::createPixel(std::string(Outline_filled_frag));
- program = gpu::Shader::createProgram(vs, ps);
- gpu::Shader::makeProgram(*program, slotBindings);
- _pipelineFilled = gpu::Pipeline::create(program, state);
- }
- return isFilled ? _pipelineFilled : _pipeline;
-}
-
-DebugOutline::DebugOutline() {
- _geometryId = DependencyManager::get()->allocateID();
-}
-
-DebugOutline::~DebugOutline() {
- auto geometryCache = DependencyManager::get();
- if (geometryCache) {
- geometryCache->releaseID(_geometryId);
- }
-}
-
-void DebugOutline::configure(const Config& config) {
- _isDisplayDepthEnabled = config.viewOutlinedDepth;
-}
-
-void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) {
- const auto outlineFramebuffer = input;
-
- if (_isDisplayDepthEnabled && outlineFramebuffer) {
- assert(renderContext->args);
- assert(renderContext->args->hasViewFrustum());
- RenderArgs* args = renderContext->args;
-
- gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
- batch.enableStereo(false);
- batch.setViewportTransform(args->_viewport);
-
- const auto geometryBuffer = DependencyManager::get();
-
- glm::mat4 projMat;
- Transform viewMat;
- args->getViewFrustum().evalProjectionMatrix(projMat);
- args->getViewFrustum().evalViewTransform(viewMat);
- batch.setProjectionTransform(projMat);
- batch.setViewTransform(viewMat, true);
- batch.setModelTransform(Transform());
-
- batch.setPipeline(getDebugPipeline());
- batch.setResourceTexture(0, outlineFramebuffer->getDepthTexture());
-
- const glm::vec4 color(1.0f, 0.5f, 0.2f, 1.0f);
- const glm::vec2 bottomLeft(-1.0f, -1.0f);
- const glm::vec2 topRight(1.0f, 1.0f);
- geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryId);
-
- batch.setResourceTexture(0, nullptr);
- });
- }
-}
-
-const gpu::PipelinePointer& DebugOutline::getDebugPipeline() {
- if (!_debugPipeline) {
- static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert };
- static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag };
- static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" };
- static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER);
- Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO,
- "Could not find source placeholder");
- static const std::string DEFAULT_DEPTH_SHADER{
- "vec4 getFragmentColor() {"
- " float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x;"
- " Zdb = 1.0-(1.0-Zdb)*100;"
- " return vec4(Zdb, Zdb, Zdb, 1.0);"
- " }"
- };
-
- auto bakedFragmentShader = FRAGMENT_SHADER;
- bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEFAULT_DEPTH_SHADER);
-
- static const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
- const auto ps = gpu::Shader::createPixel(bakedFragmentShader);
- const auto program = gpu::Shader::createProgram(vs, ps);
-
- gpu::Shader::BindingSet slotBindings;
- slotBindings.insert(gpu::Shader::Binding("depthMap", 0));
- gpu::Shader::makeProgram(*program, slotBindings);
-
- auto state = std::make_shared();
- state->setDepthTest(gpu::State::DepthTest(false));
- _debugPipeline = gpu::Pipeline::create(program, state);
- }
-
- return _debugPipeline;
-}
-
-DrawOutlineTask::DrawOutlineTask() {
-
-}
-
-void DrawOutlineTask::configure(const Config& config) {
-
-}
-
-void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
- const auto input = inputs.get();
- const auto selectedMetas = inputs.getN