mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 13:43:49 +02:00
Merge pull request #11801 from highfidelity/RC59
Beta Release 59 - Includes up to Developer Release 7426
This commit is contained in:
commit
f7c27966a9
178 changed files with 4023 additions and 2524 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -41,8 +41,15 @@ EntityServer::EntityServer(ReceivedMessage& message) :
|
|||
DependencyManager::set<ScriptCache>();
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->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
|
||||
|
|
|
@ -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<OctreeQueryNode*>(params.nodeData);
|
||||
nodeData->stats.encodeStarted();
|
||||
auto entityNode = _node.toStrongRef();
|
||||
auto entityNodeData = static_cast<EntityNodeData*>(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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -96,6 +96,14 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer<ReceivedMessage>
|
|||
_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++;
|
||||
|
|
|
@ -82,8 +82,12 @@ bool OctreeSendThread::process() {
|
|||
if (auto node = _node.lock()) {
|
||||
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(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);
|
||||
}
|
||||
|
|
76
cmake/externals/hifiAudioCodec/CMakeLists.txt
vendored
76
cmake/externals/hifiAudioCodec/CMakeLists.txt
vendored
|
@ -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()
|
||||
|
|
4
cmake/externals/wasapi/CMakeLists.txt
vendored
4
cmake/externals/wasapi/CMakeLists.txt
vendored
|
@ -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 ""
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -19,12 +19,13 @@
|
|||
Upload an entities file (e.g.: models.json.gz) to replace the content of this domain.<br>
|
||||
Note: <strong>Your domain's content will be replaced by the content you upload</strong>, but the backup files of your domain's content will not immediately be changed.
|
||||
</p>
|
||||
<p>
|
||||
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:<br>
|
||||
<pre>C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
||||
<pre>/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
||||
<pre>/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
||||
</p>
|
||||
<p>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:</p>
|
||||
<label class="control-label">Windows</label>
|
||||
<pre>C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
||||
<label class="control-label">OSX</label>
|
||||
<pre>/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
||||
<label class="control-label">Linux</label>
|
||||
<pre>/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
||||
<br>
|
||||
<input type="file" name="entities-file" class="form-control-file" accept=".json, .gz">
|
||||
<br>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: "<b>The Wallet app is in closed Beta.</b><br><br>To request entry and <b>receive free HFC</b>, please contact " +
|
||||
"<b>info@highfidelity.com</b> 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"});
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -1825,6 +1825,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// Preload Tablet sounds
|
||||
DependencyManager::get<TabletScriptingInterface>()->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");
|
||||
}
|
||||
|
|
|
@ -708,7 +708,7 @@ private:
|
|||
|
||||
friend class RenderEventHandler;
|
||||
|
||||
std::atomic<bool> _pendingIdleEvent { false };
|
||||
std::atomic<bool> _pendingRenderEvent { false };
|
||||
std::atomic<bool> _pendingIdleEvent { true };
|
||||
std::atomic<bool> _pendingRenderEvent { true };
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() {
|
||||
setPassphrase("");
|
||||
});
|
||||
}
|
||||
|
||||
void QmlCommerce::getWalletStatus() {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<Wallet>();
|
||||
|
@ -717,50 +718,86 @@ bool Wallet::changePassphrase(const QString& newPassphrase) {
|
|||
}
|
||||
|
||||
void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
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<const unsigned char*>(encryptedText.constData()),
|
||||
decryptedText,
|
||||
rsa,
|
||||
RSA_PKCS1_OAEP_PADDING);
|
||||
|
||||
RSA_free(rsa);
|
||||
|
||||
if (decryptionStatus != -1) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray decryptedTextByteArray = QByteArray(reinterpret_cast<const char*>(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<const char*>(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() {
|
||||
|
|
|
@ -25,7 +25,6 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
|
|||
_distanceScaleEnd(distanceScaleEnd),
|
||||
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->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<EntityScriptingInterface>()->getEntityProperties(_objectLockEnd.first);
|
||||
pos = props.getPosition();
|
||||
rot = props.getRotation();
|
||||
EntityItemProperties props = DependencyManager::get<EntityScriptingInterface>()->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<QUuid, bool>(objectID, isOverlay);
|
||||
_lockEndObject.id = objectID;
|
||||
_lockEndObject.isOverlay = isOverlay;
|
||||
_lockEndObject.offsetMat = offsetMat;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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<QUuid>& ignoreItems) const;
|
||||
void setIncludeItems(const QVector<QUuid>& includeItems) const;
|
||||
|
@ -91,7 +97,7 @@ private:
|
|||
bool _centerEndY;
|
||||
bool _lockEnd;
|
||||
bool _distanceScaleEnd;
|
||||
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
|
||||
LockEndObject _lockEndObject;
|
||||
|
||||
const QUuid _rayPickUID;
|
||||
|
||||
|
|
|
@ -113,9 +113,9 @@ void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const;
|
||||
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& 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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <class T> bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) {
|
||||
GameplayObjects currentList = _selectedItemsListMap.value(listName);
|
||||
currentList.addToGameplayObjects(idToAdd);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Overlay>(itemID, [latestTransform](Overlay& data) {
|
||||
transaction.updateItem<Overlay>(itemID, [latestTransform, latestVisible](Overlay& data) {
|
||||
auto overlay3D = dynamic_cast<Base3DOverlay*>(&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();
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
#include <EntityTreeRenderer.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <commerce/Ledger.h>
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
@ -34,14 +38,14 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
_selectionScriptingInterface = DependencyManager::get<SelectionScriptingInterface>();
|
||||
|
||||
_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<EntityScriptingInterface>().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<NodeList>();
|
||||
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<TabletProxy*>(_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<NodeList>();
|
||||
|
||||
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<EntityTreeRenderer>()->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<Ledger>();
|
||||
_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<Ledger>();
|
||||
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<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
|
||||
_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<EntityTreeRenderer>()->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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,10 +47,12 @@ class ContextOverlayInterface : public QObject, public Dependency {
|
|||
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
|
||||
std::shared_ptr<Image3DOverlay> _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<ReceivedMessage> 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
|
||||
|
|
|
@ -44,7 +44,7 @@ Cube3DOverlay::~Cube3DOverlay() {
|
|||
}
|
||||
|
||||
void Cube3DOverlay::render(RenderArgs* args) {
|
||||
if (!_visible) {
|
||||
if (!_renderVisible) {
|
||||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<GeometryCache>();
|
||||
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<GeometryCache>();
|
||||
|
@ -124,8 +114,3 @@ void Rectangle3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
Rectangle3DOverlay* Rectangle3DOverlay::createClone() const {
|
||||
return new Rectangle3DOverlay(this);
|
||||
}
|
||||
|
||||
Transform Rectangle3DOverlay::evalRenderTransform() {
|
||||
return getTransform();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,6 @@ public:
|
|||
|
||||
virtual Rectangle3DOverlay* createClone() const override;
|
||||
|
||||
protected:
|
||||
Transform evalRenderTransform() override;
|
||||
|
||||
private:
|
||||
int _geometryCacheID;
|
||||
std::array<int, 4> _rectGeometryIds;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<AnimClip>(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();
|
||||
|
|
|
@ -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<QString, RoleAnimState> _roleAnimStates;
|
||||
|
||||
float _leftHandOverlayAlpha { 0.0f };
|
||||
float _rightHandOverlayAlpha { 0.0f };
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,21 +15,7 @@
|
|||
#include <string>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
/* 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 <inttypes.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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<NodeList>();
|
||||
|
||||
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<AddressManager>()->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<AddressManager>()->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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtEndian>
|
||||
#include <QJsonDocument>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
@ -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<const unsigned char*>(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<const unsigned char*>(digestByteArray.constData());
|
||||
int digestLength = digestByteArray.length();
|
||||
|
||||
const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8());
|
||||
const unsigned char* signature = reinterpret_cast<const unsigned char*>(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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -14,6 +14,15 @@
|
|||
#include <QObject>
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
@ -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<const unsigned char*>(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<const unsigned char*>(digestByteArray.constData());
|
||||
int digestLength = digestByteArray.length();
|
||||
|
||||
const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8());
|
||||
const unsigned char* signature = reinterpret_cast<const unsigned char*>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<glm::vec3>& strokeColors) const;
|
||||
|
||||
QByteArray getStaticCertificateJSON() const;
|
||||
QByteArray getStaticCertificateHash() const;
|
||||
bool verifyStaticCertificateProperties();
|
||||
|
||||
protected:
|
||||
QString getCollisionMaskAsString() const;
|
||||
void setCollisionMaskFromString(const QString& maskString);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<NodeList>();
|
||||
|
||||
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<NodeList>();
|
||||
|
||||
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<NodeList>();
|
||||
|
||||
// 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<NodeList>();
|
||||
|
@ -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.";
|
||||
|
|
|
@ -93,6 +93,8 @@ public:
|
|||
void fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& 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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<SkyboxPropertyGroup>([&] { 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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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@>
|
||||
|
|
|
@ -9,12 +9,30 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include <memory>
|
||||
#include <gpu/Resource.h>
|
||||
|
||||
#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<gpu::Buffer>(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<Parameters>();
|
||||
|
||||
if (params.directionalLightBlend != hazeDirectionalLightBlend) {
|
||||
_hazeParametersBuffer.edit<Parameters>().directionalLightBlend = hazeDirectionalLightBlend;
|
||||
if (params.hazeGlareBlend != hazeGlareBlend) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeGlareBlend = hazeGlareBlend;
|
||||
}
|
||||
}
|
||||
|
||||
void Haze::setDirectionalLightColor(const glm::vec3 hazeDirectionalLightColor) {
|
||||
void Haze::setHazeGlareColor(const glm::vec3 hazeGlareColor) {
|
||||
auto& params = _hazeParametersBuffer.get<Parameters>();
|
||||
|
||||
if (params.directionalLightColor.r != hazeDirectionalLightColor.r) {
|
||||
_hazeParametersBuffer.edit<Parameters>().directionalLightColor.r = hazeDirectionalLightColor.r;
|
||||
if (params.hazeGlareColor.r != hazeGlareColor.r) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeGlareColor.r = hazeGlareColor.r;
|
||||
}
|
||||
if (params.directionalLightColor.g != hazeDirectionalLightColor.g) {
|
||||
_hazeParametersBuffer.edit<Parameters>().directionalLightColor.g = hazeDirectionalLightColor.g;
|
||||
if (params.hazeGlareColor.g != hazeGlareColor.g) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeGlareColor.g = hazeGlareColor.g;
|
||||
}
|
||||
if (params.directionalLightColor.b != hazeDirectionalLightColor.b) {
|
||||
_hazeParametersBuffer.edit<Parameters>().directionalLightColor.b = hazeDirectionalLightColor.b;
|
||||
if (params.hazeGlareColor.b != hazeGlareColor.b) {
|
||||
_hazeParametersBuffer.edit<Parameters>().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<Parameters>();
|
||||
|
||||
if (((params.hazeMode & HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED) == HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED ) && !isHazeAttenuateKeyLight) {
|
||||
_hazeParametersBuffer.edit<Parameters>().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<Parameters>().hazeMode |= HAZE_MODE_IS_DIRECTIONAL_LIGHT_ATTENUATED;
|
||||
if (((params.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) && !isHazeAttenuateKeyLight) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeMode &= ~HAZE_MODE_IS_KEYLIGHT_ATTENUATED;
|
||||
} else if (((params.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) != HAZE_MODE_IS_KEYLIGHT_ATTENUATED) && isHazeAttenuateKeyLight) {
|
||||
_hazeParametersBuffer.edit<Parameters>().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<Parameters>();
|
||||
|
||||
if (params.hazeAltitudeFactor != hazeAltitudeFactor) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeAltitudeFactor = hazeAltitudeFactor;
|
||||
if (params.hazeHeightFactor != hazeHeightFactor) {
|
||||
_hazeParametersBuffer.edit<Parameters>().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<Parameters>();
|
||||
|
||||
if (params.hazeBackgroundBlendValue != hazeBackgroundBlendValue) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeBackgroundBlendValue = hazeBackgroundBlendValue;
|
||||
if (params.hazeBackgroundBlend != hazeBackgroundBlend) {
|
||||
_hazeParametersBuffer.edit<Parameters>().hazeBackgroundBlend = hazeBackgroundBlend;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,71 +12,70 @@
|
|||
#define hifi_model_Haze_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <gpu/Resource.h>
|
||||
|
||||
#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() {}
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<int>(LookupTrigger::UserInput));
|
||||
|
||||
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(
|
||||
shouldMatchOrientation ? LookupTrigger::UserInput : LookupTrigger::VisitUserFromPAL
|
||||
));
|
||||
// this is a username - pull the captured name and lookup that user's location
|
||||
DependencyManager::get<AccountManager>()->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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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:
|
||||
// <hifi repo>\domain-server\resources\web\settings\js\settings.js
|
||||
// don't forget to ALSO change the Domain Server Metaverse Server URL inside of:
|
||||
// <hifi repo>\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;
|
||||
|
|
|
@ -124,6 +124,8 @@ public:
|
|||
OctreeFileReplacementFromUrl,
|
||||
ChallengeOwnership,
|
||||
EntityScriptCallMethod,
|
||||
ChallengeOwnershipRequest,
|
||||
ChallengeOwnershipReply,
|
||||
NUM_PACKET_TYPE
|
||||
};
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <inttypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
@ -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; }
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <UUID.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<btCollisionShape*>(shape);
|
||||
if (nonConstShape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) {
|
||||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(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;
|
||||
}
|
||||
|
|
|
@ -17,25 +17,11 @@
|
|||
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -17,7 +17,29 @@
|
|||
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#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<DoubleHashKey, ShapeReference> _shapeMap;
|
||||
btAlignedObjectArray<DoubleHashKey> _pendingGarbage;
|
||||
// btHashMap is required because it supports memory alignment of the btCollisionShapes
|
||||
btHashMap<HashKey, ShapeReference> _shapeMap;
|
||||
btAlignedObjectArray<HashKey> _pendingGarbage;
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeManager_h
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <gpu/Context.h>
|
||||
|
||||
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);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue