diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 42924a8487..73444d1198 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -64,6 +64,7 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::get()->setPacketSender(&_entityEditSender); DependencyManager::set(); + DependencyManager::set(); DependencyManager::registerInheritance(); @@ -833,6 +834,8 @@ void Agent::aboutToFinish() { DependencyManager::get()->cleanup(); + DependencyManager::destroy(); + // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 34eb138697..d56b22466e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -65,7 +65,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : // hash the available codecs (on the mixer) _availableCodecs.clear(); // Make sure struct is clean - auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); + auto pluginManager = DependencyManager::set(); + auto codecPlugins = pluginManager->getCodecPlugins(); std::for_each(codecPlugins.cbegin(), codecPlugins.cend(), [&](const CodecPluginPointer& codec) { _availableCodecs[codec->getName()] = codec; @@ -106,6 +107,10 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); } +void AudioMixer::aboutToFinish() { + DependencyManager::destroy(); +} + void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { if (message->getType() == PacketType::SilentAudioFrame) { _numSilentPackets++; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 8c47893aa3..f9eb18da6d 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -58,6 +58,9 @@ public: to.getPublicSocket() != from.getPublicSocket() && to.getLocalSocket() != from.getLocalSocket(); } + + virtual void aboutToFinish() override; + public slots: void run() override; void sendStatsPacket() override; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index eea8e8b470..607ab28b20 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -58,6 +58,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::get()->setPacketSender(&_entityEditSender); DependencyManager::set(); + DependencyManager::set(); DependencyManager::registerInheritance(); @@ -572,6 +573,8 @@ void EntityScriptServer::aboutToFinish() { DependencyManager::get()->cleanup(); + DependencyManager::destroy(); + // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 41ca5762dc..069fc12fc5 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -22,7 +22,7 @@ macro(optional_win_executable_signing) # setup a post build command to sign the executable add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${SIGNTOOL_EXECUTABLE} sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH} + COMMAND ${SIGNTOOL_EXECUTABLE} sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 ${EXECUTABLE_PATH} ) else () message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 64e3fbe889..c51e4ffd72 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -130,7 +130,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 !endif ; Good. Now we can carry on writing the real installer. diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml index 38e65af4ca..bf7807c85d 100644 --- a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -135,6 +135,8 @@ Item { placeholderText: qsTr("Password") echoMode: TextInput.Password + + Keys.onReturnPressed: linkAccountBody.login() } } diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 6cbd1c4837..814778a4b1 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -177,6 +177,8 @@ Item { root.text = ""; root.isPassword = true; } + + Keys.onReturnPressed: linkAccountBody.login() } CheckBox { diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index 5eb99e0ece..bb30696e4c 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -164,6 +164,8 @@ Item { root.text = ""; root.isPassword = focus } + + Keys.onReturnPressed: signupBody.signup() } Row { diff --git a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml index 731acc7e5b..126e62fc30 100644 --- a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml @@ -56,8 +56,8 @@ Preference { id: slider value: preference.value width: 100 - minimumValue: MyAvatar.getDomainMinScale() - maximumValue: MyAvatar.getDomainMaxScale() + minimumValue: preference.min + maximumValue: preference.max stepSize: preference.step onValueChanged: { spinner.realValue = value @@ -74,8 +74,8 @@ Preference { id: spinner decimals: preference.decimals realValue: preference.value - minimumValue: MyAvatar.getDomainMinScale() - maximumValue: MyAvatar.getDomainMaxScale() + minimumValue: preference.min + maximumValue: preference.max width: 100 onValueChanged: { slider.value = realValue; diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index ba50b7f238..cc1ba49984 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -129,12 +129,10 @@ Rectangle { id: stereoMic spacing: muteMic.spacing; text: qsTr("Enable stereo input"); - checked: AudioScriptingInterface.isStereoInput(); + checked: AudioScriptingInterface.isStereoInput; onClicked: { - var success = AudioScriptingInterface.setStereoInput(checked); - if (!success) { - checked = !checked; - } + AudioScriptingInterface.isStereoInput = checked; + checked = Qt.binding(function() { return AudioScriptingInterface.isStereoInput; }); // restore binding } } } diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 16c1b55930..653d814020 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -92,9 +92,9 @@ Rectangle { onBuyResult: { if (result.status !== 'success') { - failureErrorText.text = result.message; + failureErrorText.text = result.data.message; root.activeView = "checkoutFailure"; - UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); + UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.data.message); } else { root.certificateId = result.data.certificate_id; root.itemHref = result.data.download_url; diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index cb4913f999..861de001d8 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -17,7 +17,7 @@ PreferencesDialog { id: root objectName: "GeneralPreferencesDialog" title: "General Settings" - showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"] + showCategories: ["User Interface", "Mouse Sensitivity", "HMD", "Snapshots", "Privacy"] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml index 63801019b9..4f1100f20b 100644 --- a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml @@ -32,6 +32,6 @@ StackView { TabletPreferencesDialog { id: root objectName: "TabletGeneralPreferences" - showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"] + showCategories: ["User Interface", "Mouse Sensitivity", "HMD", "Snapshots", "Privacy"] } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fba64e1e00..92300df406 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -270,9 +270,6 @@ public: } _renderContext->doneCurrent(); - // Deleting the object with automatically shutdown the thread - connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); - // Transfer to a new thread moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) { hifi::qt::addBlockingForbiddenThread("Render", renderThread); @@ -815,6 +812,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { } // Tell the plugin manager about our statically linked plugins + DependencyManager::set(); auto pluginManager = PluginManager::getInstance(); pluginManager->setInputPluginProvider([] { return getInputPlugins(); }); pluginManager->setDisplayPluginProvider([] { return getDisplayPlugins(); }); @@ -1379,6 +1377,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo initializeRenderEngine(); qCDebug(interfaceapp, "Initialized Render Engine."); + // Overlays need to exist before we set the ContextOverlayInterface dependency + _overlays.init(); // do this before scripts load + DependencyManager::set(); + // Initialize the user interface and menu system // Needs to happen AFTER the render engine initialization to access its configuration initializeUi(); @@ -1515,10 +1517,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // allow you to move an entity around in your hand _entityEditSender.setPacketsPerSecond(3000); // super high!! - // Overlays need to exist before we set the ContextOverlayInterface dependency - _overlays.init(); // do this before scripts load - DependencyManager::set(); - // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -2556,25 +2554,28 @@ Application::~Application() { _octreeProcessor.terminate(); _entityEditSender.terminate(); + if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { + steamClient->shutdown(); + } + DependencyManager::destroy(); + + DependencyManager::destroy(); // must be destroyed before the FramebufferCache + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); - DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::get()->cleanup(); // remove the NodeList from the DependencyManager DependencyManager::destroy(); - if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { - steamClient->shutdown(); - } - #if 0 ConnexionClient::getInstance().destroy(); #endif @@ -2594,6 +2595,8 @@ Application::~Application() { // Can't log to file passed this point, FileLogger about to be deleted qInstallMessageHandler(LogHandler::verboseMessageHandler); + + _renderEventHandler->deleteLater(); } void Application::initializeGL() { @@ -2720,7 +2723,7 @@ void Application::initializeDisplayPlugins() { setDisplayPlugin(defaultDisplayPlugin); // Now set the desired plugin if it's not the same as the default plugin - if (targetDisplayPlugin != defaultDisplayPlugin) { + if (!targetDisplayPlugin && (targetDisplayPlugin != defaultDisplayPlugin)) { setDisplayPlugin(targetDisplayPlugin); } @@ -2894,6 +2897,7 @@ void Application::initializeUi() { auto compositorHelper = DependencyManager::get(); connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { if (isHMDMode()) { + auto compositorHelper = DependencyManager::get(); // don't capture outer smartpointer showCursor(compositorHelper->getAllowMouseCapture() ? Cursor::Manager::lookupIcon(_preferredCursor.get()) : Cursor::Icon::SYSTEM); diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp index 2daa49dcf7..6b4840e3e5 100644 --- a/interface/src/Application_render.cpp +++ b/interface/src/Application_render.cpp @@ -139,7 +139,10 @@ void Application::paintGL() { frame->frameIndex = _renderFrameCount; frame->framebuffer = finalFramebuffer; frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) { - DependencyManager::get()->releaseFramebuffer(framebuffer); + auto frameBufferCache = DependencyManager::get(); + if (frameBufferCache) { + frameBufferCache->releaseFramebuffer(framebuffer); + } }; // deliver final scene rendering commands to the display plugin { diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index c63095a204..8a25c21946 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -36,13 +36,13 @@ #include #include #include -#include #include #include "Application.h" #include "InterfaceLogging.h" #include "Menu.h" #include "MyAvatar.h" +#include "OtherAvatar.h" #include "SceneScriptingInterface.h" // 50 times per second - target is 45hz, but this helps account for any small deviations @@ -192,6 +192,15 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { while (!sortedAvatars.empty()) { const SortableAvatar& sortData = sortedAvatars.top(); const auto avatar = std::static_pointer_cast(sortData.getAvatar()); + const auto otherAvatar = std::static_pointer_cast(sortData.getAvatar()); + + // if the geometry is loaded then turn off the orb + if (avatar->getSkeletonModel()->isLoaded()) { + // remove the orb if it is there + otherAvatar->removeOrb(); + } else { + otherAvatar->updateOrbPosition(); + } bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); if (ignoring) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0b5b62f91f..ed7ce87db2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1098,7 +1098,6 @@ void MyAvatar::saveData() { settings.setValue("displayName", _displayName); settings.setValue("collisionSoundURL", _collisionSoundURL); settings.setValue("useSnapTurn", _useSnapTurn); - settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving); settings.setValue("userHeight", getUserHeight()); settings.setValue("enabledFlying", getFlyingEnabled()); @@ -1254,7 +1253,6 @@ void MyAvatar::loadData() { setDisplayName(settings.value("displayName").toString()); setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString()); setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool()); - setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool()); setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower()); setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble()); settings.endGroup(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3589ccf0af..a3b07d400f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -250,7 +250,7 @@ public: Q_ENUM(DriveKeys) explicit MyAvatar(QThread* thread); - ~MyAvatar(); + virtual ~MyAvatar(); void instantiableAvatar() override {}; void registerMetaTypes(ScriptEnginePointer engine); @@ -469,16 +469,6 @@ public: * @param {boolean} on */ Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; } - /**jsdoc - * @function MyAvatar.getClearOverlayWhenMoving - * @returns {boolean} - */ - Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; } - /**jsdoc - * @function MyAvatar.setClearOverlayWhenMoving - * @param {boolean} on - */ - Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; } /**jsdoc @@ -1496,7 +1486,6 @@ private: ThreadSafeValueCache _prefOverrideAnimGraphUrl; QUrl _fstAnimGraphOverrideUrl; bool _useSnapTurn { true }; - bool _clearOverlayWhenMoving { true }; QString _dominantHand { DOMINANT_RIGHT_HAND }; const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // degrees diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp new file mode 100644 index 0000000000..5e51658128 --- /dev/null +++ b/interface/src/avatar/OtherAvatar.cpp @@ -0,0 +1,60 @@ +// +// Created by Bradley Austin Davis on 2017/04/27 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "OtherAvatar.h" +#include "Application.h" + +OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) { + // give the pointer to our head to inherited _headData variable from AvatarData + _headData = new Head(this); + _skeletonModel = std::make_shared(this, nullptr); + _skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY); + connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished); + connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); + connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset); + + // add the purple orb + createOrb(); +} + +OtherAvatar::~OtherAvatar() { + removeOrb(); +} + +void OtherAvatar::removeOrb() { + if (qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) { + qApp->getOverlays().deleteOverlay(_otherAvatarOrbMeshPlaceholderID); + } +} + +void OtherAvatar::updateOrbPosition() { + if (_otherAvatarOrbMeshPlaceholder != nullptr) { + _otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition()); + } +} + +void OtherAvatar::createOrb() { + if (_otherAvatarOrbMeshPlaceholderID == UNKNOWN_OVERLAY_ID || + !qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) { + _otherAvatarOrbMeshPlaceholder = std::make_shared(); + _otherAvatarOrbMeshPlaceholder->setAlpha(1.0f); + _otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF }); + _otherAvatarOrbMeshPlaceholder->setIsSolid(false); + _otherAvatarOrbMeshPlaceholder->setPulseMin(0.5); + _otherAvatarOrbMeshPlaceholder->setPulseMax(1.0); + _otherAvatarOrbMeshPlaceholder->setColorPulse(1.0); + _otherAvatarOrbMeshPlaceholder->setIgnoreRayIntersection(true); + _otherAvatarOrbMeshPlaceholder->setDrawInFront(false); + _otherAvatarOrbMeshPlaceholderID = qApp->getOverlays().addOverlay(_otherAvatarOrbMeshPlaceholder); + // Position focus + _otherAvatarOrbMeshPlaceholder->setWorldOrientation(glm::quat(0.0f, 0.0f, 0.0f, 1.0)); + _otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition()); + _otherAvatarOrbMeshPlaceholder->setDimensions(glm::vec3(0.5f, 0.5f, 0.5f)); + _otherAvatarOrbMeshPlaceholder->setVisible(true); + } +} diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h new file mode 100644 index 0000000000..f33952b78b --- /dev/null +++ b/interface/src/avatar/OtherAvatar.h @@ -0,0 +1,32 @@ +// +// Created by Bradley Austin Davis on 2017/04/27 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OtherAvatar_h +#define hifi_OtherAvatar_h + +#include +#include "ui/overlays/Overlays.h" +#include "ui/overlays/Sphere3DOverlay.h" +#include "InterfaceLogging.h" + +class OtherAvatar : public Avatar { +public: + explicit OtherAvatar(QThread* thread); + virtual ~OtherAvatar(); + + virtual void instantiableAvatar() override { }; + virtual void createOrb() override; + void updateOrbPosition(); + void removeOrb(); + +protected: + std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; + OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; +}; + +#endif // hifi_OtherAvatar_h diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp index 2f14c33dc7..afafe1a350 100644 --- a/interface/src/scripting/SettingsScriptingInterface.cpp +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -35,5 +35,8 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar } void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) { - Setting::Handle(setting).set(value); + // Make a deep-copy of the string. + // Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine. + QString deepCopy = QString::fromUtf16(setting.utf16()); + Setting::Handle(deepCopy).set(value); } diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index d131bb3467..e27001567f 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -88,38 +88,24 @@ void OverlayConductor::update(float dt) { _hmdMode = false; } - bool isAtRest = updateAvatarIsAtRest(); - bool isMoving = !isAtRest; - bool shouldRecenter = false; - if (_flags & SuppressedByMove) { - if (!isMoving) { - _flags &= ~SuppressedByMove; - shouldRecenter = true; - } - } else { - if (myAvatar->getClearOverlayWhenMoving() && isMoving) { - _flags |= SuppressedByMove; - } - } - - if (_flags & SuppressedByHead) { - if (isAtRest) { - _flags &= ~SuppressedByHead; + if (_suppressedByHead) { + if (updateAvatarIsAtRest()) { + _suppressedByHead = false; shouldRecenter = true; } } else { if (_hmdMode && headOutsideOverlay()) { - _flags |= SuppressedByHead; + _suppressedByHead = true; } } - bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && (0 == (_flags & SuppressMask)); + bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && !_suppressedByHead; if (targetVisible != currentVisible) { offscreenUi->setPinned(!targetVisible); } - if (shouldRecenter && !_flags) { + if (shouldRecenter && !_suppressedByHead) { centerUI(); } } diff --git a/interface/src/ui/OverlayConductor.h b/interface/src/ui/OverlayConductor.h index cf69c32fc5..b47e23d28a 100644 --- a/interface/src/ui/OverlayConductor.h +++ b/interface/src/ui/OverlayConductor.h @@ -25,13 +25,7 @@ private: bool headOutsideOverlay() const; bool updateAvatarIsAtRest(); - enum SupressionFlags { - SuppressedByMove = 0x01, - SuppressedByHead = 0x02, - SuppressMask = 0x03, - }; - - uint8_t _flags { SuppressedByMove }; + bool _suppressedByHead { false }; bool _hmdMode { false }; // used by updateAvatarIsAtRest diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 3d3c432e92..9712f0688a 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -161,12 +161,6 @@ void setupPreferences() { preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter)); } - { - auto getter = [=]()->bool { return myAvatar->getClearOverlayWhenMoving(); }; - auto setter = [=](bool value) { myAvatar->setClearOverlayWhenMoving(value); }; - preferences->addPreference(new CheckPreference(UI_CATEGORY, "Clear overlays when moving", getter, setter)); - } - static const QString VIEW_CATEGORY{ "View" }; { auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); }; @@ -233,6 +227,8 @@ void setupPreferences() { auto getter = [=]()->float { return myAvatar->getTargetScale(); }; auto setter = [=](float value) { myAvatar->setTargetScale(value); }; auto preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter); + preference->setMin(0.25); + preference->setMax(4); preference->setStep(0.05f); preference->setDecimals(2); preferences->addPreference(preference); @@ -309,17 +305,21 @@ void setupPreferences() { { auto getter = [=]()->float { return myAvatar->getPitchSpeed(); }; auto setter = [=](float value) { myAvatar->setPitchSpeed(value); }; - auto preference = new SpinnerPreference(AVATAR_CAMERA, "Pitch speed (degrees/second)", getter, setter); + auto preference = new SpinnerSliderPreference(AVATAR_CAMERA, "Y input:", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); + preference->setStep(1); + preference->setDecimals(1); preferences->addPreference(preference); } { auto getter = [=]()->float { return myAvatar->getYawSpeed(); }; auto setter = [=](float value) { myAvatar->setYawSpeed(value); }; - auto preference = new SpinnerPreference(AVATAR_CAMERA, "Yaw speed (degrees/second)", getter, setter); + auto preference = new SpinnerSliderPreference(AVATAR_CAMERA, "X input:", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); + preference->setStep(1); + preference->setDecimals(1); preferences->addPreference(preference); } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a5f79290cd..a6f0416a30 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1426,6 +1426,8 @@ bool AudioClient::setIsStereoInput(bool isStereoInput) { // restart the input device switchInputToAudioDevice(_inputDeviceInfo); + + emit isStereoInputChanged(_isStereoInput); } return stereoInputChanged; @@ -1463,6 +1465,8 @@ void AudioClient::outputFormatChanged() { } bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) { + Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread"); + qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << inputDeviceInfo.deviceName() << "]"; bool supportedFormat = false; @@ -1663,6 +1667,8 @@ void AudioClient::outputNotify() { } bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) { + Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread"); + qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]"; bool supportedFormat = false; @@ -2021,7 +2027,7 @@ void AudioClient::setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 sca void AudioClient::startThread() { - moveToNewNamedThread(this, "Audio Thread", [this] { start(); }); + moveToNewNamedThread(this, "Audio Thread", [this] { start(); }, QThread::TimeCriticalPriority); } void AudioClient::setInputVolume(float volume, bool emitSignal) { diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 30cbceeb0e..bbfd79d0aa 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -44,6 +44,9 @@ public slots: virtual bool setIsStereoInput(bool stereo) = 0; virtual bool isStereoInput() = 0; + +signals: + void isStereoInputChanged(bool isStereo); }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index a99838d810..843235c0e1 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1338,6 +1338,9 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { } void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { + if (!isMyAvatar()) { + createOrb(); + } AvatarData::setSkeletonModelURL(skeletonModelURL); if (QThread::currentThread() == thread()) { _skeletonModel->setURL(_skeletonModelURL); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 98246330c4..bb9d6d8cc9 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -23,7 +23,6 @@ #include #include - #include "Head.h" #include "SkeletonModel.h" #include "Rig.h" @@ -41,7 +40,6 @@ static const float SCALING_RATIO = .05f; extern const float CHAT_MESSAGE_SCALE; extern const float CHAT_MESSAGE_HEIGHT; - enum ScreenTintLayer { SCREEN_TINT_BEFORE_LANDSCAPE = 0, SCREEN_TINT_BEFORE_AVATARS, @@ -69,7 +67,7 @@ public: static void setShowNamesAboveHeads(bool show); explicit Avatar(QThread* thread); - ~Avatar(); + virtual ~Avatar(); virtual void instantiableAvatar() = 0; @@ -109,6 +107,7 @@ public: float getLODDistance() const; virtual bool isMyAvatar() const override { return false; } + virtual void createOrb() { } virtual QVector getJointRotations() const override; using AvatarData::getJointRotation; @@ -167,8 +166,8 @@ public: virtual int parseDataFromBuffer(const QByteArray& buffer) override; - static void renderJointConnectingCone( gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2, - float radius1, float radius2, const glm::vec4& color); + static void renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2, + float radius1, float radius2, const glm::vec4& color); virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { } @@ -235,7 +234,7 @@ public: /// Scales a world space position vector relative to the avatar position and scale /// \param vector position to be scaled. Will store the result - void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; + void scaleVectorRelativeToPosition(glm::vec3& positionToScale) const; void slamPosition(const glm::vec3& position); virtual void updateAttitude(const glm::quat& orientation) override; @@ -254,7 +253,6 @@ public: void setPositionViaScript(const glm::vec3& position) override; void setOrientationViaScript(const glm::quat& orientation) override; - /**jsdoc * @function MyAvatar.getParentID * @returns {Uuid} @@ -283,7 +281,6 @@ public: // This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript. Q_INVOKABLE virtual void setParentJointIndex(quint16 parentJointIndex) override; - /**jsdoc * Returns an array of joints, where each joint is an object containing name, index, and parentIndex fields. * @function MyAvatar.getSkeleton @@ -349,7 +346,6 @@ public: // not all subclasses of AvatarData have access to this data. virtual bool canMeasureEyeHeight() const override { return true; } - virtual float getModelScale() const { return _modelScale; } virtual void setModelScale(float scale) { _modelScale = scale; } virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getModelScale()); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.cpp deleted file mode 100644 index 7678c03276..0000000000 --- a/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by Bradley Austin Davis on 2017/04/27 -// Copyright 2013-2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "OtherAvatar.h" - -OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) { - // give the pointer to our head to inherited _headData variable from AvatarData - _headData = new Head(this); - _skeletonModel = std::make_shared(this, nullptr); - _skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY); - connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished); - connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); - connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset); -} diff --git a/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h b/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h deleted file mode 100644 index df09d7fd99..0000000000 --- a/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Created by Bradley Austin Davis on 2017/04/27 -// Copyright 2013-2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_OtherAvatar_h -#define hifi_OtherAvatar_h - -#include "Avatar.h" - -class OtherAvatar : public Avatar { -public: - explicit OtherAvatar(QThread* thread); - virtual void instantiableAvatar() override {}; -}; - -#endif // hifi_OtherAvatar_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 378ce541d7..09d9823728 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1269,6 +1269,8 @@ bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& poin EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; + // There is no entity + return false; } EntityTypes::EntityType entityType = entity->getType(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a58f01a83b..0315ba7186 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2521,6 +2521,13 @@ bool EntityTree::readFromMap(QVariantMap& map) { } } + // Zero out the spread values that were fixed in version ParticleEntityFix so they behave the same as before + if (contentVersion < (int)EntityVersion::ParticleEntityFix) { + properties.setRadiusSpread(0.0f); + properties.setAlphaSpread(0.0f); + properties.setColorSpread({0, 0, 0}); + } + EntityItemPointer entity = addEntity(entityItemID, properties); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp index 91f1d8bb8c..b75f89f7ae 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp @@ -203,10 +203,11 @@ void GLBackend::releaseResourceTexture(uint32_t slot) { } void GLBackend::resetResourceStage() { - for (uint32_t i = 0; i < _resource._buffers.size(); i++) { + uint32_t i; + for (i = 0; i < _resource._buffers.size(); i++) { releaseResourceBuffer(i); } - for (uint32_t i = 0; i < _resource._textures.size(); i++) { + for (i = 0; i < _resource._textures.size(); i++) { releaseResourceTexture(i); } } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTexture.cpp index e11f8f01c7..e9494a1271 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTexture.cpp @@ -59,7 +59,11 @@ const size_t GLVariableAllocationSupport::MAX_BUFFER_SIZE = MAX_TRANSFER_SIZE; GLenum GLTexture::getGLTextureType(const Texture& texture) { switch (texture.getType()) { case Texture::TEX_2D: - return GL_TEXTURE_2D; + if (!texture.isArray()) { + return GL_TEXTURE_2D; + } else { + return GL_TEXTURE_2D_ARRAY; + } break; case Texture::TEX_CUBE: @@ -77,6 +81,7 @@ GLenum GLTexture::getGLTextureType(const Texture& texture) { uint8_t GLTexture::getFaceCount(GLenum target) { switch (target) { case GL_TEXTURE_2D: + case GL_TEXTURE_2D_ARRAY: return TEXTURE_2D_NUM_FACES; case GL_TEXTURE_CUBE_MAP: return TEXTURE_CUBE_NUM_FACES; @@ -86,17 +91,22 @@ uint8_t GLTexture::getFaceCount(GLenum target) { } } const std::vector& GLTexture::getFaceTargets(GLenum target) { - static std::vector cubeFaceTargets { + static const std::vector cubeFaceTargets { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - static std::vector faceTargets { + static const std::vector faceTargets { GL_TEXTURE_2D }; + static const std::vector arrayFaceTargets{ + GL_TEXTURE_2D_ARRAY + }; switch (target) { case GL_TEXTURE_2D: return faceTargets; + case GL_TEXTURE_2D_ARRAY: + return arrayFaceTargets; case GL_TEXTURE_CUBE_MAP: return cubeFaceTargets; default: diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendOutput.cpp index a5ef2d92e1..1d512103bd 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendOutput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendOutput.cpp @@ -64,7 +64,12 @@ public: } if (gltexture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + if (gltexture->_target == GL_TEXTURE_2D) { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + } else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, colorAttachments[unit], gltexture->_texture, 0, + b._subresource); + } _colorBuffers.push_back(colorAttachments[unit]); } else { glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0); @@ -91,7 +96,12 @@ public: } if (gltexture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); + if (gltexture->_target == GL_TEXTURE_2D) { + glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); + } else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachement, gltexture->_texture, 0, + _gpuObject.getDepthStencilBufferSubresource()); + } } else { glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0); } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index a255cc5878..97b1a96a1d 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -182,7 +182,7 @@ void GL41Texture::syncSampler() const { glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); if (sampler.doComparison()) { - glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameteri(_target, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); } else { glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); @@ -197,7 +197,7 @@ void GL41Texture::syncSampler() const { glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); - glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY, sampler.getMaxAnisotropy()); } using GL41FixedAllocationTexture = GL41Backend::GL41FixedAllocationTexture; @@ -215,12 +215,19 @@ GL41FixedAllocationTexture::~GL41FixedAllocationTexture() { void GL41FixedAllocationTexture::allocateStorage() const { const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); const auto numMips = _gpuObject.getNumMips(); + const auto numSlices = _gpuObject.getNumSlices(); // glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); for (GLint level = 0; level < numMips; level++) { Vec3u dimensions = _gpuObject.evalMipDimensions(level); for (GLenum target : getFaceTargets(_target)) { - glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr); + if (!_gpuObject.isArray()) { + glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, + texelFormat.type, nullptr); + } else { + glTexImage3D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices, 0, + texelFormat.format, texelFormat.type, nullptr); + } } } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp index ca53d6c624..86332558e3 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp @@ -60,7 +60,11 @@ public: } if (gltexture) { - glNamedFramebufferTexture(_id, colorAttachments[unit], gltexture->_texture, 0); + if (gltexture->_target == GL_TEXTURE_2D) { + glNamedFramebufferTexture(_id, colorAttachments[unit], gltexture->_texture, 0); + } else { + glNamedFramebufferTextureLayer(_id, colorAttachments[unit], gltexture->_texture, 0, b._subresource); + } _colorBuffers.push_back(colorAttachments[unit]); } else { glNamedFramebufferTexture(_id, colorAttachments[unit], 0, 0); @@ -87,14 +91,18 @@ public: } if (gltexture) { - glNamedFramebufferTexture(_id, attachement, gltexture->_texture, 0); + if (gltexture->_target == GL_TEXTURE_2D) { + glNamedFramebufferTexture(_id, attachement, gltexture->_texture, 0); + } else { + glNamedFramebufferTextureLayer(_id, attachement, gltexture->_texture, 0, + _gpuObject.getDepthStencilBufferSubresource()); + } } else { glNamedFramebufferTexture(_id, attachement, 0, 0); } _depthStamp = _gpuObject.getDepthStamp(); } - // Last but not least, define where we draw if (!_colorBuffers.empty()) { glNamedFramebufferDrawBuffers(_id, (GLsizei)_colorBuffers.size(), _colorBuffers.data()); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index fda7ac22dd..e02f12819e 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -152,7 +152,7 @@ public: glSamplerParameteri(result, GL_TEXTURE_MIN_FILTER, fm.minFilter); glSamplerParameteri(result, GL_TEXTURE_MAG_FILTER, fm.magFilter); if (sampler.doComparison()) { - glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glSamplerParameteri(result, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); } else { glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_NONE); @@ -341,7 +341,7 @@ void GL45Texture::syncSampler() const { glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); if (sampler.doComparison()) { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); } else { glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); @@ -374,8 +374,13 @@ void GL45FixedAllocationTexture::allocateStorage() const { const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); const auto dimensions = _gpuObject.getDimensions(); const auto mips = _gpuObject.getNumMips(); + const auto numSlices = _gpuObject.getNumSlices(); - glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); + if (!_gpuObject.isArray()) { + glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); + } else { + glTextureStorage3D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices); + } glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, mips - 1); diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp index 0bf1548a4b..9c3a83ce13 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp @@ -64,7 +64,12 @@ public: } if (gltexture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + if (gltexture->_target == GL_TEXTURE_2D) { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + } else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, colorAttachments[unit], gltexture->_texture, 0, + b._subresource); + } _colorBuffers.push_back(colorAttachments[unit]); } else { glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0); @@ -91,7 +96,12 @@ public: } if (gltexture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); + if (gltexture->_target == GL_TEXTURE_2D) { + glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); + } else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachement, gltexture->_texture, 0, + _gpuObject.getDepthStencilBufferSubresource()); + } } else { glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0); } diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp index bbc02c2af6..911dfb8bb8 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp @@ -268,16 +268,27 @@ GLsizei getCompressedImageSize(int width, int height, GLenum internalFormat) { void GLESFixedAllocationTexture::allocateStorage() const { const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); const auto numMips = _gpuObject.getNumMips(); + const auto numSlices = _gpuObject.getNumSlices(); // glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); for (GLint level = 0; level < numMips; level++) { Vec3u dimensions = _gpuObject.evalMipDimensions(level); for (GLenum target : getFaceTargets(_target)) { if (texelFormat.isCompressed()) { - glCompressedTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, - getCompressedImageSize(dimensions.x, dimensions.y, texelFormat.internalFormat), nullptr); + auto size = getCompressedImageSize(dimensions.x, dimensions.y, texelFormat.internalFormat); + if (!_gpuObject.isArray()) { + glCompressedTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, size, nullptr); + } else { + glCompressedTexImage3D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices, 0, size * numSlices, nullptr); + } } else { - glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr); + if (!_gpuObject.isArray()) { + glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, + texelFormat.type, nullptr); + } else { + glTexImage3D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices, 0, + texelFormat.format, texelFormat.type, nullptr); + } } } } diff --git a/libraries/gpu/src/gpu/Frame.cpp b/libraries/gpu/src/gpu/Frame.cpp index d08a8ab56d..f1001d97d2 100644 --- a/libraries/gpu/src/gpu/Frame.cpp +++ b/libraries/gpu/src/gpu/Frame.cpp @@ -21,10 +21,7 @@ Frame::~Frame() { framebuffer.reset(); } - assert(bufferUpdates.empty()); - if (!bufferUpdates.empty()) { - qFatal("Buffer sync error... frame destroyed without buffer updates being applied"); - } + bufferUpdates.clear(); } void Frame::finish() { diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index a92243f808..34262b0cd9 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -184,6 +184,10 @@ TexturePointer Texture::createRenderBuffer(const Element& texelFormat, uint16 wi return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler); } +TexturePointer Texture::createRenderBufferArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips, const Sampler& sampler) { + return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, numSlices, numMips, sampler); +} + TexturePointer Texture::create1D(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) { return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, numMips, sampler); } @@ -192,6 +196,10 @@ TexturePointer Texture::create2D(const Element& texelFormat, uint16 width, uint1 return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler); } +TexturePointer Texture::create2DArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips, const Sampler& sampler) { + return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, numSlices, numMips, sampler); +} + TexturePointer Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) { return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler); } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 09b2bc9475..9ad5dc0816 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -374,9 +374,11 @@ public: static const uint16 SINGLE_MIP = 1; static TexturePointer create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); + static TexturePointer create2DArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler()); static TexturePointer createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); + static TexturePointer createRenderBufferArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler()); diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 0d4abe78d3..1b7b552078 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -515,7 +515,7 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) { header.getPixelHeight(), header.getPixelDepth(), 1, // num Samples - header.getNumberOfSlices(), + header.isArray() ? header.getNumberOfSlices() : 0, header.getNumberOfLevels(), samplerDesc); texture->setUsage(gpuktxKeyValue._usage); diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 54a8188a42..d755a482e3 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -163,6 +163,7 @@ namespace ktx { uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); } uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); } uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); } + bool isArray() const { return numberOfArrayElements > 0; } bool isCompressed() const { return glFormat == COMPRESSED_FORMAT; } uint32_t evalMaxDimension() const; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 6df15129a2..553f0d0a61 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -39,8 +39,13 @@ ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(at } ResourceManager::~ResourceManager() { - _thread.terminate(); - _thread.wait(); + if (_thread.isRunning()) { + _thread.quit(); + static const auto MAX_RESOURCE_MANAGER_THREAD_QUITTING_TIME = MSECS_PER_SECOND / 2; + if (!_thread.wait(MAX_RESOURCE_MANAGER_THREAD_QUITTING_TIME)) { + _thread.terminate(); + } + } } void ResourceManager::setUrlPrefixOverride(const QString& prefix, const QString& replacement) { diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index c1fe6ccd85..0bc86a28ad 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -239,7 +239,7 @@ void Connection::sync() { sendACK(); } - if (_lossList.getLength() > 0) { + if (_congestionControl->shouldNAK() && _lossList.getLength() > 0) { // check if we need to re-transmit a loss list // we do this if it has been longer than the current nakInterval since we last sent auto now = p_high_resolution_clock::now(); @@ -271,10 +271,13 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { SequenceNumber nextACKNumber = nextACK(); Q_ASSERT_X(nextACKNumber >= _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong"); - - if (nextACKNumber == _lastSentACK) { - // We already sent this ACK, but check if we should re-send it. - if (nextACKNumber < _lastReceivedAcknowledgedACK) { + + // if our congestion control doesn't want to send an ACK for every packet received + // check if we already sent this ACK + if (_congestionControl->_ackInterval > 1 && nextACKNumber == _lastSentACK) { + + // if we use ACK2s, check if the receiving side already confirmed receipt of this ACK + if (_congestionControl->shouldACK2() && nextACKNumber < _lastReceivedAcknowledgedACK) { // we already got an ACK2 for this ACK we would be sending, don't bother return; } @@ -287,11 +290,11 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } } // we have received new packets since the last sent ACK + // or our congestion control dictates that we always send ACKs // update the last sent ACK _lastSentACK = nextACKNumber; - _ackPacket->reset(); // We need to reset it every time. // pack in the ACK sub-sequence number @@ -448,20 +451,22 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in // mark our last receive time as now (to push the potential expiry farther) _lastReceiveTime = p_high_resolution_clock::now(); - - // check if this is a packet pair we should estimate bandwidth from, or just a regular packet - if (((uint32_t) sequenceNumber & 0xF) == 0) { - _receiveWindow.onProbePair1Arrival(); - } else if (((uint32_t) sequenceNumber & 0xF) == 1) { - // only use this packet for bandwidth estimation if we didn't just receive a control packet in its place - if (!_receivedControlProbeTail) { - _receiveWindow.onProbePair2Arrival(); - } else { - // reset our control probe tail marker so the next probe that comes with data can be used - _receivedControlProbeTail = false; + + if (_congestionControl->shouldProbe()) { + // check if this is a packet pair we should estimate bandwidth from, or just a regular packet + if (((uint32_t) sequenceNumber & 0xF) == 0) { + _receiveWindow.onProbePair1Arrival(); + } else if (((uint32_t) sequenceNumber & 0xF) == 1) { + // only use this packet for bandwidth estimation if we didn't just receive a control packet in its place + if (!_receivedControlProbeTail) { + _receiveWindow.onProbePair2Arrival(); + } else { + // reset our control probe tail marker so the next probe that comes with data can be used + _receivedControlProbeTail = false; + } } - } + _receiveWindow.onPacketArrival(); // If this is not the next sequence number, report loss diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index e9c084e132..94ce16cf00 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -40,9 +40,8 @@ void PluginManager::setInputPluginSettingsPersister(const InputPluginSettingsPer _inputSettingsPersister = persister; } -PluginManager* PluginManager::getInstance() { - static PluginManager _manager; - return &_manager; +PluginManagerPointer PluginManager::getInstance() { + return DependencyManager::get(); } QString getPluginNameFromMetaData(QJsonObject object) { @@ -136,9 +135,6 @@ const LoaderList& getLoadedPlugins() { return loadedPlugins; } -PluginManager::PluginManager() { -} - const CodecPluginList& PluginManager::getCodecPlugins() { static CodecPluginList codecPlugins; static std::once_flag once; diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index f16ad7d09f..65a4012aed 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -9,12 +9,19 @@ #include +#include + #include "Forward.h" -class PluginManager : public QObject { + +class PluginManager; +using PluginManagerPointer = QSharedPointer; + +class PluginManager : public QObject, public Dependency { + SINGLETON_DEPENDENCY + public: - static PluginManager* getInstance(); - PluginManager(); + static PluginManagerPointer getInstance(); const DisplayPluginList& getDisplayPlugins(); const InputPluginList& getInputPlugins(); @@ -39,6 +46,8 @@ public: void setInputPluginSettingsPersister(const InputPluginSettingsPersister& persister); private: + PluginManager() = default; + DisplayPluginProvider _displayPluginProvider { []()->DisplayPluginList { return {}; } }; InputPluginProvider _inputPluginProvider { []()->InputPluginList { return {}; } }; CodecPluginProvider _codecPluginProvider { []()->CodecPluginList { return {}; } }; diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index 4f612588ce..ea6f1ce324 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -66,7 +66,7 @@ OffscreenSurface::OffscreenSurface() } OffscreenSurface::~OffscreenSurface() { - delete _sharedObject; + _sharedObject->deleteLater(); } bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) { diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index c17044be6d..8575df399e 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -60,7 +60,8 @@ enum TextureSlot { enum ParamSlot { CameraCorrection = 0, DeferredFrameTransform, - ShadowTransform + ShadowTransform, + DebugParametersBuffer }; static const std::string DEFAULT_ALBEDO_SHADER { @@ -139,12 +140,11 @@ static const std::string DEFAULT_LIGHTING_SHADER { " }" }; -static const std::string DEFAULT_SHADOW_SHADER{ - "uniform sampler2DShadow shadowMap;" +static const std::string DEFAULT_SHADOW_DEPTH_SHADER{ "vec4 getFragmentColor() {" " for (int i = 255; i >= 0; --i) {" " float depth = i / 255.0;" - " if (texture(shadowMap, vec3(uv, depth)) > 0.5) {" + " if (texture(shadowMaps, vec4(uv, parameters._shadowCascadeIndex, depth)) > 0.5) {" " return vec4(vec3(depth), 1.0);" " }" " }" @@ -323,7 +323,7 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust case ShadowCascade1Mode: case ShadowCascade2Mode: case ShadowCascade3Mode: - return DEFAULT_SHADOW_SHADER; + return DEFAULT_SHADOW_DEPTH_SHADER; case ShadowCascadeIndicesMode: return DEFAULT_SHADOW_CASCADE_SHADER; case LinearDepthMode: @@ -396,6 +396,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str slotBindings.insert(gpu::Shader::Binding("cameraCorrectionBuffer", CameraCorrection)); slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", DeferredFrameTransform)); slotBindings.insert(gpu::Shader::Binding("shadowTransformBuffer", ShadowTransform)); + slotBindings.insert(gpu::Shader::Binding("parametersBuffer", DebugParametersBuffer)); slotBindings.insert(gpu::Shader::Binding("albedoMap", Albedo)); slotBindings.insert(gpu::Shader::Binding("normalMap", Normal)); @@ -403,7 +404,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); slotBindings.insert(gpu::Shader::Binding("obscuranceMap", AmbientOcclusion)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); - slotBindings.insert(gpu::Shader::Binding("shadowMap", Shadow)); + slotBindings.insert(gpu::Shader::Binding("shadowMaps", Shadow)); slotBindings.insert(gpu::Shader::Binding("linearDepthMap", LinearDepth)); slotBindings.insert(gpu::Shader::Binding("halfLinearDepthMap", HalfLinearDepth)); slotBindings.insert(gpu::Shader::Binding("halfNormalMap", HalfNormal)); @@ -432,8 +433,11 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str } void DebugDeferredBuffer::configure(const Config& config) { + auto& parameters = _parameters.edit(); + _mode = (Mode)config.mode; _size = config.size; + parameters._shadowCascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)SHADOW_CASCADE_MAX_COUNT - 1); } void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const Inputs& inputs) { @@ -483,14 +487,15 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I batch.setResourceTexture(Velocity, velocityFramebuffer->getVelocityTexture()); } + batch.setUniformBuffer(DebugParametersBuffer, _parameters); + auto lightStage = renderContext->_scene->getStage(); assert(lightStage); assert(lightStage->getNumLights() > 0); auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; if (globalShadow) { - const auto cascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)globalShadow->getCascadeCount() - 1); - batch.setResourceTexture(Shadow, globalShadow->getCascade(cascadeIndex).map); + batch.setResourceTexture(Shadow, globalShadow->map); batch.setUniformBuffer(ShadowTransform, globalShadow->getBuffer()); batch.setUniformBuffer(DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 5384a77b76..9daa8fd530 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -30,7 +30,7 @@ public: DebugDeferredBufferConfig() : render::Job::Config(false) {} void setMode(int newMode); - + int mode{ 0 }; glm::vec4 size{ 0.0f, -1.0f, 1.0f, 1.0f }; signals: @@ -39,20 +39,26 @@ signals: class DebugDeferredBuffer { public: - using Inputs = render::VaryingSet6; + using Inputs = render::VaryingSet6; using Config = DebugDeferredBufferConfig; using JobModel = render::Job::ModelI; - + DebugDeferredBuffer(); ~DebugDeferredBuffer(); void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); - + protected: friend class DebugDeferredBufferConfig; - enum Mode : uint8_t { + enum Mode : uint8_t + { // Use Mode suffix to avoid collisions Off = 0, DepthMode, @@ -83,7 +89,7 @@ protected: AmbientOcclusionMode, AmbientOcclusionBlurredMode, VelocityMode, - CustomMode, // Needs to stay last + CustomMode, // Needs to stay last NumModes, }; @@ -92,20 +98,25 @@ private: Mode _mode{ Off }; glm::vec4 _size; +#include "debug_deferred_buffer_shared.slh" + + using ParametersBuffer = gpu::StructBuffer; + struct CustomPipeline { gpu::PipelinePointer pipeline; mutable QFileInfo info; }; using StandardPipelines = std::array; using CustomPipelines = std::unordered_map; - + bool pipelineNeedsUpdate(Mode mode, std::string customFile = std::string()) const; const gpu::PipelinePointer& getPipeline(Mode mode, std::string customFile = std::string()); std::string getShaderSourceCode(Mode mode, std::string customFile = std::string()); - + + ParametersBuffer _parameters; StandardPipelines _pipelines; CustomPipelines _customPipelines; - int _geometryId { 0 }; + int _geometryId{ 0 }; }; -#endif // hifi_DebugDeferredBuffer_h \ No newline at end of file +#endif // hifi_DebugDeferredBuffer_h \ No newline at end of file diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 9223e0fa03..452e5b5ccd 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -68,7 +68,7 @@ enum DeferredShader_MapSlot { SCATTERING_SPECULAR_UNIT = 9, SKYBOX_MAP_UNIT = render::ShapePipeline::Slot::LIGHT_AMBIENT_MAP, // unit = 10 SHADOW_MAP_UNIT = 11, - nextAvailableUnit = SHADOW_MAP_UNIT + SHADOW_CASCADE_MAX_COUNT + nextAvailableUnit = SHADOW_MAP_UNIT }; enum DeferredShader_BufferSlot { DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0, @@ -534,9 +534,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Bind the shadow buffers if (globalShadow) { - for (unsigned int i = 0; i < globalShadow->getCascadeCount(); i++) { - batch.setResourceTexture(SHADOW_MAP_UNIT+i, globalShadow->getCascade(i).map); - } + batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map); } auto program = deferredLightingEffect->_directionalSkyboxLight; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index ceac4ae3c8..369c62c197 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -74,8 +74,6 @@ LightStage::Shadow::Cascade::Cascade() : _frustum{ std::make_shared() }, _minDistance{ 0.0f }, _maxDistance{ 20.0f } { - framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); - map = framebuffer->getDepthStencilBuffer(); } const glm::mat4& LightStage::Shadow::Cascade::getView() const { @@ -127,8 +125,29 @@ LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsi Schema schema; schema.cascadeCount = cascadeCount; _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); + + // Create shadow cascade texture array + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format + map = gpu::TexturePointer(gpu::Texture::createRenderBufferArray(depthFormat, MAP_SIZE, MAP_SIZE, cascadeCount)); + gpu::Sampler::Desc samplerDesc; + samplerDesc._borderColor = glm::vec4(1.0f); + samplerDesc._wrapModeU = gpu::Sampler::WRAP_BORDER; + samplerDesc._wrapModeV = gpu::Sampler::WRAP_BORDER; + samplerDesc._filter = gpu::Sampler::FILTER_MIN_MAG_LINEAR; + samplerDesc._comparisonFunc = gpu::LESS; + + map->setSampler(gpu::Sampler(samplerDesc)); + _cascades.resize(cascadeCount); + for (uint cascadeIndex=0; cascadeIndex < cascadeCount; cascadeIndex++) { + auto& cascade = _cascades[cascadeIndex]; + std::string name = "Shadowmap Cascade "; + name += '0' + cascadeIndex; + cascade.framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name)); + cascade.framebuffer->setDepthBuffer(map, depthFormat, cascadeIndex); + } + setMaxDistance(maxDistance); } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 9812426fa6..b8a49d81bb 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -53,7 +53,6 @@ public: Cascade(); gpu::FramebufferPointer framebuffer; - gpu::TexturePointer map; const std::shared_ptr& getFrustum() const { return _frustum; } @@ -93,6 +92,8 @@ public: const graphics::LightPointer& getLight() const { return _light; } + gpu::TexturePointer map; + protected: #include "Shadows_shared.slh" diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 63d07af1c2..24715f0afb 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -60,7 +60,7 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs& if (_opaquePass) { gpu::doInBatch("DrawOverlay3D::run::clear", args->_context, [&](gpu::Batch& batch){ batch.enableStereo(false); - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTHSTENCIL, glm::vec4(), 1.f, 0, false); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, false); }); } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index fbb4bba263..91eb777199 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -227,7 +227,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende } const auto setupOutput = task.addJob("ShadowSetup"); - const auto queryResolution = setupOutput.getN(2); + const auto queryResolution = setupOutput.getN(1); // Fetch and cull the items from the scene static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); @@ -248,10 +248,12 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto sortedShapes = task.addJob("DepthSortShadow", sortedPipelines, true); render::Varying cascadeFrustums[SHADOW_CASCADE_MAX_COUNT] = { - ViewFrustumPointer(), - ViewFrustumPointer(), + ViewFrustumPointer() +#if SHADOW_CASCADE_MAX_COUNT>1 + ,ViewFrustumPointer(), ViewFrustumPointer(), ViewFrustumPointer() +#endif }; for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { @@ -293,13 +295,15 @@ RenderShadowSetup::RenderShadowSetup() : void RenderShadowSetup::configure(const Config& configuration) { setConstantBias(0, configuration.constantBias0); - setConstantBias(1, configuration.constantBias1); - setConstantBias(2, configuration.constantBias2); - setConstantBias(3, configuration.constantBias3); setSlopeBias(0, configuration.slopeBias0); +#if SHADOW_CASCADE_MAX_COUNT>1 + setConstantBias(1, configuration.constantBias1); setSlopeBias(1, configuration.slopeBias1); + setConstantBias(2, configuration.constantBias2); setSlopeBias(2, configuration.slopeBias2); + setConstantBias(3, configuration.constantBias3); setSlopeBias(3, configuration.slopeBias3); +#endif } void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) { diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 36eb35c757..235ea519ab 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -17,11 +17,11 @@ #define SHADOW_SCREEN_SPACE_DITHER 1 // the shadow texture -uniform sampler2DShadow shadowMaps[SHADOW_CASCADE_MAX_COUNT]; +uniform sampler2DArrayShadow shadowMaps; // Sample the shadowMap with PCF (built-in) float fetchShadow(int cascadeIndex, vec3 shadowTexcoord) { - return texture(shadowMaps[cascadeIndex], shadowTexcoord); + return texture(shadowMaps, vec4(shadowTexcoord.xy, cascadeIndex, shadowTexcoord.z)); } vec2 PCFkernel[4] = vec2[4]( diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index fded04ca87..5f974acfeb 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -23,11 +23,18 @@ uniform sampler2D occlusionMap; uniform sampler2D occlusionBlurredMap; uniform sampler2D scatteringMap; uniform sampler2D velocityMap; +uniform sampler2DArrayShadow shadowMaps; <@include ShadowCore.slh@> <$declareDeferredCurvature()$> +<@include debug_deferred_buffer_shared.slh@> + +layout(std140) uniform parametersBuffer { + DebugParameters parameters; +}; + float curvatureAO(float k) { return 1.0f - (0.0022f * k * k) + (0.0776f * k) + 0.7369f; } diff --git a/libraries/render-utils/src/debug_deferred_buffer_shared.slh b/libraries/render-utils/src/debug_deferred_buffer_shared.slh new file mode 100644 index 0000000000..2d11a66d61 --- /dev/null +++ b/libraries/render-utils/src/debug_deferred_buffer_shared.slh @@ -0,0 +1,17 @@ +// glsl / C++ compatible source as interface for FadeEffect +#ifdef __cplusplus +# define INT32 glm::int32 +#else +# define INT32 int +#endif + +struct DebugParameters +{ + INT32 _shadowCascadeIndex; +}; + + // <@if 1@> + // Trigger Scribe include + // <@endif@> +// + diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 3f55e6dedc..8cfe7683ce 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -370,10 +370,13 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input const auto& inShapes = inputs.get0(); const auto& cullFilter = inputs.get1(); const auto& boundsFilter = inputs.get2(); - const auto& antiFrustum = inputs.get3(); + ViewFrustumPointer antiFrustum; auto& outShapes = outputs.edit0(); auto& outBounds = outputs.edit1(); + if (!inputs[3].isNull()) { + antiFrustum = inputs.get3(); + } outShapes.clear(); outBounds = AABox(); diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index f248c20d41..be419e8005 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -23,6 +23,21 @@ void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); } + +void AudioScriptingInterface::setLocalAudioInterface(AbstractAudioInterface* audioInterface) { + if (_localAudioInterface) { + disconnect(_localAudioInterface, &AbstractAudioInterface::isStereoInputChanged, + this, &AudioScriptingInterface::isStereoInputChanged); + } + + _localAudioInterface = audioInterface; + + if (_localAudioInterface) { + connect(_localAudioInterface, &AbstractAudioInterface::isStereoInputChanged, + this, &AudioScriptingInterface::isStereoInputChanged); + } +} + ScriptAudioInjector* AudioScriptingInterface::playSystemSound(SharedSoundPointer sound, const QVector3D& position) { AudioInjectorOptions options; options.position = glm::vec3(position.x(), position.y(), position.z()); @@ -61,11 +76,10 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound } bool AudioScriptingInterface::setStereoInput(bool stereo) { - bool stereoInputChanged = false; if (_localAudioInterface) { - stereoInputChanged = _localAudioInterface->setIsStereoInput(stereo); + QMetaObject::invokeMethod(_localAudioInterface, "setIsStereoInput", Q_ARG(bool, stereo)); } - return stereoInputChanged; + return true; } bool AudioScriptingInterface::isStereoInput() { diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 36fe29243d..843fa3e8f0 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -23,9 +23,11 @@ class AudioScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY + Q_PROPERTY(bool isStereoInput READ isStereoInput WRITE setStereoInput NOTIFY isStereoInputChanged) + public: virtual ~AudioScriptingInterface() {} - void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } + void setLocalAudioInterface(AbstractAudioInterface* audioInterface); protected: AudioScriptingInterface() {} @@ -52,7 +54,7 @@ protected: /**jsdoc * @function Audio.setStereoInput * @param {boolean} stereo - * @returns {boolean} + * @returns {boolean} */ Q_INVOKABLE bool setStereoInput(bool stereo); @@ -114,6 +116,13 @@ signals: */ void inputReceived(const QByteArray& inputSamples); + /**jsdoc + * @function Audio.isStereoInputChanged + * @param {boolean} isStereo + * @returns {Signal} + */ + void isStereoInputChanged(bool isStereo); + private: AbstractAudioInterface* _localAudioInterface { nullptr }; }; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index f8c99b192f..99c02ba1f6 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1639,22 +1639,24 @@ QVariantMap ScriptEngine::fetchModuleSource(const QString& modulePath, const boo loader->start(MAX_RETRIES); if (!loader->isFinished()) { - QTimer monitor; - QEventLoop loop; - QObject::connect(loader, &BatchLoader::finished, this, [&monitor, &loop]{ - monitor.stop(); - loop.quit(); + // This lambda can get called AFTER this local scope has completed. + // This is why we pass smart ptrs to the lambda instead of references to local variables. + auto monitor = std::make_shared(); + auto loop = std::make_shared(); + QObject::connect(loader, &BatchLoader::finished, this, [monitor, loop] { + monitor->stop(); + loop->quit(); }); // this helps detect the case where stop() is invoked during the download // but not seen in time to abort processing in onload()... - connect(&monitor, &QTimer::timeout, this, [this, &loop]{ + connect(monitor.get(), &QTimer::timeout, this, [this, loop] { if (isStopping()) { - loop.exit(-1); + loop->exit(-1); } }); - monitor.start(500); - loop.exec(); + monitor->start(500); + loop->exec(); } loader->deleteLater(); return req; diff --git a/libraries/workload/src/workload/Space.cpp b/libraries/workload/src/workload/Space.cpp index 27a8639f3a..54fad79741 100644 --- a/libraries/workload/src/workload/Space.cpp +++ b/libraries/workload/src/workload/Space.cpp @@ -44,6 +44,11 @@ void Space::processResets(const Transaction::Resets& transactions) { for (auto& reset : transactions) { // Access the true item auto proxyID = std::get<0>(reset); + + // Guard against proxyID being past the end of the list. + if (proxyID < 0 || proxyID >= (int32_t)_proxies.size() || proxyID >= (int32_t)_owners.size()) { + continue; + } auto& item = _proxies[proxyID]; // Reset the item with a new payload diff --git a/scripts/system/edit.js b/scripts/system/edit.js index e9c7a49378..08e7a541d5 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -2373,7 +2373,6 @@ function selectParticleEntity(entityID) { particleExplorerTool.createWebView(); particleExplorerTool.setActiveParticleEntity(entityID); - particleExplorerTool.setActiveParticleProperties(properties); // Switch to particle explorer var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); diff --git a/scripts/system/emote.js b/scripts/system/emote.js index b99972253f..d484078b7b 100644 --- a/scripts/system/emote.js +++ b/scripts/system/emote.js @@ -101,6 +101,7 @@ function onWebEventReceived(event) { // If user provides input during a sit, the avatar animation state should be restored Controller.keyPressEvent.connect(restoreAnimation); + Controller.enableMapping(eventMappingName); MyAvatar.overrideAnimation(ANIMATIONS[emoteName].url, FPS, false, 0, frameCount); } else { @@ -132,6 +133,7 @@ function restoreAnimation() { // Make sure the input is disconnected after animations are restored so it doesn't affect any emotes other than sit Controller.keyPressEvent.disconnect(restoreAnimation); + Controller.disableMapping(eventMappingName); } // Note peek() so as to not interfere with other mappings. @@ -151,7 +153,7 @@ eventMapping.from(Controller.Standard.RS).peek().to(restoreAnimation); eventMapping.from(Controller.Standard.RightGrip).peek().to(restoreAnimation); eventMapping.from(Controller.Standard.Back).peek().to(restoreAnimation); eventMapping.from(Controller.Standard.Start).peek().to(restoreAnimation); -Controller.enableMapping(eventMappingName); + button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 3fda7588df..06ad7d3e03 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -99,12 +99,17 @@ EntityListTool = function(opts) { url: url, locked: properties.locked, visible: properties.visible, - verticesCount: valueIfDefined(properties.renderInfo.verticesCount), - texturesCount: valueIfDefined(properties.renderInfo.texturesCount), - texturesSize: valueIfDefined(properties.renderInfo.texturesSize), - hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent), + verticesCount: (properties.renderInfo !== undefined ? + valueIfDefined(properties.renderInfo.verticesCount) : ""), + texturesCount: (properties.renderInfo !== undefined ? + valueIfDefined(properties.renderInfo.texturesCount) : ""), + texturesSize: (properties.renderInfo !== undefined ? + valueIfDefined(properties.renderInfo.texturesSize) : ""), + hasTransparent: (properties.renderInfo !== undefined ? + valueIfDefined(properties.renderInfo.hasTransparent) : ""), isBaked: properties.type == "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false, - drawCalls: valueIfDefined(properties.renderInfo.drawCalls), + drawCalls: (properties.renderInfo !== undefined ? + valueIfDefined(properties.renderInfo.drawCalls) : ""), hasScript: properties.script !== "" }); } diff --git a/scripts/system/particle_explorer/hifi-entity-ui.js b/scripts/system/particle_explorer/hifi-entity-ui.js index 36505a0b7f..62a0aadc86 100644 --- a/scripts/system/particle_explorer/hifi-entity-ui.js +++ b/scripts/system/particle_explorer/hifi-entity-ui.js @@ -61,12 +61,18 @@ function HifiEntityUI(parent) { this.parent = parent; var self = this; + this.sendPackage = {}; this.settingsUpdateLock = false; - this.webBridgeSync = _.debounce(function (id, val) { - if (self.EventBridge && !self.settingsUpdateLock) { - var sendPackage = {}; - sendPackage[id] = val; - self.submitChanges(sendPackage); + this.webBridgeSync = function(id, val) { + if (!this.settingsUpdateLock) { + this.sendPackage[id] = val; + this.webBridgeSyncDebounce(); + } + }; + this.webBridgeSyncDebounce = _.debounce(function () { + if (self.EventBridge) { + self.submitChanges(self.sendPackage); + self.sendPackage = {}; } }, DEBOUNCE_TIMEOUT); } @@ -159,7 +165,6 @@ HifiEntityUI.prototype = { var self = this; var fields = document.getElementsByTagName("input"); - self.settingsUpdateLock = true; if (!currentProperties.locked) { for (var i = 0; i < fields.length; i++) { fields[i].removeAttribute("disabled"); @@ -179,7 +184,7 @@ HifiEntityUI.prototype = { for (var e in keys) { if (keys.hasOwnProperty(e)) { var value = keys[e]; - + var property = currentProperties[value]; var field = self.builtRows[value]; if (field) { @@ -235,10 +240,6 @@ HifiEntityUI.prototype = { } } } - // Now unlocking settings Update lock for sending messages on callbacks. - setTimeout(function () { - self.settingsUpdateLock = false; - }, DEBOUNCE_TIMEOUT * 2.5); }, connect: function (EventBridge) { this.EventBridge = EventBridge; @@ -253,28 +254,9 @@ HifiEntityUI.prototype = { data = JSON.parse(data); if (data.messageType === 'particle_settings') { - // Update settings - var currentProperties = data.currentProperties; - // Update uninitialized variables - if (!currentProperties.alphaStart) { - currentProperties.alphaStart = currentProperties.alpha; - } - if (!currentProperties.alphaFinish) { - currentProperties.alphaFinish = currentProperties.alpha; - } - if (!currentProperties.radiusStart) { - currentProperties.radiusStart = currentProperties.particleRadius; - } - if (!currentProperties.radiusFinish) { - currentProperties.radiusFinish = currentProperties.particleRadius; - } - if (!currentProperties.colorStart || !currentProperties.colorStart.red) { - currentProperties.colorStart = currentProperties.color; - } - if (!currentProperties.colorFinish || !currentProperties.colorFinish.red) { - currentProperties.colorFinish = currentProperties.color; - } - self.fillFields(currentProperties); + self.settingsUpdateLock = true; + self.fillFields(data.currentProperties); + self.settingsUpdateLock = false; // Do expected property match with structure; } else if (data.messageType === 'particle_close') { self.disableFields(); diff --git a/scripts/system/particle_explorer/particleExplorerTool.js b/scripts/system/particle_explorer/particleExplorerTool.js index a1f06fda35..80256a12e3 100644 --- a/scripts/system/particle_explorer/particleExplorerTool.js +++ b/scripts/system/particle_explorer/particleExplorerTool.js @@ -9,7 +9,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global window, alert, ParticleExplorerTool, EventBridge, dat, listenForSettingsUpdates,createVec3Folder,createQuatFolder,writeVec3ToInterface,writeDataToInterface*/ +/* global window, alert, ParticleExplorerTool, EventBridge, dat, listenForSettingsUpdates, createVec3Folder, + createQuatFolder, writeVec3ToInterface, writeDataToInterface */ var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html'); @@ -17,7 +18,7 @@ var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html'); ParticleExplorerTool = function() { var that = {}; that.activeParticleEntity = 0; - that.activeParticleProperties = {}; + that.updatedActiveParticleProperties = {}; that.createWebView = function() { that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); @@ -30,7 +31,7 @@ ParticleExplorerTool = function() { return; } that.activeParticleEntity = 0; - that.activeParticleProperties = {}; + that.updatedActiveParticleProperties = {}; var messageData = { messageType: "particle_close" @@ -38,46 +39,86 @@ ParticleExplorerTool = function() { that.webView.emitScriptEvent(JSON.stringify(messageData)); }; - function sendActiveParticleProperties() { + function sendParticleProperties(properties) { that.webView.emitScriptEvent(JSON.stringify({ messageType: "particle_settings", - currentProperties: that.activeParticleProperties + currentProperties: properties })); } + function sendActiveParticleProperties() { + var properties = Entities.getEntityProperties(that.activeParticleEntity); + if (properties.emitOrientation) { + properties.emitOrientation = Quat.safeEulerAngles(properties.emitOrientation); + } + // Update uninitialized variables + if (isNaN(properties.alphaStart)) { + properties.alphaStart = properties.alpha; + } + if (isNaN(properties.alphaFinish)) { + properties.alphaFinish = properties.alpha; + } + if (isNaN(properties.radiusStart)) { + properties.radiusStart = properties.particleRadius; + } + if (isNaN(properties.radiusFinish)) { + properties.radiusFinish = properties.particleRadius; + } + if (isNaN(properties.colorStart.red)) { + properties.colorStart = properties.color; + } + if (isNaN(properties.colorFinish.red)) { + properties.colorFinish = properties.color; + } + sendParticleProperties(properties); + } + + function sendUpdatedActiveParticleProperties() { + sendParticleProperties(that.updatedActiveParticleProperties); + that.updatedActiveParticleProperties = {}; + } + that.webEventReceived = function(message) { var data = JSON.parse(message); if (data.messageType === "settings_update") { - if (data.updatedSettings.emitOrientation) { - data.updatedSettings.emitOrientation = Quat.fromVec3Degrees(data.updatedSettings.emitOrientation); - } - Entities.editEntity(that.activeParticleEntity, data.updatedSettings); - - for (var key in data.updatedSettings) { - if (that.activeParticleProperties.hasOwnProperty(key)) { - that.activeParticleProperties[key] = data.updatedSettings[key]; - } - } + var updatedSettings = data.updatedSettings; var optionalProps = ["alphaStart", "alphaFinish", "radiusStart", "radiusFinish", "colorStart", "colorFinish"]; var fallbackProps = ["alpha", "particleRadius", "color"]; - var entityProps = Entities.getEntityProperties(that.activeParticleProperties, optionalProps); + for (var i = 0; i < optionalProps.length; i++) { + var fallbackProp = fallbackProps[Math.floor(i / 2)]; + var optionalValue = updatedSettings[optionalProps[i]]; + var fallbackValue = updatedSettings[fallbackProp]; + if (optionalValue && fallbackValue) { + delete updatedSettings[optionalProps[i]]; + } + } + + if (updatedSettings.emitOrientation) { + updatedSettings.emitOrientation = Quat.fromVec3Degrees(updatedSettings.emitOrientation); + } + + Entities.editEntity(that.activeParticleEntity, updatedSettings); + + var entityProps = Entities.getEntityProperties(that.activeParticleEntity, optionalProps); + var needsUpdate = false; for (var i = 0; i < optionalProps.length; i++) { - var fallback = fallbackProps[Math.floor(i / 2)]; - if (data.updatedSettings[fallback]) { - var prop = optionalProps[i]; - if (!that.activeParticleProperties[prop] || (fallback === "color" && !that.activeParticleProperties[prop].red)) { - that.activeParticleProperties[prop] = entityProps[fallback]; + var fallbackProp = fallbackProps[Math.floor(i / 2)]; + var fallbackValue = updatedSettings[fallbackProp]; + if (fallbackValue) { + var optionalProp = optionalProps[i]; + if ((fallbackProp !== "color" && isNaN(entityProps[optionalProp])) || (fallbackProp === "color" && isNaN(entityProps[optionalProp].red))) { + that.updatedActiveParticleProperties[optionalProp] = fallbackValue; needsUpdate = true; } } } if (needsUpdate) { - sendActiveParticleProperties(); + sendUpdatedActiveParticleProperties(); } - + } else if (data.messageType === "page_loaded") { sendActiveParticleProperties(); } @@ -85,12 +126,8 @@ ParticleExplorerTool = function() { that.setActiveParticleEntity = function(id) { that.activeParticleEntity = id; - }; - - that.setActiveParticleProperties = function(properties) { - that.activeParticleProperties = properties; sendActiveParticleProperties(); }; - + return that; }; diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 9b540aefc8..e265ddb621 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -17,7 +17,6 @@ var SNAPSHOT_DELAY = 500; // 500ms var FINISH_SOUND_DELAY = 350; var resetOverlays; var reticleVisible; -var clearOverlayWhenMoving; var buttonName = "SNAP"; var buttonConnected = false; @@ -286,6 +285,7 @@ function printToPolaroid(image_url) { var polaroid_url = image_url; var model_pos = Vec3.sum(MyAvatar.position, Vec3.multiply(1.25, Quat.getForward(MyAvatar.orientation))); + model_pos.y += 0.2; // Print a bit closer to the head var model_q1 = MyAvatar.orientation; var model_q2 = Quat.angleAxis(90, Quat.getRight(model_q1)); @@ -295,11 +295,11 @@ function printToPolaroid(image_url) { "type": 'Model', "shapeType": 'box', - "name": "New Snapshot", - "description": "Printed from Snaps", + "name": "Snapshot by " + MyAvatar.sessionDisplayName, + "description": "Printed from SNAP app", "modelURL": POLAROID_MODEL_URL, - "dimensions": { "x": 0.5667, "y": 0.0212, "z": 0.4176 }, + "dimensions": { "x": 0.5667, "y": 0.042, "z": 0.4176 }, "position": model_pos, "rotation": model_rot, @@ -307,9 +307,9 @@ function printToPolaroid(image_url) { "density": 200, "restitution": 0.15, - "gravity": { "x": 0, "y": -4.5, "z": 0 }, + "gravity": { "x": 0, "y": -2.5, "z": 0 }, - "velocity": { "x": 0, "y": 3.5, "z": 0 }, + "velocity": { "x": 0, "y": 1.95, "z": 0 }, "angularVelocity": { "x": -1.0, "y": 0, "z": -1.3 }, "dynamic": true, @@ -438,11 +438,6 @@ function takeSnapshot() { isUploadingPrintableStill = true; updatePrintPermissions(); - // Raising the desktop for the share dialog at end will interact badly with clearOverlayWhenMoving. - // Turn it off now, before we start futzing with things (and possibly moving). - clearOverlayWhenMoving = MyAvatar.getClearOverlayWhenMoving(); // Do not use Settings. MyAvatar keeps a separate copy. - MyAvatar.setClearOverlayWhenMoving(false); - // We will record snapshots based on the starting location. That could change, e.g., when recording a .gif. // Even the domainID could change (e.g., if the user falls into a teleporter while recording). href = location.href; @@ -544,9 +539,6 @@ function stillSnapshotTaken(pathStillSnapshot, notify) { // last element in data array tells dialog whether we can share or not Settings.setValue("previousStillSnapPath", pathStillSnapshot); - if (clearOverlayWhenMoving) { - MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog - } HMD.openTablet(); isDomainOpen(domainID, function (canShare) { @@ -590,9 +582,6 @@ function processingGifStarted(pathStillSnapshot) { } Settings.setValue("previousStillSnapPath", pathStillSnapshot); - if (clearOverlayWhenMoving) { - MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog - } HMD.openTablet(); isDomainOpen(domainID, function (canShare) {