From 41d014ca0c374709c9d1ea1d1b16f959ae9a1a54 Mon Sep 17 00:00:00 2001 From: beholder Date: Wed, 6 Sep 2017 02:11:40 +0300 Subject: [PATCH 01/23] 6718 PR11082: Help text cannot be dismissed by clicking on the text inside the box. --- .../resources/qml/hifi/LetterboxMessage.qml | 41 +------------------ 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 6f41154d4d..7ce66adf11 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -137,48 +137,11 @@ Item { } } } - // Left gray MouseArea MouseArea { - anchors.left: parent.left; - anchors.right: textContainer.left; - anchors.top: textContainer.top; - anchors.bottom: textContainer.bottom; + anchors.fill: parent acceptedButtons: Qt.LeftButton onClicked: { - letterbox.visible = false - } - } - // Right gray MouseArea - MouseArea { - anchors.left: textContainer.left; - anchors.right: parent.left; - anchors.top: textContainer.top; - anchors.bottom: textContainer.bottom; - acceptedButtons: Qt.LeftButton - onClicked: { - letterbox.visible = false - } - } - // Top gray MouseArea - MouseArea { - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - anchors.bottom: textContainer.top; - acceptedButtons: Qt.LeftButton - onClicked: { - letterbox.visible = false - } - } - // Bottom gray MouseArea - MouseArea { - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: textContainer.bottom; - anchors.bottom: parent.bottom; - acceptedButtons: Qt.LeftButton - onClicked: { - letterbox.visible = false + letterbox.visible = false; } } } From 33c8e90e3415499c3bb083002fa57ac7c2cff8d1 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Wed, 13 Sep 2017 15:32:02 -0400 Subject: [PATCH 02/23] [QML] Fixes FogBugz Case 6107: Can't sort on import menu (details below). Looking through the log revealed the following warning: ".../qml/dialogs/FileDialog.qml:489: Error: Cannot assign to non-existent property 'sortOrder'" There was some refactoring to address some HMD functionality in 51b44d90 which resulted in an update to fileTableView's model. This appears to be the point at which sorting stopped working. This updates the fileTableView's sorting methods to use fileTableModel as opposed to fileTableView's model(filesModel). This appears safe given fileTableModel internally wraps around filesModel and is responsible for updating its value. I'm relatively new to QML/Qt; any comments or suggestions are welcome. Tagging @vladest since they may want to be aware given 51b44d90. Case Link: https://highfidelity.fogbugz.com/f/cases/6107 Reviewed-by: Leander Hasty Changes Committed: modified: interface/resources/qml/dialogs/FileDialog.qml --- interface/resources/qml/dialogs/FileDialog.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 106e067968..b9633104d5 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -486,9 +486,9 @@ ModalWindow { model: filesModel function updateSort() { - model.sortOrder = sortIndicatorOrder; - model.sortColumn = sortIndicatorColumn; - model.update(); + fileTableModel.sortOrder = sortIndicatorOrder; + fileTableModel.sortColumn = sortIndicatorColumn; + fileTableModel.update(); } onSortIndicatorColumnChanged: { updateSort(); } From 7233c472579460e9c02f88069ab07fc1be51f873 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 14 Sep 2017 15:36:12 +0200 Subject: [PATCH 03/23] use selection model of TreeView --- interface/resources/qml/hifi/dialogs/RunningScripts.qml | 4 ++-- interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 952cc03733..c949be319f 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -387,9 +387,9 @@ ScrollingWindow { readOnly: true Connections { - target: treeView + target: treeView.selection onCurrentIndexChanged: { - var path = scriptsModel.data(treeView.currentIndex, 0x100) + var path = scriptsModel.data(treeView.selection.currentIndex, 0x100) if (path) { selectedScript.text = path } else { diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 5677cc92a1..340d2e9ac7 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -416,9 +416,9 @@ Rectangle { readOnly: true Connections { - target: treeView + target: treeView.selection onCurrentIndexChanged: { - var path = scriptsModel.data(treeView.currentIndex, 0x100) + var path = scriptsModel.data(treeView.selection.currentIndex, 0x100) if (path) { selectedScript.text = path } else { From 75e7146c5bedb0b0c445a604a750bb555ffe3547 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Sep 2017 09:49:33 -0700 Subject: [PATCH 04/23] Fix polyline crash and flicker --- .../entities-renderer/src/RenderablePolyLineEntityItem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 3db7fb2c30..1cecb0b036 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -126,6 +126,7 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& auto textures = entity->getTextures(); QString path = textures.isEmpty() ? PathUtils::resourcesPath() + "images/paintStroke.png" : textures; if (!_texture || _lastTextures != path) { + _lastTextures = path; _texture = DependencyManager::get()->getTexture(QUrl(path)); } } @@ -220,7 +221,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { batch.setModelTransform(Transform{ _modelTransform }.setScale(vec3(1))); batch.setUniformBuffer(PAINTSTROKE_UNIFORM_SLOT, _uniformBuffer); - if (_texture->isLoaded()) { + if (_texture && _texture->isLoaded()) { batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture()); } else { batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, nullptr); From 501eee8b10b9e9853a235f24fde2a663ce00922a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Sep 2017 23:38:02 -0700 Subject: [PATCH 05/23] Fix transform of polylines with high update rates --- .../entities-renderer/src/RenderablePolyLineEntityItem.cpp | 6 +++++- .../entities-renderer/src/RenderablePolyLineEntityItem.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 1cecb0b036..50226ef8ae 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -141,6 +141,10 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo auto normalsChanged = entity->normalsChanged(); entity->resetPolyLineChanged(); + _polylineTransform = Transform(); + _polylineTransform.setTranslation(entity->getPosition()); + _polylineTransform.setRotation(entity->getRotation()); + if (pointsChanged) { _lastPoints = entity->getLinePoints(); } @@ -218,7 +222,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; - batch.setModelTransform(Transform{ _modelTransform }.setScale(vec3(1))); + batch.setModelTransform(_polylineTransform); batch.setUniformBuffer(PAINTSTROKE_UNIFORM_SLOT, _uniformBuffer); if (_texture && _texture->isLoaded()) { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 88b5ebdb9f..b0bdcf545b 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -47,6 +47,7 @@ protected: void updateGeometry(const std::vector& vertices); static std::vector updateVertices(const QVector& points, const QVector& normals, const QVector& strokeWidths); + Transform _polylineTransform; QVector _lastPoints; QVector _lastNormals; QVector _lastStrokeWidths; From d89f2b77dae1b0fee9c142570815413325a42f4c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 14 Sep 2017 10:42:21 -0700 Subject: [PATCH 06/23] rework ScriptEngine lifetimes using 'smart' pointers --- assignment-client/src/Agent.cpp | 7 ++- assignment-client/src/Agent.h | 2 +- .../src/scripts/EntityScriptServer.cpp | 12 ++-- interface/src/Application.cpp | 51 ++++++++------- interface/src/Application.h | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +- interface/src/avatar/MyAvatar.h | 3 +- interface/src/ui/JSConsole.cpp | 2 +- interface/src/ui/TestingDialog.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 40 +++--------- .../entities/src/EntityScriptingInterface.cpp | 4 +- .../entities/src/EntityScriptingInterface.h | 6 +- .../src/AbstractScriptingServicesInterface.h | 2 +- .../src/RecordingScriptingInterface.h | 5 +- libraries/script-engine/src/ScriptEngine.cpp | 46 +++++++------- libraries/script-engine/src/ScriptEngine.h | 10 ++- libraries/script-engine/src/ScriptEngines.cpp | 62 +++++++++---------- libraries/script-engine/src/ScriptEngines.h | 19 +++--- 18 files changed, 135 insertions(+), 146 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index e50c7180d1..4efc3343d1 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -354,15 +354,16 @@ void Agent::scriptRequestFinished() { void Agent::executeScript() { - _scriptEngine = std::unique_ptr(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload)); + _scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload); _scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do - DependencyManager::get()->setScriptEngine(_scriptEngine.get()); + DependencyManager::get()->setScriptEngine(_scriptEngine); // setup an Avatar for the script to use auto scriptedAvatar = DependencyManager::get(); - connect(_scriptEngine.get(), SIGNAL(update(float)), scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection); + connect(_scriptEngine.data(), SIGNAL(update(float)), + scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection); scriptedAvatar->setForceFaceTrackerConnected(true); // call model URL setters with empty URLs so our avatar, if user, will have the default models diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index b10f72db9a..cf18c0ed18 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -88,7 +88,7 @@ private: void encodeFrameOfZeros(QByteArray& encodedZeros); void computeLoudness(const QByteArray* decodedBuffer, QSharedPointer); - std::unique_ptr _scriptEngine; + QSharedPointer _scriptEngine; EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index e7433e7c05..fd53ab2391 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -415,8 +415,7 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { void EntityScriptServer::resetEntitiesScriptEngine() { auto engineName = QString("about:Entities %1").arg(++_entitiesScriptEngineCount); - auto newEngine = QSharedPointer(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName), - &ScriptEngine::deleteLater); + auto newEngine = scriptEngineFactory(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName); auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor); newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); @@ -437,11 +436,14 @@ void EntityScriptServer::resetEntitiesScriptEngine() { newEngine->runInThread(); - DependencyManager::get()->setEntitiesScriptEngine(newEngine.data()); + auto newEngineSP = qSharedPointerCast(newEngine); + DependencyManager::get()->setEntitiesScriptEngine(newEngineSP); - disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); + disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, + this, &EntityScriptServer::updateEntityPPS); _entitiesScriptEngine.swap(newEngine); - connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); + connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, + this, &EntityScriptServer::updateEntityPPS); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3650c495f2..86ed0a6666 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -963,7 +963,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get().data(), &AddressManager::storeCurrentAddress); auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer([this](ScriptEngine* engine){ + scriptEngines->registerScriptInitializer([this](QSharedPointer engine){ registerScriptEngineWithApplicationServices(engine); }); @@ -5930,7 +5930,7 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer void Application::packetSent(quint64 length) { } -void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) { +void Application::registerScriptEngineWithApplicationServices(QSharedPointer scriptEngine) { scriptEngine->setEmitScriptUpdatesFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); @@ -5944,7 +5944,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri entityScriptingInterface->setEntityTree(getEntities()->getTree()); // give the script engine to the RecordingScriptingInterface for its callbacks - DependencyManager::get()->setScriptEngine(scriptEngine); + DependencyManager::get()->setScriptEngine(QSharedPointer(scriptEngine)); if (property(hifi::properties::TEST).isValid()) { scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance()); @@ -5965,29 +5965,31 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface(); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); - connect(scriptEngine, &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); + connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); scriptEngine->registerGlobalObject("Overlays", &_overlays); - qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue); - qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, + qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); scriptEngine->registerGlobalObject("OffscreenFlags", DependencyManager::get()->getFlags()); scriptEngine->registerGlobalObject("Desktop", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue, wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), + wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue, wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), + wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); - - DependencyManager::get().data()->setToolbarScriptingInterface(DependencyManager::get().data()); + auto toolbarScriptingInterface = DependencyManager::get().data(); + DependencyManager::get().data()->setToolbarScriptingInterface(toolbarScriptingInterface); scriptEngine->registerGlobalObject("Window", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue); scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter, "Window"); // register `location` on the global object. @@ -6019,7 +6021,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance()); - qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); scriptEngine->registerGlobalObject("FaceTracker", DependencyManager::get().data()); @@ -6047,11 +6049,11 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { - scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine, steamClient.get())); + scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get())); } auto scriptingInterface = DependencyManager::get(); scriptEngine->registerGlobalObject("Controller", scriptingInterface.data()); - UserInputMapper::registerControllerTypes(scriptEngine); + UserInputMapper::registerControllerTypes(scriptEngine.data()); auto recordingInterface = DependencyManager::get(); scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); @@ -6062,14 +6064,19 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Selection", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); // connect this script engines printedMessage signal to the global ScriptEngines these various messages - connect(scriptEngine, &ScriptEngine::printedMessage, DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); - connect(scriptEngine, &ScriptEngine::errorMessage, DependencyManager::get().data(), &ScriptEngines::onErrorMessage); - connect(scriptEngine, &ScriptEngine::warningMessage, DependencyManager::get().data(), &ScriptEngines::onWarningMessage); - connect(scriptEngine, &ScriptEngine::infoMessage, DependencyManager::get().data(), &ScriptEngines::onInfoMessage); - connect(scriptEngine, &ScriptEngine::clearDebugWindow, DependencyManager::get().data(), &ScriptEngines::onClearDebugWindow); + connect(scriptEngine.data(), &ScriptEngine::printedMessage, + DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); + connect(scriptEngine.data(), &ScriptEngine::errorMessage, + DependencyManager::get().data(), &ScriptEngines::onErrorMessage); + connect(scriptEngine.data(), &ScriptEngine::warningMessage, + DependencyManager::get().data(), &ScriptEngines::onWarningMessage); + connect(scriptEngine.data(), &ScriptEngine::infoMessage, + DependencyManager::get().data(), &ScriptEngines::onInfoMessage); + connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, + DependencyManager::get().data(), &ScriptEngines::onClearDebugWindow); } diff --git a/interface/src/Application.h b/interface/src/Application.h index c7f83ad28f..a8783e8e2b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -218,7 +218,7 @@ public: NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } - virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override; + virtual void registerScriptEngineWithApplicationServices(QSharedPointer scriptEngine) override; virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); } virtual QThread* getMainThread() override { return thread(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8592ff3d74..5b34ab6ea2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -262,7 +262,7 @@ void MyAvatar::setDominantHand(const QString& hand) { } } -void MyAvatar::registerMetaTypes(QScriptEngine* engine) { +void MyAvatar::registerMetaTypes(QSharedPointer engine) { QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); engine->globalObject().setProperty("MyAvatar", value); @@ -273,8 +273,8 @@ void MyAvatar::registerMetaTypes(QScriptEngine* engine) { } engine->globalObject().setProperty("DriveKeys", driveKeys); - qScriptRegisterMetaType(engine, audioListenModeToScriptValue, audioListenModeFromScriptValue); - qScriptRegisterMetaType(engine, driveKeysToScriptValue, driveKeysFromScriptValue); + qScriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue); + qScriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue); } void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 65dcc12e7d..c3d74a9609 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -169,7 +170,7 @@ public: ~MyAvatar(); void instantiableAvatar() override {}; - void registerMetaTypes(QScriptEngine* engine); + void registerMetaTypes(QSharedPointer engine); virtual void simulateAttachments(float deltaTime) override; diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 8c1ff87d13..6b079cbc93 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -111,7 +111,7 @@ void JSConsole::setScriptEngine(const QSharedPointer& scriptEngin // if scriptEngine is NULL then create one and keep track of it using _ownScriptEngine if (scriptEngine.isNull()) { - _scriptEngine = QSharedPointer(DependencyManager::get()->loadScript(_consoleFileName, false), &QObject::deleteLater); + _scriptEngine = DependencyManager::get()->loadScript(_consoleFileName, false); } else { _scriptEngine = scriptEngine; } diff --git a/interface/src/ui/TestingDialog.cpp b/interface/src/ui/TestingDialog.cpp index bba14cd5d7..6f499f2a8d 100644 --- a/interface/src/ui/TestingDialog.cpp +++ b/interface/src/ui/TestingDialog.cpp @@ -24,7 +24,7 @@ TestingDialog::TestingDialog(QWidget* parent) : _console->setFixedHeight(TESTING_CONSOLE_HEIGHT); auto _engines = DependencyManager::get(); - _engine.reset(_engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath)); + _engine = _engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); _console->setScriptEngine(_engine); connect(_engine.data(), &ScriptEngine::finished, this, &TestingDialog::onTestingFinished); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index d754d59721..e8ad163964 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -70,45 +70,21 @@ EntityRendererPointer EntityTreeRenderer::renderableForEntityId(const EntityItem return itr->second; } -render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const { - auto renderable = renderableForEntityId(id); - return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID; +render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const { + auto renderable = renderableForEntityId(id); + return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID; } int EntityTreeRenderer::_entitiesScriptEngineCount = 0; -void entitiesScriptEngineDeleter(ScriptEngine* engine) { - class WaitRunnable : public QRunnable { - public: - WaitRunnable(ScriptEngine* engine) : _engine(engine) {} - virtual void run() override { - _engine->waitTillDoneRunning(); - _engine->deleteLater(); - } - - private: - ScriptEngine* _engine; - }; - - // Wait for the scripting thread from the thread pool to avoid hanging the main thread - auto threadPool = QThreadPool::globalInstance(); - if (threadPool) { - threadPool->start(new WaitRunnable(engine)); - } else { - delete engine; - } -} - void EntityTreeRenderer::resetEntitiesScriptEngine() { - // Keep a ref to oldEngine until newEngine is ready so EntityScriptingInterface has something to use auto oldEngine = _entitiesScriptEngine; - - auto newEngine = new ScriptEngine(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); - _entitiesScriptEngine = QSharedPointer(newEngine, entitiesScriptEngineDeleter); - - _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine.data()); + _entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, + QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); + _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine); _entitiesScriptEngine->runInThread(); - DependencyManager::get()->setEntitiesScriptEngine(_entitiesScriptEngine.data()); + auto entitiesScriptEngineProvider = qSharedPointerCast(_entitiesScriptEngine); + DependencyManager::get()->setEntitiesScriptEngine(entitiesScriptEngineProvider); } void EntityTreeRenderer::clear() { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 127da47ae2..f91bc14fe4 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -539,7 +539,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { } } -void EntityScriptingInterface::setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine) { +void EntityScriptingInterface::setEntitiesScriptEngine(QSharedPointer engine) { std::lock_guard lock(_entitiesScriptEngineLock); _entitiesScriptEngine = engine; } @@ -749,7 +749,7 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, QScriptValue h request->deleteLater(); }); auto entityScriptingInterface = DependencyManager::get(); - entityScriptingInterface->withEntitiesScriptEngine([&](EntitiesScriptEngineProvider* entitiesScriptEngine) { + entityScriptingInterface->withEntitiesScriptEngine([&](QSharedPointer entitiesScriptEngine) { if (entitiesScriptEngine) { request->setFuture(entitiesScriptEngine->getLocalEntityScriptDetails(entityID)); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 1eb754ef1c..9b2b6360f3 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -99,7 +99,7 @@ public: void setEntityTree(EntityTreePointer modelTree); EntityTreePointer getEntityTree() { return _entityTree; } - void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine); + void setEntitiesScriptEngine(QSharedPointer engine); float calculateCost(float mass, float oldVelocity, float newVelocity); void resetActivityTracking(); @@ -405,7 +405,7 @@ signals: void webEventReceived(const EntityItemID& entityItemID, const QVariant& message); protected: - void withEntitiesScriptEngine(std::function function) { + void withEntitiesScriptEngine(std::function)> function) { std::lock_guard lock(_entitiesScriptEngineLock); function(_entitiesScriptEngine); }; @@ -427,7 +427,7 @@ private: EntityTreePointer _entityTree; std::recursive_mutex _entitiesScriptEngineLock; - EntitiesScriptEngineProvider* _entitiesScriptEngine { nullptr }; + QSharedPointer _entitiesScriptEngine; bool _bidOnSimulationOwnership { false }; float _currentAvatarEnergy = { FLT_MAX }; diff --git a/libraries/script-engine/src/AbstractScriptingServicesInterface.h b/libraries/script-engine/src/AbstractScriptingServicesInterface.h index de18338fca..afc3bb1227 100644 --- a/libraries/script-engine/src/AbstractScriptingServicesInterface.h +++ b/libraries/script-engine/src/AbstractScriptingServicesInterface.h @@ -18,7 +18,7 @@ class ScriptEngine; class AbstractScriptingServicesInterface { public: /// Registers application specific services with a script engine. - virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0; + virtual void registerScriptEngineWithApplicationServices(QSharedPointer scriptEngine) = 0; }; diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index c4220958a2..bc0b019251 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -28,7 +29,7 @@ class RecordingScriptingInterface : public QObject, public Dependency { public: RecordingScriptingInterface(); - void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; } + void setScriptEngine(QSharedPointer scriptEngine) { _scriptEngine = scriptEngine; } public slots: void loadRecording(const QString& url, QScriptValue callback = QScriptValue()); @@ -85,7 +86,7 @@ protected: Flag _useSkeletonModel { false }; recording::ClipPointer _lastClip; - QScriptEngine* _scriptEngine; + QSharedPointer _scriptEngine; QSet _clipLoaders; }; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 8b8eed02fd..ba75ed9856 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -153,6 +153,15 @@ QString ScriptEngine::logException(const QScriptValue& exception) { return message; } +QSharedPointer scriptEngineFactory(ScriptEngine::Context context, + const QString& scriptContents, + const QString& fileNameString) { + ScriptEngine* engine = new ScriptEngine(context, scriptContents, fileNameString); + QSharedPointer engineSP = QSharedPointer(engine); + DependencyManager::get()->addScriptEngine(qSharedPointerCast(engineSP)); + return engineSP; +} + int ScriptEngine::processLevelMaxRetries { ScriptRequest::MAX_RETRIES }; ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const QString& fileNameString) : BaseScriptEngine(), @@ -160,10 +169,10 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const _scriptContents(scriptContents), _timerFunctionMap(), _fileNameString(fileNameString), - _arrayBufferClass(new ArrayBufferClass(this)) + _arrayBufferClass(new ArrayBufferClass(this)), + // don't delete `ScriptEngines` until all `ScriptEngine`s are gone + _scriptEngines(DependencyManager::get()) { - DependencyManager::get()->addScriptEngine(this); - connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { if (hasUncaughtException()) { // the engine's uncaughtException() seems to produce much better stack traces here @@ -208,22 +217,9 @@ QString ScriptEngine::getContext() const { } ScriptEngine::~ScriptEngine() { - // FIXME: are these scriptInfoMessage/scriptWarningMessage segfaulting anybody else at app shutdown? -#if !defined(Q_OS_LINUX) - scriptInfoMessage("Script Engine shutting down:" + getFilename()); -#else - qCDebug(scriptengine) << "~ScriptEngine()" << this; -#endif - auto scriptEngines = DependencyManager::get(); if (scriptEngines) { - scriptEngines->removeScriptEngine(this); - } else { -#if !defined(Q_OS_LINUX) - scriptWarningMessage("Script destroyed after ScriptEngines!"); -#else - qCWarning(scriptengine) << ("Script destroyed after ScriptEngines!"); -#endif + scriptEngines->removeScriptEngine(qSharedPointerCast(sharedFromThis())); } } @@ -294,7 +290,7 @@ void ScriptEngine::runDebuggable() { stopAllTimers(); // make sure all our timers are stopped if the script is ending emit scriptEnding(); - emit finished(_fileNameString, this); + emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); _isRunning = false; emit runningStateChanged(); @@ -503,7 +499,8 @@ static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters.animVariantMapFromScriptValue(value); } // ... while these two are not. But none of the four are ever used. -static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, const AnimVariantResultHandler& resultHandler) { +static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, + const AnimVariantResultHandler& resultHandler) { qCCritical(scriptengine) << "Attempt to marshall result handler to javascript"; assert(false); return QScriptValue(); @@ -516,7 +513,8 @@ static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantR // Templated qScriptRegisterMetaType fails to compile with raw pointers using ScriptableResourceRawPtr = ScriptableResource*; -static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, const ScriptableResourceRawPtr& resource) { +static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, + const ScriptableResourceRawPtr& resource) { // The first script to encounter this resource will track its memory. // In this way, it will be more likely to GC. // This fails in the case that the resource is used across many scripts, but @@ -539,11 +537,11 @@ static void scriptableResourceFromScriptValue(const QScriptValue& value, Scripta resource = static_cast(value.toQObject()); } -static QScriptValue createScriptableResourcePrototype(QScriptEngine* engine) { +static QScriptValue createScriptableResourcePrototype(QSharedPointer engine) { auto prototype = engine->newObject(); // Expose enum State to JS/QML via properties - QObject* state = new QObject(engine); + QObject* state = new QObject(engine.data()); state->setObjectName("ResourceState"); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < metaEnum.keyCount(); ++i) { @@ -693,7 +691,7 @@ void ScriptEngine::init() { qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); // Scriptable cache access - auto resourcePrototype = createScriptableResourcePrototype(this); + auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast(sharedFromThis())); globalObject().setProperty("Resource", resourcePrototype); setDefaultPrototype(qMetaTypeId(), resourcePrototype); qScriptRegisterMetaType(this, scriptableResourceToScriptValue, scriptableResourceFromScriptValue); @@ -1178,7 +1176,7 @@ void ScriptEngine::run() { } } - emit finished(_fileNameString, this); + emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); _isRunning = false; emit runningStateChanged(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 7c473a305b..e743753da1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -53,6 +53,8 @@ static const int SCRIPT_FPS = 60; static const int DEFAULT_MAX_ENTITY_PPS = 9000; static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; +class ScriptEngines; + class CallbackData { public: QScriptValue function; @@ -242,7 +244,7 @@ signals: void errorLoadingScript(const QString& scriptFilename); void update(float deltaTime); void scriptEnding(); - void finished(const QString& fileNameString, ScriptEngine* engine); + void finished(const QString& fileNameString, QSharedPointer); void cleanupMenuItem(const QString& menuItemString); void printedMessage(const QString& message, const QString& scriptName); void errorMessage(const QString& message, const QString& scriptName); @@ -328,6 +330,12 @@ protected: static const QString _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS; Setting::Handle _enableExtendedJSExceptions { _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS, true }; + + QSharedPointer _scriptEngines; }; +QSharedPointer scriptEngineFactory(ScriptEngine::Context context, + const QString& scriptContents, + const QString& fileNameString); + #endif // hifi_ScriptEngine_h diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 57b04eeb82..686d8cae03 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -137,16 +137,14 @@ void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) { _scriptInitializers.push_back(initializer); } -void ScriptEngines::addScriptEngine(ScriptEngine* engine) { - if (_isStopped) { - engine->deleteLater(); - } else { +void ScriptEngines::addScriptEngine(QSharedPointer engine) { + if (!_isStopped) { QMutexLocker locker(&_allScriptsMutex); _allKnownScriptEngines.insert(engine); } } -void ScriptEngines::removeScriptEngine(ScriptEngine* engine) { +void ScriptEngines::removeScriptEngine(QSharedPointer engine) { // If we're not already in the middle of stopping all scripts, then we should remove ourselves // from the list of running scripts. We don't do this if we're in the process of stopping all scripts // because that method removes scripts from its list as it iterates them @@ -161,9 +159,9 @@ void ScriptEngines::shutdownScripting() { QMutexLocker locker(&_allScriptsMutex); qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); - QMutableSetIterator i(_allKnownScriptEngines); + QMutableSetIterator> i(_allKnownScriptEngines); while (i.hasNext()) { - ScriptEngine* scriptEngine = i.next(); + QSharedPointer scriptEngine = i.next(); QString scriptName = scriptEngine->getFilename(); // NOTE: typically all script engines are running. But there's at least one known exception to this, the @@ -187,12 +185,9 @@ void ScriptEngines::shutdownScripting() { qCDebug(scriptengine) << "waiting on script:" << scriptName; scriptEngine->waitTillDoneRunning(); qCDebug(scriptengine) << "done waiting on script:" << scriptName; - - scriptEngine->deleteLater(); - - // Once the script is stopped, we can remove it from our set - i.remove(); } + // Once the script is stopped, we can remove it from our set + i.remove(); } qCDebug(scriptengine) << "DONE Stopping all scripts...."; } @@ -369,9 +364,9 @@ void ScriptEngines::stopAllScripts(bool restart) { _isReloading = true; } - for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); + for (QHash>::const_iterator it = _scriptEnginesHash.constBegin(); it != _scriptEnginesHash.constEnd(); it++) { - ScriptEngine *scriptEngine = it.value(); + QSharedPointer scriptEngine = it.value(); // skip already stopped scripts if (scriptEngine->isFinished() || scriptEngine->isStopping()) { continue; @@ -417,11 +412,12 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { QReadLocker lock(&_scriptEnginesHashLock); if (_scriptEnginesHash.contains(scriptURL)) { - ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL]; + QSharedPointer scriptEngine = _scriptEnginesHash[scriptURL]; if (restart) { auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(scriptURL); - connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { + connect(scriptEngine.data(), &ScriptEngine::finished, + this, [this](QString scriptName, QSharedPointer engine) { reloadScript(scriptName); }); } @@ -449,11 +445,11 @@ void ScriptEngines::reloadAllScripts() { stopAllScripts(true); } -ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, +QSharedPointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow, bool reload) { if (thread() != QThread::currentThread()) { - ScriptEngine* result { nullptr }; - BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEngine*, result), + QSharedPointer result { nullptr }; + BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(QSharedPointer, result), Q_ARG(QUrl, scriptFilename), Q_ARG(bool, isUserLoaded), Q_ARG(bool, loadScriptFromEditor), @@ -479,19 +475,16 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL return scriptEngine; } - scriptEngine = new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()); + scriptEngine = QSharedPointer(new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName())); + addScriptEngine(scriptEngine); scriptEngine->setUserLoaded(isUserLoaded); - connect(scriptEngine, &ScriptEngine::doneRunning, this, [scriptEngine] { - scriptEngine->deleteLater(); - }, Qt::QueuedConnection); - if (scriptFilename.isEmpty() || !scriptUrl.isValid()) { launchScriptEngine(scriptEngine); } else { // connect to the appropriate signals of this script engine - connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); - connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); + connect(scriptEngine.data(), &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); + connect(scriptEngine.data(), &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); // get the script engine object to load the script at the designated script URL scriptEngine->loadURL(scriptUrl, reload); @@ -500,8 +493,8 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL return scriptEngine; } -ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { - ScriptEngine* result = nullptr; +QSharedPointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { + QSharedPointer result; { QReadLocker lock(&_scriptEnginesHashLock); const QUrl scriptURL = normalizeScriptURL(rawScriptURL); @@ -516,7 +509,8 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { // FIXME - change to new version of ScriptCache loading notification void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { UserActivityLogger::getInstance().loadedScript(rawScriptURL); - ScriptEngine* scriptEngine = qobject_cast(sender()); + QSharedPointer baseScriptEngine = qobject_cast(sender())->sharedFromThis(); + QSharedPointer scriptEngine = qSharedPointerCast(baseScriptEngine); launchScriptEngine(scriptEngine); @@ -532,12 +526,12 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { emit scriptCountChanged(); } -void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) { - connect(scriptEngine, &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); - connect(scriptEngine, &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) { +void ScriptEngines::launchScriptEngine(QSharedPointer scriptEngine) { + connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); + connect(scriptEngine.data(), &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded); }); - connect(scriptEngine, &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) { + connect(scriptEngine.data(), &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded, false, false, true); }); @@ -558,7 +552,7 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) { } } -void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) { +void ScriptEngines::onScriptFinished(const QString& rawScriptURL, QSharedPointer engine) { bool removed = false; { QWriteLocker lock(&_scriptEnginesHashLock); diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 70634345eb..396b5cc67f 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -33,7 +33,7 @@ class ScriptEngines : public QObject, public Dependency { Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT) public: - using ScriptInitializer = std::function; + using ScriptInitializer = std::function)>; ScriptEngines(ScriptEngine::Context context); void registerScriptInitializer(ScriptInitializer initializer); @@ -45,7 +45,7 @@ public: void loadDefaultScripts(); void setScriptsLocation(const QString& scriptsLocation); QStringList getRunningScripts(); - ScriptEngine* getScriptEngine(const QUrl& scriptHash); + QSharedPointer getScriptEngine(const QUrl& scriptHash); ScriptsModel* scriptsModel() { return &_scriptsModel; }; ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; }; @@ -53,7 +53,7 @@ public: QString getDefaultScriptsLocation() const; Q_INVOKABLE void loadOneScript(const QString& scriptFilename); - Q_INVOKABLE ScriptEngine* loadScript(const QUrl& scriptFilename = QString(), + Q_INVOKABLE QSharedPointer loadScript(const QUrl& scriptFilename = QString(), bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false); Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false); @@ -72,6 +72,8 @@ public: void shutdownScripting(); bool isStopped() const { return _isStopped; } + void addScriptEngine(QSharedPointer); + signals: void scriptCountChanged(); void scriptsReloading(); @@ -92,22 +94,21 @@ public slots: void onClearDebugWindow(); protected slots: - void onScriptFinished(const QString& fileNameString, ScriptEngine* engine); + void onScriptFinished(const QString& fileNameString, QSharedPointer engine); protected: friend class ScriptEngine; void reloadScript(const QString& scriptName) { loadScript(scriptName, true, false, false, true); } - void addScriptEngine(ScriptEngine* engine); - void removeScriptEngine(ScriptEngine* engine); + void removeScriptEngine(QSharedPointer); void onScriptEngineLoaded(const QString& scriptFilename); void onScriptEngineError(const QString& scriptFilename); - void launchScriptEngine(ScriptEngine* engine); + void launchScriptEngine(QSharedPointer); ScriptEngine::Context _context; QReadWriteLock _scriptEnginesHashLock; - QHash _scriptEnginesHash; - QSet _allKnownScriptEngines; + QHash> _scriptEnginesHash; + QSet> _allKnownScriptEngines; QMutex _allScriptsMutex; std::list _scriptInitializers; mutable Setting::Handle _scriptsLocationHandle; From aef85eb69d59768fdf7b7cf680b6b3bf071e53f3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 14 Sep 2017 10:48:14 -0700 Subject: [PATCH 07/23] Fix polyline rendering using default texture --- .../src/RenderablePolyLineEntityItem.cpp | 14 +++++++++----- .../src/RenderablePolyLineEntityItem.h | 1 - 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 50226ef8ae..8c1a6318f9 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -121,15 +121,19 @@ bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP } void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + static const QUrl DEFAULT_POLYLINE_TEXTURE = QUrl(PathUtils::resourcesPath() + "images/paintStroke.png"); + QUrl entityTextures = DEFAULT_POLYLINE_TEXTURE; if (entity->texturesChanged()) { entity->resetTexturesChanged(); auto textures = entity->getTextures(); - QString path = textures.isEmpty() ? PathUtils::resourcesPath() + "images/paintStroke.png" : textures; - if (!_texture || _lastTextures != path) { - _lastTextures = path; - _texture = DependencyManager::get()->getTexture(QUrl(path)); + if (!textures.isEmpty()) { + entityTextures = QUrl(textures); } } + + if (!_texture || _texture->getURL() != entityTextures) { + _texture = DependencyManager::get()->getTexture(entityTextures); + } } void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { @@ -228,7 +232,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { if (_texture && _texture->isLoaded()) { batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture()); } else { - batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, nullptr); + batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, DependencyManager::get()->getWhiteTexture()); } batch.setInputFormat(polylineFormat); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index b0bdcf545b..610ee53cf7 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -55,7 +55,6 @@ protected: gpu::BufferView _uniformBuffer; uint32_t _numVertices { 0 }; bool _empty{ true }; - QString _lastTextures; NetworkTexturePointer _texture; }; From 24b6cd71fc5a249b7b18d3ecd84663e86e433af3 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Thu, 14 Sep 2017 14:49:49 -0400 Subject: [PATCH 08/23] [Case 6107] Fixes Tablet import sorting (details below). This ports the fix from FileDialog to TabletFileDialog. * There appears to be 2 versions of this file: * qml/dialogs/TabletFileDialog.qml * qml/hifi/tablet/tabletWindows/TabletFileDialog.qml Testing the tablet within desktop mode works without this fix most likely because it uses qml/hifi/tablet/tabletWindows/TabletFileDialog.qml which didn't receive the same refactor pass via d3282a4e. Tested on Vive: Menu -> Edit -> Import Entities Changes Committed: modified: interface/resources/qml/dialogs/TabletFileDialog.qml --- interface/resources/qml/dialogs/TabletFileDialog.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index 9e1d0a9f5a..d3b738469e 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -484,9 +484,9 @@ TabletModalWindow { model: filesModel function updateSort() { - model.sortOrder = sortIndicatorOrder; - model.sortColumn = sortIndicatorColumn; - model.update(); + fileTableModel.sortOrder = sortIndicatorOrder; + fileTableModel.sortColumn = sortIndicatorColumn; + fileTableModel.update(); } onSortIndicatorColumnChanged: { updateSort(); } From 688ee68cf9309a8c8733450e9ed5969f3906d9a3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 13 Sep 2017 21:38:54 -0700 Subject: [PATCH 09/23] Ensure thread-safety for model pointer access --- .../src/RenderableModelEntityItem.cpp | 201 ++++++++++-------- .../src/RenderableModelEntityItem.h | 21 +- 2 files changed, 131 insertions(+), 91 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c6bad008e4..2508b598af 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -36,6 +36,29 @@ static CollisionRenderMeshCache collisionMeshCache; +void ModelEntityWrapper::setModel(const ModelPointer& model) { + withWriteLock([&] { + if (_model != model) { + _model = model; + if (_model) { + _needsInitialSimulation = true; + } + } + }); +} + +ModelPointer ModelEntityWrapper::getModel() const { + return resultWithReadLock([&] { + return _model; + }); +} + +bool ModelEntityWrapper::isModelLoaded() const { + return resultWithReadLock([&] { + return _model.operator bool() && _model->isLoaded(); + }); +} + EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) }; entity->setProperties(properties); @@ -43,7 +66,7 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI } RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) : - ModelEntityItem(entityItemID), + ModelEntityWrapper(entityItemID), _dimensionsInitialized(dimensionsInitialized) { } @@ -83,41 +106,47 @@ QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextu } void RenderableModelEntityItem::doInitialModelSimulation() { + ModelPointer model = getModel(); + if (!model) { + return; + } // The machinery for updateModelBounds will give existing models the opportunity to fix their // translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to // make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the // entity values to change -- it just allows the model to match once it comes in. - _model->setScaleToFit(false, getDimensions()); - _model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); + model->setScaleToFit(false, getDimensions()); + model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); // now recalculate the bounds and registration - _model->setScaleToFit(true, getDimensions()); - _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); - _model->setRotation(getRotation()); - _model->setTranslation(getPosition()); + model->setScaleToFit(true, getDimensions()); + model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); + model->setRotation(getRotation()); + model->setTranslation(getPosition()); { - PerformanceTimer perfTimer("_model->simulate"); - _model->simulate(0.0f); + PerformanceTimer perfTimer("model->simulate"); + model->simulate(0.0f); } _needsInitialSimulation = false; } void RenderableModelEntityItem::autoResizeJointArrays() { - if (_model && _model->isLoaded() && !_needsInitialSimulation) { - resizeJointArrays(_model->getJointStateCount()); + ModelPointer model = getModel(); + if (model && model->isLoaded() && !_needsInitialSimulation) { + resizeJointArrays(model->getJointStateCount()); } } bool RenderableModelEntityItem::needsUpdateModelBounds() const { - if (!hasModel() || !_model) { + ModelPointer model = getModel(); + if (!hasModel() || !model) { return false; } - if (!_dimensionsInitialized || !_model->isActive()) { + if (!_dimensionsInitialized || !model->isActive()) { return false; } - if (_model->needsReload()) { + if (model->needsReload()) { return true; } @@ -129,21 +158,21 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const { return true; } - if (_model->getScaleToFitDimensions() != getDimensions()) { + if (model->getScaleToFitDimensions() != getDimensions()) { return true; } - if (_model->getRegistrationPoint() != getRegistrationPoint()) { + if (model->getRegistrationPoint() != getRegistrationPoint()) { return true; } bool success; auto transform = getTransform(success); if (success) { - if (_model->getTranslation() != transform.getTranslation()) { + if (model->getTranslation() != transform.getTranslation()) { return true; } - if (_model->getRotation() != transform.getRotation()) { + if (model->getRotation() != transform.getRotation()) { return true; } } @@ -158,16 +187,6 @@ void RenderableModelEntityItem::updateModelBounds() { } } -void RenderableModelEntityItem::setModel(const ModelPointer& model) { - withWriteLock([&] { - if (_model != model) { - _model = model; - if (_model) { - _needsInitialSimulation = true; - } - } - }); -} EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties); // get the properties from our base class @@ -175,43 +194,44 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag properties.setTextureNames(_originalTextures); } - if (_model) { - properties.setRenderInfoVertexCount(_model->getRenderInfoVertexCount()); - properties.setRenderInfoTextureCount(_model->getRenderInfoTextureCount()); - properties.setRenderInfoTextureSize(_model->getRenderInfoTextureSize()); - properties.setRenderInfoDrawCalls(_model->getRenderInfoDrawCalls()); - properties.setRenderInfoHasTransparent(_model->getRenderInfoHasTransparent()); + ModelPointer model = getModel(); + if (model) { + properties.setRenderInfoVertexCount(model->getRenderInfoVertexCount()); + properties.setRenderInfoTextureCount(model->getRenderInfoTextureCount()); + properties.setRenderInfoTextureSize(model->getRenderInfoTextureSize()); + properties.setRenderInfoDrawCalls(model->getRenderInfoDrawCalls()); + properties.setRenderInfoHasTransparent(model->getRenderInfoHasTransparent()); + + if (model->isLoaded()) { + // TODO: improve naturalDimensions in the future, + // for now we've added this hack for setting natural dimensions of models + Extents meshExtents = model->getFBXGeometry().getUnscaledMeshExtents(); + properties.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum); + properties.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum); + } } - if (_model && _model->isLoaded()) { - // TODO: improve naturalDimensions in the future, - // for now we've added this hack for setting natural dimensions of models - Extents meshExtents = _model->getFBXGeometry().getUnscaledMeshExtents(); - properties.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum); - properties.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum); - } return properties; } bool RenderableModelEntityItem::supportsDetailedRayIntersection() const { - return resultWithReadLock([&] { - return _model && _model->isLoaded(); - }); + return isModelLoaded(); } bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { - if (!_model) { + auto model = getModel(); + if (!model) { return true; } // qCDebug(entitiesrenderer) << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:" // << precisionPicking; QString extraInfo; - return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, + return model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo, precisionPicking, false); } @@ -242,7 +262,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { // parse it twice. auto currentCompoundShapeURL = getCompoundShapeURL(); ModelEntityItem::setCompoundShapeURL(url); - if (getCompoundShapeURL() != currentCompoundShapeURL || !_model) { + if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) { if (getShapeType() == SHAPE_TYPE_COMPOUND) { getCollisionGeometryResource(); } @@ -252,17 +272,18 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { bool RenderableModelEntityItem::isReadyToComputeShape() const { ShapeType type = getShapeType(); + auto model = getModel(); if (type == SHAPE_TYPE_COMPOUND) { - if (!_model || getCompoundShapeURL().isEmpty()) { + if (!model || getCompoundShapeURL().isEmpty()) { return false; } - if (_model->getURL().isEmpty()) { + if (model->getURL().isEmpty()) { // we need a render geometry with a scale to proceed, so give up. return false; } - if (_model->isLoaded()) { + if (model->isLoaded()) { if (!getCompoundShapeURL().isEmpty() && !_compoundShapeResource) { const_cast(this)->getCollisionGeometryResource(); } @@ -281,7 +302,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() const { // the model is still being downloaded. return false; } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { - return (_model && _model->isLoaded()); + return isModelLoaded(); } return true; } @@ -292,6 +313,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { ShapeType type = getShapeType(); glm::vec3 dimensions = getDimensions(); + auto model = getModel(); if (type == SHAPE_TYPE_COMPOUND) { updateModelBounds(); @@ -373,14 +395,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { // to the visual model and apply them to the collision model (without regard for the // collision model's extents). - glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().getUnscaledMeshExtents().size(); + glm::vec3 scaleToFit = dimensions / model->getFBXGeometry().getUnscaledMeshExtents().size(); // multiply each point by scale before handing the point-set off to the physics engine. // also determine the extents of the collision model. glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); for (int32_t i = 0; i < pointCollection.size(); i++) { for (int32_t j = 0; j < pointCollection[i].size(); j++) { // back compensate for registration so we can apply that offset to the shapeInfo later - pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + _model->getOffset()) - registrationOffset; + pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + model->getOffset()) - registrationOffset; } } shapeInfo.setParams(type, dimensions, getCompoundShapeURL()); @@ -389,11 +411,11 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { assert(_model && _model->isLoaded()); updateModelBounds(); - _model->updateGeometry(); + model->updateGeometry(); // compute meshPart local transforms QVector localTransforms; - const FBXGeometry& fbxGeometry = _model->getFBXGeometry(); + const FBXGeometry& fbxGeometry = model->getFBXGeometry(); int numFbxMeshes = fbxGeometry.meshes.size(); int totalNumVertices = 0; glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT)); @@ -401,7 +423,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { const FBXMesh& mesh = fbxGeometry.meshes.at(i); if (mesh.clusters.size() > 0) { const FBXCluster& cluster = mesh.clusters.at(0); - auto jointMatrix = _model->getRig().getJointTransform(cluster.jointIndex); + auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex); // we backtranslate by the registration offset so we can apply that offset to the shapeInfo later localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix); } else { @@ -417,7 +439,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { return; } - auto& meshes = _model->getGeometry()->getMeshes(); + auto& meshes = model->getGeometry()->getMeshes(); int32_t numMeshes = (int32_t)(meshes.size()); const int MAX_ALLOWED_MESH_COUNT = 1000; @@ -631,7 +653,8 @@ void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { - if (EntityItem::contains(point) && _model && _compoundShapeResource && _compoundShapeResource->isLoaded()) { + auto model = getModel(); + if (EntityItem::contains(point) && model && _compoundShapeResource && _compoundShapeResource->isLoaded()) { return _compoundShapeResource->getFBXGeometry().convexHullContains(worldToEntity(point)); } @@ -639,11 +662,12 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { } bool RenderableModelEntityItem::shouldBePhysical() const { + auto model = getModel(); // If we have a model, make sure it hasn't failed to download. // If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready. - if (_model && getShapeType() == SHAPE_TYPE_COMPOUND && _model->didCollisionGeometryRequestFail()) { + if (model && getShapeType() == SHAPE_TYPE_COMPOUND && model->didCollisionGeometryRequestFail()) { return false; - } else if (_model && getShapeType() != SHAPE_TYPE_NONE && _model->didVisualGeometryRequestFail()) { + } else if (model && getShapeType() != SHAPE_TYPE_NONE && model->didVisualGeometryRequestFail()) { return false; } else { return ModelEntityItem::shouldBePhysical(); @@ -651,9 +675,10 @@ bool RenderableModelEntityItem::shouldBePhysical() const { } glm::quat RenderableModelEntityItem::getAbsoluteJointRotationInObjectFrame(int index) const { - if (_model) { + auto model = getModel(); + if (model) { glm::quat result; - if (_model->getAbsoluteJointRotationInRigFrame(index, result)) { + if (model->getAbsoluteJointRotationInRigFrame(index, result)) { return result; } } @@ -661,9 +686,10 @@ glm::quat RenderableModelEntityItem::getAbsoluteJointRotationInObjectFrame(int i } glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(int index) const { - if (_model) { + auto model = getModel(); + if (model) { glm::vec3 result; - if (_model->getAbsoluteJointTranslationInRigFrame(index, result)) { + if (model->getAbsoluteJointTranslationInRigFrame(index, result)) { return result; } } @@ -671,10 +697,11 @@ glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(in } bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { - if (!_model) { + auto model = getModel(); + if (!model) { return false; } - const Rig& rig = _model->getRig(); + const Rig& rig = model->getRig(); int jointParentIndex = rig.getJointParentIndex(index); if (jointParentIndex == -1) { return setLocalJointRotation(index, rotation); @@ -700,10 +727,11 @@ bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, } bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) { - if (!_model) { + auto model = getModel(); + if (!model) { return false; } - const Rig& rig = _model->getRig(); + const Rig& rig = model->getRig(); int jointParentIndex = rig.getJointParentIndex(index); if (jointParentIndex == -1) { @@ -730,9 +758,10 @@ bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int ind } glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const { - if (_model) { + auto model = getModel(); + if (model) { glm::quat result; - if (_model->getJointRotation(index, result)) { + if (model->getJointRotation(index, result)) { return result; } } @@ -740,9 +769,10 @@ glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const { } glm::vec3 RenderableModelEntityItem::getLocalJointTranslation(int index) const { - if (_model) { + auto model = getModel(); + if (model) { glm::vec3 result; - if (_model->getJointTranslation(index, result)) { + if (model->getJointTranslation(index, result)) { return result; } } @@ -810,19 +840,22 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector& tra void RenderableModelEntityItem::locationChanged(bool tellPhysics) { PerformanceTimer pertTimer("locationChanged"); EntityItem::locationChanged(tellPhysics); - if (_model && _model->isLoaded()) { - _model->updateRenderItems(); + auto model = getModel(); + if (model && model->isLoaded()) { + model->updateRenderItems(); } } int RenderableModelEntityItem::getJointIndex(const QString& name) const { - return (_model && _model->isActive()) ? _model->getRig().indexOfJoint(name) : -1; + auto model = getModel(); + return (model && model->isActive()) ? model->getRig().indexOfJoint(name) : -1; } QStringList RenderableModelEntityItem::getJointNames() const { QStringList result; - if (_model && _model->isActive()) { - const Rig& rig = _model->getRig(); + auto model = getModel(); + if (model && model->isActive()) { + const Rig& rig = model->getRig(); int jointCount = rig.getJointStateCount(); for (int jointIndex = 0; jointIndex < jointCount; jointIndex++) { result << rig.nameOfJoint(jointIndex); @@ -832,19 +865,16 @@ QStringList RenderableModelEntityItem::getJointNames() const { } bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) { - if (!_model || !_model->isLoaded()) { + auto model = getModel(); + if (!model || !model->isLoaded()) { return false; } - BLOCKING_INVOKE_METHOD(_model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result)); + BLOCKING_INVOKE_METHOD(model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result)); return !result.isEmpty(); } void RenderableModelEntityItem::copyAnimationJointDataToModel() { - ModelPointer model; - withReadLock([&] { - model = _model; - }); - + auto model = getModel(); if (!model || !model->isLoaded()) { return; } @@ -859,7 +889,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() { jointData.rotationDirty = false; } if (jointData.translationDirty) { - _model->setJointTranslation(index, true, jointData.joint.translation, 1.0f); + model->setJointTranslation(index, true, jointData.joint.translation, 1.0f); jointData.translationDirty = false; } } @@ -1192,7 +1222,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce // When the individual mesh parts of a model finish fading, they will mark their Model as needing updating // we will watch for that and ask the model to update it's render items if (model->getRenderItemsNeedUpdate()) { - qDebug() << "QQQ" << __FUNCTION__ << "Update model render items" << model->getURL(); model->updateRenderItems(); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index d8ecbeb282..b9c751761d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -34,10 +34,24 @@ class ModelEntityRenderer; } } //#define MODEL_ENTITY_USE_FADE_EFFECT - -class RenderableModelEntityItem : public ModelEntityItem { +class ModelEntityWrapper : public ModelEntityItem { + using Parent = ModelEntityItem; friend class render::entities::ModelEntityRenderer; +protected: + ModelEntityWrapper(const EntityItemID& entityItemID) : Parent(entityItemID) {} + void setModel(const ModelPointer& model); + ModelPointer getModel() const; + bool isModelLoaded() const; + + bool _needsInitialSimulation{ true }; +private: + ModelPointer _model; +}; + +class RenderableModelEntityItem : public ModelEntityWrapper { + friend class render::entities::ModelEntityRenderer; + using Parent = ModelEntityWrapper; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -97,14 +111,11 @@ private: bool isAnimatingSomething() const; void autoResizeJointArrays(); void copyAnimationJointDataToModel(); - void setModel(const ModelPointer& model); void getCollisionGeometryResource(); GeometryResource::Pointer _compoundShapeResource; bool _originalTexturesRead { false }; QVariantMap _originalTextures; - ModelPointer _model; - bool _needsInitialSimulation { true }; bool _dimensionsInitialized { true }; bool _needsJointSimulation { false }; bool _showCollisionGeometry { false }; From af4bc593076f00c57ee1683dd87af4e9c9661478 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 14 Sep 2017 23:31:51 +0200 Subject: [PATCH 10/23] clone local avatar entities --- scripts/system/html/entityProperties.html | 16 +++++--- scripts/system/html/js/entityProperties.js | 40 +++++++++++++------- scripts/system/libraries/cloneEntityUtils.js | 4 +- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 42a938e78d..43cd281bbd 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -1,4 +1,4 @@ -