fixed merge conflicts

This commit is contained in:
ericrius1 2016-01-05 16:28:22 -08:00
commit eb44e54d87
80 changed files with 1175 additions and 470 deletions

View file

@ -11,9 +11,14 @@
#include "AssignmentParentFinder.h" #include "AssignmentParentFinder.h"
SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID) const { SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID, bool& success) const {
SpatiallyNestableWeakPointer parent; SpatiallyNestableWeakPointer parent;
// search entities // search entities
parent = _tree->findEntityByEntityItemID(parentID); parent = _tree->findEntityByEntityItemID(parentID);
if (parent.expired()) {
success = false;
} else {
success = true;
}
return parent; return parent;
} }

View file

@ -25,7 +25,7 @@ class AssignmentParentFinder : public SpatialParentFinder {
public: public:
AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { } AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { }
virtual ~AssignmentParentFinder() { } virtual ~AssignmentParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID) const; virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success) const;
protected: protected:
EntityTreePointer _tree; EntityTreePointer _tree;

View file

@ -5,7 +5,7 @@ include(ExternalProject)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://zlib.net/zlib128.zip URL http://hifi-public.s3.amazonaws.com/dependencies/zlib128.zip
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
LOG_DOWNLOAD 1 LOG_DOWNLOAD 1

View file

@ -1372,6 +1372,7 @@ function MyController(hand) {
} }
} }
if (!this.setupHoldAction()) { if (!this.setupHoldAction()) {
return; return;
} }

View file

@ -1,6 +1,6 @@
// //
// actionInspector.js // actionInspector.js
// examples // examples/debugging/
// //
// Created by Seth Alves on 2015-9-30. // Created by Seth Alves on 2015-9-30.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
Script.include("libraries/utils.js"); Script.include("../libraries/utils.js");
var INSPECT_RADIUS = 10; var INSPECT_RADIUS = 10;

View file

@ -1,6 +1,6 @@
// //
// grabInspector.js // grabInspector.js
// examples // examples/debugging/
// //
// Created by Seth Alves on 2015-9-30. // Created by Seth Alves on 2015-9-30.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
Script.include("libraries/utils.js"); Script.include("../libraries/utils.js");
var INSPECT_RADIUS = 10; var INSPECT_RADIUS = 10;
var overlays = {}; var overlays = {};

View file

@ -0,0 +1,58 @@
//
// grabInspector.js
// examples/debugging/
//
// Created by Seth Alves on 2015-12-19.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// This script draws an overlay cube around nearby entities to show their queryAABoxes.
Script.include("../libraries/utils.js");
var INSPECT_RADIUS = 10;
var overlays = {};
function updateOverlay(entityID, queryAACube) {
var cubeCenter = {x: queryAACube.x + queryAACube.scale / 2.0,
y: queryAACube.y + queryAACube.scale / 2.0,
z: queryAACube.z + queryAACube.scale / 2.0};
if (entityID in overlays) {
var overlay = overlays[entityID];
Overlays.editOverlay(overlay, {
position: cubeCenter,
size: queryAACube.scale
});
} else {
overlays[entityID] = Overlays.addOverlay("cube", {
position: cubeCenter,
size: queryAACube.scale,
color: { red: 0, green: 0, blue: 255},
alpha: 1,
// borderSize: ...,
solid: false
});
}
}
Script.setInterval(function() {
var nearbyEntities = Entities.findEntities(MyAvatar.position, INSPECT_RADIUS);
for (var entityIndex = 0; entityIndex < nearbyEntities.length; entityIndex++) {
var entityID = nearbyEntities[entityIndex];
var queryAACube = Entities.getEntityProperties(entityID, ["queryAACube"]).queryAACube;
updateOverlay(entityID, queryAACube);
}
}, 100);
function cleanup() {
for (var entityID in overlays) {
Overlays.deleteOverlay(overlays[entityID]);
}
}
Script.scriptEnding.connect(cleanup);

View file

@ -17,13 +17,14 @@
} }
Target.prototype = { Target.prototype = {
hasPlayedSound: false, hasBecomeActive: false,
preload: function(entityID) { preload: function(entityID) {
this.entityID = entityID; this.entityID = entityID;
var SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/Clay_Pigeon_02.L.wav"; var SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/Clay_Pigeon_02.L.wav";
this.hitSound = SoundCache.getSound(SOUND_URL); this.hitSound = SoundCache.getSound(SOUND_URL);
}, },
collisionWithEntity: function(me, otherEntity) { collisionWithEntity: function(me, otherEntity) {
if (this.hasBecomeActive === false) {
var position = Entities.getEntityProperties(me, "position").position; var position = Entities.getEntityProperties(me, "position").position;
Entities.editEntity(me, { Entities.editEntity(me, {
gravity: { gravity: {
@ -38,13 +39,12 @@
} }
}); });
if (this.hasPlayedSound === false) {
this.audioInjector = Audio.playSound(this.hitSound, { this.audioInjector = Audio.playSound(this.hitSound, {
position: position, position: position,
volume: 0.5 volume: 0.5
}); });
this.hasPlayedSound = true; this.hasBecomeActive = true;
} }

View file

@ -11,7 +11,7 @@
{ "from": "Standard.DR", "to": "Actions.UiNavLateral" }, { "from": "Standard.DR", "to": "Actions.UiNavLateral" },
{ "from": "Standard.LB", "to": "Actions.UiNavGroup","filters": "invert" }, { "from": "Standard.LB", "to": "Actions.UiNavGroup","filters": "invert" },
{ "from": "Standard.RB", "to": "Actions.UiNavGroup" }, { "from": "Standard.RB", "to": "Actions.UiNavGroup" },
{ "from": [ "Standard.A", "Standard.X", "Standard.RT", "Standard.LT" ], "to": "Actions.UiNavSelect" }, { "from": [ "Standard.A", "Standard.X" ], "to": "Actions.UiNavSelect" },
{ "from": [ "Standard.B", "Standard.Y", "Standard.RightPrimaryThumb", "Standard.LeftPrimaryThumb" ], "to": "Actions.UiNavBack" }, { "from": [ "Standard.B", "Standard.Y", "Standard.RightPrimaryThumb", "Standard.LeftPrimaryThumb" ], "to": "Actions.UiNavBack" },
{ {
"from": [ "Standard.RT", "Standard.LT" ], "from": [ "Standard.RT", "Standard.LT" ],

View file

@ -169,8 +169,10 @@ DialogContainer {
switch (event.key) { switch (event.key) {
case Qt.Key_Escape: case Qt.Key_Escape:
case Qt.Key_Back: case Qt.Key_Back:
if (enabled) {
enabled = false enabled = false
event.accepted = true event.accepted = true
}
break break
case Qt.Key_Enter: case Qt.Key_Enter:
case Qt.Key_Return: case Qt.Key_Return:

View file

@ -96,6 +96,9 @@ DialogContainer {
} }
Keys.onPressed: { Keys.onPressed: {
if (!enabled) {
return
}
switch (event.key) { switch (event.key) {
case Qt.Key_Escape: case Qt.Key_Escape:
case Qt.Key_Back: case Qt.Key_Back:

View file

@ -343,8 +343,10 @@ DialogContainer {
switch (event.key) { switch (event.key) {
case Qt.Key_Escape: case Qt.Key_Escape:
case Qt.Key_Back: case Qt.Key_Back:
if (enabled) {
enabled = false enabled = false
event.accepted = true event.accepted = true
}
break break
case Qt.Key_Enter: case Qt.Key_Enter:
case Qt.Key_Return: case Qt.Key_Return:

View file

@ -300,6 +300,10 @@ VrDialog {
Keys.onPressed: { Keys.onPressed: {
if (!enabled) {
return
}
if (event.modifiers === Qt.ControlModifier) if (event.modifiers === Qt.ControlModifier)
switch (event.key) { switch (event.key) {
case Qt.Key_A: case Qt.Key_A:

View file

@ -10,7 +10,6 @@ import "styles"
VrDialog { VrDialog {
id: root id: root
objectName: "topLevelWindow"
HifiConstants { id: hifi } HifiConstants { id: hifi }
title: "QmlWindow" title: "QmlWindow"
resizable: true resizable: true
@ -43,10 +42,6 @@ VrDialog {
focus: true focus: true
property var dialog: root property var dialog: root
onLoaded: {
forceActiveFocus()
}
Keys.onPressed: { Keys.onPressed: {
console.log("QmlWindow pageLoader keypress") console.log("QmlWindow pageLoader keypress")
} }

View file

@ -1,11 +1,16 @@
import Hifi 1.0 import Hifi 1.0
import QtQuick 2.3 import QtQuick 2.5
import QtQuick.Controls 1.4
// This is our primary 'window' object to which all dialogs and controls will // This is our primary 'window' object to which all dialogs and controls will
// be childed. // be childed.
Root { Root {
id: root id: root
objectName: "desktopRoot"
anchors.fill: parent anchors.fill: parent
property var rootMenu: Menu {
objectName: "rootMenu"
}
onParentChanged: { onParentChanged: {
forceActiveFocus(); forceActiveFocus();

View file

@ -1,9 +0,0 @@
import QtQuick 2.4
import QtQuick.Controls 1.3
Item {
Menu {
id: root
objectName: "rootMenu"
}
}

View file

@ -5,6 +5,7 @@ import "../styles"
Item { Item {
id: root id: root
objectName: "topLevelWindow"
HifiConstants { id: hifi } HifiConstants { id: hifi }
implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth
implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2 implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2

View file

@ -88,6 +88,7 @@
#include <ObjectMotionState.h> #include <ObjectMotionState.h>
#include <OctalCode.h> #include <OctalCode.h>
#include <OctreeSceneStats.h> #include <OctreeSceneStats.h>
#include <OffscreenUi.h>
#include <gl/OffscreenGLCanvas.h> #include <gl/OffscreenGLCanvas.h>
#include <PathUtils.h> #include <PathUtils.h>
#include <PerfStat.h> #include <PerfStat.h>
@ -1177,7 +1178,6 @@ void Application::initializeUi() {
offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setProxyWindow(_window->windowHandle());
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
offscreenUi->load("Root.qml"); offscreenUi->load("Root.qml");
offscreenUi->load("RootMenu.qml");
// FIXME either expose so that dialogs can set this themselves or // FIXME either expose so that dialogs can set this themselves or
// do better detection in the offscreen UI of what has focus // do better detection in the offscreen UI of what has focus
offscreenUi->setNavigationFocused(false); offscreenUi->setNavigationFocused(false);
@ -4381,7 +4381,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
QMessageBox::StandardButton reply; QMessageBox::StandardButton reply;
QString message = "Would you like to run this script:\n" + scriptFilenameOrURL; QString message = "Would you like to run this script:\n" + scriptFilenameOrURL;
reply = QMessageBox::question(getWindow(), "Run Script", message, QMessageBox::Yes|QMessageBox::No); reply = OffscreenUi::question(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) { if (reply == QMessageBox::Yes) {
qCDebug(interfaceapp) << "Chose to run the script: " << scriptFilenameOrURL; qCDebug(interfaceapp) << "Chose to run the script: " << scriptFilenameOrURL;
@ -4394,7 +4394,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
bool Application::askToUploadAsset(const QString& filename) { bool Application::askToUploadAsset(const QString& filename) {
if (!DependencyManager::get<NodeList>()->getThisNodeCanRez()) { if (!DependencyManager::get<NodeList>()->getThisNodeCanRez()) {
QMessageBox::warning(_window, "Failed Upload", OffscreenUi::warning(_window, "Failed Upload",
QString("You don't have upload rights on that domain.\n\n")); QString("You don't have upload rights on that domain.\n\n"));
return false; return false;
} }
@ -4438,7 +4438,7 @@ bool Application::askToUploadAsset(const QString& filename) {
} }
// display a message box with the error // display a message box with the error
QMessageBox::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename)); OffscreenUi::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename));
return false; return false;
} }
@ -4629,7 +4629,7 @@ void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
// FIXME - change to new version of ScriptCache loading notification // FIXME - change to new version of ScriptCache loading notification
void Application::handleScriptLoadError(const QString& scriptFilename) { void Application::handleScriptLoadError(const QString& scriptFilename) {
qCDebug(interfaceapp) << "Application::loadScript(), script failed to load..."; qCDebug(interfaceapp) << "Application::loadScript(), script failed to load...";
QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load."); OffscreenUi::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load.");
} }
QStringList Application::getRunningScripts() { QStringList Application::getRunningScripts() {

View file

@ -16,22 +16,31 @@
#include "InterfaceParentFinder.h" #include "InterfaceParentFinder.h"
SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success) const {
SpatiallyNestableWeakPointer parent; SpatiallyNestableWeakPointer parent;
if (parentID.isNull()) { if (parentID.isNull()) {
success = true;
return parent; return parent;
} }
// search entities // search entities
EntityTreeRenderer* treeRenderer = qApp->getEntities(); EntityTreeRenderer* treeRenderer = qApp->getEntities();
EntityTreePointer tree = treeRenderer->getTree(); EntityTreePointer tree = treeRenderer ? treeRenderer->getTree() : nullptr;
parent = tree->findEntityByEntityItemID(parentID); parent = tree ? tree->findEntityByEntityItemID(parentID) : nullptr;
if (!parent.expired()) { if (!parent.expired()) {
success = true;
return parent; return parent;
} }
// search avatars // search avatars
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>(); QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
return avatarManager->getAvatarBySessionID(parentID); parent = avatarManager->getAvatarBySessionID(parentID);
if (!parent.expired()) {
success = true;
return parent;
}
success = false;
return parent;
} }

View file

@ -21,7 +21,7 @@ class InterfaceParentFinder : public SpatialParentFinder {
public: public:
InterfaceParentFinder() { } InterfaceParentFinder() { }
virtual ~InterfaceParentFinder() { } virtual ~InterfaceParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID) const; virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success) const;
}; };
#endif // hifi_InterfaceParentFinder_h #endif // hifi_InterfaceParentFinder_h

View file

@ -15,6 +15,7 @@
#include <QTemporaryDir> #include <QTemporaryDir>
#include <FSTReader.h> #include <FSTReader.h>
#include <OffscreenUi.h>
#include "ModelSelector.h" #include "ModelSelector.h"
#include "ModelPropertiesDialog.h" #include "ModelPropertiesDialog.h"
@ -78,7 +79,7 @@ bool ModelPackager::loadModel() {
if (_modelFile.completeSuffix().contains("fst")) { if (_modelFile.completeSuffix().contains("fst")) {
QFile fst(_modelFile.filePath()); QFile fst(_modelFile.filePath());
if (!fst.open(QFile::ReadOnly | QFile::Text)) { if (!fst.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(NULL, OffscreenUi::warning(NULL,
QString("ModelPackager::loadModel()"), QString("ModelPackager::loadModel()"),
QString("Could not open FST file %1").arg(_modelFile.filePath()), QString("Could not open FST file %1").arg(_modelFile.filePath()),
QMessageBox::Ok); QMessageBox::Ok);
@ -97,7 +98,7 @@ bool ModelPackager::loadModel() {
// open the fbx file // open the fbx file
QFile fbx(_fbxInfo.filePath()); QFile fbx(_fbxInfo.filePath());
if (!_fbxInfo.exists() || !_fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) { if (!_fbxInfo.exists() || !_fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) {
QMessageBox::warning(NULL, OffscreenUi::warning(NULL,
QString("ModelPackager::loadModel()"), QString("ModelPackager::loadModel()"),
QString("Could not open FBX file %1").arg(_fbxInfo.filePath()), QString("Could not open FBX file %1").arg(_fbxInfo.filePath()),
QMessageBox::Ok); QMessageBox::Ok);
@ -402,7 +403,7 @@ bool ModelPackager::copyTextures(const QString& oldDir, const QDir& newDir) {
} }
if (!errors.isEmpty()) { if (!errors.isEmpty()) {
QMessageBox::warning(nullptr, "ModelPackager::copyTextures()", OffscreenUi::warning(nullptr, "ModelPackager::copyTextures()",
"Missing textures:" + errors); "Missing textures:" + errors);
qCDebug(interfaceapp) << "ModelPackager::copyTextures():" << errors; qCDebug(interfaceapp) << "ModelPackager::copyTextures():" << errors;
return false; return false;

View file

@ -21,6 +21,7 @@
#include <FSTReader.h> #include <FSTReader.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <OffscreenUi.h>
#include "ModelPropertiesDialog.h" #include "ModelPropertiesDialog.h"
@ -200,7 +201,7 @@ void ModelPropertiesDialog::chooseTextureDirectory() {
return; return;
} }
if (!directory.startsWith(_basePath)) { if (!directory.startsWith(_basePath)) {
QMessageBox::warning(NULL, "Invalid texture directory", "Texture directory must be child of base path."); OffscreenUi::warning(NULL, "Invalid texture directory", "Texture directory must be child of base path.");
return; return;
} }
_textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1)); _textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1));

View file

@ -25,6 +25,7 @@
#include <AssetUpload.h> #include <AssetUpload.h>
#include <ResourceManager.h> #include <ResourceManager.h>
#include "OffscreenUi.h"
#include "../ui/AssetUploadDialogFactory.h" #include "../ui/AssetUploadDialogFactory.h"
Q_DECLARE_LOGGING_CATEGORY(asset_migrator); Q_DECLARE_LOGGING_CATEGORY(asset_migrator);
@ -52,7 +53,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
" continue?\n\nMake sure you are connected to the right domain." " continue?\n\nMake sure you are connected to the right domain."
}; };
auto button = QMessageBox::question(_dialogParent, MESSAGE_BOX_TITLE, MIGRATION_CONFIRMATION_TEXT, auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, MIGRATION_CONFIRMATION_TEXT,
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (button == QMessageBox::No) { if (button == QMessageBox::No) {
@ -67,7 +68,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
QByteArray jsonData; QByteArray jsonData;
if (!gunzip(compressedJsonData, jsonData)) { if (!gunzip(compressedJsonData, jsonData)) {
QMessageBox::warning(_dialogParent, "Error", "The file at" + filename + "was not in gzip format."); OffscreenUi::warning(_dialogParent, "Error", "The file at" + filename + "was not in gzip format.");
} }
QJsonDocument modelsJSON = QJsonDocument::fromJson(jsonData); QJsonDocument modelsJSON = QJsonDocument::fromJson(jsonData);
@ -107,7 +108,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
if (request->getResult() == ResourceRequest::Success) { if (request->getResult() == ResourceRequest::Success) {
migrateResource(request); migrateResource(request);
} else { } else {
QMessageBox::warning(_dialogParent, "Error", OffscreenUi::warning(_dialogParent, "Error",
QString("Could not retrieve asset at %1").arg(modelURL.toString())); QString("Could not retrieve asset at %1").arg(modelURL.toString()));
} }
request->deleteLater(); request->deleteLater();
@ -115,7 +116,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
request->send(); request->send();
} else { } else {
QMessageBox::warning(_dialogParent, "Error", OffscreenUi::warning(_dialogParent, "Error",
QString("Could not create request for asset at %1").arg(modelURL.toString())); QString("Could not create request for asset at %1").arg(modelURL.toString()));
} }
@ -129,7 +130,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
_doneReading = true; _doneReading = true;
} else { } else {
QMessageBox::warning(_dialogParent, "Error", OffscreenUi::warning(_dialogParent, "Error",
"There was a problem loading that entity-server file for ATP asset migration. Please try again"); "There was a problem loading that entity-server file for ATP asset migration. Please try again");
} }
} }
@ -212,7 +213,7 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) {
"Select \"No\" to be prompted for each discovered asset." "Select \"No\" to be prompted for each discovered asset."
}; };
auto button = QMessageBox::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT, auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT,
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (button == QMessageBox::Yes) { if (button == QMessageBox::Yes) {
@ -226,7 +227,7 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) {
return true; return true;
} else { } else {
// present a dialog asking the user if they want to migrate this specific resource // present a dialog asking the user if they want to migrate this specific resource
auto button = QMessageBox::question(_dialogParent, MESSAGE_BOX_TITLE, auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE,
"Would you like to migrate the following resource?\n" + url.toString(), "Would you like to migrate the following resource?\n" + url.toString(),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return button == QMessageBox::Yes; return button == QMessageBox::Yes;
@ -254,11 +255,11 @@ void ATPAssetMigrator::saveEntityServerFile() {
QMessageBox::information(_dialogParent, "Success", QMessageBox::information(_dialogParent, "Success",
QString("Your new entities file has been saved at %1").arg(saveName)); QString("Your new entities file has been saved at %1").arg(saveName));
} else { } else {
QMessageBox::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file."); OffscreenUi::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file.");
} }
} else { } else {
QMessageBox::warning(_dialogParent, "Error", OffscreenUi::warning(_dialogParent, "Error",
QString("Could not open file at %1 to write new entities file to.").arg(saveName)); QString("Could not open file at %1 to write new entities file to.").arg(saveName));
} }
} }

View file

@ -237,6 +237,7 @@ void Avatar::simulate(float deltaTime) {
measureMotionDerivatives(deltaTime); measureMotionDerivatives(deltaTime);
simulateAttachments(deltaTime); simulateAttachments(deltaTime);
updatePalms();
} }
bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
@ -1021,6 +1022,9 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
if (_moving && _motionState) { if (_moving && _motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION); _motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
} }
if (_moving || _hasNewJointRotations || _hasNewJointTranslations) {
locationChanged();
}
endUpdate(); endUpdate();
return bytesRead; return bytesRead;
@ -1152,34 +1156,24 @@ void Avatar::rebuildCollisionShape() {
} }
} }
// thread-safe
glm::vec3 Avatar::getLeftPalmPosition() { glm::vec3 Avatar::getLeftPalmPosition() {
glm::vec3 leftHandPosition; return _leftPalmPositionCache.get();
getSkeletonModel().getLeftHandPosition(leftHandPosition);
glm::quat leftRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
leftHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftRotation);
return leftHandPosition;
} }
// thread-safe
glm::quat Avatar::getLeftPalmRotation() { glm::quat Avatar::getLeftPalmRotation() {
glm::quat leftRotation; return _leftPalmRotationCache.get();
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
return leftRotation;
} }
// thread-safe
glm::vec3 Avatar::getRightPalmPosition() { glm::vec3 Avatar::getRightPalmPosition() {
glm::vec3 rightHandPosition; return _rightPalmPositionCache.get();
getSkeletonModel().getRightHandPosition(rightHandPosition);
glm::quat rightRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
rightHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightRotation);
return rightHandPosition;
} }
// thread-safe
glm::quat Avatar::getRightPalmRotation() { glm::quat Avatar::getRightPalmRotation() {
glm::quat rightRotation; return _rightPalmRotationCache.get();
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
return rightRotation;
} }
void Avatar::setPosition(const glm::vec3& position) { void Avatar::setPosition(const glm::vec3& position) {
@ -1191,3 +1185,24 @@ void Avatar::setOrientation(const glm::quat& orientation) {
AvatarData::setOrientation(orientation); AvatarData::setOrientation(orientation);
updateAttitude(); updateAttitude();
} }
void Avatar::updatePalms() {
// get palm rotations
glm::quat leftPalmRotation, rightPalmRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation);
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation);
// get palm positions
glm::vec3 leftPalmPosition, rightPalmPosition;
getSkeletonModel().getLeftHandPosition(leftPalmPosition);
getSkeletonModel().getRightHandPosition(rightPalmPosition);
leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation);
rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation);
// update thread-safe caches
_leftPalmRotationCache.set(leftPalmRotation);
_rightPalmRotationCache.set(rightPalmRotation);
_leftPalmPositionCache.set(leftPalmPosition);
_rightPalmPositionCache.set(rightPalmPosition);
}

View file

@ -27,6 +27,7 @@
#include "SkeletonModel.h" #include "SkeletonModel.h"
#include "world.h" #include "world.h"
#include "Rig.h" #include "Rig.h"
#include <ThreadSafeValueCache.h>
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
@ -159,7 +160,9 @@ public:
AvatarMotionState* getMotionState() { return _motionState; } AvatarMotionState* getMotionState() { return _motionState; }
using SpatiallyNestable::setPosition;
virtual void setPosition(const glm::vec3& position) override; virtual void setPosition(const glm::vec3& position) override;
using SpatiallyNestable::setOrientation;
virtual void setOrientation(const glm::quat& orientation) override; virtual void setOrientation(const glm::quat& orientation) override;
public slots: public slots:
@ -225,8 +228,15 @@ protected:
virtual void updateJointMappings() override; virtual void updateJointMappings() override;
virtual void updatePalms();
render::ItemID _renderItemID; render::ItemID _renderItemID;
ThreadSafeValueCache<glm::vec3> _leftPalmPositionCache { glm::vec3() };
ThreadSafeValueCache<glm::quat> _leftPalmRotationCache { glm::quat() };
ThreadSafeValueCache<glm::vec3> _rightPalmPositionCache { glm::vec3() };
ThreadSafeValueCache<glm::quat> _rightPalmRotationCache { glm::quat() };
private: private:
bool _initialized; bool _initialized;
NetworkTexturePointer _billboardTexture; NetworkTexturePointer _billboardTexture;

View file

@ -89,6 +89,8 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
// code here for future reference. // code here for future reference.
// _palmRotationFromRigidBody = avatarRotationInverse * palmRotation; // _palmRotationFromRigidBody = avatarRotationInverse * palmRotation;
}); });
activateBody();
} }
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) { std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) {
@ -197,7 +199,6 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
if (_kinematic) { if (_kinematic) {
doKinematicUpdate(deltaTimeStep); doKinematicUpdate(deltaTimeStep);
} else { } else {
activateBody();
forceBodyNonStatic(); forceBodyNonStatic();
ObjectActionSpring::updateActionWorker(deltaTimeStep); ObjectActionSpring::updateActionWorker(deltaTimeStep);
} }
@ -247,7 +248,6 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
_previousSet = true; _previousSet = true;
}); });
activateBody();
forceBodyNonStatic(); forceBodyNonStatic();
} }
@ -344,7 +344,6 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
ownerEntity->setActionDataNeedsTransmit(true); ownerEntity->setActionDataNeedsTransmit(true);
} }
}); });
activateBody();
} }
return true; return true;
@ -431,6 +430,5 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
_active = true; _active = true;
}); });
activateBody();
forceBodyNonStatic(); forceBodyNonStatic();
} }

View file

@ -417,6 +417,8 @@ void MyAvatar::updateSensorToWorldMatrix() {
// position when driven from the head. // position when driven from the head.
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition()); glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix); _sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
lateUpdatePalms();
} }
// Update avatar head rotation with sensor data // Update avatar head rotation with sensor data
@ -1839,3 +1841,8 @@ QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioList
void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMode& audioListenerMode) { void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMode& audioListenerMode) {
audioListenerMode = (AudioListenerMode)object.toUInt16(); audioListenerMode = (AudioListenerMode)object.toUInt16();
} }
void MyAvatar::lateUpdatePalms() {
Avatar::updatePalms();
}

View file

@ -311,12 +311,14 @@ private:
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity); void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
PalmData getActivePalmData(int palmIndex) const;
// derive avatar body position and orientation from the current HMD Sensor location. // derive avatar body position and orientation from the current HMD Sensor location.
// results are in HMD frame // results are in HMD frame
glm::mat4 deriveBodyFromHMDSensor() const; glm::mat4 deriveBodyFromHMDSensor() const;
virtual void updatePalms() override {}
void lateUpdatePalms();
float _driveKeys[MAX_DRIVE_KEYS]; float _driveKeys[MAX_DRIVE_KEYS];
bool _wasPushing; bool _wasPushing;
bool _isPushing; bool _isPushing;

View file

@ -139,7 +139,7 @@ void EyeTracker::onStreamStarted() {
qCWarning(interfaceapp) << "Eye Tracker: Error starting streaming:" << smiReturnValueToString(result); qCWarning(interfaceapp) << "Eye Tracker: Error starting streaming:" << smiReturnValueToString(result);
// Display error dialog unless SMI SDK has already displayed an error message. // Display error dialog unless SMI SDK has already displayed an error message.
if (result != SMI_ERROR_HMD_NOT_SUPPORTED) { if (result != SMI_ERROR_HMD_NOT_SUPPORTED) {
QMessageBox::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result)); OffscreenUi::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result));
} }
} else { } else {
qCDebug(interfaceapp) << "Eye Tracker: Started streaming"; qCDebug(interfaceapp) << "Eye Tracker: Started streaming";
@ -152,7 +152,7 @@ void EyeTracker::onStreamStarted() {
result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION);
if (result != SMI_RET_SUCCESS) { if (result != SMI_RET_SUCCESS) {
qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result); qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result);
QMessageBox::warning(nullptr, "Eye Tracker Error", "Error loading calibration" OffscreenUi::warning(nullptr, "Eye Tracker Error", "Error loading calibration"
+ smiReturnValueToString(result)); + smiReturnValueToString(result));
} else { } else {
qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration"; qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration";
@ -168,7 +168,7 @@ void EyeTracker::setEnabled(bool enabled, bool simulate) {
int result = smi_setCallback(eyeTrackerCallback); int result = smi_setCallback(eyeTrackerCallback);
if (result != SMI_RET_SUCCESS) { if (result != SMI_RET_SUCCESS) {
qCWarning(interfaceapp) << "Eye Tracker: Error setting callback:" << smiReturnValueToString(result); qCWarning(interfaceapp) << "Eye Tracker: Error setting callback:" << smiReturnValueToString(result);
QMessageBox::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result)); OffscreenUi::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result));
} else { } else {
_isInitialized = true; _isInitialized = true;
} }
@ -273,7 +273,7 @@ void EyeTracker::calibrate(int points) {
} }
if (result != SMI_RET_SUCCESS) { if (result != SMI_RET_SUCCESS) {
QMessageBox::warning(nullptr, "Eye Tracker Error", "Calibration error: " + smiReturnValueToString(result)); OffscreenUi::warning(nullptr, "Eye Tracker Error", "Calibration error: " + smiReturnValueToString(result));
} }
} }
#endif #endif

View file

@ -21,6 +21,7 @@
#include "DomainHandler.h" #include "DomainHandler.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "Menu.h" #include "Menu.h"
#include "OffscreenUi.h"
#include "ui/ModelsBrowser.h" #include "ui/ModelsBrowser.h"
#include "WindowScriptingInterface.h" #include "WindowScriptingInterface.h"
@ -153,12 +154,11 @@ QScriptValue WindowScriptingInterface::peekNonBlockingFormResult(QScriptValue fo
return retVal; return retVal;
} }
/// Display an alert box /// Display an alert box
/// \param const QString& message message to display /// \param const QString& message message to display
/// \return QScriptValue::UndefinedValue /// \return QScriptValue::UndefinedValue
QScriptValue WindowScriptingInterface::showAlert(const QString& message) { QScriptValue WindowScriptingInterface::showAlert(const QString& message) {
QMessageBox::warning(qApp->getWindow(), "", message); OffscreenUi::warning("", message);
return QScriptValue::UndefinedValue; return QScriptValue::UndefinedValue;
} }
@ -166,8 +166,11 @@ QScriptValue WindowScriptingInterface::showAlert(const QString& message) {
/// \param const QString& message message to display /// \param const QString& message message to display
/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise /// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise
QScriptValue WindowScriptingInterface::showConfirm(const QString& message) { QScriptValue WindowScriptingInterface::showConfirm(const QString& message) {
QMessageBox::StandardButton response = QMessageBox::question(qApp->getWindow(), "", message); bool confirm = false;
return QScriptValue(response == QMessageBox::Yes); OffscreenUi::question("", message, [&](QMessageBox::StandardButton response){
confirm = (response == QMessageBox::Yes);
});
return QScriptValue(confirm);
} }
void WindowScriptingInterface::chooseDirectory() { void WindowScriptingInterface::chooseDirectory() {
@ -185,7 +188,7 @@ void WindowScriptingInterface::chooseDirectory() {
} }
if (!validateAs.exactMatch(directory)) { if (!validateAs.exactMatch(directory)) {
QMessageBox::warning(NULL, "Invalid Directory", errorMessage); OffscreenUi::warning(NULL, "Invalid Directory", errorMessage);
return; return;
} }
@ -597,7 +600,6 @@ QScriptValue WindowScriptingInterface::showPrompt(const QString& message, const
if (promptDialog.exec() == QDialog::Accepted) { if (promptDialog.exec() == QDialog::Accepted) {
return QScriptValue(promptDialog.textValue()); return QScriptValue(promptDialog.textValue());
} }
return QScriptValue::NullValue; return QScriptValue::NullValue;
} }

View file

@ -23,6 +23,7 @@
#include <AssetUpload.h> #include <AssetUpload.h>
#include <AssetUtils.h> #include <AssetUtils.h>
#include <NodeList.h> #include <NodeList.h>
#include <OffscreenUi.h>
#include <ResourceManager.h> #include <ResourceManager.h>
AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() { AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() {
@ -146,5 +147,5 @@ void AssetUploadDialogFactory::showErrorDialog(AssetUpload* upload, QWidget* dia
dialogMessage += errorMessage; dialogMessage += errorMessage;
QMessageBox::warning(dialogParent, "Failed Upload", dialogMessage); OffscreenUi::warning(dialogParent, "Failed Upload", dialogMessage);
} }

View file

@ -22,6 +22,7 @@
#include <NetworkAccessManager.h> #include <NetworkAccessManager.h>
#include "DiskCacheEditor.h" #include "DiskCacheEditor.h"
#include "OffscreenUi.h"
DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) { DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) {
@ -136,7 +137,7 @@ void DiskCacheEditor::refresh() {
void DiskCacheEditor::clear() { void DiskCacheEditor::clear() {
QMessageBox::StandardButton buttonClicked = QMessageBox::StandardButton buttonClicked =
QMessageBox::question(_dialog, "Clearing disk cache", OffscreenUi::question(_dialog, "Clearing disk cache",
"You are about to erase all the content of the disk cache," "You are about to erase all the content of the disk cache,"
"are you sure you want to do that?"); "are you sure you want to do that?");
if (buttonClicked == QMessageBox::Yes) { if (buttonClicked == QMessageBox::Yes) {

View file

@ -26,6 +26,7 @@
#include <QWidget> #include <QWidget>
#include <NetworkAccessManager.h> #include <NetworkAccessManager.h>
#include <OffscreenUi.h>
#include "Application.h" #include "Application.h"
#include "ScriptHighlighting.h" #include "ScriptHighlighting.h"
@ -120,7 +121,7 @@ bool ScriptEditorWidget::setRunning(bool run) {
bool ScriptEditorWidget::saveFile(const QString &scriptPath) { bool ScriptEditorWidget::saveFile(const QString &scriptPath) {
QFile file(scriptPath); QFile file(scriptPath);
if (!file.open(QFile::WriteOnly | QFile::Text)) { if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("Interface"), tr("Cannot write script %1:\n%2.").arg(scriptPath) OffscreenUi::warning(this, tr("Interface"), tr("Cannot write script %1:\n%2.").arg(scriptPath)
.arg(file.errorString())); .arg(file.errorString()));
return false; return false;
} }
@ -141,7 +142,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
QFile file(scriptPath); QFile file(scriptPath);
if (!file.open(QFile::ReadOnly | QFile::Text)) { if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("Interface"), tr("Cannot read script %1:\n%2.").arg(scriptPath) OffscreenUi::warning(this, tr("Interface"), tr("Cannot read script %1:\n%2.").arg(scriptPath)
.arg(file.errorString())); .arg(file.errorString()));
return; return;
} }
@ -208,7 +209,7 @@ void ScriptEditorWidget::setScriptFile(const QString& scriptPath) {
bool ScriptEditorWidget::questionSave() { bool ScriptEditorWidget::questionSave() {
if (_scriptEditorWidgetUI->scriptEdit->document()->isModified()) { if (_scriptEditorWidgetUI->scriptEdit->document()->isModified()) {
QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Interface"), QMessageBox::StandardButton button = OffscreenUi::warning(this, tr("Interface"),
tr("The script has been modified.\nDo you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | tr("The script has been modified.\nDo you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard |
QMessageBox::Cancel, QMessageBox::Save); QMessageBox::Cancel, QMessageBox::Save);
return button == QMessageBox::Save ? save() : (button == QMessageBox::Discard); return button == QMessageBox::Save ? save() : (button == QMessageBox::Discard);
@ -222,7 +223,7 @@ void ScriptEditorWidget::onWindowActivated() {
if (QFileInfo(_currentScript).lastModified() > _currentScriptModified) { if (QFileInfo(_currentScript).lastModified() > _currentScriptModified) {
if (static_cast<ScriptEditorWindow*>(this->parent()->parent()->parent())->autoReloadScripts() if (static_cast<ScriptEditorWindow*>(this->parent()->parent()->parent())->autoReloadScripts()
|| QMessageBox::warning(this, _currentScript, || OffscreenUi::warning(this, _currentScript,
tr("This file has been modified outside of the Interface editor.") + "\n\n" tr("This file has been modified outside of the Interface editor.") + "\n\n"
+ (isModified() + (isModified()
? tr("Do you want to reload it and lose the changes you've made in the Interface editor?") ? tr("Do you want to reload it and lose the changes you've made in the Interface editor?")

View file

@ -20,6 +20,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QUrlQuery> #include <QUrlQuery>
#include <OffscreenUi.h>
const int NARROW_SNAPSHOT_DIALOG_SIZE = 500; const int NARROW_SNAPSHOT_DIALOG_SIZE = 500;
const int WIDE_SNAPSHOT_DIALOG_WIDTH = 650; const int WIDE_SNAPSHOT_DIALOG_WIDTH = 650;
@ -87,7 +88,7 @@ void SnapshotShareDialog::accept() {
void SnapshotShareDialog::uploadSnapshot() { void SnapshotShareDialog::uploadSnapshot() {
if (AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().isEmpty()) { if (AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().isEmpty()) {
QMessageBox::warning(this, "", OffscreenUi::warning(this, "",
"Your Discourse API key is missing, you cannot share snapshots. Please try to relog."); "Your Discourse API key is missing, you cannot share snapshots. Please try to relog.");
return; return;
} }
@ -178,7 +179,7 @@ void SnapshotShareDialog::postRequestFinished() {
errorMessage = errorArray.first().toString(); errorMessage = errorArray.first().toString();
} }
} }
QMessageBox::warning(this, "", errorMessage); OffscreenUi::warning(this, "", errorMessage);
_ui.shareButton->setEnabled(true); _ui.shareButton->setEnabled(true);
_ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE); _ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE);
} }
@ -193,7 +194,7 @@ void SnapshotShareDialog::uploadRequestFinished() {
if (responseObject.contains("url")) { if (responseObject.contains("url")) {
sendForumPost(responseObject["url"].toString()); sendForumPost(responseObject["url"].toString());
} else { } else {
QMessageBox::warning(this, "", SHARE_DEFAULT_ERROR); OffscreenUi::warning(this, "", SHARE_DEFAULT_ERROR);
_ui.shareButton->setEnabled(true); _ui.shareButton->setEnabled(true);
_ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE); _ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE);
} }

View file

@ -90,10 +90,18 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() {
// There are a number of possible strategies for this set of tools through endRender, below. // There are a number of possible strategies for this set of tools through endRender, below.
void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) {
avatarLock.lock(); avatarLock.lock();
Transform trans = getTransform(); bool success;
Transform trans = getTransform(success);
if (!success) {
qDebug() << "Warning -- AvatarData::nextAttitude failed";
return;
}
trans.setTranslation(position); trans.setTranslation(position);
trans.setRotation(orientation); trans.setRotation(orientation);
SpatiallyNestable::setTransform(trans); SpatiallyNestable::setTransform(trans, success);
if (!success) {
qDebug() << "Warning -- AvatarData::nextAttitude failed";
}
avatarLock.unlock(); avatarLock.unlock();
updateAttitude(); updateAttitude();
} }
@ -208,8 +216,9 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED);
} }
// referential state // referential state
SpatiallyNestablePointer parent = getParentPointer(); bool success;
if (parent) { SpatiallyNestablePointer parent = getParentPointer(success);
if (parent && success) {
setAtBit(bitItems, HAS_REFERENTIAL); setAtBit(bitItems, HAS_REFERENTIAL);
} }
*destinationBuffer++ = bitItems; *destinationBuffer++ = bitItems;
@ -1446,7 +1455,11 @@ QJsonObject AvatarData::toJson() const {
} }
auto recordingBasis = getRecordingBasis(); auto recordingBasis = getRecordingBasis();
Transform avatarTransform = getTransform(); bool success;
Transform avatarTransform = getTransform(success);
if (!success) {
qDebug() << "Warning -- AvatarData::toJson couldn't get avatar transform";
}
avatarTransform.setScale(getTargetScale()); avatarTransform.setScale(getTargetScale());
if (recordingBasis) { if (recordingBasis) {
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis); root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
@ -1635,3 +1648,13 @@ void AvatarData::setPosition(const glm::vec3& position) {
void AvatarData::setOrientation(const glm::quat& orientation) { void AvatarData::setOrientation(const glm::quat& orientation) {
SpatiallyNestable::setOrientation(orientation); SpatiallyNestable::setOrientation(orientation);
} }
glm::quat AvatarData::getAbsoluteJointRotationInObjectFrame(int index) const {
assert(false);
return glm::quat();
}
glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const {
assert(false);
return glm::vec3();
}

View file

@ -201,7 +201,9 @@ public:
float getBodyRoll() const; float getBodyRoll() const;
void setBodyRoll(float bodyRoll); void setBodyRoll(float bodyRoll);
using SpatiallyNestable::setPosition;
virtual void setPosition(const glm::vec3& position) override; virtual void setPosition(const glm::vec3& position) override;
using SpatiallyNestable::setOrientation;
virtual void setOrientation(const glm::quat& orientation) override; virtual void setOrientation(const glm::quat& orientation) override;
void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time.
@ -354,6 +356,9 @@ public slots:
void setJointMappingsFromNetworkReply(); void setJointMappingsFromNetworkReply();
void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); } void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); }
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
protected: protected:
glm::vec3 _handPosition; glm::vec3 _handPosition;

View file

@ -767,7 +767,12 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
const float stretchFactor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); bool success;
auto minAACube = entity->getMinimumAACube(success);
if (!success) {
return;
}
const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position); AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
} }

View file

@ -56,14 +56,20 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
bool success;
auto transToCenter = getTransformToCenter(success);
if (!success) {
return;
}
if (_procedural->ready()) { if (_procedural->ready()) {
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well batch.setModelTransform(transToCenter); // we want to include the scale as well
_procedural->prepare(batch, getPosition(), getDimensions()); _procedural->prepare(batch, getPosition(), getDimensions());
auto color = _procedural->getColor(cubeColor); auto color = _procedural->getColor(cubeColor);
batch._glColor4f(color.r, color.g, color.b, color.a); batch._glColor4f(color.r, color.g, color.b, color.a);
DependencyManager::get<GeometryCache>()->renderCube(batch); DependencyManager::get<GeometryCache>()->renderCube(batch);
} else { } else {
DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor); DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, transToCenter, cubeColor);
} }
static const auto triCount = DependencyManager::get<GeometryCache>()->getCubeTriangleCount(); static const auto triCount = DependencyManager::get<GeometryCache>()->getCubeTriangleCount();
args->_details._trianglesRendered += (int)triCount; args->_details._trianglesRendered += (int)triCount;

View file

@ -28,7 +28,12 @@ namespace render {
template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload) { template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload) {
if (payload && payload->entity) { if (payload && payload->entity) {
return payload->entity->getAABox(); bool success;
auto result = payload->entity->getAABox(success);
if (!success) {
return render::Item::Bound();
}
return result;
} }
return render::Item::Bound(); return render::Item::Bound();
} }

View file

@ -196,7 +196,12 @@ namespace render {
template <> const Item::Bound payloadGetBound(const RenderableModelEntityItemMeta::Pointer& payload) { template <> const Item::Bound payloadGetBound(const RenderableModelEntityItemMeta::Pointer& payload) {
if (payload && payload->entity) { if (payload && payload->entity) {
return payload->entity->getAABox(); bool success;
auto result = payload->entity->getAABox(success);
if (!success) {
return render::Item::Bound();
}
return result;
} }
return render::Item::Bound(); return render::Item::Bound();
} }
@ -338,11 +343,14 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
} else { } else {
static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
auto shapeTransform = getTransformToCenter(); bool success;
auto shapeTransform = getTransformToCenter(success);
if (success) {
batch.setModelTransform(Transform()); // we want to include the scale as well batch.setModelTransform(Transform()); // we want to include the scale as well
DependencyManager::get<DeferredLightingEffect>()->renderWireCubeInstance(batch, shapeTransform, greenColor); DependencyManager::get<DeferredLightingEffect>()->renderWireCubeInstance(batch, shapeTransform, greenColor);
} }
} }
}
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
Model* result = NULL; Model* result = NULL;

View file

@ -236,9 +236,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
particlePrimitives->emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed)); particlePrimitives->emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed));
} }
auto bounds = getAABox(); bool successb, successp, successr;
auto position = getPosition(); auto bounds = getAABox(successb);
auto rotation = getRotation(); auto position = getPosition(successp);
auto rotation = getOrientation(successr);
bool success = successb && successp && successr;
if (!success) {
return;
}
Transform transform; Transform transform;
if (!getEmitterShouldTrail()) { if (!getEmitterShouldTrail()) {
transform.setTranslation(position); transform.setTranslation(position);

View file

@ -142,9 +142,11 @@ glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
glm::vec3 center = getCenterPosition(); bool success; // TODO -- Does this actually have to happen in world space?
glm::vec3 position = getPosition(); glm::vec3 center = getCenterPosition(success);
glm::vec3 position = getPosition(success);
glm::vec3 positionToCenter = center - position; glm::vec3 positionToCenter = center - position;
positionToCenter -= getDimensions() * Vectors::HALF - getSurfacePositionAdjustment(); positionToCenter -= getDimensions() * Vectors::HALF - getSurfacePositionAdjustment();
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter); glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
glm::mat4 scaled = glm::scale(centerToCorner, scale); glm::mat4 scaled = glm::scale(centerToCorner, scale);
@ -581,7 +583,12 @@ namespace render {
template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload) { template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload) {
if (payload && payload->_owner) { if (payload && payload->_owner) {
auto polyVoxEntity = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(payload->_owner); auto polyVoxEntity = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(payload->_owner);
return polyVoxEntity->getAABox(); bool success;
auto result = polyVoxEntity->getAABox(success);
if (!success) {
return render::Item::Bound();
}
return result;
} }
return render::Item::Bound(); return render::Item::Bound();
} }

View file

@ -59,7 +59,11 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha()); glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha());
Transform modelTransform = getTransformToCenter(); bool success;
Transform modelTransform = getTransformToCenter(success);
if (!success) {
return;
}
modelTransform.postScale(SPHERE_ENTITY_SCALE); modelTransform.postScale(SPHERE_ENTITY_SCALE);
if (_procedural->ready()) { if (_procedural->ready()) {
batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation

View file

@ -45,7 +45,11 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
Transform transformToTopLeft = getTransformToCenter(); bool success;
Transform transformToTopLeft = getTransformToCenter(success);
if (!success) {
return;
}
if (getFaceCamera()) { if (getFaceCamera()) {
//rotate about vertical to face the camera //rotate about vertical to face the camera
glm::vec3 dPosition = args->_viewFrustum->getPosition() - getPosition(); glm::vec3 dPosition = args->_viewFrustum->getPosition() - getPosition();

View file

@ -185,7 +185,11 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
batch.setModelTransform(getTransformToCenter()); bool success;
batch.setModelTransform(getTransformToCenter(success));
if (!success) {
return;
}
bool textured = false, culled = false, emissive = false; bool textured = false, culled = false, emissive = false;
if (_texture) { if (_texture) {
batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture);

View file

@ -135,7 +135,11 @@ void RenderableZoneEntityItem::render(RenderArgs* args) {
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
batch.setModelTransform(Transform()); batch.setModelTransform(Transform());
auto shapeTransform = getTransformToCenter(); bool success;
auto shapeTransform = getTransformToCenter(success);
if (!success) {
break;
}
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>(); auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
if (getShapeType() == SHAPE_TYPE_SPHERE) { if (getShapeType() == SHAPE_TYPE_SPHERE) {
shapeTransform.postScale(SPHERE_ENTITY_SCALE); shapeTransform.postScale(SPHERE_ENTITY_SCALE);
@ -190,7 +194,12 @@ namespace render {
template <> const Item::Bound payloadGetBound(const RenderableZoneEntityItemMeta::Pointer& payload) { template <> const Item::Bound payloadGetBound(const RenderableZoneEntityItemMeta::Pointer& payload) {
if (payload && payload->entity) { if (payload && payload->entity) {
return payload->entity->getAABox(); bool success;
auto result = payload->entity->getAABox(success);
if (!success) {
return render::Item::Bound();
}
return result;
} }
return render::Item::Bound(); return render::Item::Bound();
} }

View file

@ -25,7 +25,13 @@ AddEntityOperator::AddEntityOperator(EntityTreePointer tree, EntityItemPointer n
// caller must have verified existence of newEntity // caller must have verified existence of newEntity
assert(_newEntity); assert(_newEntity);
_newEntityBox = _newEntity->getMaximumAACube().clamp((float)(-HALF_TREE_SCALE), (float)HALF_TREE_SCALE); bool success;
auto queryCube = _newEntity->getQueryAACube(success);
if (!success) {
_newEntity->markAncestorMissing(true);
}
_newEntityBox = queryCube.clamp((float)(-HALF_TREE_SCALE), (float)HALF_TREE_SCALE);
} }
bool AddEntityOperator::preRecursion(OctreeElementPointer element) { bool AddEntityOperator::preRecursion(OctreeElementPointer element) {

View file

@ -1,83 +0,0 @@
//
// BoundingBoxRelatedProperties.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-9-24
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntityItemProperties.h"
#include "BoundingBoxRelatedProperties.h"
#include "EntityTree.h"
BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity) :
position(entity->getPosition()),
rotation(entity->getRotation()),
registrationPoint(entity->getRegistrationPoint()),
dimensions(entity->getDimensions()),
parentID(entity->getParentID()) {
}
BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity,
const EntityItemProperties& propertiesWithUpdates) :
BoundingBoxRelatedProperties(entity) {
if (propertiesWithUpdates.parentIDChanged()) {
parentID = propertiesWithUpdates.getParentID();
}
bool parentFound = false;
if (parentID != UNKNOWN_ENTITY_ID) {
EntityTreePointer tree = entity->getTree();
EntityItemPointer parentZone = tree->findEntityByID(parentID);
if (parentZone) {
parentFound = true;
glm::vec3 localPosition = propertiesWithUpdates.containsPositionChange() ?
propertiesWithUpdates.getPosition() :
entity->getLocalPosition();
glm::quat localRotation = propertiesWithUpdates.rotationChanged() ?
propertiesWithUpdates.getRotation() :
entity->getLocalOrientation();
const Transform parentTransform = parentZone->getTransformToCenter();
Transform parentDescaled(parentTransform.getRotation(), glm::vec3(1.0f), parentTransform.getTranslation());
Transform localTransform(localRotation, glm::vec3(1.0f), localPosition);
Transform result;
Transform::mult(result, parentDescaled, localTransform);
position = result.getTranslation();
rotation = result.getRotation();
}
}
if (!parentFound) {
if (propertiesWithUpdates.containsPositionChange()) {
position = propertiesWithUpdates.getPosition();
}
if (propertiesWithUpdates.rotationChanged()) {
rotation = propertiesWithUpdates.getRotation();
}
}
if (propertiesWithUpdates.registrationPointChanged()) {
registrationPoint = propertiesWithUpdates.getRegistrationPoint();
}
if (propertiesWithUpdates.dimensionsChanged()) {
dimensions = propertiesWithUpdates.getDimensions();
}
}
AACube BoundingBoxRelatedProperties::getMaximumAACube() const {
// see EntityItem::getMaximumAACube for comments which explain the following.
glm::vec3 scaledRegistrationPoint = (dimensions * registrationPoint);
glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(scaledRegistrationPoint, registrationRemainder);
float radius = glm::length(furthestExtentFromRegistration);
glm::vec3 minimumCorner = position - glm::vec3(radius, radius, radius);
return AACube(minimumCorner, radius * 2.0f);
}

View file

@ -1,30 +0,0 @@
//
// BoundingBoxRelatedProperties.h
// libraries/entities/src
//
// Created by Seth Alves on 2015-9-24
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntityItem.h"
#ifndef hifi_BoundingBoxRelatedProperties_h
#define hifi_BoundingBoxRelatedProperties_h
class BoundingBoxRelatedProperties {
public:
BoundingBoxRelatedProperties(EntityItemPointer entity);
BoundingBoxRelatedProperties(EntityItemPointer entity, const EntityItemProperties& propertiesWithUpdates);
AACube getMaximumAACube() const;
glm::vec3 position;
glm::quat rotation;
glm::vec3 registrationPoint;
glm::vec3 dimensions;
EntityItemID parentID;
};
#endif // hifi_BoundingBoxRelatedProperties_h

View file

@ -133,6 +133,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_ACTION_DATA; requestedProperties += PROP_ACTION_DATA;
requestedProperties += PROP_PARENT_ID; requestedProperties += PROP_PARENT_ID;
requestedProperties += PROP_PARENT_JOINT_INDEX; requestedProperties += PROP_PARENT_JOINT_INDEX;
requestedProperties += PROP_QUERY_AA_CUBE;
return requestedProperties; return requestedProperties;
} }
@ -269,6 +270,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getActionData()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getActionData());
APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, getParentID()); APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, getParentID());
APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex()); APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex());
APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, getQueryAACube());
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties, requestedProperties,
@ -693,6 +695,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID);
READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex);
READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube);
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, somethingChanged); propertyFlags, overwriteLocalData, somethingChanged);
@ -1047,6 +1051,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData); COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(queryAACube, getQueryAACube);
properties._defaultSettings = false; properties._defaultSettings = false;
@ -1111,6 +1116,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData); SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube);
if (somethingChanged) { if (somethingChanged) {
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
@ -1152,8 +1158,8 @@ void EntityItem::recordCreationTime() {
_lastSimulated = now; _lastSimulated = now;
} }
const Transform EntityItem::getTransformToCenter() const { const Transform EntityItem::getTransformToCenter(bool& success) const {
Transform result = getTransform(); Transform result = getTransform(success);
if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
result.postTranslate(ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()); // Position to center result.postTranslate(ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()); // Position to center
} }
@ -1171,11 +1177,11 @@ void EntityItem::setDimensions(const glm::vec3& value) {
/// The maximum bounding cube for the entity, independent of it's rotation. /// The maximum bounding cube for the entity, independent of it's rotation.
/// This accounts for the registration point (upon which rotation occurs around). /// This accounts for the registration point (upon which rotation occurs around).
/// ///
const AACube& EntityItem::getMaximumAACube() const { AACube EntityItem::getMaximumAACube(bool& success) const {
if (_recalcMaxAACube) { if (_recalcMaxAACube) {
// * we know that the position is the center of rotation // * we know that the position is the center of rotation
glm::vec3 centerOfRotation = getPosition(); // also where _registration point is glm::vec3 centerOfRotation = getPosition(success); // also where _registration point is
if (success) {
// * we know that the registration point is the center of rotation // * we know that the registration point is the center of rotation
// * we can calculate the length of the furthest extent from the registration point // * we can calculate the length of the furthest extent from the registration point
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint) // as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
@ -1194,13 +1200,16 @@ const AACube& EntityItem::getMaximumAACube() const {
_maxAACube = AACube(minimumCorner, radius * 2.0f); _maxAACube = AACube(minimumCorner, radius * 2.0f);
_recalcMaxAACube = false; _recalcMaxAACube = false;
} }
} else {
success = true;
}
return _maxAACube; return _maxAACube;
} }
/// The minimum bounding cube for the entity accounting for it's rotation. /// The minimum bounding cube for the entity accounting for it's rotation.
/// This accounts for the registration point (upon which rotation occurs around). /// This accounts for the registration point (upon which rotation occurs around).
/// ///
const AACube& EntityItem::getMinimumAACube() const { AACube EntityItem::getMinimumAACube(bool& success) const {
if (_recalcMinAACube) { if (_recalcMinAACube) {
// _position represents the position of the registration point. // _position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
@ -1208,11 +1217,13 @@ const AACube& EntityItem::getMinimumAACube() const {
glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * getRegistrationPoint()); glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * getRegistrationPoint());
glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder; glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); Extents rotatedExtentsRelativeToRegistrationPoint =
unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
// shift the extents to be relative to the position/registration point // shift the extents to be relative to the position/registration point
rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition()); rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition(success));
if (success) {
// the cube that best encompasses extents is... // the cube that best encompasses extents is...
AABox box(rotatedExtentsRelativeToRegistrationPoint); AABox box(rotatedExtentsRelativeToRegistrationPoint);
glm::vec3 centerOfBox = box.calcCenter(); glm::vec3 centerOfBox = box.calcCenter();
@ -1223,10 +1234,13 @@ const AACube& EntityItem::getMinimumAACube() const {
_minAACube = AACube(cornerOfCube, longestSide); _minAACube = AACube(cornerOfCube, longestSide);
_recalcMinAACube = false; _recalcMinAACube = false;
} }
} else {
success = true;
}
return _minAACube; return _minAACube;
} }
const AABox& EntityItem::getAABox() const { AABox EntityItem::getAABox(bool& success) const {
if (_recalcAABox) { if (_recalcAABox) {
// _position represents the position of the registration point. // _position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
@ -1234,17 +1248,37 @@ const AABox& EntityItem::getAABox() const {
glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * _registrationPoint); glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder; glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); Extents rotatedExtentsRelativeToRegistrationPoint =
unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
// shift the extents to be relative to the position/registration point // shift the extents to be relative to the position/registration point
rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition()); rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition(success));
if (success) {
_cachedAABox = AABox(rotatedExtentsRelativeToRegistrationPoint); _cachedAABox = AABox(rotatedExtentsRelativeToRegistrationPoint);
_recalcAABox = false; _recalcAABox = false;
} }
} else {
success = true;
}
return _cachedAABox; return _cachedAABox;
} }
AACube EntityItem::getQueryAACube(bool& success) const {
AACube result = SpatiallyNestable::getQueryAACube(success);
if (success) {
return result;
}
// this is for when we've loaded an older json file that didn't have queryAACube properties.
result = getMaximumAACube(success);
if (success) {
_queryAACube = result;
_queryAACubeSet = true;
}
return result;
}
// NOTE: This should only be used in cases of old bitstreams which only contain radius data // NOTE: This should only be used in cases of old bitstreams which only contain radius data
// 0,0,0 --> maxDimension,maxDimension,maxDimension // 0,0,0 --> maxDimension,maxDimension,maxDimension
// ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension)
@ -1274,7 +1308,9 @@ float EntityItem::getRadius() const {
bool EntityItem::contains(const glm::vec3& point) const { bool EntityItem::contains(const glm::vec3& point) const {
if (getShapeType() == SHAPE_TYPE_COMPOUND) { if (getShapeType() == SHAPE_TYPE_COMPOUND) {
return getAABox().contains(point); bool success;
bool result = getAABox(success).contains(point);
return result && success;
} else { } else {
ShapeInfo info; ShapeInfo info;
info.setParams(getShapeType(), glm::vec3(0.5f)); info.setParams(getShapeType(), glm::vec3(0.5f));
@ -1817,6 +1853,14 @@ QList<EntityActionPointer> EntityItem::getActionsOfType(EntityActionType typeToG
return result; return result;
} }
glm::quat EntityItem::getAbsoluteJointRotationInObjectFrame(int index) const {
return glm::quat();
}
glm::vec3 EntityItem::getAbsoluteJointTranslationInObjectFrame(int index) const {
return glm::vec3(0.0f);
}
void EntityItem::locationChanged() { void EntityItem::locationChanged() {
requiresRecalcBoxes(); requiresRecalcBoxes();
SpatiallyNestable::locationChanged(); // tell all the children, also SpatiallyNestable::locationChanged(); // tell all the children, also

View file

@ -161,11 +161,10 @@ public:
// attributes applicable to all entity types // attributes applicable to all entity types
EntityTypes::EntityType getType() const { return _type; } EntityTypes::EntityType getType() const { return _type; }
inline glm::vec3 getCenterPosition() const { return getTransformToCenter().getTranslation(); } inline glm::vec3 getCenterPosition(bool& success) const { return getTransformToCenter(success).getTranslation(); }
void setCenterPosition(const glm::vec3& position); void setCenterPosition(const glm::vec3& position);
const Transform getTransformToCenter() const; const Transform getTransformToCenter(bool& success) const;
void setTranformToCenter(const Transform& transform);
inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; } inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; }
@ -232,9 +231,12 @@ public:
quint64 getExpiry() const; quint64 getExpiry() const;
// position, size, and bounds related helpers // position, size, and bounds related helpers
const AACube& getMaximumAACube() const; virtual AACube getMaximumAACube(bool& success) const override;
const AACube& getMinimumAACube() const; AACube getMinimumAACube(bool& success) const;
const AABox& getAABox() const; /// axis aligned bounding box in world-frame (meters) AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters)
using SpatiallyNestable::getQueryAACube;
virtual AACube getQueryAACube(bool& success) const override;
const QString& getScript() const { return _script; } const QString& getScript() const { return _script; }
void setScript(const QString& value) { _script = value; } void setScript(const QString& value) { _script = value; }
@ -379,8 +381,8 @@ public:
QList<EntityActionPointer> getActionsOfType(EntityActionType typeToGet); QList<EntityActionPointer> getActionsOfType(EntityActionType typeToGet);
// these are in the frame of this object // these are in the frame of this object
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override { return glm::quat(); } virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override { return glm::vec3(0.0f); } virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
virtual void loader() {} // called indirectly when urls for geometry are updated virtual void loader() {} // called indirectly when urls for geometry are updated

View file

@ -262,6 +262,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID);
CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID);
CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex);
CHECK_PROPERTY_CHANGE(PROP_QUERY_AA_CUBE, queryAACube);
changedProperties += _animation.getChangedProperties(); changedProperties += _animation.getChangedProperties();
changedProperties += _keyLight.getChangedProperties(); changedProperties += _keyLight.getChangedProperties();
@ -473,10 +474,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube);
// FIXME - I don't think these properties are supported any more // FIXME - I don't think these properties are supported any more
//COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
//COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
@ -601,6 +605,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex);
COPY_PROPERTY_FROM_QSCRIPTVALUE(queryAACube, AACube, setQueryAACube);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, glmVec3, setLocalPosition); COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, glmVec3, setLocalPosition);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation);
@ -922,6 +927,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription());
APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID()); APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID());
APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex()); APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex());
APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, properties.getQueryAACube());
if (properties.getType() == EntityTypes::Web) { if (properties.getType() == EntityTypes::Web) {
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl()); APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
@ -1208,6 +1214,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUERY_AA_CUBE, AACube, setQueryAACube);
if (properties.getType() == EntityTypes::Web) { if (properties.getType() == EntityTypes::Web) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
@ -1460,32 +1467,8 @@ void EntityItemProperties::markAllChanged() {
_parentIDChanged = true; _parentIDChanged = true;
_parentJointIndexChanged = true; _parentJointIndexChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation. _queryAACubeChanged = true;
/// This accounts for the registration point (upon which rotation occurs around).
///
AACube EntityItemProperties::getMaximumAACube() const {
// * we know that the position is the center of rotation
glm::vec3 centerOfRotation = _position; // also where _registration point is
// * we know that the registration point is the center of rotation
// * we can calculate the length of the furthest extent from the registration point
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
// * we know that if you rotate in any direction you would create a sphere
// that has a radius of the length of furthest extent from registration point
float radius = glm::length(furthestExtentFromRegistration);
// * we know that the minimum bounding cube of this maximum possible sphere is
// (center - radius) to (center + radius)
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
float diameter = radius * 2.0f;
return AACube(minimumCorner, diameter);
} }
// The minimum bounding box for the entity. // The minimum bounding box for the entity.
@ -1785,6 +1768,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (parentJointIndexChanged()) { if (parentJointIndexChanged()) {
out += "parentJointIndex"; out += "parentJointIndex";
} }
if (queryAACubeChanged()) {
out += "queryAACube";
}
getAnimation().listChangedProperties(out); getAnimation().listChangedProperties(out);
getKeyLight().listChangedProperties(out); getKeyLight().listChangedProperties(out);
@ -1798,3 +1784,7 @@ QList<QString> EntityItemProperties::listChangedProperties() {
bool EntityItemProperties::parentDependentPropertyChanged() const { bool EntityItemProperties::parentDependentPropertyChanged() const {
return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged(); return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged();
} }
bool EntityItemProperties::parentRelatedPropertyChanged() const {
return parentDependentPropertyChanged() || parentIDChanged() || parentJointIndexChanged();
}

View file

@ -84,8 +84,8 @@ public:
EntityPropertyFlags getChangedProperties() const; EntityPropertyFlags getChangedProperties() const;
bool parentDependentPropertyChanged() const; // was there a changed in a property that requires parent info to interpret? bool parentDependentPropertyChanged() const; // was there a changed in a property that requires parent info to interpret?
bool parentRelatedPropertyChanged() const; // parentDependentPropertyChanged or parentID or parentJointIndex
AACube getMaximumAACube() const;
AABox getAABox() const; AABox getAABox() const;
void debugDump() const; void debugDump() const;
@ -192,7 +192,8 @@ public:
DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID);
DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID);
DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID);
DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, -1);
DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube());
// these are used when bouncing location data into and out of scripts // these are used when bouncing location data into and out of scripts
DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3);
@ -397,6 +398,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentID, parentID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentID, parentID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentJointIndex, parentJointIndex, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentJointIndex, parentJointIndex, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, QueryAACube, queryAACube, "");
properties.getAnimation().debugDump(); properties.getAnimation().debugDump();
properties.getAtmosphere().debugDump(); properties.getAtmosphere().debugDump();

View file

@ -122,6 +122,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); } inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); }
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \ #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \
if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \
@ -225,6 +228,13 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal
return glm::vec3(0); return glm::vec3(0);
} }
inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
AACube result;
aaCubeFromScriptValue(v, result);
return result;
}
inline qVectorFloat qVectorFloat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { inline qVectorFloat qVectorFloat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true; isValid = true;
return qVectorFloatFromScriptValue(v); return qVectorFloatFromScriptValue(v);

View file

@ -157,6 +157,8 @@ enum EntityPropertyList {
PROP_LOCAL_POSITION, // only used to convert values to and from scripts PROP_LOCAL_POSITION, // only used to convert values to and from scripts
PROP_LOCAL_ROTATION, // only used to convert values to and from scripts PROP_LOCAL_ROTATION, // only used to convert values to and from scripts
PROP_QUERY_AA_CUBE, // how the EntityTree considers the size and position on an entity
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line // ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM, PROP_AFTER_LAST_ITEM,

View file

@ -72,12 +72,15 @@ EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties
scriptSideProperties.setLocalPosition(entitySideProperties.getPosition()); scriptSideProperties.setLocalPosition(entitySideProperties.getPosition());
scriptSideProperties.setLocalRotation(entitySideProperties.getRotation()); scriptSideProperties.setLocalRotation(entitySideProperties.getRotation());
bool success;
glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(), glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(),
entitySideProperties.getParentID(), entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex()); entitySideProperties.getParentJointIndex(),
success);
glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(), glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(),
entitySideProperties.getParentID(), entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex()); entitySideProperties.getParentJointIndex(),
success);
scriptSideProperties.setPosition(worldPosition); scriptSideProperties.setPosition(worldPosition);
scriptSideProperties.setRotation(worldRotation); scriptSideProperties.setRotation(worldRotation);
@ -89,13 +92,15 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
// convert position and rotation properties from world-space to local, unless localPosition and localRotation // convert position and rotation properties from world-space to local, unless localPosition and localRotation
// are set. If they are set, they overwrite position and rotation. // are set. If they are set, they overwrite position and rotation.
EntityItemProperties entitySideProperties = scriptSideProperties; EntityItemProperties entitySideProperties = scriptSideProperties;
bool success;
if (scriptSideProperties.localPositionChanged()) { if (scriptSideProperties.localPositionChanged()) {
entitySideProperties.setPosition(scriptSideProperties.getLocalPosition()); entitySideProperties.setPosition(scriptSideProperties.getLocalPosition());
} else if (scriptSideProperties.positionChanged()) { } else if (scriptSideProperties.positionChanged()) {
glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(), glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(),
entitySideProperties.getParentID(), entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex()); entitySideProperties.getParentJointIndex(),
success);
entitySideProperties.setPosition(localPosition); entitySideProperties.setPosition(localPosition);
} }
@ -104,7 +109,8 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
} else if (scriptSideProperties.rotationChanged()) { } else if (scriptSideProperties.rotationChanged()) {
glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(), glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(),
entitySideProperties.getParentID(), entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex()); entitySideProperties.getParentJointIndex(),
success);
entitySideProperties.setRotation(localRotation); entitySideProperties.setRotation(localRotation);
} }
@ -128,6 +134,10 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID(); const QUuid myNodeID = nodeList->getSessionUUID();
propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY);
if (propertiesWithSimID.parentRelatedPropertyChanged()) {
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
propertiesWithSimID.setQueryAACube(entity->getQueryAACube());
}
// and make note of it now, so we can act on it right away. // and make note of it now, so we can act on it right away.
entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY);
@ -193,16 +203,15 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) { QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
EntityItemProperties properties = scriptSideProperties; EntityItemProperties properties = scriptSideProperties;
EntityItemID entityID(id); EntityItemID entityID(id);
// If we have a local entity tree set, then also update it.
if (!_entityTree) { if (!_entityTree) {
queueEntityMessage(PacketType::EntityEdit, entityID, properties); queueEntityMessage(PacketType::EntityEdit, entityID, properties);
return id; return id;
} }
// If we have a local entity tree set, then also update it.
bool updatedEntity = false; bool updatedEntity = false;
_entityTree->withWriteLock([&] { _entityTree->withWriteLock([&] {
if (scriptSideProperties.parentDependentPropertyChanged() || if (scriptSideProperties.parentRelatedPropertyChanged()) {
scriptSideProperties.parentIDChanged() || scriptSideProperties.parentJointIndexChanged()) {
// All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them. // All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them.
// If any of these changed, pull any missing properties from the entity. // If any of these changed, pull any missing properties from the entity.
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
@ -265,7 +274,24 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
entity->flagForOwnership(); entity->flagForOwnership();
} }
} }
if (properties.parentRelatedPropertyChanged() && entity->computePuffedQueryAACube()) {
properties.setQueryAACube(entity->getQueryAACube());
}
entity->setLastBroadcast(usecTimestampNow()); entity->setLastBroadcast(usecTimestampNow());
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
// if they've changed.
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (descendant->getNestableType() == NestableType::Entity) {
if (descendant->computePuffedQueryAACube()) {
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
entityDescendant->setLastBroadcast(usecTimestampNow());
}
}
});
} }
}); });
queueEntityMessage(PacketType::EntityEdit, entityID, properties); queueEntityMessage(PacketType::EntityEdit, entityID, properties);

View file

@ -119,8 +119,9 @@ void EntitySimulation::sortEntitiesThatMoved() {
while (itemItr != _entitiesToSort.end()) { while (itemItr != _entitiesToSort.end()) {
EntityItemPointer entity = *itemItr; EntityItemPointer entity = *itemItr;
// check to see if this movement has sent the entity outside of the domain. // check to see if this movement has sent the entity outside of the domain.
AACube newCube = entity->getMaximumAACube(); bool success;
if (!domainBounds.touches(newCube)) { AACube newCube = entity->getQueryAACube(success);
if (success && !domainBounds.touches(newCube)) {
qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds.";
_entitiesToDelete.insert(entity); _entitiesToDelete.insert(entity);
_mortalEntities.remove(entity); _mortalEntities.remove(entity);
@ -200,8 +201,9 @@ void EntitySimulation::changeEntity(EntityItemPointer entity) {
uint32_t dirtyFlags = entity->getDirtyFlags(); uint32_t dirtyFlags = entity->getDirtyFlags();
if (dirtyFlags & Simulation::DIRTY_POSITION) { if (dirtyFlags & Simulation::DIRTY_POSITION) {
AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE), (float)TREE_SCALE); AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE), (float)TREE_SCALE);
AACube newCube = entity->getMaximumAACube(); bool success;
if (!domainBounds.touches(newCube)) { AACube newCube = entity->getQueryAACube(success);
if (success && !domainBounds.touches(newCube)) {
qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds.";
_entitiesToDelete.insert(entity); _entitiesToDelete.insert(entity);
_mortalEntities.remove(entity); _mortalEntities.remove(entity);

View file

@ -89,6 +89,9 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
_isDirty = true; _isDirty = true;
maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL()); maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL());
emit addingEntity(entity->getEntityItemID()); emit addingEntity(entity->getEntityItemID());
// find and hook up any entities with this entity as a (previously) missing parent
fixupMissingParents();
} }
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) { bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {
@ -142,8 +145,12 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
EntityItemProperties tempProperties; EntityItemProperties tempProperties;
tempProperties.setLocked(wantsLocked); tempProperties.setLocked(wantsLocked);
BoundingBoxRelatedProperties newBBRelProperties(entity, tempProperties); bool success;
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties); AACube queryCube = entity->getQueryAACube(success);
if (!success) {
qCDebug(entities) << "Warning -- failed to get query-cube for" << entity->getID();
}
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, queryCube);
recurseTreeWithOperator(&theOperator); recurseTreeWithOperator(&theOperator);
entity->setProperties(tempProperties); entity->setProperties(tempProperties);
_isDirty = true; _isDirty = true;
@ -211,8 +218,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
QString collisionSoundURLBefore = entity->getCollisionSoundURL(); QString collisionSoundURLBefore = entity->getCollisionSoundURL();
uint32_t preFlags = entity->getDirtyFlags(); uint32_t preFlags = entity->getDirtyFlags();
BoundingBoxRelatedProperties newBBRelProperties(entity, properties); UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, properties.getQueryAACube());
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties);
recurseTreeWithOperator(&theOperator); recurseTreeWithOperator(&theOperator);
entity->setProperties(properties); entity->setProperties(properties);
@ -229,14 +235,19 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
if (!childEntity) { if (!childEntity) {
continue; continue;
} }
BoundingBoxRelatedProperties newChildBBRelProperties(childEntity);
EntityTreeElementPointer containingElement = childEntity->getElement(); EntityTreeElementPointer containingElement = childEntity->getElement();
if (!containingElement) { if (!containingElement) {
continue; continue;
} }
UpdateEntityOperator theChildOperator(getThisPointer(),
containingElement, bool success;
childEntity, newChildBBRelProperties); AACube queryCube = childEntity->getQueryAACube(success);
if (!success) {
_missingParent.append(childEntity);
continue;
}
UpdateEntityOperator theChildOperator(getThisPointer(), containingElement, childEntity, queryCube);
recurseTreeWithOperator(&theChildOperator); recurseTreeWithOperator(&theChildOperator);
foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) { foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) {
if (childChild && childChild->getNestableType() == NestableType::Entity) { if (childChild && childChild->getNestableType() == NestableType::Entity) {
@ -316,6 +327,11 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti
// Recurse the tree and store the entity in the correct tree element // Recurse the tree and store the entity in the correct tree element
AddEntityOperator theOperator(getThisPointer(), result); AddEntityOperator theOperator(getThisPointer(), result);
recurseTreeWithOperator(&theOperator); recurseTreeWithOperator(&theOperator);
if (result->getAncestorMissing()) {
// we added the entity, but didn't know about all its ancestors, so it went into the wrong place.
// add it to a list of entities needing to be fixed once their parents are known.
_missingParent.append(result);
}
postAddEntity(result); postAddEntity(result);
} }
@ -757,6 +773,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
changedProperties[index] = QString("parentJointIndex:") + QString::number((int)value); changedProperties[index] = QString("parentJointIndex:") + QString::number((int)value);
} }
} }
if (properties.parentIDChanged()) {
int index = changedProperties.indexOf("parentID");
if (index >= 0) {
QUuid value = properties.getParentID();
changedProperties[index] = QString("parentID:") + value.toString();
}
}
} }
int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
@ -918,7 +942,38 @@ void EntityTree::entityChanged(EntityItemPointer entity) {
} }
} }
void EntityTree::fixupMissingParents() {
MovingEntitiesOperator moveOperator(getThisPointer());
QMutableVectorIterator<EntityItemWeakPointer> iter(_missingParent);
while (iter.hasNext()) {
EntityItemWeakPointer entityWP = iter.next();
EntityItemPointer entity = entityWP.lock();
if (entity) {
bool success;
AACube newCube = entity->getQueryAACube(success);
if (success) {
// this entity's parent (or ancestry) was previously not fully known, and now is. Update its
// location in the EntityTree.
moveOperator.addEntityToMoveList(entity, newCube);
iter.remove();
entity->markAncestorMissing(false);
}
} else {
// entity was deleted before we found its parent.
iter.remove();
}
}
if (moveOperator.hasMovingEntities()) {
PerformanceTimer perfTimer("recurseTreeWithOperator");
recurseTreeWithOperator(&moveOperator);
}
}
void EntityTree::update() { void EntityTree::update() {
fixupMissingParents();
if (_simulation) { if (_simulation) {
withWriteLock([&] { withWriteLock([&] {
_simulation->updateEntities(); _simulation->updateEntities();

View file

@ -307,6 +307,9 @@ protected:
quint64 _totalEditDeltas = 0; quint64 _totalEditDeltas = 0;
quint64 _maxEditDelta = 0; quint64 _maxEditDelta = 0;
quint64 _treeResetTime = 0; quint64 _treeResetTime = 0;
void fixupMissingParents();
QVector<EntityItemWeakPointer> _missingParent;
}; };
#endif // hifi_EntityTree_h #endif // hifi_EntityTree_h

View file

@ -302,8 +302,9 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
// simulation changing what's visible. consider the case where the entity contains an angular velocity // simulation changing what's visible. consider the case where the entity contains an angular velocity
// the entity may not be in view and then in view a frame later, let the client side handle it's view // the entity may not be in view and then in view a frame later, let the client side handle it's view
// frustum culling on rendering. // frustum culling on rendering.
AACube entityCube = entity->getMaximumAACube(); bool success;
if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) { AACube entityCube = entity->getQueryAACube(success);
if (!success || params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
includeThisEntity = false; // out of view, don't include it includeThisEntity = false; // out of view, don't include it
} }
} }
@ -413,19 +414,29 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
} }
bool EntityTreeElement::containsEntityBounds(EntityItemPointer entity) const { bool EntityTreeElement::containsEntityBounds(EntityItemPointer entity) const {
return containsBounds(entity->getMaximumAACube()); bool success;
auto queryCube = entity->getQueryAACube(success);
if (!success) {
return false;
}
return containsBounds(queryCube);
} }
bool EntityTreeElement::bestFitEntityBounds(EntityItemPointer entity) const { bool EntityTreeElement::bestFitEntityBounds(EntityItemPointer entity) const {
return bestFitBounds(entity->getMaximumAACube()); bool success;
auto queryCube = entity->getQueryAACube(success);
if (!success) {
return false;
}
return bestFitBounds(queryCube);
} }
bool EntityTreeElement::containsBounds(const EntityItemProperties& properties) const { bool EntityTreeElement::containsBounds(const EntityItemProperties& properties) const {
return containsBounds(properties.getMaximumAACube()); return containsBounds(properties.getQueryAACube());
} }
bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) const { bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) const {
return bestFitBounds(properties.getMaximumAACube()); return bestFitBounds(properties.getQueryAACube());
} }
bool EntityTreeElement::containsBounds(const AACube& bounds) const { bool EntityTreeElement::containsBounds(const AACube& bounds) const {
@ -526,7 +537,12 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
return; return;
} }
AABox entityBox = entity->getAABox(); bool success;
AABox entityBox = entity->getAABox(success);
if (!success) {
return;
}
float localDistance; float localDistance;
BoxFace localFace; BoxFace localFace;
glm::vec3 localSurfaceNormal; glm::vec3 localSurfaceNormal;
@ -631,11 +647,12 @@ EntityItemPointer EntityTreeElement::getClosestEntity(glm::vec3 position) const
void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector<EntityItemPointer>& foundEntities) const { void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector<EntityItemPointer>& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) { forEachEntity([&](EntityItemPointer entity) {
AABox entityBox = entity->getAABox(); bool success;
AABox entityBox = entity->getAABox(success);
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case // if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
glm::vec3 penetration; glm::vec3 penetration;
if (entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) { if (success && entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
glm::vec3 dimensions = entity->getDimensions(); glm::vec3 dimensions = entity->getDimensions();
@ -651,10 +668,13 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
// maximum bounding sphere, which is actually larger than our actual radius // maximum bounding sphere, which is actually larger than our actual radius
float entityTrueRadius = dimensions.x / 2.0f; float entityTrueRadius = dimensions.x / 2.0f;
bool success;
if (findSphereSpherePenetration(searchPosition, searchRadius, if (findSphereSpherePenetration(searchPosition, searchRadius,
entity->getCenterPosition(), entityTrueRadius, penetration)) { entity->getCenterPosition(success), entityTrueRadius, penetration)) {
if (success) {
foundEntities.push_back(entity); foundEntities.push_back(entity);
} }
}
} else { } else {
// determine the worldToEntityMatrix that doesn't include scale because // determine the worldToEntityMatrix that doesn't include scale because
// we're going to use the registration aware aa box in the entity frame // we're going to use the registration aware aa box in the entity frame
@ -679,7 +699,8 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
void EntityTreeElement::getEntities(const AACube& cube, QVector<EntityItemPointer>& foundEntities) { void EntityTreeElement::getEntities(const AACube& cube, QVector<EntityItemPointer>& foundEntities) {
forEachEntity([&](EntityItemPointer entity) { forEachEntity([&](EntityItemPointer entity) {
AABox entityBox = entity->getAABox(); bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
// FIXME - consider allowing the entity to determine penetration so that // FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to // entities could presumably dull actuall hull testing if they wanted to
@ -696,7 +717,7 @@ void EntityTreeElement::getEntities(const AACube& cube, QVector<EntityItemPointe
// //
// If the entities AABox touches the search cube then consider it to be found // If the entities AABox touches the search cube then consider it to be found
if (entityBox.touches(cube)) { if (success && entityBox.touches(cube)) {
foundEntities.push_back(entity); foundEntities.push_back(entity);
} }
}); });
@ -704,7 +725,8 @@ void EntityTreeElement::getEntities(const AACube& cube, QVector<EntityItemPointe
void EntityTreeElement::getEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities) { void EntityTreeElement::getEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities) {
forEachEntity([&](EntityItemPointer entity) { forEachEntity([&](EntityItemPointer entity) {
AABox entityBox = entity->getAABox(); bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
// FIXME - consider allowing the entity to determine penetration so that // FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to // entities could presumably dull actuall hull testing if they wanted to
@ -721,7 +743,7 @@ void EntityTreeElement::getEntities(const AABox& box, QVector<EntityItemPointer>
// //
// If the entities AABox touches the search cube then consider it to be found // If the entities AABox touches the search cube then consider it to be found
if (entityBox.touches(box)) { if (success && entityBox.touches(box)) {
foundEntities.push_back(entity); foundEntities.push_back(entity);
} }
}); });
@ -940,7 +962,11 @@ bool EntityTreeElement::pruneChildren() {
void EntityTreeElement::expandExtentsToContents(Extents& extents) { void EntityTreeElement::expandExtentsToContents(Extents& extents) {
withReadLock([&] { withReadLock([&] {
foreach(EntityItemPointer entity, _entityItems) { foreach(EntityItemPointer entity, _entityItems) {
extents.add(entity->getAABox()); bool success;
AABox aaBox = entity->getAABox(success);
if (success) {
extents.add(aaBox);
}
} }
}); });
} }

View file

@ -110,7 +110,11 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
// then translate back to work coordinates // then translate back to work coordinates
glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f)); glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
distance = glm::distance(origin, hitAt); distance = glm::distance(origin, hitAt);
surfaceNormal = glm::normalize(hitAt - getCenterPosition()); bool success;
surfaceNormal = glm::normalize(hitAt - getCenterPosition(success));
if (!success) {
return false;
}
return true; return true;
} }
return false; return false;

View file

@ -14,12 +14,11 @@
UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree, UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
EntityTreeElementPointer containingElement, EntityTreeElementPointer containingElement,
EntityItemPointer existingEntity, EntityItemPointer existingEntity,
const BoundingBoxRelatedProperties& newProperties) : const AACube newQueryAACube) :
_tree(tree), _tree(tree),
_existingEntity(existingEntity), _existingEntity(existingEntity),
_containingElement(containingElement), _containingElement(containingElement),
_containingElementCube(containingElement->getAACube()), _containingElementCube(containingElement->getAACube()),
_newProperties(newProperties),
_entityItemID(existingEntity->getEntityItemID()), _entityItemID(existingEntity->getEntityItemID()),
_foundOld(false), _foundOld(false),
_foundNew(false), _foundNew(false),
@ -41,13 +40,13 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
// entity into the the element, or do we want to use the entities "relaxed" bounds // entity into the the element, or do we want to use the entities "relaxed" bounds
// which can handle all potential rotations? // which can handle all potential rotations?
// the getMaximumAACube is the relaxed form. // the getMaximumAACube is the relaxed form.
_oldEntityCube = _existingEntity->getMaximumAACube(); _oldEntityCube = _existingEntity->getQueryAACube();
_oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds _oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
// If our new properties don't have bounds details (no change to position, etc) or if this containing element would // If our new properties don't have bounds details (no change to position, etc) or if this containing element would
// be the best fit for our new properties, then just do the new portion of the store pass, since the change path will // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will
// be the same for both parts of the update // be the same for both parts of the update
bool oldElementBestFit = _containingElement->bestFitBounds(newProperties.getMaximumAACube()); bool oldElementBestFit = _containingElement->bestFitBounds(newQueryAACube);
// For some reason we've seen a case where the original containing element isn't a best fit for the old properties // For some reason we've seen a case where the original containing element isn't a best fit for the old properties
// in this case we want to move it, even if the properties haven't changed. // in this case we want to move it, even if the properties haven't changed.

View file

@ -12,7 +12,6 @@
#ifndef hifi_UpdateEntityOperator_h #ifndef hifi_UpdateEntityOperator_h
#define hifi_UpdateEntityOperator_h #define hifi_UpdateEntityOperator_h
#include "BoundingBoxRelatedProperties.h"
#include "EntitiesLogging.h" #include "EntitiesLogging.h"
#include "EntityItem.h" #include "EntityItem.h"
#include "EntityItemProperties.h" #include "EntityItemProperties.h"
@ -22,7 +21,7 @@
class UpdateEntityOperator : public RecurseOctreeOperator { class UpdateEntityOperator : public RecurseOctreeOperator {
public: public:
UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement, UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement,
EntityItemPointer existingEntity, const BoundingBoxRelatedProperties& newProperties); EntityItemPointer existingEntity, const AACube newQueryAACube);
~UpdateEntityOperator(); ~UpdateEntityOperator();
@ -34,7 +33,6 @@ private:
EntityItemPointer _existingEntity; EntityItemPointer _existingEntity;
EntityTreeElementPointer _containingElement; EntityTreeElementPointer _containingElement;
AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element
BoundingBoxRelatedProperties _newProperties;
EntityItemID _entityItemID; EntityItemID _entityItemID;
bool _foundOld; bool _foundOld;
bool _foundNew; bool _foundNew;

View file

@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityAdd: case PacketType::EntityAdd:
case PacketType::EntityEdit: case PacketType::EntityEdit:
case PacketType::EntityData: case PacketType::EntityData:
return VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP; return VERSION_ENTITITES_HAVE_QUERY_BOX;
case PacketType::AvatarData: case PacketType::AvatarData:
case PacketType::BulkAvatarData: case PacketType::BulkAvatarData:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SoftAttachmentSupport); return static_cast<PacketVersion>(AvatarMixerPacketVersion::SoftAttachmentSupport);

View file

@ -161,7 +161,8 @@ const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48;
const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49;
const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50;
const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51;
const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52; const PacketVersion VERSION_ENTITITES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52;
const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 53;
enum class AvatarMixerPacketVersion : PacketVersion { enum class AvatarMixerPacketVersion : PacketVersion {
TranslationSupport = 17, TranslationSupport = 17,

View file

@ -23,6 +23,11 @@ AtomicUIntStat OctreePacketData::_totalBytesOfValues { 0 };
AtomicUIntStat OctreePacketData::_totalBytesOfPositions { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfPositions { 0 };
AtomicUIntStat OctreePacketData::_totalBytesOfRawData { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfRawData { 0 };
struct aaCubeData {
glm::vec3 corner;
float scale;
};
OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) { OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) {
changeSettings(enableCompression, targetSize); // does reset... changeSettings(enableCompression, targetSize); // does reset...
} }
@ -461,6 +466,17 @@ bool OctreePacketData::appendValue(const QByteArray& bytes) {
return success; return success;
} }
bool OctreePacketData::appendValue(const AACube& aaCube) {
aaCubeData cube { aaCube.getCorner(), aaCube.getScale() };
const unsigned char* data = (const unsigned char*)&cube;
int length = sizeof(aaCubeData);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendPosition(const glm::vec3& value) { bool OctreePacketData::appendPosition(const glm::vec3& value) {
const unsigned char* data = (const unsigned char*)&value; const unsigned char* data = (const unsigned char*)&value;
@ -638,3 +654,10 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteA
result = value; result = value;
return sizeof(length) + length; return sizeof(length) + length;
} }
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, AACube& result) {
aaCubeData cube;
memcpy(&cube, dataBytes, sizeof(aaCubeData));
result = AACube(cube.corner, cube.scale);
return sizeof(aaCubeData);
}

View file

@ -187,6 +187,9 @@ public:
/// appends a QByteArray value to the end of the stream, may fail if new data stream is too long to fit in packet /// appends a QByteArray value to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QByteArray& bytes); bool appendValue(const QByteArray& bytes);
/// appends an AACube value to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const AACube& aaCube);
/// appends a position to the end of the stream, may fail if new data stream is too long to fit in packet /// appends a position to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendPosition(const glm::vec3& value); bool appendPosition(const glm::vec3& value);
@ -253,6 +256,7 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<glm::vec3>& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<glm::vec3>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<float>& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<float>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, AACube& result);
private: private:
/// appends raw bytes, might fail if byte would cause packet to be too large /// appends raw bytes, might fail if byte would cause packet to be too large

View file

@ -374,6 +374,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
return true; return true;
} }
if (_entity->queryAABoxNeedsUpdate()) {
return true;
}
if (_entity->getSimulatorID() != sessionID) { if (_entity->getSimulatorID() != sessionID) {
// we don't own the simulation, but maybe we should... // we don't own the simulation, but maybe we should...
if (_outgoingPriority != NO_PRORITY) { if (_outgoingPriority != NO_PRORITY) {
@ -466,6 +470,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
properties.setActionData(_serverActionData); properties.setActionData(_serverActionData);
} }
if (properties.parentRelatedPropertyChanged() && _entity->computePuffedQueryAACube()) {
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
properties.setQueryAACube(_entity->getQueryAACube());
}
// set the LastEdited of the properties but NOT the entity itself // set the LastEdited of the properties but NOT the entity itself
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
properties.setLastEdited(now); properties.setLastEdited(now);
@ -502,6 +511,20 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties); entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties);
_entity->setLastBroadcast(usecTimestampNow()); _entity->setLastBroadcast(usecTimestampNow());
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
// if they've changed.
_entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (descendant->getNestableType() == NestableType::Entity) {
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
if (descendant->computePuffedQueryAACube()) {
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
entityDescendant->setLastBroadcast(usecTimestampNow());
}
}
});
_lastStep = step; _lastStep = step;
} }

View file

@ -23,15 +23,15 @@ ObjectAction::~ObjectAction() {
} }
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) { void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
bool ownerEntityExpired = false;
quint64 expiresWhen = 0; quint64 expiresWhen = 0;
EntityItemPointer ownerEntity = nullptr;
withReadLock([&]{ withReadLock([&]{
ownerEntityExpired = _ownerEntity.expired(); ownerEntity = _ownerEntity.lock();
expiresWhen = _expires; expiresWhen = _expires;
}); });
if (ownerEntityExpired) { if (!ownerEntity) {
qDebug() << "warning -- action with no entity removing self from btCollisionWorld."; qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld); btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
if (dynamicsWorld) { if (dynamicsWorld) {
@ -43,10 +43,8 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
if (expiresWhen > 0) { if (expiresWhen > 0) {
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
if (now > expiresWhen) { if (now > expiresWhen) {
EntityItemPointer ownerEntity = nullptr;
QUuid myID; QUuid myID;
withWriteLock([&]{ withWriteLock([&]{
ownerEntity = _ownerEntity.lock();
_active = false; _active = false;
myID = getID(); myID = getID();
}); });

View file

@ -95,6 +95,9 @@ const float METERS_PER_MILLIMETER = 0.01f;
void Model::setScaleInternal(const glm::vec3& scale) { void Model::setScaleInternal(const glm::vec3& scale) {
if (glm::distance(_scale, scale) > METERS_PER_MILLIMETER) { if (glm::distance(_scale, scale) > METERS_PER_MILLIMETER) {
_scale = scale; _scale = scale;
if (_scale.x == 0.0f || _scale.y == 0.0f || _scale.z == 0.0f) {
assert(false);
}
initJointTransforms(); initJointTransforms();
} }
} }

View file

@ -465,3 +465,16 @@ AABox AACube::clamp(float min, float max) const {
return temp.clamp(min, max); return temp.clamp(min, max);
} }
AACube& AACube::operator += (const glm::vec3& point) {
glm::vec3 oldMaximumPoint = getMaximumPoint();
_corner = glm::vec3(glm::min(_corner.x, point.x),
glm::min(_corner.y, point.y),
glm::min(_corner.z, point.z));
glm::vec3 scaleOld = oldMaximumPoint - _corner;
glm::vec3 scalePoint = point - _corner;
_scale = glm::max(_scale, scalePoint.x, scalePoint.y, scalePoint.z);
_scale = glm::max(_scale, scaleOld.x, scaleOld.y, scaleOld.z);
return (*this);
}

View file

@ -64,6 +64,8 @@ public:
AABox clamp(const glm::vec3& min, const glm::vec3& max) const; AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
AABox clamp(float min, float max) const; AABox clamp(float min, float max) const;
AACube& operator += (const glm::vec3& point);
private: private:
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;

View file

@ -42,7 +42,7 @@ void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue);
qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue);
qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue);
qScriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue);
} }
QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) { QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) {
@ -238,6 +238,26 @@ QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color) {
return object; return object;
} }
QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube) {
QScriptValue obj = engine->newObject();
const glm::vec3& corner = aaCube.getCorner();
obj.setProperty("x", corner.x);
obj.setProperty("y", corner.y);
obj.setProperty("z", corner.z);
obj.setProperty("scale", aaCube.getScale());
return obj;
}
void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube) {
glm::vec3 corner;
corner.x = object.property("x").toVariant().toFloat();
corner.y = object.property("y").toVariant().toFloat();
corner.z = object.property("z").toVariant().toFloat();
float scale = object.property("scale").toVariant().toFloat();
aaCube.setBox(corner, scale);
}
void qColorFromScriptValue(const QScriptValue& object, QColor& color) { void qColorFromScriptValue(const QScriptValue& object, QColor& color) {
if (object.isNumber()) { if (object.isNumber()) {
color.setRgb(object.toUInt32()); color.setRgb(object.toUInt32());

View file

@ -18,6 +18,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include "AACube.h"
#include "SharedUtil.h" #include "SharedUtil.h"
class QColor; class QColor;
@ -30,6 +31,7 @@ Q_DECLARE_METATYPE(glm::quat)
Q_DECLARE_METATYPE(xColor) Q_DECLARE_METATYPE(xColor)
Q_DECLARE_METATYPE(QVector<glm::vec3>) Q_DECLARE_METATYPE(QVector<glm::vec3>)
Q_DECLARE_METATYPE(QVector<float>) Q_DECLARE_METATYPE(QVector<float>)
Q_DECLARE_METATYPE(AACube)
void registerMetaTypes(QScriptEngine* engine); void registerMetaTypes(QScriptEngine* engine);
@ -67,6 +69,9 @@ QVector<float> qVectorFloatFromScriptValue(const QScriptValue& array);
QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array); QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array);
QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube);
void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube);
class PickRay { class PickRay {
public: public:
PickRay() : origin(0.0f), direction(0.0f) { } PickRay() : origin(0.0f), direction(0.0f) { }

View file

@ -31,7 +31,7 @@ public:
SpatialParentFinder() { } SpatialParentFinder() { }
virtual ~SpatialParentFinder() { } virtual ~SpatialParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID) const = 0; virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success) const = 0;
}; };
#endif // hifi_SpatialParentFinder_h #endif // hifi_SpatialParentFinder_h

View file

@ -14,6 +14,7 @@
#include "DependencyManager.h" #include "DependencyManager.h"
#include "SpatiallyNestable.h" #include "SpatiallyNestable.h"
const float defaultAACubeSize = 1.0f;
SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
_nestableType(nestableType), _nestableType(nestableType),
@ -24,21 +25,25 @@ SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
_transform.setRotation(glm::quat()); _transform.setRotation(glm::quat());
} }
Transform SpatiallyNestable::getParentTransform() const { Transform SpatiallyNestable::getParentTransform(bool& success) const {
Transform result; Transform result;
SpatiallyNestablePointer parent = getParentPointer(); SpatiallyNestablePointer parent = getParentPointer(success);
if (!success) {
return result;
}
if (parent) { if (parent) {
Transform parentTransform = parent->getTransform(_parentJointIndex); Transform parentTransform = parent->getTransform(_parentJointIndex, success);
result = parentTransform.setScale(1.0f); result = parentTransform.setScale(1.0f); // TODO: scaling
} }
return result; return result;
} }
SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) const {
SpatiallyNestablePointer parent = _parent.lock(); SpatiallyNestablePointer parent = _parent.lock();
if (!parent && _parentID.isNull()) { if (!parent && _parentID.isNull()) {
// no parent // no parent
success = true;
return nullptr; return nullptr;
} }
@ -48,6 +53,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
parent->beParentOfChild(getThisPointer()); parent->beParentOfChild(getThisPointer());
_parentKnowsMe = true; _parentKnowsMe = true;
} }
success = true;
return parent; return parent;
} }
@ -63,9 +69,14 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
// we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing // we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>(); QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) { if (!parentFinder) {
success = false;
return nullptr; return nullptr;
} }
_parent = parentFinder->find(_parentID); _parent = parentFinder->find(_parentID, success);
if (!success) {
return nullptr;
}
parent = _parent.lock(); parent = _parent.lock();
if (parent) { if (parent) {
parent->beParentOfChild(thisPointer); parent->beParentOfChild(thisPointer);
@ -73,7 +84,9 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
} }
if (parent || _parentID.isNull()) { if (parent || _parentID.isNull()) {
thisPointer->parentChanged(); success = true;
} else {
success = false;
} }
return parent; return parent;
@ -96,131 +109,255 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) {
_parentID = parentID; _parentID = parentID;
_parentKnowsMe = false; _parentKnowsMe = false;
} }
parentChanged();
} }
glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex) { void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) {
_parentJointIndex = parentJointIndex;
}
glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position,
const QUuid& parentID, int parentJointIndex,
bool& success) {
Transform result;
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>(); QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) {
success = false;
return glm::vec3(0.0f);
}
Transform parentTransform; Transform parentTransform;
if (parentFinder) { auto parentWP = parentFinder->find(parentID, success);
auto parentWP = parentFinder->find(parentID); if (!success) {
return glm::vec3(0.0f);
}
auto parent = parentWP.lock(); auto parent = parentWP.lock();
if (!parentID.isNull() && !parent) {
success = false;
return glm::vec3(0.0f);
}
if (parent) { if (parent) {
parentTransform = parent->getTransform(parentJointIndex); parentTransform = parent->getTransform(parentJointIndex, success);
parentTransform.setScale(1.0f); if (!success) {
return glm::vec3(0.0f);
} }
parentTransform.setScale(1.0f); // TODO: scale
} }
success = true;
Transform positionTransform; Transform positionTransform;
positionTransform.setTranslation(position); positionTransform.setTranslation(position);
Transform myWorldTransform; Transform myWorldTransform;
Transform::mult(myWorldTransform, parentTransform, positionTransform); Transform::mult(myWorldTransform, parentTransform, positionTransform);
myWorldTransform.setTranslation(position); myWorldTransform.setTranslation(position);
Transform result;
Transform::inverseMult(result, parentTransform, myWorldTransform); Transform::inverseMult(result, parentTransform, myWorldTransform);
return result.getTranslation(); return result.getTranslation();
} }
glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex) { glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
const QUuid& parentID, int parentJointIndex,
bool& success) {
Transform result;
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>(); QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) {
success = false;
return glm::quat();
}
Transform parentTransform; Transform parentTransform;
if (parentFinder) { auto parentWP = parentFinder->find(parentID, success);
auto parentWP = parentFinder->find(parentID); if (!success) {
return glm::quat();
}
auto parent = parentWP.lock(); auto parent = parentWP.lock();
if (!parentID.isNull() && !parent) {
success = false;
return glm::quat();
}
if (parent) { if (parent) {
parentTransform = parent->getTransform(parentJointIndex); parentTransform = parent->getTransform(parentJointIndex, success);
parentTransform.setScale(1.0f); if (!success) {
return glm::quat();
} }
parentTransform.setScale(1.0f); // TODO: scale
} }
success = true;
Transform orientationTransform; Transform orientationTransform;
orientationTransform.setRotation(orientation); orientationTransform.setRotation(orientation);
Transform myWorldTransform; Transform myWorldTransform;
Transform::mult(myWorldTransform, parentTransform, orientationTransform); Transform::mult(myWorldTransform, parentTransform, orientationTransform);
myWorldTransform.setRotation(orientation); myWorldTransform.setRotation(orientation);
Transform result;
Transform::inverseMult(result, parentTransform, myWorldTransform); Transform::inverseMult(result, parentTransform, myWorldTransform);
return result.getRotation(); return result.getRotation();
} }
glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex) { glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position,
const QUuid& parentID, int parentJointIndex,
bool& success) {
Transform result;
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>(); QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) {
success = false;
return glm::vec3(0.0f);
}
Transform parentTransform; Transform parentTransform;
if (parentFinder) { auto parentWP = parentFinder->find(parentID, success);
auto parentWP = parentFinder->find(parentID); if (!success) {
return glm::vec3(0.0f);
}
auto parent = parentWP.lock(); auto parent = parentWP.lock();
if (!parentID.isNull() && !parent) {
success = false;
return glm::vec3(0.0f);
}
if (parent) { if (parent) {
parentTransform = parent->getTransform(parentJointIndex); parentTransform = parent->getTransform(parentJointIndex, success);
parentTransform.setScale(1.0f); if (!success) {
return glm::vec3(0.0f);
} }
parentTransform.setScale(1.0f); // TODO: scale
} }
success = true;
Transform positionTransform; Transform positionTransform;
positionTransform.setTranslation(position); positionTransform.setTranslation(position);
Transform result;
Transform::mult(result, parentTransform, positionTransform); Transform::mult(result, parentTransform, positionTransform);
return result.getTranslation(); return result.getTranslation();
} }
glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex) { glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation,
const QUuid& parentID, int parentJointIndex,
bool& success) {
Transform result;
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>(); QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) {
success = false;
return glm::quat();
}
Transform parentTransform; Transform parentTransform;
if (parentFinder) { auto parentWP = parentFinder->find(parentID, success);
auto parentWP = parentFinder->find(parentID); if (!success) {
return glm::quat();
}
auto parent = parentWP.lock(); auto parent = parentWP.lock();
if (!parentID.isNull() && !parent) {
success = false;
return glm::quat();
}
if (parent) { if (parent) {
parentTransform = parent->getTransform(parentJointIndex); parentTransform = parent->getTransform(parentJointIndex, success);
if (!success) {
return glm::quat();
}
parentTransform.setScale(1.0f); parentTransform.setScale(1.0f);
} }
} success = true;
Transform orientationTransform; Transform orientationTransform;
orientationTransform.setRotation(orientation); orientationTransform.setRotation(orientation);
Transform result;
Transform::mult(result, parentTransform, orientationTransform); Transform::mult(result, parentTransform, orientationTransform);
return result.getRotation(); return result.getRotation();
} }
glm::vec3 SpatiallyNestable::getPosition(bool& success) const {
return getTransform(success).getTranslation();
}
glm::vec3 SpatiallyNestable::getPosition() const { glm::vec3 SpatiallyNestable::getPosition() const {
return getTransform().getTranslation(); bool success;
auto result = getPosition(success);
#ifdef WANT_DEBUG
if (!success) {
qDebug() << "Warning -- getPosition failed" << getID();
}
#endif
return result;
} }
glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const {
return getTransform(jointIndex).getTranslation(); return getTransform(jointIndex, success).getTranslation();
} }
void SpatiallyNestable::setPosition(const glm::vec3& position) { void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) {
Transform parentTransform = getParentTransform(); Transform parentTransform = getParentTransform(success);
Transform myWorldTransform; Transform myWorldTransform;
_transformLock.withWriteLock([&] { _transformLock.withWriteLock([&] {
Transform::mult(myWorldTransform, parentTransform, _transform); Transform::mult(myWorldTransform, parentTransform, _transform);
myWorldTransform.setTranslation(position); myWorldTransform.setTranslation(position);
Transform::inverseMult(_transform, parentTransform, myWorldTransform); Transform::inverseMult(_transform, parentTransform, myWorldTransform);
}); });
if (success) {
locationChanged(); locationChanged();
} else {
qDebug() << "setPosition failed for" << getID();
}
}
void SpatiallyNestable::setPosition(const glm::vec3& position) {
bool success;
setPosition(position, success);
#ifdef WANT_DEBUG
if (!success) {
qDebug() << "Warning -- setPosition failed" << getID();
}
#endif
}
glm::quat SpatiallyNestable::getOrientation(bool& success) const {
return getTransform(success).getRotation();
} }
glm::quat SpatiallyNestable::getOrientation() const { glm::quat SpatiallyNestable::getOrientation() const {
return getTransform().getRotation(); bool success;
auto result = getOrientation(success);
#ifdef WANT_DEBUG
if (!success) {
qDebug() << "Warning -- getOrientation failed" << getID();
}
#endif
return result;
} }
glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const {
return getTransform(jointIndex).getRotation(); return getTransform(jointIndex, success).getRotation();
} }
void SpatiallyNestable::setOrientation(const glm::quat& orientation) { void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success) {
Transform parentTransform = getParentTransform(); Transform parentTransform = getParentTransform(success);
Transform myWorldTransform; Transform myWorldTransform;
_transformLock.withWriteLock([&] { _transformLock.withWriteLock([&] {
Transform::mult(myWorldTransform, parentTransform, _transform); Transform::mult(myWorldTransform, parentTransform, _transform);
myWorldTransform.setRotation(orientation); myWorldTransform.setRotation(orientation);
Transform::inverseMult(_transform, parentTransform, myWorldTransform); Transform::inverseMult(_transform, parentTransform, myWorldTransform);
}); });
if (success) {
locationChanged(); locationChanged();
} }
}
const Transform SpatiallyNestable::getTransform() const { void SpatiallyNestable::setOrientation(const glm::quat& orientation) {
bool success;
setOrientation(orientation, success);
#ifdef WANT_DEBUG
if (!success) {
qDebug() << "Warning -- setOrientation failed" << getID();
}
#endif
}
const Transform SpatiallyNestable::getTransform(bool& success) const {
// return a world-space transform for this object's location // return a world-space transform for this object's location
Transform parentTransform = getParentTransform(); Transform parentTransform = getParentTransform(success);
Transform result; Transform result;
_transformLock.withReadLock([&] { _transformLock.withReadLock([&] {
Transform::mult(result, parentTransform, _transform); Transform::mult(result, parentTransform, _transform);
@ -228,25 +365,34 @@ const Transform SpatiallyNestable::getTransform() const {
return result; return result;
} }
const Transform SpatiallyNestable::getTransform(int jointIndex) const { const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) const {
// this returns the world-space transform for this object. It finds its parent's transform (which may // this returns the world-space transform for this object. It finds its parent's transform (which may
// cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it.
Transform worldTransform = getTransform();
Transform jointInObjectFrame = getAbsoluteJointTransformInObjectFrame(jointIndex);
Transform jointInWorldFrame; Transform jointInWorldFrame;
Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame);
Transform worldTransform = getTransform(success);
if (!success) {
return jointInWorldFrame; return jointInWorldFrame;
} }
void SpatiallyNestable::setTransform(const Transform& transform) { Transform jointInObjectFrame = getAbsoluteJointTransformInObjectFrame(jointIndex);
Transform parentTransform = getParentTransform(); Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame);
success = true;
return jointInWorldFrame;
}
void SpatiallyNestable::setTransform(const Transform& transform, bool& success) {
Transform parentTransform = getParentTransform(success);
_transformLock.withWriteLock([&] { _transformLock.withWriteLock([&] {
Transform::inverseMult(_transform, parentTransform, transform); Transform::inverseMult(_transform, parentTransform, transform);
}); });
if (success) {
locationChanged(); locationChanged();
} }
}
glm::vec3 SpatiallyNestable::getScale() const { glm::vec3 SpatiallyNestable::getScale() const {
// TODO: scale
glm::vec3 result; glm::vec3 result;
_transformLock.withReadLock([&] { _transformLock.withReadLock([&] {
result = _transform.getScale(); result = _transform.getScale();
@ -255,11 +401,12 @@ glm::vec3 SpatiallyNestable::getScale() const {
} }
glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { glm::vec3 SpatiallyNestable::getScale(int jointIndex) const {
// XXX ... something with joints // TODO: scale
return getScale(); return getScale();
} }
void SpatiallyNestable::setScale(const glm::vec3& scale) { void SpatiallyNestable::setScale(const glm::vec3& scale) {
// TODO: scale
_transformLock.withWriteLock([&] { _transformLock.withWriteLock([&] {
_transform.setScale(scale); _transform.setScale(scale);
}); });
@ -312,6 +459,7 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) {
} }
glm::vec3 SpatiallyNestable::getLocalScale() const { glm::vec3 SpatiallyNestable::getLocalScale() const {
// TODO: scale
glm::vec3 result; glm::vec3 result;
_transformLock.withReadLock([&] { _transformLock.withReadLock([&] {
result = _transform.getScale(); result = _transform.getScale();
@ -320,6 +468,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const {
} }
void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
// TODO: scale
_transformLock.withWriteLock([&] { _transformLock.withWriteLock([&] {
_transform.setScale(scale); _transform.setScale(scale);
}); });
@ -380,3 +529,83 @@ void SpatiallyNestable::locationChanged() {
object->locationChanged(); object->locationChanged();
}); });
} }
AACube SpatiallyNestable::getMaximumAACube(bool& success) const {
return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize);
}
void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) {
_queryAACube = queryAACube;
if (queryAACube.getScale() > 0.0f) {
_queryAACubeSet = true;
}
}
bool SpatiallyNestable::queryAABoxNeedsUpdate() const {
bool success;
AACube currentAACube = getMaximumAACube(success);
if (!success) {
qDebug() << "can't getMaximumAACube for" << getID();
return false;
}
// make sure children are still in their boxes, also.
bool childNeedsUpdate = false;
getThisPointer()->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (!childNeedsUpdate && descendant->queryAABoxNeedsUpdate()) {
childNeedsUpdate = true;
}
});
if (childNeedsUpdate) {
return true;
}
if (_queryAACubeSet && _queryAACube.contains(currentAACube)) {
return false;
}
return true;
}
bool SpatiallyNestable::computePuffedQueryAACube() {
if (!queryAABoxNeedsUpdate()) {
return false;
}
bool success;
AACube currentAACube = getMaximumAACube(success);
// make an AACube with edges thrice as long and centered on the object
_queryAACube = AACube(currentAACube.getCorner() - glm::vec3(currentAACube.getScale()), currentAACube.getScale() * 3.0f);
_queryAACubeSet = true;
getThisPointer()->forEachDescendant([&](SpatiallyNestablePointer descendant) {
bool success;
AACube descendantAACube = descendant->getQueryAACube(success);
if (success) {
if (_queryAACube.contains(descendantAACube)) {
return;
}
_queryAACube += descendantAACube.getMinimumPoint();
_queryAACube += descendantAACube.getMaximumPoint();
}
});
return true;
}
AACube SpatiallyNestable::getQueryAACube(bool& success) const {
if (_queryAACubeSet) {
success = true;
return _queryAACube;
}
success = false;
return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize);
}
AACube SpatiallyNestable::getQueryAACube() const {
bool success;
auto result = getQueryAACube(success);
if (!success) {
qDebug() << "getQueryAACube failed for" << getID();
}
return result;
}

View file

@ -15,6 +15,7 @@
#include <QUuid> #include <QUuid>
#include "Transform.h" #include "Transform.h"
#include "AACube.h"
#include "SpatialParentFinder.h" #include "SpatialParentFinder.h"
#include "shared/ReadWriteLockable.h" #include "shared/ReadWriteLockable.h"
@ -38,37 +39,49 @@ public:
virtual const QUuid& getID() const { return _id; } virtual const QUuid& getID() const { return _id; }
virtual void setID(const QUuid& id) { _id = id; } virtual void setID(const QUuid& id) { _id = id; }
virtual const QUuid getParentID() const { return _parentID; } virtual QUuid getParentID() const { return _parentID; }
virtual void setParentID(const QUuid& parentID); virtual void setParentID(const QUuid& parentID);
virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual quint16 getParentJointIndex() const { return _parentJointIndex; }
virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex);
static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex); static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success);
static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex); static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex); static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success);
static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex); static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
// world frame // world frame
virtual const Transform getTransform() const; virtual const Transform getTransform(bool& success) const;
virtual void setTransform(const Transform& transform); virtual void setTransform(const Transform& transform, bool& success);
virtual Transform getParentTransform() const; virtual Transform getParentTransform(bool& success) const;
virtual glm::vec3 getPosition(bool& success) const;
virtual glm::vec3 getPosition() const; virtual glm::vec3 getPosition() const;
virtual void setPosition(const glm::vec3& position, bool& success);
virtual void setPosition(const glm::vec3& position); virtual void setPosition(const glm::vec3& position);
virtual glm::quat getOrientation(bool& success) const;
virtual glm::quat getOrientation() const; virtual glm::quat getOrientation() const;
virtual glm::quat getOrientation(int jointIndex) const; virtual glm::quat getOrientation(int jointIndex, bool& success) const;
virtual void setOrientation(const glm::quat& orientation, bool& success);
virtual void setOrientation(const glm::quat& orientation); virtual void setOrientation(const glm::quat& orientation);
virtual AACube getMaximumAACube(bool& success) const;
virtual bool computePuffedQueryAACube();
virtual void setQueryAACube(const AACube& queryAACube);
virtual bool queryAABoxNeedsUpdate() const;
virtual AACube getQueryAACube(bool& success) const;
virtual AACube getQueryAACube() const;
virtual glm::vec3 getScale() const; virtual glm::vec3 getScale() const;
virtual void setScale(const glm::vec3& scale); virtual void setScale(const glm::vec3& scale);
// get world-frame values for a specific joint // get world-frame values for a specific joint
virtual const Transform getTransform(int jointIndex) const; virtual const Transform getTransform(int jointIndex, bool& success) const;
virtual glm::vec3 getPosition(int jointIndex) const; virtual glm::vec3 getPosition(int jointIndex, bool& success) const;
virtual glm::vec3 getScale(int jointIndex) const; virtual glm::vec3 getScale(int jointIndex) const;
// object's parent's frame // object's parent's frame
@ -89,17 +102,23 @@ public:
// this object's frame // this object's frame
virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const; virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const;
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { assert(false); return glm::quat(); } virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const = 0;
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { assert(false); return glm::vec3(); } virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const = 0;
SpatiallyNestablePointer getThisPointer() const; SpatiallyNestablePointer getThisPointer() const;
void markAncestorMissing(bool value) { _missingAncestor = value; }
bool getAncestorMissing() { return _missingAncestor; }
void forEachChild(std::function<void(SpatiallyNestablePointer)> actor);
void forEachDescendant(std::function<void(SpatiallyNestablePointer)> actor);
protected: protected:
const NestableType _nestableType; // EntityItem or an AvatarData const NestableType _nestableType; // EntityItem or an AvatarData
QUuid _id; QUuid _id;
QUuid _parentID; // what is this thing's transform relative to? QUuid _parentID; // what is this thing's transform relative to?
quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to?
SpatiallyNestablePointer getParentPointer() const; SpatiallyNestablePointer getParentPointer(bool& success) const;
mutable SpatiallyNestableWeakPointer _parent; mutable SpatiallyNestableWeakPointer _parent;
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const;
@ -108,12 +127,14 @@ protected:
mutable ReadWriteLockable _childrenLock; mutable ReadWriteLockable _childrenLock;
mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children; mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children;
virtual void parentChanged() {} // called when parent pointer is updated
virtual void locationChanged(); // called when a this object's location has changed virtual void locationChanged(); // called when a this object's location has changed
virtual void dimensionsChanged() {} // called when a this object's dimensions have changed virtual void dimensionsChanged() {} // called when a this object's dimensions have changed
void forEachChild(std::function<void(SpatiallyNestablePointer)> actor); // _queryAACube is used to decide where something lives in the octree
void forEachDescendant(std::function<void(SpatiallyNestablePointer)> actor); mutable AACube _queryAACube;
mutable bool _queryAACubeSet { false };
bool _missingAncestor { false };
private: private:
mutable ReadWriteLockable _transformLock; mutable ReadWriteLockable _transformLock;

View file

@ -0,0 +1,49 @@
//
// ThreadSafeValueCache.h
// interface/src/avatar
//
// Copyright 2012 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ThreadSafeValueCache_h
#define hifi_ThreadSafeValueCache_h
#include <mutex>
// Helper class for for sharing a value type between threads.
// It allows many threads to get or set a value atomically.
// This provides cache semantics, any get will return the last set value.
//
// For example: This can be used to copy values between C++ code running on the application thread
// and JavaScript which is running on a different thread.
template <typename T>
class ThreadSafeValueCache {
public:
ThreadSafeValueCache(const T& v) : _value { v } {}
// returns atomic copy of the cached value.
T get() const {
std::lock_guard<std::mutex> guard(_mutex);
return _value;
}
// will reflect copy of value into the cache.
void set(const T& v) {
std::lock_guard<std::mutex> guard(_mutex);
_value = v;
}
private:
mutable std::mutex _mutex;
T _value;
// no copies
ThreadSafeValueCache(const ThreadSafeValueCache&) = delete;
ThreadSafeValueCache& operator=(const ThreadSafeValueCache&) = delete;
};
#endif // #define hifi_ThreadSafeValueCache_h

View file

@ -176,9 +176,34 @@ void OffscreenUi::information(const QString& title, const QString& text,
void OffscreenUi::question(const QString& title, const QString& text, void OffscreenUi::question(const QString& title, const QString& text,
ButtonCallback callback, ButtonCallback callback,
QMessageBox::StandardButtons buttons) { QMessageBox::StandardButtons buttons) {
messageBox(title, text, callback,
bool waiting = true;
ButtonCallback blockingCallback = [&](QMessageBox::StandardButton response){
callback(response); // call the actual callback
waiting = false;
};
messageBox(title, text, blockingCallback,
static_cast<QMessageBox::Icon>(MessageDialog::Question), buttons); static_cast<QMessageBox::Icon>(MessageDialog::Question), buttons);
// block until the call back has been called
while (waiting) {
QCoreApplication::processEvents();
} }
}
QMessageBox::StandardButton OffscreenUi::question(void* ignored, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
QMessageBox::StandardButton result = defaultButton;
OffscreenUi::question(title, text, [&](QMessageBox::StandardButton response){
result = response;
}, buttons);
return result;
}
void OffscreenUi::warning(const QString& title, const QString& text, void OffscreenUi::warning(const QString& title, const QString& text,
ButtonCallback callback, ButtonCallback callback,
@ -187,6 +212,26 @@ void OffscreenUi::warning(const QString& title, const QString& text,
static_cast<QMessageBox::Icon>(MessageDialog::Warning), buttons); static_cast<QMessageBox::Icon>(MessageDialog::Warning), buttons);
} }
QMessageBox::StandardButton OffscreenUi::warning(void* ignored, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
bool waiting = true;
QMessageBox::StandardButton result = defaultButton;
OffscreenUi::warning(title, text, [&](QMessageBox::StandardButton response){
result = response;
waiting = false;
}, buttons);
// block until the call back has been called
while (waiting) {
QCoreApplication::processEvents();
}
return result;
}
void OffscreenUi::critical(const QString& title, const QString& text, void OffscreenUi::critical(const QString& title, const QString& text,
ButtonCallback callback, ButtonCallback callback,
QMessageBox::StandardButtons buttons) { QMessageBox::StandardButtons buttons) {

View file

@ -45,14 +45,25 @@ public:
ButtonCallback callback = NO_OP_CALLBACK, ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::Ok); QMessageBox::StandardButtons buttons = QMessageBox::Ok);
/// Note: will block until user clicks a response to the question
static void question(const QString& title, const QString& text, static void question(const QString& title, const QString& text,
ButtonCallback callback = NO_OP_CALLBACK, ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No)); QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No));
/// Same design as QMessageBox::question(), will block, returns result
static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
static void warning(const QString& title, const QString& text, static void warning(const QString& title, const QString& text,
ButtonCallback callback = NO_OP_CALLBACK, ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::Ok); QMessageBox::StandardButtons buttons = QMessageBox::Ok);
/// Same design as QMessageBox::warning(), will block, returns result
static QMessageBox::StandardButton warning(void* ignored, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
static void critical(const QString& title, const QString& text, static void critical(const QString& title, const QString& text,
ButtonCallback callback = NO_OP_CALLBACK, ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::Ok); QMessageBox::StandardButtons buttons = QMessageBox::Ok);