From 49ea560e4e2fec110bb4c2e29376a4fc1b4aae21 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Dec 2015 16:33:40 -0700 Subject: [PATCH 01/37] make QTimers in ThreadedAssignment not be raw pointers --- .../networking/src/ThreadedAssignment.cpp | 63 ++++++------------- libraries/networking/src/ThreadedAssignment.h | 8 +-- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 2f5ab7a015..bdf2518de8 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -20,10 +20,16 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) : Assignment(message), - _isFinished(false) - + _isFinished(false), + _domainServerTimer(this), + _statsTimer(this) { + static const int STATS_TIMEOUT_MS = 1000; + _statsTimer.setInterval(STATS_TIMEOUT_MS); + connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); + connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit); + _domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS); } void ThreadedAssignment::setFinished(bool isFinished) { @@ -47,16 +53,10 @@ void ThreadedAssignment::setFinished(bool isFinished) { // send a disconnect packet to the domain nodeList->getDomainHandler().disconnect(); - if (_domainServerTimer) { - // stop the domain-server check in timer by calling deleteLater so it gets cleaned up on NL thread - _domainServerTimer->deleteLater(); - _domainServerTimer = nullptr; - } + // stop our owned timers - if (_statsTimer) { - _statsTimer->deleteLater(); - _statsTimer = nullptr; - } + _domainServerTimer.stop(); + _statsTimer.stop(); // call our virtual aboutToFinish method - this gives the ThreadedAssignment subclass a chance to cleanup aboutToFinish(); @@ -66,30 +66,21 @@ void ThreadedAssignment::setFinished(bool isFinished) { } } -void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { +void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType) { // change the logging target name while the assignment is running LogHandler::getInstance().setTargetName(targetName); auto nodeList = DependencyManager::get(); nodeList->setOwnerType(nodeType); - _domainServerTimer = new QTimer; - connect(_domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); - _domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); - // send a domain-server check in immediately checkInWithDomainServerOrExit(); - - // move the domain server time to the NL so check-ins fire from there - _domainServerTimer->moveToThread(nodeList->thread()); - if (shouldSendStats) { - // start sending stats packet once we connect to the domain - connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, this, &ThreadedAssignment::startSendingStats); - - // stop sending stats if we disconnect - connect(&nodeList->getDomainHandler(), &DomainHandler::disconnectedFromDomain, this, &ThreadedAssignment::stopSendingStats); - } + // start sending stats packet once we connect to the domain + connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain()), &_statsTimer, SLOT(start())); + + // stop sending stats if we disconnect + connect(&nodeList->getDomainHandler(), &DomainHandler::disconnectedFromDomain, &_statsTimer, &QTimer::stop); } void ThreadedAssignment::addPacketStatsAndSendStatsPacket(QJsonObject &statsObject) { @@ -111,28 +102,12 @@ void ThreadedAssignment::sendStatsPacket() { addPacketStatsAndSendStatsPacket(statsObject); } -void ThreadedAssignment::startSendingStats() { - // send the stats packet every 1s - if (!_statsTimer) { - _statsTimer = new QTimer; - connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); - } - - _statsTimer->start(1000); -} - -void ThreadedAssignment::stopSendingStats() { - if (_statsTimer) { - // stop sending stats, we just disconnected from domain - _statsTimer->stop(); - } -} - void ThreadedAssignment::checkInWithDomainServerOrExit() { if (DependencyManager::get()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { setFinished(true); } else { - DependencyManager::get()->sendDomainServerCheckIn(); + auto nodeList = DependencyManager::get(); + QMetaObject::invokeMethod(nodeList.data(), "sendDomainServerCheckIn"); } } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 87d503d2bf..42d4903c2f 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -38,17 +38,15 @@ signals: void finished(); protected: - void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); + void commonInit(const QString& targetName, NodeType_t nodeType); bool _isFinished; - QTimer* _domainServerTimer = nullptr; - QTimer* _statsTimer = nullptr; + QTimer _domainServerTimer; + QTimer _statsTimer; protected slots: void domainSettingsRequestFailed(); private slots: - void startSendingStats(); - void stopSendingStats(); void checkInWithDomainServerOrExit(); }; From 9e2d06710feb773a06bf86cd869340edeedc1380 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Dec 2015 16:37:22 -0700 Subject: [PATCH 02/37] fix for connectedToDomain signal signature --- libraries/networking/src/ThreadedAssignment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index bdf2518de8..b8f8f5697f 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -77,7 +77,7 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy checkInWithDomainServerOrExit(); // start sending stats packet once we connect to the domain - connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain()), &_statsTimer, SLOT(start())); + connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), &_statsTimer, SLOT(start())); // stop sending stats if we disconnect connect(&nodeList->getDomainHandler(), &DomainHandler::disconnectedFromDomain, &_statsTimer, &QTimer::stop); From 74d168561749e38cb59635ae8fe4ceb400ec9f06 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 21 Dec 2015 16:45:33 -0700 Subject: [PATCH 03/37] remove an extra space --- libraries/networking/src/ThreadedAssignment.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index b8f8f5697f..9ec07bc5d6 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -54,7 +54,6 @@ void ThreadedAssignment::setFinished(bool isFinished) { nodeList->getDomainHandler().disconnect(); // stop our owned timers - _domainServerTimer.stop(); _statsTimer.stop(); From a0d6001fa506c1cd78113befab5e6f08e728da10 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Dec 2015 10:54:42 -0800 Subject: [PATCH 04/37] actually start domain-server check in timer --- libraries/networking/src/ThreadedAssignment.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 9ec07bc5d6..303755c8f3 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -72,8 +72,9 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy auto nodeList = DependencyManager::get(); nodeList->setOwnerType(nodeType); - // send a domain-server check in immediately + // send a domain-server check in immediately and start the timer to fire them every DOMAIN_SERVER_CHECK_IN_MSECS checkInWithDomainServerOrExit(); + _domainServerTimer.start(); // start sending stats packet once we connect to the domain connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), &_statsTimer, SLOT(start())); From f60cd09b451b76a5aab9e637ab0a2fa649ac8f99 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 3 Jan 2016 14:13:16 -0800 Subject: [PATCH 05/37] Add logging of signal slot exceptions in ScriptEngine --- libraries/script-engine/src/ScriptEngine.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ef448e93f0..f60bb41955 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -50,6 +50,8 @@ #include "MIDIEvent.h" +static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; + Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) static int functionSignatureMetaID = qRegisterMetaType(); @@ -111,7 +113,7 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName const auto line = QString::number(engine.uncaughtExceptionLineNumber()); engine.clearExceptions(); - auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); + auto message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception, fileName, line); if (!backtrace.empty()) { static const auto lineSeparator = "\n "; message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); @@ -132,6 +134,13 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _allScriptsMutex.lock(); _allKnownScriptEngines.insert(this); _allScriptsMutex.unlock(); + + connect(this, &QScriptEngine::signalHandlerException, this, [](const QScriptValue& exception) { + auto fileName = exception.property("fileName").toString(); + auto lineNumber = exception.property("lineNumber").toString(); + auto message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception.toString(), fileName, lineNumber); + qCWarning(scriptengine) << qPrintable(message); + }); } ScriptEngine::~ScriptEngine() { From 810da77abe4866bb57512d4d70c8e633c99dd921 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 4 Jan 2016 10:34:55 -0800 Subject: [PATCH 06/37] Update ScriptEngine signal exception handling to call hadUncaughtExceptions --- libraries/script-engine/src/ScriptEngine.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index f60bb41955..6e37ab056e 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -135,11 +135,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _allKnownScriptEngines.insert(this); _allScriptsMutex.unlock(); - connect(this, &QScriptEngine::signalHandlerException, this, [](const QScriptValue& exception) { - auto fileName = exception.property("fileName").toString(); - auto lineNumber = exception.property("lineNumber").toString(); - auto message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception.toString(), fileName, lineNumber); - qCWarning(scriptengine) << qPrintable(message); + connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { + hadUncaughtExceptions(*this, _fileNameString); }); } From 1b82200ecb4625da8b5cb39a97ef8810e7e989a8 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Jan 2016 17:16:45 -0800 Subject: [PATCH 07/37] Address some z-ordering issues in overlay windows --- examples/tests/qmlTest.js | 33 +--- interface/resources/qml/AddressBarDialog.qml | 1 + interface/resources/qml/Global.js | 165 ++++++++++++++++++ interface/resources/qml/QmlWindow.qml | 6 + interface/resources/qml/Root.qml | 11 +- interface/resources/qml/controls/VrDialog.qml | 18 ++ libraries/ui/src/QmlWindowClass.cpp | 5 +- 7 files changed, 206 insertions(+), 33 deletions(-) create mode 100644 interface/resources/qml/Global.js diff --git a/examples/tests/qmlTest.js b/examples/tests/qmlTest.js index f1aa59cc09..c891b6a1b7 100644 --- a/examples/tests/qmlTest.js +++ b/examples/tests/qmlTest.js @@ -8,33 +8,6 @@ qmlWindow = new OverlayWindow({ visible: true }); -//qmlWindow.eventBridge.webEventReceived.connect(function(data) { -// print("JS Side event received: " + data); -//}); -// -//var titles = ["A", "B", "C"]; -//var titleIndex = 0; -// -//Script.setInterval(function() { -// qmlWindow.eventBridge.emitScriptEvent("JS Event sent"); -// var size = qmlWindow.size; -// var position = qmlWindow.position; -// print("Window visible: " + qmlWindow.visible) -// if (qmlWindow.visible) { -// print("Window size: " + size.x + "x" + size.y) -// print("Window pos: " + position.x + "x" + position.y) -// qmlWindow.setVisible(false); -// } else { -// qmlWindow.setVisible(true); -// qmlWindow.setTitle(titles[titleIndex]); -// qmlWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100); -// titleIndex += 1; -// titleIndex %= titles.length; -// } -//}, 2 * 1000); -// -//Script.setTimeout(function() { -// print("Closing script"); -// qmlWindow.close(); -// Script.stop(); -//}, 15 * 1000) +Script.setInterval(function() { + qmlWindow.raise(); +}, 2 * 1000); diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index d84ea306b8..246efa4aa6 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -16,6 +16,7 @@ import "styles" DialogContainer { id: root HifiConstants { id: hifi } + z: 1000 objectName: "AddressBarDialog" diff --git a/interface/resources/qml/Global.js b/interface/resources/qml/Global.js new file mode 100644 index 0000000000..d41dde3c61 --- /dev/null +++ b/interface/resources/qml/Global.js @@ -0,0 +1,165 @@ +var OFFSCREEN_ROOT_OBJECT_NAME = "desktopRoot" +var OFFSCREEN_WINDOW_OBJECT_NAME = "topLevelWindow" + +function findChild(item, name) { + for (var i = 0; i < item.children.length; ++i) { + if (item.children[i].objectName === name) { + return item.children[i]; + } + } + return null; +} + +function findParent(item, name) { + while (item) { + if (item.objectName === name) { + return item; + } + item = item.parent; + } + return null; +} + +function getDesktop(item) { + return findParent(item, OFFSCREEN_ROOT_OBJECT_NAME); +} + +function findRootMenu(item) { + item = getDesktop(item); + return item ? item.rootMenu : null; +} + + +function getTopLevelWindows(item) { + var desktop = getDesktop(item); + var currentWindows = []; + if (!desktop) { + console.log("Could not find desktop for " + item) + return currentWindows; + } + + for (var i = 0; i < desktop.children.length; ++i) { + var child = desktop.children[i]; + if (Global.OFFSCREEN_WINDOW_OBJECT_NAME === child.objectName) { + var windowId = child.toString(); + currentWindows.push(child) + } + } + return currentWindows; +} + + +function getDesktopWindow(item) { + item = findParent(item, OFFSCREEN_WINDOW_OBJECT_NAME); + return item; +} + +function closeWindow(item) { + item = findDialog(item); + if (item) { + item.enabled = false + } else { + console.warn("Could not find top level dialog") + } +} + +function findMenuChild(menu, childName) { + if (!menu) { + return null; + } + + if (menu.type !== 2) { + console.warn("Tried to find child of a non-menu"); + return null; + } + + var items = menu.items; + var count = items.length; + for (var i = 0; i < count; ++i) { + var child = items[i]; + var name; + switch (child.type) { + case 2: + name = child.title; + break; + case 1: + name = child.text; + break; + default: + break; + } + + if (name && name === childName) { + return child; + } + } +} + +function findMenu(rootMenu, path) { + if ('string' === typeof(path)) { + path = [ path ] + } + + var currentMenu = rootMenu; + for (var i = 0; currentMenu && i < path.length; ++i) { + currentMenu = findMenuChild(currentMenu, path[i]); + } + + return currentMenu; +} + +function findInRootMenu(item, path) { + return findMenu(findRootMenu(item), path); +} + + +function menuItemsToListModel(parent, items) { + var newListModel = Qt.createQmlObject('import QtQuick 2.5; ListModel {}', parent); + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + switch (item.type) { + case 2: + newListModel.append({"type":item.type, "name": item.title, "item": item}) + break; + case 1: + newListModel.append({"type":item.type, "name": item.text, "item": item}) + break; + case 0: + newListModel.append({"type":item.type, "name": "-----", "item": item}) + break; + } + } + return newListModel; +} + +function raiseWindow(item) { + var targetWindow = getDesktopWindow(item); + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + var desktop = getDesktop(targetWindow); + if (!desktop) { + //console.warn("Could not find desktop for window " + targetWindow); + return; + } + + var maxZ = 0; + var minZ = 100000; + var windows = desktop.windows; + windows.sort(function(a, b){ + return a.z - b.z; + }); + var lastZ = -1; + var lastTargetZ = -1; + for (var i = 0; i < windows.length; ++i) { + var window = windows[i]; + if (window.z > lastZ) { + lastZ = window.z; + ++lastTargetZ; + } + window.z = lastTargetZ; + } + targetWindow.z = lastTargetZ + 1; +} diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index 2d8bf08dc5..f8217371e7 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -5,6 +5,8 @@ import QtWebChannel 1.0 import QtWebSockets 1.0 import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel +import "Global.js" as Global + import "controls" import "styles" @@ -23,6 +25,10 @@ VrDialog { contentImplicitWidth: clientArea.implicitWidth contentImplicitHeight: clientArea.implicitHeight property alias source: pageLoader.source + + function raiseWindow() { + Global.raiseWindow(root) + } Item { id: clientArea diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 14799f78c0..49262cb7db 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -2,16 +2,23 @@ import Hifi 1.0 import QtQuick 2.5 import QtQuick.Controls 1.4 +import "Global.js" as Global + // This is our primary 'window' object to which all dialogs and controls will // be childed. Root { id: root - objectName: "desktopRoot" - anchors.fill: parent + objectName: Global.OFFSCREEN_ROOT_OBJECT_NAME + anchors.fill: parent; + property var windows: []; property var rootMenu: Menu { objectName: "rootMenu" } + onChildrenChanged: { + windows = Global.getTopLevelWindows(root); + } + onParentChanged: { forceActiveFocus(); } diff --git a/interface/resources/qml/controls/VrDialog.qml b/interface/resources/qml/controls/VrDialog.qml index 411fdbbb0b..18cab04533 100644 --- a/interface/resources/qml/controls/VrDialog.qml +++ b/interface/resources/qml/controls/VrDialog.qml @@ -3,6 +3,8 @@ import QtQuick.Controls 1.2 import "." import "../styles" +import "../Global.js" as Global + /* * FIXME Need to create a client property here so that objects can be * placed in it without having to think about positioning within the outer @@ -45,9 +47,18 @@ DialogBase { // trigger making it visible. if (enabled) { visible = true; + if (root.parent) { + Global.raiseWindow(root); + } } } + onParentChanged: { + if (enabled && parent) { + Global.raiseWindow(root); + } + } + // The actual animator Behavior on opacity { NumberAnimation { @@ -60,6 +71,12 @@ DialogBase { onOpacityChanged: { visible = (opacity != 0.0); } + + Component.onCompleted: { + if (visible) { + Global.raiseWindow(root); + } + } // Some dialogs should be destroyed when they become invisible, // so handle that @@ -118,6 +135,7 @@ DialogBase { y: root.titleY width: root.titleWidth height: root.titleHeight + onClicked: Global.raiseWindow(root) drag { target: root diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 956a5a42c7..677f61a05d 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include @@ -141,6 +143,7 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { setupServer(); retVal = function(context, object); + context->engine()->setObjectOwnership(retVal->_qmlWindow, QQmlEngine::CppOwnership); registerObject(url.toLower(), retVal); if (!title.isEmpty()) { retVal->setTitle(title); @@ -274,7 +277,7 @@ void QmlWindowClass::hasClosed() { } void QmlWindowClass::raise() { - // FIXME + QMetaObject::invokeMethod(_qmlWindow, "raiseWindow", Qt::QueuedConnection); } #include "QmlWindowClass.moc" From 44b9bc71156c7d322a96d49a7d505960699ae622 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Jan 2016 11:10:05 -0800 Subject: [PATCH 08/37] Force active focus on the address bar line while address bar is visible --- interface/resources/qml/AddressBarDialog.qml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 246efa4aa6..6c94f9d254 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -151,6 +151,17 @@ DialogContainer { addressLine.forceActiveFocus() } } + + Timer { + running: root.enabled + interval: 500 + repeat: true + onTriggered: { + if (root.enabled && !addressLine.activeFocus) { + addressLine.forceActiveFocus() + } + } + } onVisibleChanged: { if (!visible) { From b873d92469edff1e22670da7067d9cf430079112 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 Jan 2016 14:12:58 -0800 Subject: [PATCH 09/37] try harder to ensure that a held object is active in bullet --- interface/src/avatar/AvatarActionHold.cpp | 2 +- libraries/physics/src/ObjectAction.cpp | 9 +++++++-- libraries/physics/src/ObjectAction.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 4dda14e194..12c792e631 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -90,7 +90,7 @@ void AvatarActionHold::prepareForPhysicsSimulation() { // _palmRotationFromRigidBody = avatarRotationInverse * palmRotation; }); - activateBody(); + activateBody(true); } std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) { diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp index e8e1188dc9..95af7b32fe 100644 --- a/libraries/physics/src/ObjectAction.cpp +++ b/libraries/physics/src/ObjectAction.cpp @@ -237,10 +237,15 @@ void ObjectAction::setAngularVelocity(glm::vec3 angularVelocity) { rigidBody->activate(); } -void ObjectAction::activateBody() { +void ObjectAction::activateBody(bool forceActivation) { auto rigidBody = getRigidBody(); if (rigidBody) { - rigidBody->activate(); + rigidBody->activate(forceActivation); + if (! rigidBody->isActive()) { + qDebug() << "ObjectAction::activateBody -- rigidBody->activate() failed" << (void*)rigidBody; + } + } else { + qDebug() << "ObjectAction::activateBody -- no rigid body" << (void*)rigidBody; } } diff --git a/libraries/physics/src/ObjectAction.h b/libraries/physics/src/ObjectAction.h index 4ca13f2fbf..efab75b802 100644 --- a/libraries/physics/src/ObjectAction.h +++ b/libraries/physics/src/ObjectAction.h @@ -62,7 +62,7 @@ protected: virtual void setLinearVelocity(glm::vec3 linearVelocity) override; virtual glm::vec3 getAngularVelocity() override; virtual void setAngularVelocity(glm::vec3 angularVelocity) override; - virtual void activateBody(); + virtual void activateBody(bool forceActivation = false); virtual void forceBodyNonStatic(); EntityItemWeakPointer _ownerEntity; From f0338690c871d6bb38eb3caaec0a124a85ed6e0d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Jan 2016 14:54:50 -0800 Subject: [PATCH 10/37] whitespace change --- libraries/entities/src/EntityItem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 80021d3d90..79cecfc1e5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -56,6 +56,7 @@ namespace render { #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. From 335ab3c5012a40e915165c6f8646e4cad30ff671 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Jan 2016 15:24:52 -0800 Subject: [PATCH 11/37] fix warnings --- interface/src/Application.cpp | 2 ++ interface/src/avatar/Avatar.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8673e7eac..9d3f35661d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -737,6 +737,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : case Action::UI_NAV_SELECT: key = Qt::Key_Return; break; + default: + break; } if (navAxis) { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2f7ae62e2e..f532798c2d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -585,7 +585,7 @@ bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { // virtual void Avatar::simulateAttachments(float deltaTime) { - for (int i = 0; i < _attachmentModels.size(); i++) { + for (int i = 0; i < (int)_attachmentModels.size(); i++) { const AttachmentData& attachment = _attachmentData.at(i); auto& model = _attachmentModels.at(i); int jointIndex = getJointIndex(attachment.jointName); @@ -949,14 +949,14 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { AvatarData::setAttachmentData(attachmentData); // if number of attachments has been reduced, remove excess models. - while (_attachmentModels.size() > attachmentData.size()) { + while ((int)_attachmentModels.size() > attachmentData.size()) { auto attachmentModel = _attachmentModels.back(); _attachmentModels.pop_back(); _attachmentsToRemove.push_back(attachmentModel); } for (int i = 0; i < attachmentData.size(); i++) { - if (i == _attachmentModels.size()) { + if (i == (int)_attachmentModels.size()) { // if number of attachments has been increased, we need to allocate a new model _attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel.getRig())); } From 8b9c2cde63489e863fe74b2e0f2f22163016af72 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Jan 2016 15:29:05 -0800 Subject: [PATCH 12/37] fix warnings --- libraries/ui/src/QmlWindowClass.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 956a5a42c7..0dafc84d29 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -90,7 +90,6 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, QString url; QString title; int width = 100, height = 100; - bool isToolWindow = false; bool visible = true; if (argumentCount > 1) { From b0b13fc523e022955325490b79d9d6cc798a7970 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Jan 2016 15:48:00 -0800 Subject: [PATCH 13/37] fix warning in stack manager --- stack-manager/src/AppDelegate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stack-manager/src/AppDelegate.cpp b/stack-manager/src/AppDelegate.cpp index 61d6a8ee48..c2d629faee 100644 --- a/stack-manager/src/AppDelegate.cpp +++ b/stack-manager/src/AppDelegate.cpp @@ -77,6 +77,8 @@ void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const Q fprintf(stdout, "Fatal: %s\n", qPrintable(msg)); txt += msg; break; + default: + break; } if (outStream) { From 3effa9d5e1fba8a125e34b177266c8bb3de328dc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Jan 2016 17:03:29 -0800 Subject: [PATCH 14/37] Fix skybox rendering --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8673e7eac..090da1dbd8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3739,7 +3739,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se auto backgroundRenderData = make_shared(&_environment); auto backgroundRenderPayload = make_shared(backgroundRenderData); BackgroundRenderData::_item = _main3DScene->allocateID(); - pendingChanges.resetItem(WorldBoxRenderData::_item, backgroundRenderPayload); + pendingChanges.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); } else { } From 534bfa5983916519a1f763c26c0f19c02f99265c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 28 Dec 2015 17:25:07 -0800 Subject: [PATCH 15/37] remove dangling whitespace --- interface/src/avatar/AvatarMotionState.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index acd9a45aab..9acbe6c3d4 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -76,7 +76,7 @@ void AvatarMotionState::getWorldTransform(btTransform& worldTrans) const { } } -// virtual +// virtual void AvatarMotionState::setWorldTransform(const btTransform& worldTrans) { if (!_avatar) { return; @@ -154,12 +154,12 @@ QUuid AvatarMotionState::getSimulatorID() const { return _avatar->getSessionUUID(); } -// virtual +// virtual int16_t AvatarMotionState::computeCollisionGroup() { return COLLISION_GROUP_OTHER_AVATAR; } -// virtual +// virtual void AvatarMotionState::clearObjectBackPointer() { ObjectMotionState::clearObjectBackPointer(); _avatar = nullptr; From 4208380d1c8c889e515e875212d6e022195b603b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 28 Dec 2015 17:25:19 -0800 Subject: [PATCH 16/37] namechange --- libraries/physics/src/ObjectMotionState.cpp | 1 + libraries/physics/src/PhysicsEngine.cpp | 18 +++++++++++------- libraries/physics/src/PhysicsEngine.h | 7 ++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 7389d18143..4d7df9b43c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -71,6 +71,7 @@ ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : } ObjectMotionState::~ObjectMotionState() { + // adebug TODO: move shape release out of PhysicsEngine and into into the ObjectMotionState dtor assert(!_body); assert(!_shape); } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 22695a1b66..8a84509165 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -67,7 +67,8 @@ void PhysicsEngine::init() { } } -void PhysicsEngine::addObject(ObjectMotionState* motionState) { +// private +void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { assert(motionState); btVector3 inertia(0.0f, 0.0f, 0.0f); @@ -144,7 +145,8 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) { motionState->clearIncomingDirtyFlags(); } -void PhysicsEngine::removeObject(ObjectMotionState* object) { +// private +void PhysicsEngine::removeObjectFromDynamicsWorld(ObjectMotionState* object) { // wake up anything touching this object bump(object); removeContacts(object); @@ -156,13 +158,14 @@ void PhysicsEngine::removeObject(ObjectMotionState* object) { void PhysicsEngine::deleteObjects(const VectorOfMotionStates& objects) { for (auto object : objects) { - removeObject(object); + removeObjectFromDynamicsWorld(object); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. btRigidBody* body = object->getRigidBody(); object->setRigidBody(nullptr); body->setMotionState(nullptr); delete body; + // adebug TODO: move this into ObjectMotionState dtor object->releaseShape(); delete object; } @@ -172,12 +175,13 @@ void PhysicsEngine::deleteObjects(const VectorOfMotionStates& objects) { void PhysicsEngine::deleteObjects(const SetOfMotionStates& objects) { for (auto object : objects) { btRigidBody* body = object->getRigidBody(); - removeObject(object); + removeObjectFromDynamicsWorld(object); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); body->setMotionState(nullptr); delete body; + // adebug TODO: move this into ObjectMotionState dtor object->releaseShape(); delete object; } @@ -185,7 +189,7 @@ void PhysicsEngine::deleteObjects(const SetOfMotionStates& objects) { void PhysicsEngine::addObjects(const VectorOfMotionStates& objects) { for (auto object : objects) { - addObject(object); + addObjectToDynamicsWorld(object); } } @@ -211,8 +215,8 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob } void PhysicsEngine::reinsertObject(ObjectMotionState* object) { - removeObject(object); - addObject(object); + removeObjectFromDynamicsWorld(object); + addObjectToDynamicsWorld(object); } void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 05032ccae2..b5ba36cb7c 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -54,11 +54,9 @@ public: void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; } const QUuid& getSessionID() const { return _sessionID; } - void addObject(ObjectMotionState* motionState); - void removeObject(ObjectMotionState* motionState); - void deleteObjects(const VectorOfMotionStates& objects); void deleteObjects(const SetOfMotionStates& objects); // only called during teardown + void addObjects(const VectorOfMotionStates& objects); VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects); void reinsertObject(ObjectMotionState* object); @@ -100,6 +98,9 @@ public: void forEachAction(std::function actor); private: + void addObjectToDynamicsWorld(ObjectMotionState* motionState); + void removeObjectFromDynamicsWorld(ObjectMotionState* motionState); + void removeContacts(ObjectMotionState* motionState); void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB); From b34df211dfb6c1cfbfbad0180c4cb7756e89b2db Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 29 Dec 2015 09:36:10 -0800 Subject: [PATCH 17/37] cleanup API for removal from EntitySimulation --- libraries/entities/src/EntitySimulation.cpp | 67 +++++++------------ libraries/entities/src/EntitySimulation.h | 13 ++-- libraries/entities/src/EntityTree.cpp | 3 +- .../entities/src/SimpleEntitySimulation.cpp | 1 + .../entities/src/SimpleEntitySimulation.h | 10 +-- .../physics/src/PhysicalEntitySimulation.cpp | 1 + 6 files changed, 37 insertions(+), 58 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index ad354465d0..324a7a25dd 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -47,6 +47,24 @@ void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) { _entitiesToDelete.clear(); } +void EntitySimulation::removeEntityInternal(EntityItemPointer entity) { + _mortalEntities.remove(entity); + _entitiesToUpdate.remove(entity); + _entitiesToSort.remove(entity); + _simpleKinematicEntities.remove(entity); + _allEntities.remove(entity); + entity->_simulated = false; +} + +void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { + assert(entity); + if (entity->_simulated) { + entity->clearActions(this); + _entitiesToDelete.insert(entity); + removeEntityInternal(entity); + } +} + void EntitySimulation::addEntityInternal(EntityItemPointer entity) { if (entity->isMoving() && !entity->getPhysicsInfo()) { _simpleKinematicEntities.insert(entity); @@ -71,15 +89,8 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { EntityItemPointer entity = *itemItr; quint64 expiry = entity->getExpiry(); if (expiry < now) { - _entitiesToDelete.insert(entity); itemItr = _mortalEntities.erase(itemItr); - _entitiesToUpdate.remove(entity); - _entitiesToSort.remove(entity); - _simpleKinematicEntities.remove(entity); - removeEntityInternal(entity); - - _allEntities.remove(entity); - entity->_simulated = false; + prepareEntityForDelete(entity); } else { if (expiry < _nextExpiry) { // remeber the smallest _nextExpiry so we know when to start the next search @@ -97,7 +108,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { SetOfEntities::iterator itemItr = _entitiesToUpdate.begin(); while (itemItr != _entitiesToUpdate.end()) { EntityItemPointer entity = *itemItr; - // TODO: catch transition from needing update to not as a "change" + // TODO: catch transition from needing update to not as a "change" // so we don't have to scan for it here. if (!entity->needsToCallUpdate()) { itemItr = _entitiesToUpdate.erase(itemItr); @@ -123,16 +134,8 @@ void EntitySimulation::sortEntitiesThatMoved() { AACube newCube = entity->getQueryAACube(success); if (success && !domainBounds.touches(newCube)) { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; - _entitiesToDelete.insert(entity); - _mortalEntities.remove(entity); - _entitiesToUpdate.remove(entity); - _simpleKinematicEntities.remove(entity); - removeEntityInternal(entity); - - _allEntities.remove(entity); - entity->_simulated = false; - itemItr = _entitiesToSort.erase(itemItr); + prepareEntityForDelete(entity); } else { moveOperator.addEntityToMoveList(entity, newCube); ++itemItr; @@ -165,37 +168,23 @@ void EntitySimulation::addEntity(EntityItemPointer entity) { _allEntities.insert(entity); entity->_simulated = true; - // DirtyFlags are used to signal changes to entities that have already been added, + // DirtyFlags are used to signal changes to entities that have already been added, // so we can clear them for this entity which has just been added. entity->clearDirtyFlags(); } -void EntitySimulation::removeEntity(EntityItemPointer entity) { - QMutexLocker lock(&_mutex); - assert(entity); - _entitiesToUpdate.remove(entity); - _mortalEntities.remove(entity); - _entitiesToSort.remove(entity); - _simpleKinematicEntities.remove(entity); - _entitiesToDelete.remove(entity); - removeEntityInternal(entity); - - _allEntities.remove(entity); - entity->_simulated = false; -} - void EntitySimulation::changeEntity(EntityItemPointer entity) { QMutexLocker lock(&_mutex); assert(entity); if (!entity->_simulated) { // This entity was either never added to the simulation or has been removed - // (probably for pending delete), so we don't want to keep a pointer to it + // (probably for pending delete), so we don't want to keep a pointer to it // on any internal lists. return; } // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes - // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence + // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. bool wasRemoved = false; uint32_t dirtyFlags = entity->getDirtyFlags(); @@ -205,13 +194,7 @@ void EntitySimulation::changeEntity(EntityItemPointer entity) { AACube newCube = entity->getQueryAACube(success); if (success && !domainBounds.touches(newCube)) { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; - _entitiesToDelete.insert(entity); - _mortalEntities.remove(entity); - _entitiesToUpdate.remove(entity); - _entitiesToSort.remove(entity); - _simpleKinematicEntities.remove(entity); - removeEntityInternal(entity); - entity->_simulated = false; + prepareEntityForDelete(entity); wasRemoved = true; } } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 4519effbd3..7ed9a94d4b 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -63,26 +63,21 @@ public: /// \sideeffect sets relevant backpointers in entity, but maybe later when appropriate data structures are locked void addEntity(EntityItemPointer entity); - /// \param entity pointer to EntityItem to be removed - /// \brief the actual removal may happen later when appropriate data structures are locked - /// \sideeffect nulls relevant backpointers in entity - void removeEntity(EntityItemPointer entity); - - /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation + /// \param entity pointer to EntityItem that may have changed in a way that would affect its simulation /// call this whenever an entity was changed from some EXTERNAL event (NOT by the EntitySimulation itself) void changeEntity(EntityItemPointer entity); void clearEntities(); void moveSimpleKinematics(const quint64& now); -protected: // these only called by the EntityTree? - -public: EntityTreePointer getEntityTree() { return _entityTree; } void getEntitiesToDelete(VectorOfEntities& entitiesToDelete); + /// \param entity pointer to EntityItem that needs to be put on the entitiesToDelete list and removed from others. + virtual void prepareEntityForDelete(EntityItemPointer entity); + signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ca7b892523..af6e1f5ef1 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -453,8 +453,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) } if (_simulation) { - theEntity->clearActions(_simulation); - _simulation->removeEntity(theEntity); + _simulation->prepareEntityForDelete(theEntity); } } } diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 81d9445f92..3b2523bc92 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -53,6 +53,7 @@ void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { } void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) { + EntitySimulation::removeEntityInternal(entity); _entitiesWithSimulator.remove(entity); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index fff0659067..83c51525a8 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -22,11 +22,11 @@ public: virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); } protected: - virtual void updateEntitiesInternal(const quint64& now); - virtual void addEntityInternal(EntityItemPointer entity); - virtual void removeEntityInternal(EntityItemPointer entity); - virtual void changeEntityInternal(EntityItemPointer entity); - virtual void clearEntitiesInternal(); + virtual void updateEntitiesInternal(const quint64& now) override; + virtual void addEntityInternal(EntityItemPointer entity) override; + virtual void removeEntityInternal(EntityItemPointer entity) override; + virtual void changeEntityInternal(EntityItemPointer entity) override; + virtual void clearEntitiesInternal() override; SetOfEntities _entitiesWithSimulator; }; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 5a12627abd..f050894cfb 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -55,6 +55,7 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { } void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { + EntitySimulation::removeEntityInternal(entity); EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { motionState->clearObjectBackPointer(); From f5d24a87ca47118beda69356e1f2872c99c9460b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 29 Dec 2015 11:05:02 -0800 Subject: [PATCH 18/37] remove entities from physics before we delete them --- libraries/entities/src/EntityItem.h | 4 ++ libraries/entities/src/EntitySimulation.cpp | 17 +++--- libraries/entities/src/EntitySimulation.h | 4 +- .../physics/src/PhysicalEntitySimulation.cpp | 61 +++++++++++-------- .../physics/src/PhysicalEntitySimulation.h | 10 +-- 5 files changed, 58 insertions(+), 38 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 79cecfc1e5..4d7106b858 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -337,6 +337,8 @@ public: bool isMoving() const; + bool isSimulated() const { return _simulated; } + void* getPhysicsInfo() const { return _physicsInfo; } void setPhysicsInfo(void* data) { _physicsInfo = data; } @@ -391,6 +393,8 @@ public: protected: + void setSimulated(bool simulated) { _simulated = simulated; } + const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 324a7a25dd..62912b8954 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -53,16 +53,15 @@ void EntitySimulation::removeEntityInternal(EntityItemPointer entity) { _entitiesToSort.remove(entity); _simpleKinematicEntities.remove(entity); _allEntities.remove(entity); - entity->_simulated = false; + entity->setSimulated(false); } void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { assert(entity); - if (entity->_simulated) { - entity->clearActions(this); - _entitiesToDelete.insert(entity); - removeEntityInternal(entity); - } + assert(entity->isSimulated()); + entity->clearActions(this); + removeEntityInternal(entity); + _entitiesToDelete.insert(entity); } void EntitySimulation::addEntityInternal(EntityItemPointer entity) { @@ -166,7 +165,7 @@ void EntitySimulation::addEntity(EntityItemPointer entity) { addEntityInternal(entity); _allEntities.insert(entity); - entity->_simulated = true; + entity->setSimulated(true); // DirtyFlags are used to signal changes to entities that have already been added, // so we can clear them for this entity which has just been added. @@ -176,7 +175,7 @@ void EntitySimulation::addEntity(EntityItemPointer entity) { void EntitySimulation::changeEntity(EntityItemPointer entity) { QMutexLocker lock(&_mutex); assert(entity); - if (!entity->_simulated) { + if (!entity->isSimulated()) { // This entity was either never added to the simulation or has been removed // (probably for pending delete), so we don't want to keep a pointer to it // on any internal lists. @@ -232,7 +231,7 @@ void EntitySimulation::clearEntities() { clearEntitiesInternal(); for (auto entityItr : _allEntities) { - entityItr->_simulated = false; + entityItr->setSimulated(false); } _allEntities.clear(); } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 7ed9a94d4b..f1548b50e9 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -101,6 +101,9 @@ protected: QList _actionsToAdd; QSet _actionsToRemove; +protected: + SetOfEntities _entitiesToDelete; // entities simulation decided needed to be deleted (EntityTree will actually delete) + private: void moveSimpleKinematics(); @@ -115,7 +118,6 @@ private: SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update() - SetOfEntities _entitiesToDelete; // entities simulation decided needed to be deleted (EntityTree will actually delete) }; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index f050894cfb..010969d3c9 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -47,7 +47,7 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { if (entity->shouldBePhysical()) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (!motionState) { - _pendingAdds.insert(entity); + _entitiesToAddToPhysics.insert(entity); } } else if (entity->isMoving()) { _simpleKinematicEntities.insert(entity); @@ -56,14 +56,17 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { EntitySimulation::removeEntityInternal(entity); + _entitiesToAddToPhysics.remove(entity); + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { motionState->clearObjectBackPointer(); entity->setPhysicsInfo(nullptr); - _pendingRemoves.insert(motionState); _outgoingChanges.remove(motionState); + _entitiesToRemoveFromPhysics.insert(entity); + } else { + _entitiesToDelete.insert(entity); } - _pendingAdds.remove(entity); } void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { @@ -75,8 +78,8 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { // the entity should be removed from the physical simulation _pendingChanges.remove(motionState); _physicalObjects.remove(motionState); - _pendingRemoves.insert(motionState); _outgoingChanges.remove(motionState); + _entitiesToRemoveFromPhysics.insert(entity); if (entity->isMoving()) { _simpleKinematicEntities.insert(entity); } @@ -86,7 +89,7 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { } else if (entity->shouldBePhysical()) { // The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet. // Perhaps it's shape has changed and it can now be added? - _pendingAdds.insert(entity); + _entitiesToAddToPhysics.insert(entity); _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic } else if (entity->isMoving()) { _simpleKinematicEntities.insert(entity); @@ -115,43 +118,53 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // finally clear all lists (which now have only dangling pointers) _physicalObjects.clear(); - _pendingRemoves.clear(); - _pendingAdds.clear(); + _entitiesToRemoveFromPhysics.clear(); + _entitiesToAddToPhysics.clear(); _pendingChanges.clear(); _outgoingChanges.clear(); } -// end EntitySimulation overrides +// virtual +void PhysicalEntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { + assert(entity); + assert(entity->isSimulated()); + entity->clearActions(this); + removeEntityInternal(entity); + + // the PhysicalEntitySimulation must pull the corresponding object out of the PhysicsEngine + // before the Entity is ready to delete so we first put them on this list + _entitiesToRemoveFromPhysics.insert(entity); +} +// end EntitySimulation overrides void PhysicalEntitySimulation::getObjectsToDelete(VectorOfMotionStates& result) { result.clear(); QMutexLocker lock(&_mutex); - for (auto stateItr : _pendingRemoves) { - EntityMotionState* motionState = &(*stateItr); - _pendingChanges.remove(motionState); - _physicalObjects.remove(motionState); - - EntityItemPointer entity = motionState->getEntity(); - if (entity) { - _pendingAdds.remove(entity); - entity->setPhysicsInfo(nullptr); + for (auto entity: _entitiesToRemoveFromPhysics) { + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + _pendingChanges.remove(motionState); + _physicalObjects.remove(motionState); motionState->clearObjectBackPointer(); + result.push_back(motionState); } - result.push_back(motionState); + _entitiesToAddToPhysics.remove(entity); + entity->setPhysicsInfo(nullptr); + _entitiesToDelete.insert(entity); } - _pendingRemoves.clear(); + _entitiesToRemoveFromPhysics.clear(); } void PhysicalEntitySimulation::getObjectsToAdd(VectorOfMotionStates& result) { result.clear(); QMutexLocker lock(&_mutex); - SetOfEntities::iterator entityItr = _pendingAdds.begin(); - while (entityItr != _pendingAdds.end()) { + SetOfEntities::iterator entityItr = _entitiesToAddToPhysics.begin(); + while (entityItr != _entitiesToAddToPhysics.end()) { EntityItemPointer entity = *entityItr; assert(!entity->getPhysicsInfo()); if (!entity->shouldBePhysical()) { - // this entity should no longer be on the internal _pendingAdds - entityItr = _pendingAdds.erase(entityItr); + // this entity should no longer be on the internal _entitiesToAddToPhysics + entityItr = _entitiesToAddToPhysics.erase(entityItr); if (entity->isMoving()) { _simpleKinematicEntities.insert(entity); } @@ -164,7 +177,7 @@ void PhysicalEntitySimulation::getObjectsToAdd(VectorOfMotionStates& result) { entity->setPhysicsInfo(static_cast(motionState)); _physicalObjects.insert(motionState); result.push_back(motionState); - entityItr = _pendingAdds.erase(entityItr); + entityItr = _entitiesToAddToPhysics.erase(entityItr); } else { //qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); ++entityItr; diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index c4f96e023a..ad921bd9a1 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -44,6 +44,8 @@ protected: // only called by EntitySimulation virtual void clearEntitiesInternal() override; public: + virtual void prepareEntityForDelete(EntityItemPointer entity) override; + void getObjectsToDelete(VectorOfMotionStates& result); void getObjectsToAdd(VectorOfMotionStates& result); void setObjectsToChange(const VectorOfMotionStates& objectsToChange); @@ -55,12 +57,12 @@ public: EntityEditPacketSender* getPacketSender() { return _entityPacketSender; } private: - // incoming changes - SetOfEntityMotionStates _pendingRemoves; // EntityMotionStates to be removed from PhysicsEngine (and deleted) - SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their EntityMotionState created) + // incoming changes to physics simulation + SetOfEntities _entitiesToRemoveFromPhysics; + SetOfEntities _entitiesToAddToPhysics; // entities to be be added to PhysicsEngine (and a their EntityMotionState created) SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed - // outgoing changes + // outgoing changes from physics simulation SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine From 8886f48c78bf5cc05ccf8268a8143d9f79d45645 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 29 Dec 2015 11:09:49 -0800 Subject: [PATCH 19/37] minor cleanup --- libraries/physics/src/PhysicalEntitySimulation.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index ad921bd9a1..6796c2ca90 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -57,12 +57,10 @@ public: EntityEditPacketSender* getPacketSender() { return _entityPacketSender; } private: - // incoming changes to physics simulation SetOfEntities _entitiesToRemoveFromPhysics; SetOfEntities _entitiesToAddToPhysics; // entities to be be added to PhysicsEngine (and a their EntityMotionState created) - SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed - // outgoing changes from physics simulation + SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine From 6eb177091bd79aaaccf08cb0d3d95fa8dfd6ac4b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 30 Dec 2015 15:20:53 -0800 Subject: [PATCH 20/37] overhaul of MotionState cleanup Moved MotionState deletes out of PhysicsEngine. EntityMotionStates are deleted by the PhysicsEntitySimulation. AvatarMotionStates are deleted in the Avatar dtor. --- interface/src/Application.cpp | 18 ++--- interface/src/avatar/Avatar.cpp | 8 +- interface/src/avatar/AvatarManager.cpp | 49 ++++++------ interface/src/avatar/AvatarManager.h | 11 ++- interface/src/avatar/AvatarMotionState.cpp | 31 ++------ interface/src/avatar/AvatarMotionState.h | 3 +- libraries/avatars/src/AvatarData.h | 5 -- .../src/RenderablePolyVoxEntityItem.h | 2 +- libraries/entities/src/BoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntitySimulation.cpp | 16 ++-- libraries/entities/src/EntitySimulation.h | 2 +- libraries/entities/src/EntityTree.cpp | 3 +- libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 58 ++++---------- libraries/physics/src/EntityMotionState.h | 7 +- libraries/physics/src/ObjectMotionState.cpp | 4 +- libraries/physics/src/ObjectMotionState.h | 3 - .../physics/src/PhysicalEntitySimulation.cpp | 79 ++++++++++++------- .../physics/src/PhysicalEntitySimulation.h | 8 +- libraries/physics/src/PhysicsEngine.cpp | 10 +-- libraries/physics/src/PhysicsEngine.h | 6 +- libraries/shared/src/SpatiallyNestable.h | 8 +- 25 files changed, 159 insertions(+), 182 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4a166d9b12..65d9ae1ba7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1084,8 +1084,8 @@ Application::~Application() { // remove avatars from physics engine DependencyManager::get()->clearOtherAvatars(); VectorOfMotionStates motionStates; - DependencyManager::get()->getObjectsToDelete(motionStates); - _physicsEngine->deleteObjects(motionStates); + DependencyManager::get()->getObjectsToRemoveFromPhysics(motionStates); + _physicsEngine->removeObjects(motionStates); DependencyManager::destroy(); DependencyManager::destroy(); @@ -3085,11 +3085,11 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("physics"); static VectorOfMotionStates motionStates; - _entitySimulation.getObjectsToDelete(motionStates); - _physicsEngine->deleteObjects(motionStates); + _entitySimulation.getObjectsToRemoveFromPhysics(motionStates); + _physicsEngine->removeObjects(motionStates); getEntities()->getTree()->withWriteLock([&] { - _entitySimulation.getObjectsToAdd(motionStates); + _entitySimulation.getObjectsToAddToPhysics(motionStates); _physicsEngine->addObjects(motionStates); }); @@ -3102,9 +3102,9 @@ void Application::update(float deltaTime) { _entitySimulation.applyActionChanges(); AvatarManager* avatarManager = DependencyManager::get().data(); - avatarManager->getObjectsToDelete(motionStates); - _physicsEngine->deleteObjects(motionStates); - avatarManager->getObjectsToAdd(motionStates); + avatarManager->getObjectsToRemoveFromPhysics(motionStates); + _physicsEngine->removeObjects(motionStates); + avatarManager->getObjectsToAddToPhysics(motionStates); _physicsEngine->addObjects(motionStates); avatarManager->getObjectsToChange(motionStates); _physicsEngine->changeObjects(motionStates); @@ -4083,7 +4083,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { }); foreach (EntityItemPointer entity, entities) { - if (!entity->isReadyToComputeShape()) { + if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*"); qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f532798c2d..75da6cbb35 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -108,7 +108,13 @@ Avatar::Avatar(RigPointer rig) : } Avatar::~Avatar() { - assert(_motionState == nullptr); + for(auto attachment : _unusedAttachments) { + delete attachment; + } + if (_motionState) { + delete _motionState; + _motionState = nullptr; + } } const float BILLBOARD_LOD_DISTANCE = 40.0f; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 2ef3956d99..6075c43520 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -165,7 +165,12 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); - fadingIterator = _avatarFades.erase(fadingIterator); + // only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine + if (_motionStatesToRemoveFromPhysics.empty()) { + fadingIterator = _avatarFades.erase(fadingIterator); + } else { + ++fadingIterator; + } } else { avatar->simulate(deltaTime); ++fadingIterator; @@ -193,20 +198,6 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe return newAvatar; } -// protected -void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { - auto rawPointer = std::static_pointer_cast(avatar); - AvatarMotionState* motionState = rawPointer->getMotionState(); - if (motionState) { - // clean up physics stuff - motionState->clearObjectBackPointer(); - rawPointer->setMotionState(nullptr); - _avatarMotionStates.remove(motionState); - _motionStatesToAdd.remove(motionState); - _motionStatesToDelete.push_back(motionState); - } -} - // virtual void AvatarManager::removeAvatar(const QUuid& sessionUUID) { QWriteLocker locker(&_hashLock); @@ -220,8 +211,16 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(removedAvatar); - removedAvatar->die(); - removeAvatarMotionState(removedAvatar); + Avatar* avatar = static_cast(removedAvatar.get()); + avatar->die(); + + AvatarMotionState* motionState = avatar->getMotionState(); + if (motionState) { + _motionStatesThatMightUpdate.remove(motionState); + _motionStatesToAddToPhysics.remove(motionState); + _motionStatesToRemoveFromPhysics.push_back(motionState); + } + _avatarFades.push_back(removedAvatar); } @@ -274,22 +273,22 @@ AvatarData* AvatarManager::getAvatar(QUuid avatarID) { } -void AvatarManager::getObjectsToDelete(VectorOfMotionStates& result) { +void AvatarManager::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) { result.clear(); - result.swap(_motionStatesToDelete); + result.swap(_motionStatesToRemoveFromPhysics); } -void AvatarManager::getObjectsToAdd(VectorOfMotionStates& result) { +void AvatarManager::getObjectsToAddToPhysics(VectorOfMotionStates& result) { result.clear(); - for (auto motionState : _motionStatesToAdd) { + for (auto motionState : _motionStatesToAddToPhysics) { result.push_back(motionState); } - _motionStatesToAdd.clear(); + _motionStatesToAddToPhysics.clear(); } void AvatarManager::getObjectsToChange(VectorOfMotionStates& result) { result.clear(); - for (auto state : _avatarMotionStates) { + for (auto state : _motionStatesThatMightUpdate) { if (state->_dirtyFlags > 0) { result.push_back(state); } @@ -344,8 +343,8 @@ void AvatarManager::addAvatarToSimulation(Avatar* avatar) { // we don't add to the simulation now, we put it on a list to be added later AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); avatar->setMotionState(motionState); - _motionStatesToAdd.insert(motionState); - _avatarMotionStates.insert(motionState); + _motionStatesToAddToPhysics.insert(motionState); + _motionStatesThatMightUpdate.insert(motionState); } } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 8494ce0b40..6fac652969 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -59,8 +59,8 @@ public: Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID); - void getObjectsToDelete(VectorOfMotionStates& motionStates); - void getObjectsToAdd(VectorOfMotionStates& motionStates); + void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates); + void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates); void getObjectsToChange(VectorOfMotionStates& motionStates); void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); @@ -80,7 +80,6 @@ private: // virtual overrides virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); - void removeAvatarMotionState(AvatarSharedPointer avatar); virtual void removeAvatar(const QUuid& sessionUUID); virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar); @@ -93,9 +92,9 @@ private: bool _shouldShowReceiveStats = false; - SetOfAvatarMotionStates _avatarMotionStates; - SetOfMotionStates _motionStatesToAdd; - VectorOfMotionStates _motionStatesToDelete; + SetOfAvatarMotionStates _motionStatesThatMightUpdate; + SetOfMotionStates _motionStatesToAddToPhysics; + VectorOfMotionStates _motionStatesToRemoveFromPhysics; }; Q_DECLARE_METATYPE(AvatarManager::LocalLight) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 9acbe6c3d4..f61533a5e3 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -25,20 +25,17 @@ AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : } AvatarMotionState::~AvatarMotionState() { + assert(_avatar); _avatar = nullptr; } // virtual uint32_t AvatarMotionState::getIncomingDirtyFlags() { - uint32_t dirtyFlags = 0; - if (_body && _avatar) { - dirtyFlags = _dirtyFlags; - } - return dirtyFlags; + return _body ? _dirtyFlags : 0; } void AvatarMotionState::clearIncomingDirtyFlags() { - if (_body && _avatar) { + if (_body) { _dirtyFlags = 0; } } @@ -50,12 +47,9 @@ MotionType AvatarMotionState::computeObjectMotionType() const { // virtual and protected btCollisionShape* AvatarMotionState::computeNewShape() { - if (_avatar) { - ShapeInfo shapeInfo; - _avatar->computeShapeInfo(shapeInfo); - return getShapeManager()->getShape(shapeInfo); - } - return nullptr; + ShapeInfo shapeInfo; + _avatar->computeShapeInfo(shapeInfo); + return getShapeManager()->getShape(shapeInfo); } // virtual @@ -65,9 +59,6 @@ bool AvatarMotionState::isMoving() const { // virtual void AvatarMotionState::getWorldTransform(btTransform& worldTrans) const { - if (!_avatar) { - return; - } worldTrans.setOrigin(glmToBullet(getObjectPosition())); worldTrans.setRotation(glmToBullet(getObjectRotation())); if (_body) { @@ -78,9 +69,6 @@ void AvatarMotionState::getWorldTransform(btTransform& worldTrans) const { // virtual void AvatarMotionState::setWorldTransform(const btTransform& worldTrans) { - if (!_avatar) { - return; - } // HACK: The PhysicsEngine does not actually move OTHER avatars -- instead it slaves their local RigidBody to the transform // as specified by a remote simulation. However, to give the remote simulation time to respond to our own objects we tie // the other avatar's body to its true position with a simple spring. This is a HACK that will have to be improved later. @@ -159,10 +147,3 @@ int16_t AvatarMotionState::computeCollisionGroup() { return COLLISION_GROUP_OTHER_AVATAR; } -// virtual -void AvatarMotionState::clearObjectBackPointer() { - ObjectMotionState::clearObjectBackPointer(); - _avatar = nullptr; -} - - diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index b5101d2c70..8f60c8e607 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -68,8 +68,7 @@ public: protected: virtual bool isReadyToComputeShape() { return true; } virtual btCollisionShape* computeNewShape(); - virtual void clearObjectBackPointer(); - Avatar* _avatar; + Avatar* _avatar; // do NOT use smartpointer here uint32_t _dirtyFlags; }; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 83195364bf..542b0598ce 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -344,9 +344,6 @@ public: glm::vec3 getClientGlobalPosition() { return _globalPosition; } - void die() { _isDead = true; } - bool isDead() const { return _isDead; } - public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -423,8 +420,6 @@ protected: // updates about one avatar to another. glm::vec3 _globalPosition; - bool _isDead { false }; - private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); static QUrl _defaultFullAvatarModelUrl; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 0411945ede..efd9b4afda 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -77,7 +77,7 @@ public: glm::mat4 localToVoxelMatrix() const; virtual ShapeType getShapeType() const; - virtual bool shouldBePhysical() const { return true; } + virtual bool shouldBePhysical() const { return !isDead(); } virtual bool isReadyToComputeShape(); virtual void computeShapeInfo(ShapeInfo& info); diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index 351feb7e54..6196346b9a 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -53,7 +53,7 @@ public: } virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } - virtual bool shouldBePhysical() const { return true; } + virtual bool shouldBePhysical() const { return !isDead(); } virtual void debugDump() const; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4d7106b858..83f2ad164e 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -302,7 +302,7 @@ public: virtual bool contains(const glm::vec3& point) const; - virtual bool isReadyToComputeShape() { return true; } + virtual bool isReadyToComputeShape() { return !isDead(); } virtual void computeShapeInfo(ShapeInfo& info); virtual float getVolumeEstimate() const { return getDimensions().x * getDimensions().y * getDimensions().z; } diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 62912b8954..35d5b18fda 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -38,16 +38,17 @@ void EntitySimulation::updateEntities() { sortEntitiesThatMoved(); } -void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) { +void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) { QMutexLocker lock(&_mutex); for (auto entity : _entitiesToDelete) { - // this entity is still in its tree, so we insert into the external list + // push this entity onto the external list entitiesToDelete.push_back(entity); } _entitiesToDelete.clear(); } void EntitySimulation::removeEntityInternal(EntityItemPointer entity) { + // remove from all internal lists except _entitiesToDelete _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); _entitiesToSort.remove(entity); @@ -59,6 +60,7 @@ void EntitySimulation::removeEntityInternal(EntityItemPointer entity) { void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { assert(entity); assert(entity->isSimulated()); + assert(entity->isDead()); entity->clearActions(this); removeEntityInternal(entity); _entitiesToDelete.insert(entity); @@ -89,6 +91,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { quint64 expiry = entity->getExpiry(); if (expiry < now) { itemItr = _mortalEntities.erase(itemItr); + entity->die(); prepareEntityForDelete(entity); } else { if (expiry < _nextExpiry) { @@ -134,6 +137,7 @@ void EntitySimulation::sortEntitiesThatMoved() { if (success && !domainBounds.touches(newCube)) { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; itemItr = _entitiesToSort.erase(itemItr); + entity->die(); prepareEntityForDelete(entity); } else { moveOperator.addEntityToMoveList(entity, newCube); @@ -193,6 +197,7 @@ void EntitySimulation::changeEntity(EntityItemPointer entity) { AACube newCube = entity->getQueryAACube(success); if (success && !domainBounds.touches(newCube)) { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + entity->die(); prepareEntityForDelete(entity); wasRemoved = true; } @@ -226,14 +231,15 @@ void EntitySimulation::clearEntities() { _entitiesToUpdate.clear(); _entitiesToSort.clear(); _simpleKinematicEntities.clear(); - _entitiesToDelete.clear(); clearEntitiesInternal(); - for (auto entityItr : _allEntities) { - entityItr->setSimulated(false); + for (auto entity : _allEntities) { + entity->setSimulated(false); + entity->die(); } _allEntities.clear(); + _entitiesToDelete.clear(); } void EntitySimulation::moveSimpleKinematics(const quint64& now) { diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index f1548b50e9..442ff4a74b 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -73,7 +73,7 @@ public: EntityTreePointer getEntityTree() { return _entityTree; } - void getEntitiesToDelete(VectorOfEntities& entitiesToDelete); + virtual void takeEntitiesToDelete(VectorOfEntities& entitiesToDelete); /// \param entity pointer to EntityItem that needs to be put on the entitiesToDelete list and removed from others. virtual void prepareEntityForDelete(EntityItemPointer entity); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index af6e1f5ef1..9861252d63 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -442,6 +442,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) const RemovedEntities& entities = theOperator.getEntities(); foreach(const EntityToDeleteDetails& details, entities) { EntityItemPointer theEntity = details.entity; + theEntity->die(); if (getIsServer()) { // set up the deleted entities ID @@ -1005,7 +1006,7 @@ void EntityTree::update() { withWriteLock([&] { _simulation->updateEntities(); VectorOfEntities pendingDeletes; - _simulation->getEntitiesToDelete(pendingDeletes); + _simulation->takeEntitiesToDelete(pendingDeletes); if (pendingDeletes.size() > 0) { // translate into list of ID's diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 709cd67ef5..bef4406f71 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -377,7 +377,7 @@ void ModelEntityItem::setAnimationFPS(float value) { // virtual bool ModelEntityItem::shouldBePhysical() const { - return getShapeType() != SHAPE_TYPE_NONE; + return !isDead() && getShapeType() != SHAPE_TYPE_NONE; } void ModelEntityItem::resizeJointArrays(int newSize) { diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 941d5a167c..fda5eab009 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -52,7 +52,7 @@ public: } virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; } - virtual bool shouldBePhysical() const { return true; } + virtual bool shouldBePhysical() const { return !isDead(); } virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 19206f8acc..bf323248c0 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -57,7 +57,7 @@ public: static bool getDrawZoneBoundaries() { return _drawZoneBoundaries; } static void setDrawZoneBoundaries(bool value) { _drawZoneBoundaries = value; } - virtual bool isReadyToComputeShape() { return true; } + virtual bool isReadyToComputeShape() { return false; } void updateShapeType(ShapeType type) { _shapeType = type; } virtual ShapeType getShapeType() const; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index cd07b4112f..8250064326 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -34,7 +34,7 @@ const quint64 USECS_BETWEEN_OWNERSHIP_BIDS = USECS_PER_SECOND / 5; #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS bool EntityMotionState::entityTreeIsLocked() const { - EntityTreeElementPointer element = _entity ? _entity->getElement() : nullptr; + EntityTreeElementPointer element = _entity->getElement(); EntityTreePointer tree = element ? element->getTree() : nullptr; if (!tree) { return true; @@ -48,7 +48,7 @@ bool entityTreeIsLocked() { #endif -EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) : +EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity) : ObjectMotionState(shape), _entity(entity), _sentInactive(true), @@ -69,14 +69,14 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer _loopsWithoutOwner(0) { _type = MOTIONSTATE_TYPE_ENTITY; - assert(_entity != nullptr); + assert(_entity); assert(entityTreeIsLocked()); setMass(_entity->computeMass()); } EntityMotionState::~EntityMotionState() { - // be sure to clear _entity before calling the destructor - assert(!_entity); + assert(_entity); + _entity = nullptr; } void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) { @@ -138,11 +138,6 @@ bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* return ObjectMotionState::handleHardAndEasyChanges(flags, engine); } -void EntityMotionState::clearObjectBackPointer() { - ObjectMotionState::clearObjectBackPointer(); - _entity = nullptr; -} - MotionType EntityMotionState::computeObjectMotionType() const { if (!_entity) { return MOTION_TYPE_STATIC; @@ -222,21 +217,15 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { // virtual and protected bool EntityMotionState::isReadyToComputeShape() { - if (_entity) { - return _entity->isReadyToComputeShape(); - } - return false; + return _entity->isReadyToComputeShape(); } // virtual and protected btCollisionShape* EntityMotionState::computeNewShape() { - if (_entity) { - ShapeInfo shapeInfo; - assert(entityTreeIsLocked()); - _entity->computeShapeInfo(shapeInfo); - return getShapeManager()->getShape(shapeInfo); - } - return nullptr; + ShapeInfo shapeInfo; + assert(entityTreeIsLocked()); + _entity->computeShapeInfo(shapeInfo); + return getShapeManager()->getShape(shapeInfo); } bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { @@ -553,26 +542,17 @@ void EntityMotionState::clearIncomingDirtyFlags() { // virtual quint8 EntityMotionState::getSimulationPriority() const { - if (_entity) { - return _entity->getSimulationPriority(); - } - return NO_PRORITY; + return _entity->getSimulationPriority(); } // virtual QUuid EntityMotionState::getSimulatorID() const { - if (_entity) { - assert(entityTreeIsLocked()); - return _entity->getSimulatorID(); - } - return QUuid(); + assert(entityTreeIsLocked()); + return _entity->getSimulatorID(); } -// virtual void EntityMotionState::bump(quint8 priority) { - if (_entity) { - setOutgoingPriority(glm::max(VOLUNTEER_SIMULATION_PRIORITY, --priority)); - } + setOutgoingPriority(glm::max(VOLUNTEER_SIMULATION_PRIORITY, --priority)); } void EntityMotionState::resetMeasuredBodyAcceleration() { @@ -624,18 +604,12 @@ void EntityMotionState::setMotionType(MotionType motionType) { // virtual QString EntityMotionState::getName() { - if (_entity) { - assert(entityTreeIsLocked()); - return _entity->getName(); - } - return ""; + assert(entityTreeIsLocked()); + return _entity->getName(); } // virtual int16_t EntityMotionState::computeCollisionGroup() { - if (!_entity) { - return COLLISION_GROUP_STATIC; - } if (_entity->getIgnoreForCollisions()) { return COLLISION_GROUP_COLLISIONLESS; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index c666f87221..578dc427a6 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -25,7 +25,7 @@ class EntityItem; class EntityMotionState : public ObjectMotionState { public: - EntityMotionState(btCollisionShape* shape, EntityItemPointer item); + EntityMotionState(btCollisionShape* shape, EntityItem* item); virtual ~EntityMotionState(); void updateServerPhysicsVariables(const QUuid& sessionID); @@ -73,7 +73,7 @@ public: virtual QUuid getSimulatorID() const; virtual void bump(quint8 priority); - EntityItemPointer getEntity() const { return _entity; } + EntityItem* getEntity() const { return _entity; } void resetMeasuredBodyAcceleration(); void measureBodyAcceleration(); @@ -94,10 +94,9 @@ protected: virtual bool isReadyToComputeShape(); virtual btCollisionShape* computeNewShape(); - virtual void clearObjectBackPointer(); virtual void setMotionType(MotionType motionType); - EntityItemPointer _entity; + EntityItem* _entity { nullptr }; // do NOT use smartpointer here bool _sentInactive; // true if body was inactive when we sent last update diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 4d7df9b43c..c434f67ad2 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -71,9 +71,9 @@ ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : } ObjectMotionState::~ObjectMotionState() { - // adebug TODO: move shape release out of PhysicsEngine and into into the ObjectMotionState dtor assert(!_body); - assert(!_shape); + releaseShape(); + _type = MOTIONSTATE_TYPE_INVALID; } void ObjectMotionState::setBodyLinearVelocity(const glm::vec3& velocity) const { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 8f97b25dcc..2e30269efc 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -153,9 +153,6 @@ protected: void setMotionType(MotionType motionType); void updateCCDConfiguration(); - // clearObjectBackPointer() overrrides should call the base method, then actually clear the object back pointer. - virtual void clearObjectBackPointer() { _type = MOTIONSTATE_TYPE_INVALID; } - void setRigidBody(btRigidBody* body); MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 010969d3c9..1281edb205 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -44,6 +44,7 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { assert(entity); + assert(!entity->isDead()); if (entity->shouldBePhysical()) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (!motionState) { @@ -60,8 +61,6 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - motionState->clearObjectBackPointer(); - entity->setPhysicsInfo(nullptr); _outgoingChanges.remove(motionState); _entitiesToRemoveFromPhysics.insert(entity); } else { @@ -69,6 +68,23 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { } } +void PhysicalEntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) { + QMutexLocker lock(&_mutex); + for (auto entity : _entitiesToDelete) { + // this entity is still in its tree, so we insert into the external list + entitiesToDelete.push_back(entity); + + // Someday when we invert the entities/physics lib dependencies we can let EntityItem delete its own PhysicsInfo + // rather than do it here + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + delete motionState; + entity->setPhysicsInfo(nullptr); + } + } + _entitiesToDelete.clear(); +} + void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine assert(entity); @@ -106,17 +122,26 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // first disconnect each MotionStates from its Entity for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); - EntityItemPointer entity = motionState->getEntity(); - if (entity) { - entity->setPhysicsInfo(nullptr); - } - motionState->clearObjectBackPointer(); + EntityItem* entity = motionState->getEntity(); + assert(entity); + _entitiesToDelete.insert(EntityItemPointer(entity)); } - // then delete the objects (aka MotionStates) - _physicsEngine->deleteObjects(_physicalObjects); + // then remove the objects from physics (aka MotionStates) + _physicsEngine->removeObjects(_physicalObjects); - // finally clear all lists (which now have only dangling pointers) + // delete the objects (aka MotionStates) + // Someday when we invert the entities/physics lib dependencies we can let EntityItem delete its own PhysicsInfo + // rather than do it here + for (auto entity : _entitiesToDelete) { + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + delete motionState; + entity->setPhysicsInfo(nullptr); + } + } + + // finally clear all lists maintained by this class _physicalObjects.clear(); _entitiesToRemoveFromPhysics.clear(); _entitiesToAddToPhysics.clear(); @@ -128,16 +153,13 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { void PhysicalEntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { assert(entity); assert(entity->isSimulated()); + assert(entity->isDead()); entity->clearActions(this); removeEntityInternal(entity); - - // the PhysicalEntitySimulation must pull the corresponding object out of the PhysicsEngine - // before the Entity is ready to delete so we first put them on this list - _entitiesToRemoveFromPhysics.insert(entity); } // end EntitySimulation overrides -void PhysicalEntitySimulation::getObjectsToDelete(VectorOfMotionStates& result) { +void PhysicalEntitySimulation::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) { result.clear(); QMutexLocker lock(&_mutex); for (auto entity: _entitiesToRemoveFromPhysics) { @@ -145,28 +167,30 @@ void PhysicalEntitySimulation::getObjectsToDelete(VectorOfMotionStates& result) if (motionState) { _pendingChanges.remove(motionState); _physicalObjects.remove(motionState); - motionState->clearObjectBackPointer(); result.push_back(motionState); } _entitiesToAddToPhysics.remove(entity); - entity->setPhysicsInfo(nullptr); - _entitiesToDelete.insert(entity); + if (entity->isDead()) { + _entitiesToDelete.insert(entity); + } } _entitiesToRemoveFromPhysics.clear(); } -void PhysicalEntitySimulation::getObjectsToAdd(VectorOfMotionStates& result) { +void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& result) { result.clear(); QMutexLocker lock(&_mutex); SetOfEntities::iterator entityItr = _entitiesToAddToPhysics.begin(); while (entityItr != _entitiesToAddToPhysics.end()) { - EntityItemPointer entity = *entityItr; + EntityItem* entity = (*entityItr).get(); assert(!entity->getPhysicsInfo()); - if (!entity->shouldBePhysical()) { + if (entity->isDead()) { + prepareEntityForDelete(EntityItemPointer(entity)); + } else if (!entity->shouldBePhysical()) { // this entity should no longer be on the internal _entitiesToAddToPhysics entityItr = _entitiesToAddToPhysics.erase(entityItr); if (entity->isMoving()) { - _simpleKinematicEntities.insert(entity); + _simpleKinematicEntities.insert(EntityItemPointer(entity)); } } else if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; @@ -212,13 +236,12 @@ void PhysicalEntitySimulation::handleOutgoingChanges(const VectorOfMotionStates& ObjectMotionState* state = &(*stateItr); if (state && state->getType() == MOTIONSTATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); - EntityItemPointer entity = entityState->getEntity(); - if (entity) { - if (entityState->isCandidateForOwnership(sessionID)) { - _outgoingChanges.insert(entityState); - } - _entitiesToSort.insert(entityState->getEntity()); + EntityItem* entity = entityState->getEntity(); + assert(entity); + if (entityState->isCandidateForOwnership(sessionID)) { + _outgoingChanges.insert(entityState); } + _entitiesToSort.insert(EntityItemPointer(entity)); } } diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 6796c2ca90..bc80d50d0a 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -35,6 +35,8 @@ public: virtual void addAction(EntityActionPointer action) override; virtual void applyActionChanges() override; + virtual void takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) override; + protected: // only called by EntitySimulation // overrides for EntitySimulation virtual void updateEntitiesInternal(const quint64& now) override; @@ -46,8 +48,8 @@ protected: // only called by EntitySimulation public: virtual void prepareEntityForDelete(EntityItemPointer entity) override; - void getObjectsToDelete(VectorOfMotionStates& result); - void getObjectsToAdd(VectorOfMotionStates& result); + void getObjectsToRemoveFromPhysics(VectorOfMotionStates& result); + void getObjectsToAddToPhysics(VectorOfMotionStates& result); void setObjectsToChange(const VectorOfMotionStates& objectsToChange); void getObjectsToChange(VectorOfMotionStates& result); @@ -58,7 +60,7 @@ public: private: SetOfEntities _entitiesToRemoveFromPhysics; - SetOfEntities _entitiesToAddToPhysics; // entities to be be added to PhysicsEngine (and a their EntityMotionState created) + SetOfEntities _entitiesToAddToPhysics; SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 8a84509165..9e295d5cf5 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -156,7 +156,7 @@ void PhysicsEngine::removeObjectFromDynamicsWorld(ObjectMotionState* object) { _dynamicsWorld->removeRigidBody(body); } -void PhysicsEngine::deleteObjects(const VectorOfMotionStates& objects) { +void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) { for (auto object : objects) { removeObjectFromDynamicsWorld(object); @@ -165,14 +165,11 @@ void PhysicsEngine::deleteObjects(const VectorOfMotionStates& objects) { object->setRigidBody(nullptr); body->setMotionState(nullptr); delete body; - // adebug TODO: move this into ObjectMotionState dtor - object->releaseShape(); - delete object; } } // Same as above, but takes a Set instead of a Vector. Should only be called during teardown. -void PhysicsEngine::deleteObjects(const SetOfMotionStates& objects) { +void PhysicsEngine::removeObjects(const SetOfMotionStates& objects) { for (auto object : objects) { btRigidBody* body = object->getRigidBody(); removeObjectFromDynamicsWorld(object); @@ -181,9 +178,6 @@ void PhysicsEngine::deleteObjects(const SetOfMotionStates& objects) { object->setRigidBody(nullptr); body->setMotionState(nullptr); delete body; - // adebug TODO: move this into ObjectMotionState dtor - object->releaseShape(); - delete object; } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index b5ba36cb7c..1161b89f2c 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -54,8 +54,8 @@ public: void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; } const QUuid& getSessionID() const { return _sessionID; } - void deleteObjects(const VectorOfMotionStates& objects); - void deleteObjects(const SetOfMotionStates& objects); // only called during teardown + void removeObjects(const VectorOfMotionStates& objects); + void removeObjects(const SetOfMotionStates& objects); // only called during teardown void addObjects(const VectorOfMotionStates& objects); VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects); @@ -84,8 +84,6 @@ public: /// \brief call bump on any objects that touch the object corresponding to motionState void bump(ObjectMotionState* motionState); - void removeRigidBody(btRigidBody* body); - void setCharacterController(CharacterController* character); void dumpNextStats() { _dumpNextStats = true; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index cc67aedcd3..915d247b92 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -34,7 +34,7 @@ enum class NestableType { class SpatiallyNestable : public std::enable_shared_from_this { public: SpatiallyNestable(NestableType nestableType, QUuid id); - virtual ~SpatiallyNestable() { } + virtual ~SpatiallyNestable() { assert(_isDead); } virtual const QUuid& getID() const { return _id; } virtual void setID(const QUuid& id) { _id = id; } @@ -115,6 +115,9 @@ public: void forEachChild(std::function actor); void forEachDescendant(std::function actor); + void die() { _isDead = true; } + bool isDead() const { return _isDead; } + protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; @@ -141,7 +144,8 @@ protected: private: mutable ReadWriteLockable _transformLock; Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. - mutable bool _parentKnowsMe = false; + mutable bool _parentKnowsMe { false }; + bool _isDead { false }; }; From e8e965d54810f6def87f8842d587b2e2fecc328f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Dec 2015 13:58:21 -0800 Subject: [PATCH 21/37] fix crash mode for empty LineEntityItem --- .../src/RenderablePolyLineEntityItem.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 7b3bbc4c02..fd28bc043d 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -122,13 +122,19 @@ void RenderablePolyLineEntityItem::updateVertices() { glm::vec3 v1, v2, tangent, binormal, point; int finalIndex = minVectorSize - 1; + + // Guard against an empty polyline + if (finalIndex < 0) { + return; + } + for (int i = 0; i < finalIndex; i++) { float width = _strokeWidths.at(i); point = _points.at(i); tangent = _points.at(i); - tangent = _points.at(i + 1) - point; + tangent = _points.at(i + 1) - point; glm::vec3 normal = _normals.at(i); binormal = glm::normalize(glm::cross(tangent, normal)) * width; @@ -141,11 +147,6 @@ void RenderablePolyLineEntityItem::updateVertices() { _vertices << v1 << v2; } - // Guard against an empty polyline - if (finalIndex < 0) { - return; - } - // For last point we can assume binormals are the same since it represents the last two vertices of quad point = _points.at(finalIndex); v1 = point + binormal; From 6a642bdcf85a6a9c90c096e98def1cc049caff7d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Dec 2015 13:59:47 -0800 Subject: [PATCH 22/37] fix misusage of smart-pointers --- interface/src/avatar/Avatar.cpp | 3 ++- interface/src/avatar/AvatarManager.cpp | 4 ++++ interface/src/avatar/AvatarManager.h | 2 ++ libraries/entities/src/EntityItem.cpp | 1 + libraries/physics/src/EntityMotionState.cpp | 5 ++-- libraries/physics/src/EntityMotionState.h | 16 +++++++++---- .../physics/src/PhysicalEntitySimulation.cpp | 24 +++++++++---------- libraries/shared/src/SpatiallyNestable.h | 2 +- 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 75da6cbb35..5d42d8a7bd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1,4 +1,4 @@ -// +/3/ // Avatar.cpp // interface/src/avatar // @@ -108,6 +108,7 @@ Avatar::Avatar(RigPointer rig) : } Avatar::~Avatar() { + assert(isDead()); // mark dead before calling the dtor for(auto attachment : _unusedAttachments) { delete attachment; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 6075c43520..6993fb6ae1 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -76,6 +76,10 @@ AvatarManager::AvatarManager(QObject* parent) : packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket"); } +AvatarManager::~AvatarManager() { + _myAvatar->die(); +} + void AvatarManager::init() { _myAvatar->init(); { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 6fac652969..72fcb3f862 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -34,6 +34,8 @@ public: /// Registers the script types associated with the avatar manager. static void registerMetaTypes(QScriptEngine* engine); + virtual ~AvatarManager(); + void init(); MyAvatar* getMyAvatar() { return _myAvatar.get(); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 97043a635d..fb773ee89b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,6 +85,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : } EntityItem::~EntityItem() { + assert(isDead()); // mark as dead before calling dtor // clear out any left-over actions EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8250064326..b543d9d75b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -48,9 +48,10 @@ bool entityTreeIsLocked() { #endif -EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity) : +EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) : ObjectMotionState(shape), - _entity(entity), + _entityPtr(entity), + _entity(entity.get()), _sentInactive(true), _lastStep(0), _serverPosition(0.0f), diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 578dc427a6..da78513b58 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -12,11 +12,11 @@ #ifndef hifi_EntityMotionState_h #define hifi_EntityMotionState_h +#include #include #include "ObjectMotionState.h" -class EntityItem; // From the MotionState's perspective: // Inside = physics simulation @@ -25,7 +25,7 @@ class EntityItem; class EntityMotionState : public ObjectMotionState { public: - EntityMotionState(btCollisionShape* shape, EntityItem* item); + EntityMotionState(btCollisionShape* shape, EntityItemPointer item); virtual ~EntityMotionState(); void updateServerPhysicsVariables(const QUuid& sessionID); @@ -73,7 +73,7 @@ public: virtual QUuid getSimulatorID() const; virtual void bump(quint8 priority); - EntityItem* getEntity() const { return _entity; } + EntityItemPointer getEntity() const { return _entityPtr.lock(); } void resetMeasuredBodyAcceleration(); void measureBodyAcceleration(); @@ -96,7 +96,15 @@ protected: virtual btCollisionShape* computeNewShape(); virtual void setMotionType(MotionType motionType); - EntityItem* _entity { nullptr }; // do NOT use smartpointer here + // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be + // properly "owned" by the EntityItem and will be deleted by it in the dtor. In pursuit of that + // state of affairs we can't keep a real EntityItemPointer as data member (it would produce a + // recursive dependency). Instead we keep a EntityItemWeakPointer to break that dependency while + // still granting us the capability to generate EntityItemPointers as necessary (for external data + // structures that use the MotionState to get to the EntityItem). + EntityItemWeakPointer _entityPtr; + // Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid. + EntityItem* _entity; bool _sentInactive; // true if body was inactive when we sent last update diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 1281edb205..4116ddeda0 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -122,17 +122,15 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // first disconnect each MotionStates from its Entity for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); - EntityItem* entity = motionState->getEntity(); - assert(entity); - _entitiesToDelete.insert(EntityItemPointer(entity)); + _entitiesToDelete.insert(motionState->getEntity()); } - // then remove the objects from physics (aka MotionStates) + // then remove the objects (aka MotionStates) from physics _physicsEngine->removeObjects(_physicalObjects); - // delete the objects (aka MotionStates) - // Someday when we invert the entities/physics lib dependencies we can let EntityItem delete its own PhysicsInfo - // rather than do it here + // delete the MotionStates + // TODO: after we invert the entities/physics lib dependencies we will let EntityItem delete + // its own PhysicsInfo rather than do it here for (auto entity : _entitiesToDelete) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { @@ -182,15 +180,15 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re QMutexLocker lock(&_mutex); SetOfEntities::iterator entityItr = _entitiesToAddToPhysics.begin(); while (entityItr != _entitiesToAddToPhysics.end()) { - EntityItem* entity = (*entityItr).get(); + EntityItemPointer entity = (*entityItr); assert(!entity->getPhysicsInfo()); if (entity->isDead()) { - prepareEntityForDelete(EntityItemPointer(entity)); + prepareEntityForDelete(entity); } else if (!entity->shouldBePhysical()) { // this entity should no longer be on the internal _entitiesToAddToPhysics entityItr = _entitiesToAddToPhysics.erase(entityItr); if (entity->isMoving()) { - _simpleKinematicEntities.insert(EntityItemPointer(entity)); + _simpleKinematicEntities.insert(entity); } } else if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; @@ -236,12 +234,12 @@ void PhysicalEntitySimulation::handleOutgoingChanges(const VectorOfMotionStates& ObjectMotionState* state = &(*stateItr); if (state && state->getType() == MOTIONSTATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); - EntityItem* entity = entityState->getEntity(); - assert(entity); + EntityItemPointer entity = entityState->getEntity(); + assert(entity.get()); if (entityState->isCandidateForOwnership(sessionID)) { _outgoingChanges.insert(entityState); } - _entitiesToSort.insert(EntityItemPointer(entity)); + _entitiesToSort.insert(entity); } } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 915d247b92..dc38671091 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -34,7 +34,7 @@ enum class NestableType { class SpatiallyNestable : public std::enable_shared_from_this { public: SpatiallyNestable(NestableType nestableType, QUuid id); - virtual ~SpatiallyNestable() { assert(_isDead); } + virtual ~SpatiallyNestable() { } virtual const QUuid& getID() const { return _id; } virtual void setID(const QUuid& id) { _id = id; } From e0ec9414764816e91f8dcf2c3a4e66f9b4e6bf86 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Dec 2015 15:01:32 -0800 Subject: [PATCH 23/37] fix typo --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5d42d8a7bd..abe2f0c670 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1,4 +1,4 @@ -/3/ +// // Avatar.cpp // interface/src/avatar // From 4f29156da1bd73677ef5523e55513a96cca50630 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Jan 2016 12:02:11 -0800 Subject: [PATCH 24/37] fixing asserts for EntityItem delete pipeline --- libraries/entities/src/EntityItem.cpp | 1 - libraries/entities/src/EntitySimulation.cpp | 9 +++++---- libraries/physics/src/PhysicalEntitySimulation.cpp | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fb773ee89b..97043a635d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,7 +85,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : } EntityItem::~EntityItem() { - assert(isDead()); // mark as dead before calling dtor // clear out any left-over actions EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 35d5b18fda..ab29cfb2a4 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -59,11 +59,12 @@ void EntitySimulation::removeEntityInternal(EntityItemPointer entity) { void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { assert(entity); - assert(entity->isSimulated()); assert(entity->isDead()); - entity->clearActions(this); - removeEntityInternal(entity); - _entitiesToDelete.insert(entity); + if (entity->isSimulated()) { + entity->clearActions(this); + removeEntityInternal(entity); + _entitiesToDelete.insert(entity); + } } void EntitySimulation::addEntityInternal(EntityItemPointer entity) { diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 4116ddeda0..9ef27aaf53 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -150,7 +150,6 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // virtual void PhysicalEntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { assert(entity); - assert(entity->isSimulated()); assert(entity->isDead()); entity->clearActions(this); removeEntityInternal(entity); From c1206ca73d3d02a3097c44b42480809e8fe13670 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Jan 2016 14:49:20 -0800 Subject: [PATCH 25/37] fix bad merge --- interface/src/avatar/Avatar.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index abe2f0c670..c1eb173629 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -109,9 +109,6 @@ Avatar::Avatar(RigPointer rig) : Avatar::~Avatar() { assert(isDead()); // mark dead before calling the dtor - for(auto attachment : _unusedAttachments) { - delete attachment; - } if (_motionState) { delete _motionState; _motionState = nullptr; From 36e19b43c90dd636ec6f394814ab527657804ac8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 Jan 2016 15:04:47 -0800 Subject: [PATCH 26/37] add some comments; specify const and overrides --- interface/src/avatar/AvatarManager.cpp | 2 + interface/src/avatar/AvatarMotionState.cpp | 2 +- interface/src/avatar/AvatarMotionState.h | 55 ++++++++++++--------- libraries/physics/src/EntityMotionState.cpp | 6 +-- libraries/physics/src/EntityMotionState.h | 38 +++++++------- libraries/physics/src/ObjectMotionState.h | 6 +-- 6 files changed, 61 insertions(+), 48 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 6993fb6ae1..833ed26cc9 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -215,6 +215,8 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(removedAvatar); + // removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar + // class in this context so we can call methods that don't exist at the base class. Avatar* avatar = static_cast(removedAvatar.get()); avatar->die(); diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index f61533a5e3..9ce9594d45 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -143,7 +143,7 @@ QUuid AvatarMotionState::getSimulatorID() const { } // virtual -int16_t AvatarMotionState::computeCollisionGroup() { +int16_t AvatarMotionState::computeCollisionGroup() const { return COLLISION_GROUP_OTHER_AVATAR; } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 8f60c8e607..0465ddf50b 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -21,54 +21,65 @@ class Avatar; class AvatarMotionState : public ObjectMotionState { public: AvatarMotionState(Avatar* avatar, btCollisionShape* shape); - ~AvatarMotionState(); - virtual MotionType getMotionType() const { return _motionType; } + virtual MotionType getMotionType() const override { return _motionType; } - virtual uint32_t getIncomingDirtyFlags(); - virtual void clearIncomingDirtyFlags(); + virtual uint32_t getIncomingDirtyFlags() override; + virtual void clearIncomingDirtyFlags() override; - virtual MotionType computeObjectMotionType() const; + virtual MotionType computeObjectMotionType() const override; - virtual bool isMoving() const; + virtual bool isMoving() const override; // this relays incoming position/rotation to the RigidBody - virtual void getWorldTransform(btTransform& worldTrans) const; + virtual void getWorldTransform(btTransform& worldTrans) const override; // this relays outgoing position/rotation to the EntityItem - virtual void setWorldTransform(const btTransform& worldTrans); + virtual void setWorldTransform(const btTransform& worldTrans) override; // These pure virtual methods must be implemented for each MotionState type // and make it possible to implement more complicated methods in this base class. - virtual float getObjectRestitution() const; - virtual float getObjectFriction() const; - virtual float getObjectLinearDamping() const; - virtual float getObjectAngularDamping() const; + // pure virtual overrides from ObjectMotionState + virtual float getObjectRestitution() const override; + virtual float getObjectFriction() const override; + virtual float getObjectLinearDamping() const override; + virtual float getObjectAngularDamping() const override; - virtual glm::vec3 getObjectPosition() const; - virtual glm::quat getObjectRotation() const; - virtual glm::vec3 getObjectLinearVelocity() const; - virtual glm::vec3 getObjectAngularVelocity() const; - virtual glm::vec3 getObjectGravity() const; + virtual glm::vec3 getObjectPosition() const override; + virtual glm::quat getObjectRotation() const override; + virtual glm::vec3 getObjectLinearVelocity() const override; + virtual glm::vec3 getObjectAngularVelocity() const override; + virtual glm::vec3 getObjectGravity() const override; - virtual const QUuid& getObjectID() const; + virtual const QUuid& getObjectID() const override; - virtual QUuid getSimulatorID() const; + virtual QUuid getSimulatorID() const override; void setBoundingBox(const glm::vec3& corner, const glm::vec3& diagonal); void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; } - virtual int16_t computeCollisionGroup(); + virtual int16_t computeCollisionGroup() const override; friend class AvatarManager; + friend class Avatar; protected: - virtual bool isReadyToComputeShape() { return true; } + // the dtor had been made protected to force the compiler to verify that it is only + // ever called by the Avatar class dtor. + ~AvatarMotionState(); + + virtual bool isReadyToComputeShape() const override { return true; } virtual btCollisionShape* computeNewShape(); - Avatar* _avatar; // do NOT use smartpointer here + + // The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState + // instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor. + // In other words, it is impossible for the Avatar to be deleted out from under its MotionState. + // In conclusion: weak pointer shennanigans would be pure overhead. + Avatar* _avatar; // do NOT use smartpointer here, no need for weakpointer + uint32_t _dirtyFlags; }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b543d9d75b..c1338b772c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -217,7 +217,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { // virtual and protected -bool EntityMotionState::isReadyToComputeShape() { +bool EntityMotionState::isReadyToComputeShape() const { return _entity->isReadyToComputeShape(); } @@ -604,13 +604,13 @@ void EntityMotionState::setMotionType(MotionType motionType) { // virtual -QString EntityMotionState::getName() { +QString EntityMotionState::getName() const { assert(entityTreeIsLocked()); return _entity->getName(); } // virtual -int16_t EntityMotionState::computeCollisionGroup() { +int16_t EntityMotionState::computeCollisionGroup() const { if (_entity->getIgnoreForCollisions()) { return COLLISION_GROUP_COLLISIONLESS; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index da78513b58..53e7982ae1 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -38,10 +38,10 @@ public: virtual bool isMoving() const; // this relays incoming position/rotation to the RigidBody - virtual void getWorldTransform(btTransform& worldTrans) const; + virtual void getWorldTransform(btTransform& worldTrans) const override; // this relays outgoing position/rotation to the EntityItem - virtual void setWorldTransform(const btTransform& worldTrans); + virtual void setWorldTransform(const btTransform& worldTrans) override; bool isCandidateForOwnership(const QUuid& sessionID) const; bool remoteSimulationOutOfSync(uint32_t simulationStep); @@ -55,32 +55,32 @@ public: void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } - virtual float getObjectRestitution() const { return _entity->getRestitution(); } - virtual float getObjectFriction() const { return _entity->getFriction(); } - virtual float getObjectLinearDamping() const { return _entity->getDamping(); } - virtual float getObjectAngularDamping() const { return _entity->getAngularDamping(); } + virtual float getObjectRestitution() const override { return _entity->getRestitution(); } + virtual float getObjectFriction() const override { return _entity->getFriction(); } + virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } + virtual float getObjectAngularDamping() const override { return _entity->getAngularDamping(); } - virtual glm::vec3 getObjectPosition() const { return _entity->getPosition() - ObjectMotionState::getWorldOffset(); } - virtual glm::quat getObjectRotation() const { return _entity->getRotation(); } - virtual glm::vec3 getObjectLinearVelocity() const { return _entity->getVelocity(); } - virtual glm::vec3 getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } - virtual glm::vec3 getObjectGravity() const { return _entity->getGravity(); } - virtual glm::vec3 getObjectLinearVelocityChange() const; + virtual glm::vec3 getObjectPosition() const override { return _entity->getPosition() - ObjectMotionState::getWorldOffset(); } + virtual glm::quat getObjectRotation() const override { return _entity->getRotation(); } + virtual glm::vec3 getObjectLinearVelocity() const override { return _entity->getVelocity(); } + virtual glm::vec3 getObjectAngularVelocity() const override { return _entity->getAngularVelocity(); } + virtual glm::vec3 getObjectGravity() const override { return _entity->getGravity(); } + virtual glm::vec3 getObjectLinearVelocityChange() const override; - virtual const QUuid& getObjectID() const { return _entity->getID(); } + virtual const QUuid& getObjectID() const override { return _entity->getID(); } - virtual quint8 getSimulationPriority() const; - virtual QUuid getSimulatorID() const; - virtual void bump(quint8 priority); + virtual quint8 getSimulationPriority() const override; + virtual QUuid getSimulatorID() const override; + virtual void bump(quint8 priority) override; EntityItemPointer getEntity() const { return _entityPtr.lock(); } void resetMeasuredBodyAcceleration(); void measureBodyAcceleration(); - virtual QString getName(); + virtual QString getName() const override; - virtual int16_t computeCollisionGroup(); + virtual int16_t computeCollisionGroup() const override; // eternal logic can suggest a simuator priority bid for the next outgoing update void setOutgoingPriority(quint8 priority); @@ -92,7 +92,7 @@ protected: bool entityTreeIsLocked() const; #endif - virtual bool isReadyToComputeShape(); + virtual bool isReadyToComputeShape() const override; virtual btCollisionShape* computeNewShape(); virtual void setMotionType(MotionType motionType); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 2e30269efc..e10d58e3ed 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -134,9 +134,9 @@ public: virtual QUuid getSimulatorID() const = 0; virtual void bump(quint8 priority) {} - virtual QString getName() { return ""; } + virtual QString getName() const { return ""; } - virtual int16_t computeCollisionGroup() = 0; + virtual int16_t computeCollisionGroup() const = 0; bool isActive() const { return _body ? _body->isActive() : false; } @@ -148,7 +148,7 @@ public: friend class PhysicsEngine; protected: - virtual bool isReadyToComputeShape() = 0; + virtual bool isReadyToComputeShape() const = 0; virtual btCollisionShape* computeNewShape() = 0; void setMotionType(MotionType motionType); void updateCCDConfiguration(); From 42711e5bad48e80a56c9716943919cf28eecc886 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 10:20:03 -0800 Subject: [PATCH 27/37] remove unused variable --- libraries/physics/src/PhysicsEngine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 1161b89f2c..0ca9b2aca8 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -115,7 +115,6 @@ private: ContactMap _contactMap; uint32_t _numContactFrames = 0; - uint32_t _lastNumSubstepsAtUpdateInternal = 0; /// character collisions CharacterController* _myAvatarController; From cf9af462b5958aa8a448ded214af836f6c174ddd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 Jan 2016 10:21:39 -0800 Subject: [PATCH 28/37] replace some logging with an assert --- libraries/physics/src/ObjectAction.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp index 95af7b32fe..f90286845a 100644 --- a/libraries/physics/src/ObjectAction.cpp +++ b/libraries/physics/src/ObjectAction.cpp @@ -241,9 +241,7 @@ void ObjectAction::activateBody(bool forceActivation) { auto rigidBody = getRigidBody(); if (rigidBody) { rigidBody->activate(forceActivation); - if (! rigidBody->isActive()) { - qDebug() << "ObjectAction::activateBody -- rigidBody->activate() failed" << (void*)rigidBody; - } + assert(rigidBody->isActive()); } else { qDebug() << "ObjectAction::activateBody -- no rigid body" << (void*)rigidBody; } From 144af19ebdaefb8830cbba40b1420e23202b7e8d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 7 Jan 2016 10:52:28 -0800 Subject: [PATCH 29/37] Stop looping on URL fixing --- interface/resources/qml/QmlWebWindow.qml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 188351c113..008aaeccc3 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -47,10 +47,20 @@ VrDialog { anchors.fill: parent focus: true + property var originalUrl + property var lastFixupTime: 0 + onUrlChanged: { var currentUrl = url.toString(); var newUrl = urlHandler.fixupUrl(currentUrl).toString(); if (newUrl != currentUrl) { + var now = new Date().valueOf(); + if (url === originalUrl && (now - lastFixupTime < 100)) { + console.warn("URL fixup loop detected") + return; + } + originalUrl = url + lastFixupTime = now url = newUrl; } } From 1508a637ab0909b3d556c5bc2299a15b6ddd4d5e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 12:09:02 -0800 Subject: [PATCH 30/37] Menu restructuring --- interface/src/Application.cpp | 2 +- interface/src/Application.h | 2 +- interface/src/Menu.cpp | 660 +++++++++++---------- interface/src/Menu.h | 6 +- interface/src/ui/DialogsManager.cpp | 14 - interface/src/ui/DialogsManager.h | 1 - plugins/hifiSixense/src/SixenseManager.cpp | 2 +- 7 files changed, 365 insertions(+), 322 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4a166d9b12..9ddb42f42b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1627,7 +1627,7 @@ void Application::aboutApp() { InfoView::show(INFO_HELP_PATH); } -void Application::showEditEntitiesHelp() { +void Application::showHelp() { InfoView::show(INFO_EDIT_ENTITIES_PATH); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 78b753880d..39e5453d1d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -295,7 +295,7 @@ public slots: #endif void aboutApp(); - void showEditEntitiesHelp(); + void showHelp(); void cycleCamera(); void cameraMenuChanged(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 85af912892..128190a49d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -51,13 +51,16 @@ Menu* Menu::getInstance() { } Menu::Menu() { - MenuWrapper * fileMenu = addMenu("File"); -#ifdef Q_OS_MAC - addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); -#endif auto dialogsManager = DependencyManager::get(); AccountManager& accountManager = AccountManager::getInstance(); + // File/Application menu ---------------------------------- + MenuWrapper* fileMenu = addMenu("File"); + + // File > Quit + addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp,SLOT(quit()), QAction::QuitRole); + + // File > Login menu items { addActionToQMenuAndActionHash(fileMenu, MenuOption::Login); @@ -68,256 +71,250 @@ Menu::Menu() { dialogsManager.data(), &DialogsManager::toggleLoginDialog); } - // File Menu > Scripts section -- "Advanced" grouping - addDisabledActionAndSeparator(fileMenu, "Scripts", UNSPECIFIED_POSITION, "Advanced"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, - qApp, SLOT(loadDialog()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, - Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, - qApp, SLOT(reloadAllScripts()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, - qApp, SLOT(toggleRunningScriptsWidget()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + // File > Update -- FIXME: needs implementation + addActionToQMenuAndActionHash(fileMenu, "Update"); - auto addressManager = DependencyManager::get(); + // File > Help + addActionToQMenuAndActionHash(fileMenu, MenuOption::Help, 0, qApp, SLOT(showHelp())); - addDisabledActionAndSeparator(fileMenu, "History"); + // File > Crash Reporter...-- FIXME: needs implementation + addActionToQMenuAndActionHash(fileMenu, "Crash Reporter..."); - QAction* backAction = addActionToQMenuAndActionHash(fileMenu, - MenuOption::Back, - 0, - addressManager.data(), - SLOT(goBack())); - - QAction* forwardAction = addActionToQMenuAndActionHash(fileMenu, - MenuOption::Forward, - 0, - addressManager.data(), - SLOT(goForward())); - - // connect to the AddressManager signal to enable and disable the back and forward menu items - connect(addressManager.data(), &AddressManager::goBackPossible, backAction, &QAction::setEnabled); - connect(addressManager.data(), &AddressManager::goForwardPossible, forwardAction, &QAction::setEnabled); - - // set the two actions to start disabled since the stacks are clear on startup - backAction->setDisabled(true); - forwardAction->setDisabled(true); - - addDisabledActionAndSeparator(fileMenu, "Location"); - qApp->getBookmarks()->setupMenus(this, fileMenu); - - addActionToQMenuAndActionHash(fileMenu, - MenuOption::AddressBar, - Qt::CTRL | Qt::Key_L, - dialogsManager.data(), - SLOT(toggleAddressBar())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0, - addressManager.data(), SLOT(copyAddress()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0, - addressManager.data(), SLOT(copyPath()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - addActionToQMenuAndActionHash(fileMenu, - MenuOption::Quit, - Qt::CTRL | Qt::Key_Q, - qApp, - SLOT(quit()), - QAction::QuitRole); + // File > About + addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); + // Audio menu ---------------------------------- + MenuWrapper* audioMenu = addMenu("Audio"); + auto audioIO = DependencyManager::get(); + + // Audio > Mute + addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, + audioIO.data(), SLOT(toggleMute())); + + // Audio > Level Meter [advanced] -- FIXME: needs implementation + addCheckableActionToQMenuAndActionHash(audioMenu, "Level Meter", 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); + + + // Avatar menu ---------------------------------- + MenuWrapper* avatarMenu = addMenu("Avatar"); + auto avatarManager = DependencyManager::get(); + QObject* avatar = avatarManager->getMyAvatar(); + + // Avatar > Attachments... + addActionToQMenuAndActionHash(avatarMenu, MenuOption::Attachments, 0, + dialogsManager.data(), SLOT(editAttachments())); + + // Avatar > Size + MenuWrapper* avatarSizeMenu = avatarMenu->addMenu("Size"); + + // Avatar > Size > Increase + addActionToQMenuAndActionHash(avatarSizeMenu, + MenuOption::IncreaseAvatarSize, + 0, // QML Qt::Key_Plus, + avatar, SLOT(increaseSize())); + + // Avatar > Size > Decrease + addActionToQMenuAndActionHash(avatarSizeMenu, + MenuOption::DecreaseAvatarSize, + 0, // QML Qt::Key_Minus, + avatar, SLOT(decreaseSize())); + + // Avatar > Size > Reset + addActionToQMenuAndActionHash(avatarSizeMenu, + MenuOption::ResetAvatarSize, + 0, // QML Qt::Key_Equal, + avatar, SLOT(resetSize())); + + // Avatar > Reset Sensors + addActionToQMenuAndActionHash(avatarMenu, + MenuOption::ResetSensors, + 0, // QML Qt::Key_Apostrophe, + qApp, SLOT(resetSensors())); + + + // Display menu ---------------------------------- + // FIXME - this is not yet matching Alan's spec because it doesn't have + // menus for "2D"/"3D" - we need to add support for detecting the appropriate + // default 3D display mode + addMenu(DisplayPlugin::MENU_PATH()); + MenuWrapper* displayModeMenu = addMenu(MenuOption::OutputMenu); + QActionGroup* displayModeGroup = new QActionGroup(displayModeMenu); + displayModeGroup->setExclusive(true); + + + // View menu ---------------------------------- + // FIXME - this is not yet matching Alan's spec because it bundles the camera mode + // into a sub menu. I need to double check that cameraMenuChanged() is updated + // to handle not being in a sub-menu + MenuWrapper* viewMenu = addMenu("View"); + MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode"); + QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu); + cameraModeGroup->setExclusive(true); + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + MenuOption::FirstPerson, 0, // QML Qt:: Key_P + false, qApp, SLOT(cameraMenuChanged()))); + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + MenuOption::ThirdPerson, 0, + true, qApp, SLOT(cameraMenuChanged()))); + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + MenuOption::IndependentMode, 0, + false, qApp, SLOT(cameraMenuChanged()))); + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + MenuOption::CameraEntityMode, 0, + false, qApp, SLOT(cameraMenuChanged()))); + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + MenuOption::FullscreenMirror, 0, // QML Qt::Key_H, + false, qApp, SLOT(cameraMenuChanged()))); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, + 0, //QML Qt::SHIFT | Qt::Key_H, + true); + + + // Edit menu ---------------------------------- MenuWrapper* editMenu = addMenu("Edit"); + // Edit > Undo QUndoStack* undoStack = qApp->getUndoStack(); QAction* undoAction = undoStack->createUndoAction(editMenu); undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, undoAction); + // Edit > Redo QAction* redoAction = undoStack->createRedoAction(editMenu); redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, redoAction); - addActionToQMenuAndActionHash(editMenu, - MenuOption::Preferences, - Qt::CTRL | Qt::Key_Comma, - dialogsManager.data(), - SLOT(editPreferences()), - QAction::PreferencesRole); + // Edit > Running Sccripts + addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, + qApp, SLOT(toggleRunningScriptsWidget())); - addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, - dialogsManager.data(), SLOT(editAttachments()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + // Edit > Open and Run Script from File... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, + qApp, SLOT(loadDialog()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - MenuWrapper* toolsMenu = addMenu("Tools"); - addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, - dialogsManager.data(), SLOT(showScriptEditor()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + // Edit > Open and Run Script from Url... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScriptURL, + Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + // Edit > Stop All Scripts... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Reload All Scripts... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, + qApp, SLOT(reloadAllScripts()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Scripts Editor... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, + dialogsManager.data(), SLOT(showScriptEditor()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Console... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, + DependencyManager::get().data(), + SLOT(toggleConsole()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Reload All Content [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + + // Edit > Package Model... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, + qApp, SLOT(packageModel()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + + // Navigate menu ---------------------------------- + MenuWrapper* navigateMenu = addMenu("Navigate"); + + // Navigate > Home -- FIXME: needs implementation + addActionToQMenuAndActionHash(navigateMenu, "Home"); + + addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L, + dialogsManager.data(), SLOT(toggleAddressBar())); + + // Navigate > Directory -- FIXME: needs implementation + addActionToQMenuAndActionHash(navigateMenu, "Directory"); + + // Navigate > Bookmark related menus -- Note: the Bookmark class adds its own submenus here. + qApp->getBookmarks()->setupMenus(this, navigateMenu); + + // Navigate > Copy Address [advanced] + auto addressManager = DependencyManager::get(); + addActionToQMenuAndActionHash(navigateMenu, MenuOption::CopyAddress, 0, + addressManager.data(), SLOT(copyAddress()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Navigate > Copy Path [advanced] + addActionToQMenuAndActionHash(navigateMenu, MenuOption::CopyPath, 0, + addressManager.data(), SLOT(copyPath()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + + // Market menu ---------------------------------- + MenuWrapper* marketMenu = addMenu("Market"); + + // Market > Marketplace... -- FIXME: needs implementation + addActionToQMenuAndActionHash(marketMenu, "Marketplace..."); + + + // Settings menu ---------------------------------- + MenuWrapper* settingsMenu = addMenu("Settings"); + + // Settings > Advance Menus + addCheckableActionToQMenuAndActionHash(settingsMenu, "Advanced Menus", 0, false, this, SLOT(toggleAdvancedMenus())); + + // Settings > Developer Menus + addCheckableActionToQMenuAndActionHash(settingsMenu, "Developer Menus", 0, false, this, SLOT(toggleDeveloperMenus())); + + // Settings > General... + addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, + dialogsManager.data(), SLOT(editPreferences()), QAction::PreferencesRole); + + // Settings > Avatar...-- FIXME: needs implementation + addActionToQMenuAndActionHash(settingsMenu, "Avatar..."); + + // Settings > Audio...-- FIXME: needs implementation + addActionToQMenuAndActionHash(settingsMenu, "Audio..."); + + // Settings > LOD...-- FIXME: needs implementation + addActionToQMenuAndActionHash(settingsMenu, "LOD..."); + + // Settings > Control with Speech [advanced] #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::get(); - QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(toolsMenu, MenuOption::ControlWithSpeech, - Qt::CTRL | Qt::SHIFT | Qt::Key_C, - speechRecognizer->getEnabled(), - speechRecognizer.data(), - SLOT(setEnabled(bool)), - UNSPECIFIED_POSITION, "Advanced"); + QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(settingsMenu, MenuOption::ControlWithSpeech, + Qt::CTRL | Qt::SHIFT | Qt::Key_C, + speechRecognizer->getEnabled(), + speechRecognizer.data(), + SLOT(setEnabled(bool)), + UNSPECIFIED_POSITION, "Advanced"); connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); #endif - addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, - 0, // QML Qt::Key_Backslash, - dialogsManager.data(), SLOT(showIRCLink()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, - qApp, SLOT(showFriendsWindow())); - - MenuWrapper* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); - { - QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); - auto discoverabilityManager = DependencyManager::get(); - - QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToEveryone); - - QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToFriends); - - QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToNoOne); - - connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, - discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); - } - - addActionToQMenuAndActionHash(toolsMenu, - MenuOption::ToolWindow, - Qt::CTRL | Qt::ALT | Qt::Key_T, - dialogsManager.data(), - SLOT(toggleToolWindow()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - addActionToQMenuAndActionHash(toolsMenu, - MenuOption::Console, - Qt::CTRL | Qt::ALT | Qt::Key_J, - DependencyManager::get().data(), - SLOT(toggleConsole()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - addActionToQMenuAndActionHash(toolsMenu, - MenuOption::ResetSensors, - 0, // QML Qt::Key_Apostrophe, - qApp, - SLOT(resetSensors()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0, - qApp, SLOT(packageModel()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - addMenu(DisplayPlugin::MENU_PATH()); - { - MenuWrapper* displayModeMenu = addMenu(MenuOption::OutputMenu); - QActionGroup* displayModeGroup = new QActionGroup(displayModeMenu); - displayModeGroup->setExclusive(true); - } - - MenuWrapper* avatarMenu = addMenu("Avatar"); - QObject* avatar = DependencyManager::get()->getMyAvatar(); - + // Settings > Input Devices MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced"); QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu); inputModeGroup->setExclusive(false); - - MenuWrapper* avatarSizeMenu = avatarMenu->addMenu("Size"); - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::IncreaseAvatarSize, - 0, // QML Qt::Key_Plus, - avatar, - SLOT(increaseSize())); - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::DecreaseAvatarSize, - 0, // QML Qt::Key_Minus, - avatar, - SLOT(decreaseSize())); - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::ResetAvatarSize, - 0, // QML Qt::Key_Equal, - avatar, - SLOT(resetSize())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, - NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); - - MenuWrapper* viewMenu = addMenu("View"); - addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode"); - QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu); - cameraModeGroup->setExclusive(true); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::FirstPerson, 0, // QML Qt:: Key_P - false, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::ThirdPerson, 0, - true, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::IndependentMode, 0, - false, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::CameraEntityMode, 0, - false, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::FullscreenMirror, 0, // QML Qt::Key_H, - false, qApp, SLOT(cameraMenuChanged()))); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, - 0, //QML Qt::SHIFT | Qt::Key_H, - true); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, - 0, false, qApp, SLOT(rotationModeChanged()), - UNSPECIFIED_POSITION, "Advanced"); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::WorldAxes, 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Developer"); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Developer"); - addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, - Qt::CTRL | Qt::SHIFT | Qt::Key_L, - qApp, SLOT(toggleLogDialog()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); - - addActionToQMenuAndActionHash(viewMenu, MenuOption::AudioNetworkStats, 0, - dialogsManager.data(), SLOT(audioStatsDetails()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); - - addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, - dialogsManager.data(), SLOT(bandwidthDetails()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); - addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, - dialogsManager.data(), SLOT(octreeStatsDetails()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); - - addCheckableActionToQMenuAndActionHash(viewMenu, "Advanced Menus", 0, false, this, SLOT(toggleAdvancedMenus())); - addCheckableActionToQMenuAndActionHash(viewMenu, "Developer Menus", 0, false, this, SLOT(toggleDeveloperMenus())); + // Developer menu ---------------------------------- MenuWrapper* developerMenu = addMenu("Developer", "Developer"); + // Developer > Render >>> MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, - 0, // QML Qt::SHIFT | Qt::Key_A, - true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugAmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Antialiasing); + // Developer > Render > Ambient Light MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight); QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu); ambientLightGroup->setExclusive(true); @@ -333,8 +330,10 @@ Menu::Menu() { ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false)); ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false)); + // Developer > Render > Throttle FPS If Not Focus addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true); + // Developer > Render > Resolution MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); resolutionGroup->setExclusive(true); @@ -344,37 +343,40 @@ Menu::Menu() { resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); + // Developer > Render > Stars addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, // QML Qt::Key_Asterisk, true); + // Developer > Render > LOD Tools addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, // QML Qt::SHIFT | Qt::Key_L, dialogsManager.data(), SLOT(lodTools())); - + + // Developer > Assets >>> MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); - auto& assetDialogFactory = AssetUploadDialogFactory::getInstance(); assetDialogFactory.setDialogParent(this); - QAction* assetUpload = addActionToQMenuAndActionHash(assetDeveloperMenu, - MenuOption::UploadAsset, - 0, - &assetDialogFactory, - SLOT(showDialog())); - + MenuOption::UploadAsset, + 0, + &assetDialogFactory, + SLOT(showDialog())); + // disable the asset upload action by default - it gets enabled only if asset server becomes present assetUpload->setEnabled(false); - + auto& atpMigrator = ATPAssetMigrator::getInstance(); atpMigrator.setDialogParent(this); - + addActionToQMenuAndActionHash(assetDeveloperMenu, MenuOption::AssetMigration, - 0, &atpMigrator, - SLOT(loadEntityServerFile())); - + 0, &atpMigrator, + SLOT(loadEntityServerFile())); + + // Developer > Avatar >>> MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); + // Developer > Avatar > Face Tracking MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); { QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu); @@ -423,6 +425,7 @@ Menu::Menu() { #endif #ifdef HAVE_IVIEWHMD + // Developer > Avatar > Eye Tracking MenuWrapper* eyeTrackingMenu = avatarDebugMenu->addMenu("Eye Tracking"); addCheckableActionToQMenuAndActionHash(eyeTrackingMenu, MenuOption::SMIEyeTracking, 0, false, qApp, SLOT(setActiveEyeTracker())); @@ -439,9 +442,8 @@ Menu::Menu() { qApp, SLOT(setActiveEyeTracker())); #endif - auto avatarManager = DependencyManager::get(); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false, - avatarManager.data(), SLOT(setShouldShowReceiveStats(bool))); + avatarManager.data(), SLOT(setShouldShowReceiveStats(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); @@ -450,13 +452,13 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowWhosLookingAtMe, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false, - avatar, SLOT(setEnableDebugDrawDefaultPose(bool))); + avatar, SLOT(setEnableDebugDrawDefaultPose(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawAnimPose, 0, false, - avatar, SLOT(setEnableDebugDrawAnimPose(bool))); + avatar, SLOT(setEnableDebugDrawAnimPose(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawPosition, 0, false, - avatar, SLOT(setEnableDebugDrawPosition(bool))); + avatar, SLOT(setEnableDebugDrawPosition(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true, - avatar, SLOT(setEnableMeshVisible(bool))); + avatar, SLOT(setEnableMeshVisible(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true); @@ -473,37 +475,37 @@ Menu::Menu() { avatar, SLOT(updateMotionBehaviorFromMenu()), UNSPECIFIED_POSITION, "Developer"); - - + // Developer > Hands >>> MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true, - qApp, SLOT(setLowVelocityFilter(bool))); + qApp, SLOT(setLowVelocityFilter(bool))); MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); + // Developer > Network >>> MenuWrapper* networkMenu = developerMenu->addMenu("Network"); addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false, - qApp->getEntityEditPacketSender(), - SLOT(toggleNackPackets())); + qApp->getEntityEditPacketSender(), + SLOT(toggleNackPackets())); addCheckableActionToQMenuAndActionHash(networkMenu, - MenuOption::DisableActivityLogger, - 0, - false, - &UserActivityLogger::getInstance(), - SLOT(disable(bool))); + MenuOption::DisableActivityLogger, + 0, + false, + &UserActivityLogger::getInstance(), + SLOT(disable(bool))); addActionToQMenuAndActionHash(networkMenu, MenuOption::CachesSize, 0, - dialogsManager.data(), SLOT(cachesSizeDialog())); + dialogsManager.data(), SLOT(cachesSizeDialog())); addActionToQMenuAndActionHash(networkMenu, MenuOption::DiskCacheEditor, 0, - dialogsManager.data(), SLOT(toggleDiskCacheEditor())); + dialogsManager.data(), SLOT(toggleDiskCacheEditor())); addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, - dialogsManager.data(), SLOT(showDomainConnectionDialog())); + dialogsManager.data(), SLOT(showDomainConnectionDialog())); + // Developer > Timing and Stats >>> MenuWrapper* timingMenu = developerMenu->addMenu("Timing and Stats"); - MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer"); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true); @@ -520,60 +522,34 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::ShowRealtimeEntityStats); - auto audioIO = DependencyManager::get(); + // Developer > Audio >>> MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio"); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, - 0, - true, - audioIO.data(), - SLOT(toggleAudioNoiseReduction())); - + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true, + audioIO.data(), SLOT(toggleAudioNoiseReduction())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio, 0, false, - audioIO.data(), SLOT(toggleServerEcho())); + audioIO.data(), SLOT(toggleServerEcho())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio, 0, false, - audioIO.data(), SLOT(toggleLocalEcho())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, - Qt::CTRL | Qt::Key_M, - false, - audioIO.data(), - SLOT(toggleMute())); - addActionToQMenuAndActionHash(audioDebugMenu, - MenuOption::MuteEnvironment, - 0, - audioIO.data(), - SLOT(sendMuteEnvironmentPacket())); + audioIO.data(), SLOT(toggleLocalEcho())); + addActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteEnvironment, 0, + audioIO.data(), SLOT(sendMuteEnvironmentPacket())); auto scope = DependencyManager::get(); - MenuWrapper* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope"); - addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScope, - Qt::CTRL | Qt::Key_P, false, - scope.data(), - SLOT(toggle())); - addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopePause, - Qt::CTRL | Qt::SHIFT | Qt::Key_P , - false, - scope.data(), - SLOT(togglePause())); + addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScope, Qt::CTRL | Qt::Key_P, false, + scope.data(), SLOT(toggle())); + addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopePause, Qt::CTRL | Qt::SHIFT | Qt::Key_P, false, + scope.data(), SLOT(togglePause())); + addDisabledActionAndSeparator(audioScopeMenu, "Display Frames"); { - QAction *fiveFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiveFrames, - 0, - true, - scope.data(), - SLOT(selectAudioScopeFiveFrames())); + QAction* fiveFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiveFrames, + 0, true, scope.data(), SLOT(selectAudioScopeFiveFrames())); - QAction *twentyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeTwentyFrames, - 0, - false, - scope.data(), - SLOT(selectAudioScopeTwentyFrames())); + QAction* twentyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeTwentyFrames, + 0, false, scope.data(), SLOT(selectAudioScopeTwentyFrames())); - QAction *fiftyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiftyFrames, - 0, - false, - scope.data(), - SLOT(selectAudioScopeFiftyFrames())); + QAction* fiftyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiftyFrames, + 0, false, scope.data(), SLOT(selectAudioScopeFiftyFrames())); QActionGroup* audioScopeFramesGroup = new QActionGroup(audioScopeMenu); audioScopeFramesGroup->addAction(fiveFrames); @@ -581,19 +557,101 @@ Menu::Menu() { audioScopeFramesGroup->addAction(fiftyFrames); } + // Developer > Physics >>> MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics"); addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned); addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls); + // Developer > Display Crash Options addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true); + // Developer > Crash Application addActionToQMenuAndActionHash(developerMenu, MenuOption::CrashInterface, 0, qApp, SLOT(crashApplication())); - MenuWrapper* helpMenu = addMenu("Help"); - addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); + // Developer > Log... + addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L, + qApp, SLOT(toggleLogDialog())); + + // Developer > Stats + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats); + + // Developer > Audio Stats... + addActionToQMenuAndActionHash(developerMenu, MenuOption::AudioNetworkStats, 0, + dialogsManager.data(), SLOT(audioStatsDetails())); + + // Developer > Bandwidth Stats... + addActionToQMenuAndActionHash(developerMenu, MenuOption::BandwidthDetails, 0, + dialogsManager.data(), SLOT(bandwidthDetails())); + + // Developer > Entity Stats... + addActionToQMenuAndActionHash(developerMenu, MenuOption::OctreeStats, 0, + dialogsManager.data(), SLOT(octreeStatsDetails())); + + // Developer > World Axes + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::WorldAxes); + + + +#if 0 /// -------------- REMOVED FOR NOW -------------- + addDisabledActionAndSeparator(navigateMenu, "History"); + QAction* backAction = addActionToQMenuAndActionHash(navigateMenu, MenuOption::Back, 0, addressManager.data(), SLOT(goBack())); + QAction* forwardAction = addActionToQMenuAndActionHash(navigateMenu, MenuOption::Forward, 0, addressManager.data(), SLOT(goForward())); + + // connect to the AddressManager signal to enable and disable the back and forward menu items + connect(addressManager.data(), &AddressManager::goBackPossible, backAction, &QAction::setEnabled); + connect(addressManager.data(), &AddressManager::goForwardPossible, forwardAction, &QAction::setEnabled); + + // set the two actions to start disabled since the stacks are clear on startup + backAction->setDisabled(true); + forwardAction->setDisabled(true); + + MenuWrapper* toolsMenu = addMenu("Tools"); + + addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, + qApp, SLOT(showFriendsWindow())); + + MenuWrapper* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); + { + QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); + auto discoverabilityManager = DependencyManager::get(); + + QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToEveryone); + + QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToFriends); + + QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToNoOne); + + connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, + discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); + } + + addActionToQMenuAndActionHash(toolsMenu, + MenuOption::ToolWindow, + Qt::CTRL | Qt::ALT | Qt::Key_T, + dialogsManager.data(), + SLOT(toggleToolWindow()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, + NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); + + + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, + 0, false, qApp, SLOT(rotationModeChanged()), + UNSPECIFIED_POSITION, "Advanced"); + + -#ifndef Q_OS_MAC - QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp); - connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); #endif } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 4d898caefc..6563233902 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -205,7 +205,6 @@ namespace MenuOption { const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; - const QString EditEntitiesHelp = "Edit Entities Help..."; const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString EnableCharacterController = "Enable avatar collisions"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; @@ -221,6 +220,7 @@ namespace MenuOption { const QString FrameTimer = "Show Timer"; const QString FullscreenMirror = "Fullscreen Mirror"; const QString GlowWhenSpeaking = "Glow When Speaking"; + const QString Help = "Help..."; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IndependentMode = "Independent Mode"; const QString InputMenu = "Avatar>Input Devices"; @@ -249,7 +249,7 @@ namespace MenuOption { const QString PhysicsShowOwned = "Highlight Simulation Ownership"; const QString PhysicsShowHulls = "Draw Collision Hulls"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; - const QString Preferences = "Preferences..."; + const QString Preferences = "General..."; const QString Quit = "Quit"; const QString ReloadAllScripts = "Reload All Scripts"; const QString ReloadContent = "Reload Content (Clears all caches)"; @@ -277,7 +277,7 @@ namespace MenuOption { const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET"; const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetSensors = "Reset Sensors"; - const QString RunningScripts = "Running Scripts"; + const QString RunningScripts = "Running Scripts..."; const QString RunTimingTests = "Run Timing Tests"; const QString ScriptEditor = "Script Editor..."; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 1acbf3a595..155d41c575 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -176,20 +176,6 @@ void DialogsManager::showScriptEditor() { _scriptEditor->raise(); } -void DialogsManager::showIRCLink() { - if (!_ircInfoBox) { - _ircInfoBox = new QMessageBox(QMessageBox::NoIcon, - "High Fidelity IRC", - "High Fidelity has an IRC channel on irc.freenode.net at #highfidelity.

Web chat is available here.", - QMessageBox::Ok); - _ircInfoBox->setTextFormat(Qt::RichText); - _ircInfoBox->setAttribute(Qt::WA_DeleteOnClose); - _ircInfoBox->show(); - } - - _ircInfoBox->raise(); -} - void DialogsManager::showDomainConnectionDialog() { // if the dialog already exists we delete it so the connection data is refreshed if (_domainConnectionDialog) { diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index f6ad1d6f98..e0b841fa12 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -57,7 +57,6 @@ public slots: void lodTools(); void hmdTools(bool showTools); void showScriptEditor(); - void showIRCLink(); void showDomainConnectionDialog(); // Application Update diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 768dbf9007..3377aac14c 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -58,7 +58,7 @@ bool SixenseManager::_sixenseLoaded = false; const QString SixenseManager::NAME = "Sixense"; const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra"; -const QString MENU_PARENT = "Avatar"; +const QString MENU_PARENT = "Developer"; const QString MENU_NAME = "Sixense"; const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; const QString TOGGLE_SMOOTH = "Smooth Sixense Movement"; From 660304a0a39757085c33b0fe4c48e6a29a099451 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 7 Jan 2016 12:25:25 -0800 Subject: [PATCH 31/37] Stop QML hanging the app on shutdown --- interface/src/Application.cpp | 6 ++++-- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4a166d9b12..ede6a9b9b0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -696,7 +696,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : auto userInputMapper = DependencyManager::get(); connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { using namespace controller; - static auto offscreenUi = DependencyManager::get(); + auto offscreenUi = DependencyManager::get(); if (offscreenUi->navigationFocused()) { auto actionEnum = static_cast(action); int key = Qt::Key_unknown; @@ -836,7 +836,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); })); _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { - static auto offscreenUi = DependencyManager::get(); + auto offscreenUi = DependencyManager::get(); return offscreenUi->navigationFocused() ? 1.0 : 0.0; })); @@ -1051,6 +1051,8 @@ void Application::cleanupBeforeQuit() { #ifdef HAVE_IVIEWHMD DependencyManager::destroy(); #endif + + DependencyManager::destroy(); } void Application::emptyLocalCache() { diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index f89f1f5b72..d9e8579d58 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -254,7 +254,7 @@ private: _quit = true; } - static const uint64_t MAX_SHUTDOWN_WAIT_SECS = 5; + static const uint64_t MAX_SHUTDOWN_WAIT_SECS = 2; void stop() { if (_thread.isRunning()) { qDebug() << "Stopping QML render thread " << _thread.currentThreadId(); From d51f514281980f546177ef1d7856143c37ba29ee Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 12:42:18 -0800 Subject: [PATCH 32/37] reworking of view/camera mode to match spec --- interface/src/Application.cpp | 4 +-- interface/src/Menu.cpp | 43 ++++++++++++++++--------- interface/src/Menu.h | 4 +-- interface/src/ui/ApplicationOverlay.cpp | 2 +- interface/src/ui/AvatarInputs.cpp | 6 ++-- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9ddb42f42b..5fa916743c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1338,7 +1338,7 @@ void Application::paintGL() { renderArgs._context->syncCache(); } - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror)) { PerformanceTimer perfTimer("Mirror"); auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); @@ -1985,7 +1985,7 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_H: if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::Mirror); + Menu::getInstance()->triggerOption(MenuOption::MiniMirror); } else { Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 128190a49d..96ff798c6a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -144,32 +144,43 @@ Menu::Menu() { // View menu ---------------------------------- - // FIXME - this is not yet matching Alan's spec because it bundles the camera mode - // into a sub menu. I need to double check that cameraMenuChanged() is updated - // to handle not being in a sub-menu MenuWrapper* viewMenu = addMenu("View"); - MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode"); - QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu); + QActionGroup* cameraModeGroup = new QActionGroup(viewMenu); + + // View > [camera group] cameraModeGroup->setExclusive(true); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + + // View > First Person + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 0, // QML Qt:: Key_P false, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + + // View > Third Person + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::ThirdPerson, 0, true, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::IndependentMode, 0, - false, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, - MenuOption::CameraEntityMode, 0, - false, qApp, SLOT(cameraMenuChanged()))); - cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu, + + // View > Mirror + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, 0, // QML Qt::Key_H, false, qApp, SLOT(cameraMenuChanged()))); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, + // View > Independent [advanced] + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, + MenuOption::IndependentMode, 0, + false, qApp, SLOT(cameraMenuChanged()), + UNSPECIFIED_POSITION, "Advanced")); + + // View > Entity Camera [advanced] + cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, + MenuOption::CameraEntityMode, 0, + false, qApp, SLOT(cameraMenuChanged()), + UNSPECIFIED_POSITION, "Advanced")); + + // View > Mini Mirror [advanced] + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror, 0, //QML Qt::SHIFT | Qt::Key_H, - true); + false, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); // Edit menu ---------------------------------- diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6563233902..085b349b8f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -218,7 +218,7 @@ namespace MenuOption { const QString FixGaze = "Fix Gaze (no saccade)"; const QString Forward = "Forward"; const QString FrameTimer = "Show Timer"; - const QString FullscreenMirror = "Fullscreen Mirror"; + const QString FullscreenMirror = "Mirror"; const QString GlowWhenSpeaking = "Glow When Speaking"; const QString Help = "Help..."; const QString IncreaseAvatarSize = "Increase Avatar Size"; @@ -234,7 +234,7 @@ namespace MenuOption { const QString LogExtraTimings = "Log Extra Timing Details"; const QString LowVelocityFilter = "Low Velocity Filter"; const QString MeshVisible = "Draw Mesh"; - const QString Mirror = "Mirror"; + const QString MiniMirror = "Mini Mirror"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString MuteFaceTracking = "Mute Face Tracking"; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index b11e4c7a95..9259478d46 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -158,7 +158,7 @@ void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { } void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) { - if (!qApp->isHMDMode() && Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + if (!qApp->isHMDMode() && Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror)) { gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index 7b5f80ee80..fa6eaf072d 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -62,7 +62,7 @@ void AvatarInputs::update() { if (!Menu::getInstance()) { return; } - AI_UPDATE(mirrorVisible, Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode() + AI_UPDATE(mirrorVisible, Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror) && !qApp->isHMDMode() && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)); AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)); @@ -129,7 +129,7 @@ void AvatarInputs::toggleZoom() { } void AvatarInputs::closeMirror() { - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - Menu::getInstance()->triggerOption(MenuOption::Mirror); + if (Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror)) { + Menu::getInstance()->triggerOption(MenuOption::MiniMirror); } } From 04a5f5ce1b218c85f69c46576389537e9a590f4c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 13:26:03 -0800 Subject: [PATCH 33/37] remove dead code for friends, since its handled by users.js --- interface/src/Menu.cpp | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 96ff798c6a..7de1894702 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -616,34 +616,6 @@ Menu::Menu() { forwardAction->setDisabled(true); MenuWrapper* toolsMenu = addMenu("Tools"); - - addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, - qApp, SLOT(showFriendsWindow())); - - MenuWrapper* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); - { - QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); - auto discoverabilityManager = DependencyManager::get(); - - QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToEveryone); - - QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToFriends); - - QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToNoOne); - - connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, - discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); - } - addActionToQMenuAndActionHash(toolsMenu, MenuOption::ToolWindow, Qt::CTRL | Qt::ALT | Qt::Key_T, @@ -654,15 +626,11 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, 0, false, qApp, SLOT(rotationModeChanged()), UNSPECIFIED_POSITION, "Advanced"); - - #endif } From a8383238e4c1d03d90619f128d916d36ad21f781 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 13:46:55 -0800 Subject: [PATCH 34/37] make mini mirror a standard option --- interface/src/Menu.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7de1894702..75225ea3a5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -177,10 +177,8 @@ Menu::Menu() { false, qApp, SLOT(cameraMenuChanged()), UNSPECIFIED_POSITION, "Advanced")); - // View > Mini Mirror [advanced] - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror, - 0, //QML Qt::SHIFT | Qt::Key_H, - false, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); + // View > Mini Mirror + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror); // Edit menu ---------------------------------- From cdc982c6e53789e1fcff220e218bdfff8edfaed6 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 14:22:20 -0800 Subject: [PATCH 35/37] mini mirror off by default --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 75225ea3a5..651e62e4b0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -178,7 +178,7 @@ Menu::Menu() { UNSPECIFIED_POSITION, "Advanced")); // View > Mini Mirror - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror, 0, false); // Edit menu ---------------------------------- From e9ec561a550b6c619410be3d2c2dfcdb987541bc Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 14:28:44 -0800 Subject: [PATCH 36/37] add separator in View menu --- interface/src/Menu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 651e62e4b0..b2ab826ab4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -177,6 +177,8 @@ Menu::Menu() { false, qApp, SLOT(cameraMenuChanged()), UNSPECIFIED_POSITION, "Advanced")); + viewMenu->addSeparator(); + // View > Mini Mirror addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror, 0, false); From 45b85735d33ff9b512803c61cff861f93357b491 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Jan 2016 14:37:42 -0800 Subject: [PATCH 37/37] disable the not yet implemented menu items --- interface/src/Menu.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b2ab826ab4..d57c395b48 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -72,13 +72,15 @@ Menu::Menu() { } // File > Update -- FIXME: needs implementation - addActionToQMenuAndActionHash(fileMenu, "Update"); + auto updateAction = addActionToQMenuAndActionHash(fileMenu, "Update"); + updateAction->setDisabled(true); // File > Help addActionToQMenuAndActionHash(fileMenu, MenuOption::Help, 0, qApp, SLOT(showHelp())); // File > Crash Reporter...-- FIXME: needs implementation - addActionToQMenuAndActionHash(fileMenu, "Crash Reporter..."); + auto crashReporterAction = addActionToQMenuAndActionHash(fileMenu, "Crash Reporter..."); + crashReporterAction->setDisabled(true); // File > About addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); @@ -93,7 +95,8 @@ Menu::Menu() { audioIO.data(), SLOT(toggleMute())); // Audio > Level Meter [advanced] -- FIXME: needs implementation - addCheckableActionToQMenuAndActionHash(audioMenu, "Level Meter", 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); + auto levelMeterAction = addCheckableActionToQMenuAndActionHash(audioMenu, "Level Meter", 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); + levelMeterAction->setDisabled(true); // Avatar menu ---------------------------------- @@ -246,7 +249,8 @@ Menu::Menu() { MenuWrapper* navigateMenu = addMenu("Navigate"); // Navigate > Home -- FIXME: needs implementation - addActionToQMenuAndActionHash(navigateMenu, "Home"); + auto homeAction = addActionToQMenuAndActionHash(navigateMenu, "Home"); + homeAction->setDisabled(true); addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L, dialogsManager.data(), SLOT(toggleAddressBar())); @@ -273,7 +277,8 @@ Menu::Menu() { MenuWrapper* marketMenu = addMenu("Market"); // Market > Marketplace... -- FIXME: needs implementation - addActionToQMenuAndActionHash(marketMenu, "Marketplace..."); + auto marketplaceAction = addActionToQMenuAndActionHash(marketMenu, "Marketplace..."); + marketplaceAction->setDisabled(true); // Settings menu ---------------------------------- @@ -290,13 +295,16 @@ Menu::Menu() { dialogsManager.data(), SLOT(editPreferences()), QAction::PreferencesRole); // Settings > Avatar...-- FIXME: needs implementation - addActionToQMenuAndActionHash(settingsMenu, "Avatar..."); + auto avatarAction = addActionToQMenuAndActionHash(settingsMenu, "Avatar..."); + avatarAction->setDisabled(true); // Settings > Audio...-- FIXME: needs implementation - addActionToQMenuAndActionHash(settingsMenu, "Audio..."); + auto audioAction = addActionToQMenuAndActionHash(settingsMenu, "Audio..."); + audioAction->setDisabled(true); // Settings > LOD...-- FIXME: needs implementation - addActionToQMenuAndActionHash(settingsMenu, "LOD..."); + auto lodAction = addActionToQMenuAndActionHash(settingsMenu, "LOD..."); + lodAction->setDisabled(true); // Settings > Control with Speech [advanced] #if defined(Q_OS_MAC) || defined(Q_OS_WIN)