From 73aafaf518e0a9bb23677f159069359d4a63b128 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 5 Oct 2016 18:12:58 -0700 Subject: [PATCH 01/27] Add simple sound to avatars For now I just used the piano1.wav that howard suggested long ago for another project. We use Agent.playAvatarSound, and tell the mixer to mix audio for each avatar by setting Agent.setIsListeningToAudioStream to true. --- .../tests/performance/crowd-agent.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/developer/tests/performance/crowd-agent.js b/scripts/developer/tests/performance/crowd-agent.js index 5df576cf99..48b838697b 100644 --- a/scripts/developer/tests/performance/crowd-agent.js +++ b/scripts/developer/tests/performance/crowd-agent.js @@ -15,6 +15,9 @@ // a script like summon.js calls up to n avatars to be around you. var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; +var soundIntervalId; +var SOUND_POLL_INTERVAL = 500; // ms +var SOUND_URL = "http://howard-stearns.github.io/models/sounds/piano1.wav"; print('crowd-agent version 1'); @@ -41,9 +44,26 @@ function startAgent(parameters) { // Can also be used to update. Avatar.startAnimation(data.url, data.fps || 30, 1.0, (data.loopFlag === undefined) ? true : data.loopFlag, false, data.startFrame || 0, data.endFrame); } print('crowd-agent avatars started'); + Agent.isListeningToAudioStream = true; + soundIntervalId = playSound(); + print('crowd-agent sound loop started'); +} +function playSound() { + // Load a sound + var sound = SoundCache.getSound(SOUND_URL); + function loopSound(sound) { + // since we cannot loop, for now lets just see if we are making sounds. If + // not, then play a sound. + if (!Agent.isPlayingAvatarSound) { + Agent.playAvatarSound(sound); + } + }; + return Script.setInterval(function() {loopSound(sound);}, SOUND_POLL_INTERVAL); } function stopAgent(parameters) { Agent.isAvatar = false; + Agent.isListeningToAudioStream = false; + Script.clearInterval(soundIntervalId); print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent)); } From a0c731a0c61629ccb37c492d638b5f7bd104f0a4 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 6 Oct 2016 14:57:40 -0700 Subject: [PATCH 02/27] Initial attempt Kinda works, but sounds 'scratchy'. Surely I've done something lame. --- assignment-client/src/Agent.cpp | 80 +++++++++++++++++++++++++++++++-- assignment-client/src/Agent.h | 13 +++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 65443b0574..9c8825ca65 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -33,6 +33,9 @@ #include #include +#include +#include + #include #include // TODO: consider moving to scriptengine.h @@ -71,6 +74,8 @@ Agent::Agent(ReceivedMessage& message) : { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); + packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); + connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &Agent::handleMismatchAudioFormat); } void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -213,6 +218,66 @@ void Agent::nodeActivated(SharedNodePointer activatedNode) { _pendingScriptRequest = nullptr; } + if (activatedNode->getType() == NodeType::AudioMixer) { + negotiateAudioFormat(); + } + +} + +void Agent::negotiateAudioFormat() { + auto nodeList = DependencyManager::get(); + auto negotiateFormatPacket = NLPacket::create(PacketType::NegotiateAudioFormat); + auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); + quint8 numberOfCodecs = (quint8)codecPlugins.size(); + negotiateFormatPacket->writePrimitive(numberOfCodecs); + for (auto& plugin : codecPlugins) { + auto codecName = plugin->getName(); + negotiateFormatPacket->writeString(codecName); + } + + // grab our audio mixer from the NodeList, if it exists + SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); + + if (audioMixer) { + // send off this mute packet + nodeList->sendPacket(std::move(negotiateFormatPacket), *audioMixer); + } + qInfo() << "negotiateAudioFormat called"; +} + +void Agent::handleSelectedAudioFormat(QSharedPointer message) { + QString selectedCodecName = message->readString(); + selectAudioFormat(selectedCodecName); +} + +void Agent::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { + qDebug() << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec; + selectAudioFormat(recievedCodec); +} + +void Agent::selectAudioFormat(const QString& selectedCodecName) { + _selectedCodecName = selectedCodecName; + + qDebug() << "Selected Codec:" << _selectedCodecName; + + // release any old codec encoder/decoder first... + if (_codec && _encoder) { + _codec->releaseEncoder(_encoder); + _encoder = nullptr; + _codec = nullptr; + } + _receivedAudioStream.cleanupCodec(); + + auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); + for (auto& plugin : codecPlugins) { + if (_selectedCodecName == plugin->getName()) { + _codec = plugin; + _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); + _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); + qDebug() << "Selected Codec Plugin:" << _codec.get(); + break; + } + } } void Agent::scriptRequestFinished() { @@ -438,8 +503,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { } else if (nextSoundOutput) { // write the codec - QString codecName; - audioPacket->writeString(codecName); + audioPacket->writeString(_selectedCodecName); // assume scripted avatar audio is mono and set channel flag to zero audioPacket->writePrimitive((quint8)0); @@ -448,9 +512,19 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { audioPacket->writePrimitive(scriptedAvatar->getPosition()); glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); audioPacket->writePrimitive(headOrientation); + + // encode it + QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); + QByteArray encodedBuffer; + if (_encoder) { + _encoder->encode(decodedBuffer, encodedBuffer); + } else { + encodedBuffer = decodedBuffer; + } + // write the raw audio data - audioPacket->write(reinterpret_cast(nextSoundOutput), numAvailableSamples * sizeof(int16_t)); + audioPacket->write(encodedBuffer.data(), encodedBuffer.size()); } // write audio packet to AudioMixer nodes diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 3f4e36374c..0ebb28797f 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -26,6 +26,8 @@ #include #include +#include + #include "MixedAudioStream.h" @@ -66,12 +68,16 @@ private slots: void handleAudioPacket(QSharedPointer message); void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleSelectedAudioFormat(QSharedPointer message); + void handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec); void processAgentAvatarAndAudio(float deltaTime); - void nodeActivated(SharedNodePointer activatedNode); private: + void negotiateAudioFormat(); + void selectAudioFormat(const QString& selectedCodecName); + std::unique_ptr _scriptEngine; EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; @@ -92,6 +98,11 @@ private: bool _isAvatar = false; QTimer* _avatarIdentityTimer = nullptr; QHash _outgoingScriptAudioSequenceNumbers; + + CodecPluginPointer _codec; + QString _selectedCodecName; + Encoder* _encoder { nullptr }; + }; From 95aa18f66d3b62407d7fdd4d188319152252cf54 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 6 Oct 2016 16:18:22 -0700 Subject: [PATCH 03/27] Some cleanup unnecessary stuff removed, added some cleanup code. --- assignment-client/src/Agent.cpp | 14 +++++++------- assignment-client/src/Agent.h | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9c8825ca65..067cab41da 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -75,7 +75,6 @@ Agent::Agent(ReceivedMessage& message) : this, "handleOctreePacket"); packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); - connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &Agent::handleMismatchAudioFormat); } void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -250,11 +249,6 @@ void Agent::handleSelectedAudioFormat(QSharedPointer message) { selectAudioFormat(selectedCodecName); } -void Agent::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { - qDebug() << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec; - selectAudioFormat(recievedCodec); -} - void Agent::selectAudioFormat(const QString& selectedCodecName) { _selectedCodecName = selectedCodecName; @@ -504,7 +498,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { } else if (nextSoundOutput) { // write the codec audioPacket->writeString(_selectedCodecName); - + // assume scripted avatar audio is mono and set channel flag to zero audioPacket->writePrimitive((quint8)0); @@ -559,4 +553,10 @@ void Agent::aboutToFinish() { // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); + + // cleanup codec & encoder + if (_codec && _encoder) { + _codec->releaseEncoder(_encoder); + _encoder = nullptr; + } } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 0ebb28797f..e65d03a5b1 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -69,7 +69,6 @@ private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); - void handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec); void processAgentAvatarAndAudio(float deltaTime); void nodeActivated(SharedNodePointer activatedNode); From b4c064a5386ee37c7ff049b041c7b49a3b5c4b16 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 7 Oct 2016 13:20:08 -0700 Subject: [PATCH 04/27] Hack in a 100hz timer sounds crappy, more to do, just push to not lose anything. --- assignment-client/src/Agent.cpp | 14 +++++++++----- assignment-client/src/Agent.h | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 067cab41da..9b7e8b45c5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -373,8 +373,13 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); + _avatarAudioTimer = new QTimer(this); + _avatarAudioTimer->setTimerType(Qt::PreciseTimer); + connect(_avatarAudioTimer, SIGNAL(timeout()), this, SLOT(processAgentAvatarAndAudio())); + _avatarAudioTimer->start(10); + // wire up our additional agent related processing to the update signal - QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatarAndAudio); + //QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatarAndAudio); _scriptEngine->run(); @@ -420,10 +425,10 @@ void Agent::sendAvatarIdentityPacket() { } } -void Agent::processAgentAvatarAndAudio(float deltaTime) { +void Agent::processAgentAvatarAndAudio() { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); - const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / SCRIPT_FPS + 0.5; + const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / 100;//SCRIPT_FPS + 0.5; const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); @@ -513,10 +518,9 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { if (_encoder) { _encoder->encode(decodedBuffer, encodedBuffer); } else { - encodedBuffer = decodedBuffer; + audioPacket->write(decodedBuffer.data(), decodedBuffer.size()); } - // write the raw audio data audioPacket->write(encodedBuffer.data(), encodedBuffer.size()); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index e65d03a5b1..13ed8f7958 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -70,7 +71,7 @@ private slots: void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); - void processAgentAvatarAndAudio(float deltaTime); + void processAgentAvatarAndAudio(); void nodeActivated(SharedNodePointer activatedNode); private: @@ -101,8 +102,7 @@ private: CodecPluginPointer _codec; QString _selectedCodecName; Encoder* _encoder { nullptr }; - - + QTimer* _avatarAudioTimer; }; #endif // hifi_Agent_h From b58c36cb12939af1161816559d73b926561995fe Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 10 Oct 2016 17:57:04 -0700 Subject: [PATCH 05/27] Rolling my own 100hz timer Starting with the simplest possible thing - just sleep for 10000 microseconds. Can make it adaptive if need be. --- assignment-client/src/Agent.cpp | 48 ++++++++++++++++++++++++--------- assignment-client/src/Agent.h | 21 +++++++++++++-- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9b7e8b45c5..c0e4d939af 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,18 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; +// this should send a signal every 10ms, with pretty good precision +void AvatarAudioTimer::start() { + qDebug() << "AvatarAudioTimer::start called"; + const int TARGET_INTERVAL_USEC = 10000; // 10ms + while (!_quit) { + // simplest possible timer + usleep(TARGET_INTERVAL_USEC); + emit avatarTick(); + } + qDebug() << "AvatarAudioTimer is finished"; +} + Agent::Agent(ReceivedMessage& message) : ThreadedAssignment(message), _entityEditSender(), @@ -121,7 +134,6 @@ void Agent::handleAudioPacket(QSharedPointer message) { _receivedAudioStream.parseData(*message); _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); - _receivedAudioStream.clearBuffer(); } @@ -372,11 +384,15 @@ void Agent::executeScript() { entityScriptingInterface->setEntityTree(_entityViewer.getTree()); DependencyManager::set(_entityViewer.getTree()); - - _avatarAudioTimer = new QTimer(this); - _avatarAudioTimer->setTimerType(Qt::PreciseTimer); - connect(_avatarAudioTimer, SIGNAL(timeout()), this, SLOT(processAgentAvatarAndAudio())); - _avatarAudioTimer->start(10); + + qDebug() << "Connecting avatarAudioTimer and starting..."; + AvatarAudioTimer* audioTimerWorker = new AvatarAudioTimer(); + audioTimerWorker->moveToThread(&_avatarAudioTimerThread); + connect(audioTimerWorker, &AvatarAudioTimer::avatarTick, this, &Agent::processAgentAvatarAndAudio); + connect(this, &Agent::startAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::start); + connect(this, &Agent::stopAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::stop); + connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater); + _avatarAudioTimerThread.start(); // wire up our additional agent related processing to the update signal //QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatarAndAudio); @@ -406,6 +422,10 @@ void Agent::setIsAvatar(bool isAvatar) { // start the timers _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); + + // tell the audiotimer worker to start working + emit startAvatarAudioTimer(); + } if (!_isAvatar) { @@ -428,7 +448,7 @@ void Agent::sendAvatarIdentityPacket() { void Agent::processAgentAvatarAndAudio() { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); - const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / 100;//SCRIPT_FPS + 0.5; + const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / 100 + 0.5; const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); @@ -513,16 +533,15 @@ void Agent::processAgentAvatarAndAudio() { audioPacket->writePrimitive(headOrientation); // encode it - QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); - QByteArray encodedBuffer; - if (_encoder) { + if(_encoder) { + QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); + QByteArray encodedBuffer; _encoder->encode(decodedBuffer, encodedBuffer); + audioPacket->write(encodedBuffer.data(), encodedBuffer.size()); } else { - audioPacket->write(decodedBuffer.data(), decodedBuffer.size()); + audioPacket->write(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); } - // write the raw audio data - audioPacket->write(encodedBuffer.data(), encodedBuffer.size()); } // write audio packet to AudioMixer nodes @@ -558,6 +577,9 @@ void Agent::aboutToFinish() { // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); + emit stopAvatarAudioTimer(); + _avatarAudioTimerThread.quit(); + // cleanup codec & encoder if (_codec && _encoder) { _codec->releaseEncoder(_encoder); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 13ed8f7958..ba90a3247e 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -32,6 +32,20 @@ #include "MixedAudioStream.h" +class AvatarAudioTimer : public QObject { + Q_OBJECT + +signals: + void avatarTick(); + +public slots: + void start(); + void stop() { _quit = true; } + +private: + bool _quit { false }; +}; + class Agent : public ThreadedAssignment { Q_OBJECT @@ -60,6 +74,7 @@ public: public slots: void run() override; void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); } + void processAgentAvatarAndAudio(); private slots: void requestScript(); @@ -71,9 +86,11 @@ private slots: void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); - void processAgentAvatarAndAudio(); void nodeActivated(SharedNodePointer activatedNode); +signals: + void startAvatarAudioTimer(); + void stopAvatarAudioTimer(); private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); @@ -102,7 +119,7 @@ private: CodecPluginPointer _codec; QString _selectedCodecName; Encoder* _encoder { nullptr }; - QTimer* _avatarAudioTimer; + QThread _avatarAudioTimerThread; }; #endif // hifi_Agent_h From ace8639f5baf55331085adb7ec80e122dfd8a73e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 10 Oct 2016 18:42:06 -0700 Subject: [PATCH 06/27] Bug fixes in oculus_touch default mapping * Made sticks less sensitive. Raised deadSpot min from 0.05 to 0.3. * Fixed problem were grip and trigger was mapped to Standard triggers. This was causing all sorts of problems with the handControllerGrab script. Including double lasers and a stuck right hand laser. * mapped grip to standard grip. So now you can use the grip button to drop equipped objects. * increased deadZone on grip to make inadvertent drops less likely to happen. --- .../resources/controllers/oculus_touch.json | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/interface/resources/controllers/oculus_touch.json b/interface/resources/controllers/oculus_touch.json index c50f7681d9..455f9c304b 100644 --- a/interface/resources/controllers/oculus_touch.json +++ b/interface/resources/controllers/oculus_touch.json @@ -11,42 +11,34 @@ { "from": "OculusTouch.LY", "to": "Standard.LY", "filters": [ - { "type": "deadZone", "min": 0.05 }, + { "type": "deadZone", "min": 0.3 }, "invert" ] }, - { "from": "OculusTouch.LX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.LX" }, - { "from": "OculusTouch.LT", "to": "Standard.LTClick", + { "from": "OculusTouch.LX", "filters": { "type": "deadZone", "min": 0.3 }, "to": "Standard.LX" }, + { "from": "OculusTouch.LT", "to": "Standard.LTClick", "peek": true, "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ] }, { "from": "OculusTouch.LT", "to": "Standard.LT" }, { "from": "OculusTouch.LS", "to": "Standard.LS" }, - { "from": "OculusTouch.LeftGrip", "to": "Standard.LTClick", - "peek": true, - "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ] - }, - { "from": "OculusTouch.LeftGrip", "to": "Standard.LT" }, + { "from": "OculusTouch.LeftGrip", "filters": { "type": "deadZone", "min": 0.3 }, "to": "Standard.LeftGrip" }, { "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" }, { "from": "OculusTouch.RY", "to": "Standard.RY", "filters": [ - { "type": "deadZone", "min": 0.05 }, + { "type": "deadZone", "min": 0.3 }, "invert" ] }, - { "from": "OculusTouch.RX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.RX" }, - { "from": "OculusTouch.RT", "to": "Standard.RTClick", + { "from": "OculusTouch.RX", "filters": { "type": "deadZone", "min": 0.3 }, "to": "Standard.RX" }, + { "from": "OculusTouch.RT", "to": "Standard.RTClick", "peek": true, "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ] }, { "from": "OculusTouch.RT", "to": "Standard.RT" }, { "from": "OculusTouch.RS", "to": "Standard.RS" }, - { "from": "OculusTouch.RightGrip", "to": "Standard.LTClick", - "peek": true, - "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ] - }, - { "from": "OculusTouch.RightGrip", "to": "Standard.RT" }, + { "from": "OculusTouch.RightGrip", "filters": { "type": "deadZone", "min": 0.3 }, "to": "Standard.RightGrip" }, { "from": "OculusTouch.RightHand", "to": "Standard.RightHand" }, { "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" }, From 0794d95bdcaa4625571759e6dd1bc58dca6619e9 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 10 Oct 2016 19:58:16 -0700 Subject: [PATCH 07/27] Fix merge Take the new crowd-agent.js, my changes were temporary. --- .../tests/performance/crowd-agent.js | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/scripts/developer/tests/performance/crowd-agent.js b/scripts/developer/tests/performance/crowd-agent.js index ffcff331d7..6b73d66c4f 100644 --- a/scripts/developer/tests/performance/crowd-agent.js +++ b/scripts/developer/tests/performance/crowd-agent.js @@ -15,9 +15,6 @@ // a script like summon.js calls up to n avatars to be around you. var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; -var soundIntervalId; -var SOUND_POLL_INTERVAL = 500; // ms -var SOUND_URL = "http://howard-stearns.github.io/models/sounds/piano1.wav"; print('crowd-agent version 2'); @@ -67,26 +64,9 @@ function startAgent(parameters) { // Can also be used to update. Avatar.startAnimation(data.url, data.fps || 30, 1.0, (data.loopFlag === undefined) ? true : data.loopFlag, false, data.startFrame || 0, data.endFrame); } print('crowd-agent avatars started'); - Agent.isListeningToAudioStream = true; - soundIntervalId = playSound(); - print('crowd-agent sound loop started'); -} -function playSound() { - // Load a sound - var sound = SoundCache.getSound(SOUND_URL); - function loopSound(sound) { - // since we cannot loop, for now lets just see if we are making sounds. If - // not, then play a sound. - if (!Agent.isPlayingAvatarSound) { - Agent.playAvatarSound(sound); - } - }; - return Script.setInterval(function() {loopSound(sound);}, SOUND_POLL_INTERVAL); } function stopAgent(parameters) { Agent.isAvatar = false; - Agent.isListeningToAudioStream = false; - Script.clearInterval(soundIntervalId); print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent)); } From ef844cbd00bc8b74d563c3102b02f879cab16fb4 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 11 Oct 2016 09:33:55 -0700 Subject: [PATCH 08/27] Cleanup artifacts Seems playAvatarSound could be called from a thread other than the Agent's thread. So, artifacts happen when that pointer changes while a 'tick' is happening. Also cleaned up code a bit, got rid of some hard-coded stuff I had in just for dev purposes. --- assignment-client/src/Agent.cpp | 35 ++++++++++++++++++++------------- assignment-client/src/Agent.h | 2 +- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index dc9b572a2e..9be55c15a7 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -52,10 +52,15 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; // this should send a signal every 10ms, with pretty good precision void AvatarAudioTimer::start() { qDebug() << "AvatarAudioTimer::start called"; + auto startTime = usecTimestampNow(); + quint64 frameCounter = 0; const int TARGET_INTERVAL_USEC = 10000; // 10ms while (!_quit) { + frameCounter++; // simplest possible timer - usleep(TARGET_INTERVAL_USEC); + quint64 targetTime = startTime + frameCounter * TARGET_INTERVAL_USEC; + quint64 interval = std::max((quint64)0, targetTime - usecTimestampNow()); + usleep(interval); emit avatarTick(); } qDebug() << "AvatarAudioTimer is finished"; @@ -91,6 +96,16 @@ Agent::Agent(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); } +void Agent::playAvatarSound(SharedSoundPointer sound) { + // this must happen on Agent's main thread + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "playAvatarSound", Q_ARG(SharedSoundPointer, sound)); + return; + } else { + setAvatarSound(sound); + } +} + void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { auto packetType = message->getType(); @@ -233,7 +248,6 @@ void Agent::nodeActivated(SharedNodePointer activatedNode) { if (activatedNode->getType() == NodeType::AudioMixer) { negotiateAudioFormat(); } - } void Agent::negotiateAudioFormat() { @@ -254,7 +268,6 @@ void Agent::negotiateAudioFormat() { // send off this mute packet nodeList->sendPacket(std::move(negotiateFormatPacket), *audioMixer); } - qInfo() << "negotiateAudioFormat called"; } void Agent::handleSelectedAudioFormat(QSharedPointer message) { @@ -386,7 +399,6 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); - qDebug() << "Connecting avatarAudioTimer and starting..."; AvatarAudioTimer* audioTimerWorker = new AvatarAudioTimer(); audioTimerWorker->moveToThread(&_avatarAudioTimerThread); connect(audioTimerWorker, &AvatarAudioTimer::avatarTick, this, &Agent::processAgentAvatarAndAudio); @@ -395,9 +407,6 @@ void Agent::executeScript() { connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater); _avatarAudioTimerThread.start(); - // wire up our additional agent related processing to the update signal - //QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatarAndAudio); - _scriptEngine->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); @@ -424,7 +433,7 @@ void Agent::setIsAvatar(bool isAvatar) { // start the timers _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); - // tell the audiotimer worker to start working + // tell the avatarAudioTimer to start ticking emit startAvatarAudioTimer(); } @@ -464,8 +473,6 @@ void Agent::sendAvatarIdentityPacket() { void Agent::processAgentAvatarAndAudio() { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); - const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / 100 + 0.5; - const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); scriptedAvatar->doneEncoding(true); @@ -484,7 +491,7 @@ void Agent::processAgentAvatarAndAudio() { // if we have an avatar audio stream then send it out to our audio-mixer bool silentFrame = true; - int16_t numAvailableSamples = SCRIPT_AUDIO_BUFFER_SAMPLES; + int16_t numAvailableSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; const int16_t* nextSoundOutput = NULL; if (_avatarSound) { @@ -492,8 +499,8 @@ void Agent::processAgentAvatarAndAudio() { nextSoundOutput = reinterpret_cast(soundByteArray.data() + _numAvatarSoundSentBytes); - int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > SCRIPT_AUDIO_BUFFER_BYTES - ? SCRIPT_AUDIO_BUFFER_BYTES + int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL + ? AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL : soundByteArray.size() - _numAvatarSoundSentBytes; numAvailableSamples = (int16_t)numAvailableBytes / sizeof(int16_t); @@ -529,7 +536,7 @@ void Agent::processAgentAvatarAndAudio() { } // write the number of silent samples so the audio-mixer can uphold timing - audioPacket->writePrimitive(SCRIPT_AUDIO_BUFFER_SAMPLES); + audioPacket->writePrimitive(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); // use the orientation and position of this avatar for the source of this audio audioPacket->writePrimitive(scriptedAvatar->getPosition()); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index ba90a3247e..e89a8a9b13 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -73,7 +73,7 @@ public: public slots: void run() override; - void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); } + void playAvatarSound(SharedSoundPointer avatarSound);// { setAvatarSound(avatarSound); } void processAgentAvatarAndAudio(); private slots: From 1fb7b42f0b63d6e6d8fa1454a97ab233be47c4e7 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 11 Oct 2016 09:37:42 -0700 Subject: [PATCH 09/27] One more comment removed --- assignment-client/src/Agent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index e89a8a9b13..cbb1af2e33 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -73,7 +73,7 @@ public: public slots: void run() override; - void playAvatarSound(SharedSoundPointer avatarSound);// { setAvatarSound(avatarSound); } + void playAvatarSound(SharedSoundPointer avatarSound); void processAgentAvatarAndAudio(); private slots: From 884d22a59b94d8a5676ea20598a022cf9e082dee Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 11 Oct 2016 16:06:55 -0700 Subject: [PATCH 10/27] make agent avatar animations work again, and use them in crowds --- .../src/avatars/ScriptableAvatar.cpp | 40 ++++++++++++------- .../src/avatars/ScriptableAvatar.h | 3 ++ .../tests/performance/crowd-agent.js | 1 + scripts/developer/tests/performance/summon.js | 20 +++++----- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 82e88f67ef..15877eed25 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -46,14 +46,21 @@ AnimationDetails ScriptableAvatar::getAnimationDetails() { return _animationDetails; } +void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { + _bind.reset(); + _animSkeleton.reset(); + AvatarData::setSkeletonModelURL(skeletonModelURL); +} void ScriptableAvatar::update(float deltatime) { if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton. _bind = DependencyManager::get()->getAnimation(_skeletonFBXURL); } // Run animation - if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0 && _bind->isLoaded()) { - + if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0 && !_bind.isNull() && _bind->isLoaded()) { + if (!_animSkeleton) { + _animSkeleton = std::make_shared(_bind->getGeometry()); + } float currentFrame = _animationDetails.currentFrame + deltatime * _animationDetails.fps; if (_animationDetails.loop || currentFrame < _animationDetails.lastFrame) { while (currentFrame >= _animationDetails.lastFrame) { @@ -64,14 +71,16 @@ void ScriptableAvatar::update(float deltatime) { const QVector& modelJoints = _bind->getGeometry().joints; QStringList animationJointNames = _animation->getJointNames(); - if (_jointData.size() != modelJoints.size()) { - _jointData.resize(modelJoints.size()); + const int nJoints = modelJoints.size(); + if (_jointData.size() != nJoints) { + _jointData.resize(nJoints); } const int frameCount = _animation->getFrames().size(); const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount); const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount); const float frameFraction = glm::fract(currentFrame); + std::vector poses = _animSkeleton->getRelativeDefaultPoses(); for (int i = 0; i < animationJointNames.size(); i++) { const QString& name = animationJointNames[i]; @@ -79,18 +88,21 @@ void ScriptableAvatar::update(float deltatime) { // trusting the .fst (which is sometimes not updated to match changes to .fbx). int mapping = _bind->getGeometry().getJointIndex(name); if (mapping != -1 && !_maskedJoints.contains(name)) { - JointData& data = _jointData[mapping]; - - auto newRotation = modelJoints[mapping].preRotation * - safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction); - // We could probably do translations as in interpolation in model space (rather than the parent space that each frame is in), - // but we don't do so for MyAvatar yet, so let's not be different here. - if (data.rotation != newRotation) { - data.rotation = newRotation; - data.rotationSet = true; - } + // Eventually, this should probably deal with post rotations and translations, too. + poses[mapping].rot = modelJoints[mapping].preRotation * + safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);; } } + _animSkeleton->convertRelativePosesToAbsolute(poses); + for (int i = 0; i < nJoints; i++) { + JointData& data = _jointData[i]; + AnimPose& pose = poses[i]; + if (data.rotation != pose.rot) { + data.rotation = pose.rot; + data.rotationSet = true; + } + } + } else { _animation.clear(); } diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 30c48d02bf..56707de471 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -13,6 +13,7 @@ #define hifi_ScriptableAvatar_h #include +#include #include #include @@ -25,6 +26,7 @@ public: bool hold = false, float firstFrame = 0.0f, float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList()); Q_INVOKABLE void stopAnimation(); Q_INVOKABLE AnimationDetails getAnimationDetails(); + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; private slots: void update(float deltatime); @@ -34,6 +36,7 @@ private: AnimationDetails _animationDetails; QStringList _maskedJoints; AnimationPointer _bind; // a sleazy way to get the skeleton, given the various library/cmake dependencies + std::shared_ptr _animSkeleton; }; #endif // hifi_ScriptableAvatar_h \ No newline at end of file diff --git a/scripts/developer/tests/performance/crowd-agent.js b/scripts/developer/tests/performance/crowd-agent.js index 6b73d66c4f..2e54e21f45 100644 --- a/scripts/developer/tests/performance/crowd-agent.js +++ b/scripts/developer/tests/performance/crowd-agent.js @@ -22,6 +22,7 @@ print('crowd-agent version 2'); - File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development. - URLs are cached regardless of server headers. Must use cache-defeating query parameters. - JSON.stringify(Avatar) silently fails (even when Agent.isAvatar) +- If you run from a dev build directory, you must link assignment-client//resources to ../../interface//resources */ function messageSend(message) { diff --git a/scripts/developer/tests/performance/summon.js b/scripts/developer/tests/performance/summon.js index 8118f553f1..25ecd4860b 100644 --- a/scripts/developer/tests/performance/summon.js +++ b/scripts/developer/tests/performance/summon.js @@ -23,6 +23,14 @@ var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's lengt var SOUND_DATA = {url: "http://howard-stearns.github.io/models/sounds/piano1.wav"}; var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND at once. var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next +var ANIMATION_DATA = { // T-pose until we get animations working again. + "url": "http://howard-stearns.github.io/models/resources/avatar/animations/idle.fbx", + //"url": "http://howard-stearns.github.io/models/resources/avatar/animations/walk_fwd.fbx", + "startFrame": 0.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true +}; var spread = Math.sqrt(MINIMUM_AVATARS * DENSITY); // meters var turnSpread = 90; // How many degrees should turn from front range over. @@ -71,18 +79,10 @@ function messageHandler(channel, messageString, senderID) { rcpt: senderID, position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}), orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0), - soundData: chatter && SOUND_DATA/* + soundData: chatter && SOUND_DATA, // No need to specify skeletonModelURL - //skeletonModelURL: "file:///c:/Program Files/High Fidelity Release/resources/meshes/being_of_light/being_of_light.fbx", //skeletonModelURL: "file:///c:/Program Files/High Fidelity Release/resources/meshes/defaultAvatar_full.fst"/, - animationData: { // T-pose until we get animations working again. - "url": "file:///C:/Program Files/High Fidelity Release/resources/avatar/animations/idle.fbx", - //"url": "file:///c:/Program Files/High Fidelity Release/resources/avatar/animations/walk_fwd.fbx", - "startFrame": 0.0, - "endFrame": 300.0, - "timeScale": 1.0, - "loopFlag": true - }*/ + animationData: ANIMATION_DATA }); } break; From 973ee544fbce105b948d7bcb205195ea24704ae5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 11 Oct 2016 16:36:29 -0700 Subject: [PATCH 11/27] Prevent crashes in openvr on shutdown By ensuring that there is an opengl context is bound before calling VR_Shutdown() --- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 3 ++- plugins/openvr/src/ViveControllerManager.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 68bb23a84d..212f1ce46d 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -445,8 +445,9 @@ void OpenVrDisplayPlugin::internalDeactivate() { _openVrDisplayActive = false; _container->setIsOptionChecked(StandingHMDSensorMode, false); if (_system) { - // Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and + // TODO: Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and // we don't want ViveControllerManager to consider old values to be valid. + _container->makeRenderingContextCurrent(); releaseOpenVrSystem(); _system = nullptr; } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index bcfc7170dc..2d2720e388 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -132,6 +132,7 @@ void ViveControllerManager::deactivate() { _container->removeMenu(MENU_PATH); if (_system) { + _container->makeRenderingContextCurrent(); releaseOpenVrSystem(); _system = nullptr; } From 28771cbda97fee99d286e5df5ca0a3ed4c8c5508 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 11 Oct 2016 14:26:21 -0700 Subject: [PATCH 12/27] Additional plugin debugging, better plugin resource cleanup --- interface/src/Application.cpp | 3 +++ interface/src/ui/ApplicationOverlay.cpp | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 15 +++++++---- .../src/display-plugins/OpenGLDisplayPlugin.h | 3 ++- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 5 ++++ .../display-plugins/hmd/HmdDisplayPlugin.h | 1 + libraries/gpu/src/gpu/Framebuffer.cpp | 26 ++++++++++++------- libraries/gpu/src/gpu/Framebuffer.h | 9 ++++--- .../plugins/src/plugins/PluginManager.cpp | 26 +++++++++++++++++++ libraries/plugins/src/plugins/PluginManager.h | 2 ++ libraries/plugins/src/plugins/RuntimePlugin.h | 2 ++ .../src/AmbientOcclusionEffect.cpp | 4 +-- .../render-utils/src/AntialiasingEffect.cpp | 3 +-- .../render-utils/src/DeferredFramebuffer.cpp | 11 +++----- .../src/DeferredLightingEffect.cpp | 4 +-- .../render-utils/src/FramebufferCache.cpp | 4 +-- .../render-utils/src/SubsurfaceScattering.cpp | 6 ++--- .../render-utils/src/SurfaceGeometryPass.cpp | 16 ++++-------- libraries/render/src/render/BlurTask.cpp | 4 +-- plugins/hifiNeuron/src/NeuronProvider.cpp | 4 +++ plugins/hifiSdl2/src/SDL2Provider.cpp | 4 +++ plugins/hifiSixense/src/SixenseProvider.cpp | 3 +++ .../oculus/src/OculusBaseDisplayPlugin.cpp | 4 +++ plugins/oculus/src/OculusBaseDisplayPlugin.h | 1 + plugins/oculus/src/OculusDisplayPlugin.cpp | 7 ++++- plugins/oculus/src/OculusDisplayPlugin.h | 1 + plugins/oculus/src/OculusProvider.cpp | 8 ++++++ plugins/oculusLegacy/src/OculusProvider.cpp | 4 +++ plugins/openvr/src/OpenVrProvider.cpp | 7 +++++ 29 files changed, 135 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80e444462f..49f8fe8a0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1498,6 +1498,9 @@ void Application::cleanupBeforeQuit() { DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts DependencyManager::destroy(); + _displayPlugin.reset(); + PluginManager::getInstance()->shutdown(); + // Cleanup all overlays after the scripts, as scripts might add more _overlays.cleanupAllOverlays(); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f4937c4459..6fa89f299e 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -258,7 +258,7 @@ void ApplicationOverlay::buildFramebufferObject() { auto uiSize = qApp->getUiSize(); if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) { - _overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ApplicationOverlay")); } auto width = uiSize.x; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 4a5021155f..02e5a064f5 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -356,6 +356,7 @@ void OpenGLDisplayPlugin::customizeContext() { gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + cursorData.texture->setSource("cursor texture"); auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha(); cursorData.texture->setUsage(usage.build()); cursorData.texture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.byteCount(), image.constBits()); @@ -413,8 +414,6 @@ void OpenGLDisplayPlugin::customizeContext() { _cursorPipeline = gpu::Pipeline::create(program, state); } } - auto renderSize = getRecommendedRenderSize(); - _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y)); } void OpenGLDisplayPlugin::uncustomizeContext() { @@ -424,6 +423,7 @@ void OpenGLDisplayPlugin::uncustomizeContext() { _compositeFramebuffer.reset(); withPresentThreadLock([&] { _currentFrame.reset(); + _lastFrame = nullptr; while (!_newFrameQueue.empty()) { _gpuContext->consumeFrameUpdates(_newFrameQueue.front()); _newFrameQueue.pop(); @@ -559,7 +559,7 @@ void OpenGLDisplayPlugin::compositeScene() { void OpenGLDisplayPlugin::compositeLayers() { auto renderSize = getRecommendedRenderSize(); if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) { - _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y)); + _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("displayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y)); } { @@ -611,10 +611,10 @@ void OpenGLDisplayPlugin::present() { { withPresentThreadLock([&] { _renderRate.increment(); - if (_currentFrame != _lastFrame) { + if (_currentFrame.get() != _lastFrame) { _newFrameRate.increment(); } - _lastFrame = _currentFrame; + _lastFrame = _currentFrame.get(); }); // Execute the frame rendering commands PROFILE_RANGE_EX("execute", 0xff00ff00, (uint64_t)presentCount()) @@ -755,3 +755,8 @@ void OpenGLDisplayPlugin::render(std::function f) { f(batch); _gpuContext->executeBatch(batch); } + + +OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { + qDebug() << "Destroying OpenGLDisplayPlugin"; +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 74f8cdbc10..9369f6d72c 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -36,6 +36,7 @@ protected: using Lock = std::unique_lock; using Condition = std::condition_variable; public: + ~OpenGLDisplayPlugin(); // These must be final to ensure proper ordering of operations // between the main thread and the presentation thread bool activate() override final; @@ -115,7 +116,7 @@ protected: RateCounter<> _renderRate; gpu::FramePointer _currentFrame; - gpu::FramePointer _lastFrame; + gpu::Frame* _lastFrame { nullptr }; gpu::FramebufferPointer _compositeFramebuffer; gpu::PipelinePointer _overlayPipeline; gpu::PipelinePointer _simplePipeline; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 70535e7a0a..15c341e39e 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -125,6 +125,7 @@ void HmdDisplayPlugin::uncustomizeContext() { batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0)); }); _overlayRenderer = OverlayRenderer(); + _previewTexture.reset(); Parent::uncustomizeContext(); } @@ -265,6 +266,7 @@ void HmdDisplayPlugin::internalPresent() { gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + _previewTexture->setSource("HMD Preview Texture"); _previewTexture->setUsage(gpu::Texture::Usage::Builder().withColor().build()); _previewTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.byteCount(), image.constBits()); _previewTexture->autoGenerateMips(-1); @@ -633,3 +635,6 @@ void HmdDisplayPlugin::compositeExtra() { }); } +HmdDisplayPlugin::~HmdDisplayPlugin() { + qDebug() << "Destroying HmdDisplayPlugin"; +} diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index d02fc5af05..505c200e3e 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -23,6 +23,7 @@ class HmdDisplayPlugin : public OpenGLDisplayPlugin { using Parent = OpenGLDisplayPlugin; public: + ~HmdDisplayPlugin(); bool isHmd() const override final { return true; } float getIPD() const override final { return _ipd; } glm::mat4 getEyeToHeadTransform(Eye eye) const override final { return _eyeOffsets[eye]; } diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 2cd39d49ae..e8ccfce3b2 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -20,16 +20,17 @@ using namespace gpu; Framebuffer::~Framebuffer() { } -Framebuffer* Framebuffer::create() { +Framebuffer* Framebuffer::create(const std::string& name) { auto framebuffer = new Framebuffer(); + framebuffer->setName(name); framebuffer->_renderBuffers.resize(MAX_NUM_RENDER_BUFFERS); framebuffer->_colorStamps.resize(MAX_NUM_RENDER_BUFFERS, 0); return framebuffer; } -Framebuffer* Framebuffer::create( const Format& colorBufferFormat, uint16 width, uint16 height) { - auto framebuffer = Framebuffer::create(); +Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBufferFormat, uint16 width, uint16 height) { + auto framebuffer = Framebuffer::create(name); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); colorTexture->setSource("Framebuffer::colorTexture"); @@ -39,13 +40,11 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, uint16 width, return framebuffer; } -Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height) { - auto framebuffer = Framebuffer::create(); +Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height) { + auto framebuffer = Framebuffer::create(name); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); - colorTexture->setSource("Framebuffer::colorTexture"); auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); - depthTexture->setSource("Framebuffer::depthTexture"); framebuffer->setRenderBuffer(0, colorTexture); framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat); @@ -53,11 +52,10 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& } Framebuffer* Framebuffer::createShadowmap(uint16 width) { - auto framebuffer = Framebuffer::create(); + auto framebuffer = Framebuffer::create("Shadowmap"); auto depthFormat = Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format auto depthTexture = TexturePointer(Texture::create2D(depthFormat, width, width)); - depthTexture->setSource("Framebuffer::shadowMap"); Sampler::Desc samplerDesc; samplerDesc._borderColor = glm::vec4(1.0f); samplerDesc._wrapModeU = Sampler::WRAP_BORDER; @@ -155,6 +153,10 @@ int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uin if (!validateTargetCompatibility(*texture, subresource)) { return -1; } + + if (texture->source().empty()) { + texture->setSource(_name + "::color::" + std::to_string(slot)); + } } ++_colorStamps[slot]; @@ -216,7 +218,6 @@ uint32 Framebuffer::getRenderBufferSubresource(uint32 slot) const { } bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { - ++_depthStamp; if (isSwapchain()) { return false; } @@ -226,8 +227,13 @@ bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const For if (!validateTargetCompatibility(*texture)) { return false; } + + if (texture->source().empty()) { + texture->setSource(_name + "::depthStencil"); + } } + ++_depthStamp; updateSize(texture); // assign the new one diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 8c26037ada..a65aaf765b 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -88,9 +88,9 @@ public: ~Framebuffer(); static Framebuffer* create(const SwapchainPointer& swapchain); - static Framebuffer* create(); - static Framebuffer* create(const Format& colorBufferFormat, uint16 width, uint16 height); - static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height); + static Framebuffer* create(const std::string& name); + static Framebuffer* create(const std::string& name, const Format& colorBufferFormat, uint16 width, uint16 height); + static Framebuffer* create(const std::string& name, const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height); static Framebuffer* createShadowmap(uint16 width); bool isSwapchain() const; @@ -127,6 +127,8 @@ public: uint16 getWidth() const; uint16 getHeight() const; uint16 getNumSamples() const; + const std::string& getName() const { return _name; } + void setName(const std::string& name) { _name = name; } float getAspectRatio() const { return getWidth() / (float) getHeight() ; } @@ -145,6 +147,7 @@ public: static Transform evalSubregionTexcoordTransform(const glm::ivec2& sourceSurface, const glm::ivec4& destViewport); protected: + std::string _name; SwapchainPointer _swapchain; Stamp _depthStamp { 0 }; diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 4baf20c338..21b80e2370 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -276,4 +276,30 @@ void PluginManager::saveSettings() { saveInputPluginSettings(getInputPlugins()); } +void PluginManager::shutdown() { + for (auto inputPlugin : getInputPlugins()) { + if (inputPlugin->isActive()) { + inputPlugin->deactivate(); + } + } + + for (auto displayPlugins : getDisplayPlugins()) { + if (displayPlugins->isActive()) { + displayPlugins->deactivate(); + } + } + + auto loadedPlugins = getLoadedPlugins(); + // Now grab the dynamic plugins + for (auto loader : getLoadedPlugins()) { + InputProvider* inputProvider = qobject_cast(loader->instance()); + if (inputProvider) { + inputProvider->destroyInputPlugins(); + } + DisplayProvider* displayProvider = qobject_cast(loader->instance()); + if (displayProvider) { + displayProvider->destroyDisplayPlugins(); + } + } +} #endif diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index 30d52298da..83aad7abcd 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -28,6 +28,8 @@ public: void disableInputs(const QStringList& inputs); void saveSettings(); void setContainer(PluginContainer* container) { _container = container; } + + void shutdown(); private: PluginContainer* _container { nullptr }; }; diff --git a/libraries/plugins/src/plugins/RuntimePlugin.h b/libraries/plugins/src/plugins/RuntimePlugin.h index 9bf15f344d..bb6f0251c2 100644 --- a/libraries/plugins/src/plugins/RuntimePlugin.h +++ b/libraries/plugins/src/plugins/RuntimePlugin.h @@ -19,6 +19,7 @@ public: virtual ~DisplayProvider() {} virtual DisplayPluginList getDisplayPlugins() = 0; + virtual void destroyDisplayPlugins() = 0; }; #define DisplayProvider_iid "com.highfidelity.plugins.display" @@ -29,6 +30,7 @@ class InputProvider { public: virtual ~InputProvider() {} virtual InputPluginList getInputPlugins() = 0; + virtual void destroyInputPlugins() = 0; }; #define InputProvider_iid "com.highfidelity.plugins.input" diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 3bf887e1b6..d652cbd872 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -75,11 +75,11 @@ void AmbientOcclusionFramebuffer::allocate() { auto height = _frameSize.y; _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); _occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); } diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 8147b06846..43b889df64 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -41,11 +41,10 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { if (!_antialiasingBuffer) { // Link the antialiasing FBO to texture - _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing")); auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get()->getLightingTexture()->getTexelFormat(); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - _antialiasingTexture->setSource("Antialiasing::_antialiasingTexture"); _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); } diff --git a/libraries/render-utils/src/DeferredFramebuffer.cpp b/libraries/render-utils/src/DeferredFramebuffer.cpp index 067687f9ef..e8783e0e0d 100644 --- a/libraries/render-utils/src/DeferredFramebuffer.cpp +++ b/libraries/render-utils/src/DeferredFramebuffer.cpp @@ -43,8 +43,8 @@ void DeferredFramebuffer::updatePrimaryDepth(const gpu::TexturePointer& depthBuf void DeferredFramebuffer::allocate() { - _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); - _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("deferred")); + _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create("deferredDepthColor")); auto colorFormat = gpu::Element::COLOR_SRGBA_32; auto linearFormat = gpu::Element::COLOR_RGBA_32; @@ -54,11 +54,8 @@ void DeferredFramebuffer::allocate() { auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _deferredColorTexture->setSource("DeferredFramebuffer::_deferredColorTexture"); _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(linearFormat, width, height, defaultSampler)); - _deferredNormalTexture->setSource("DeferredFramebuffer::_deferredNormalTexture"); _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _deferredSpecularTexture->setSource("DeferredFramebuffer::_deferredSpecularTexture"); _deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture); _deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture); @@ -69,7 +66,6 @@ void DeferredFramebuffer::allocate() { auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format if (!_primaryDepthTexture) { _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); - _primaryDepthTexture->setSource("DeferredFramebuffer::_primaryDepthTexture"); } _deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); @@ -80,8 +76,7 @@ void DeferredFramebuffer::allocate() { auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler)); - _lightingTexture->setSource("DeferredFramebuffer::_lightingTexture"); - _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("lighting")); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 2e169e5cc3..02632c15a9 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -346,12 +346,11 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con } if (!_primaryFramebuffer) { - _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("deferredPrimary")); auto colorFormat = gpu::Element::COLOR_SRGBA_32; auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler)); - primaryColorTexture->setSource("PreparePrimaryFramebuffer::primaryColorTexture"); _primaryFramebuffer->setRenderBuffer(0, primaryColorTexture); @@ -359,7 +358,6 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler)); - primaryDepthTexture->setSource("PreparePrimaryFramebuffer::primaryDepthTexture"); _primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); } diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 8930792d11..27429595b4 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -36,7 +36,7 @@ void FramebufferCache::createPrimaryFramebuffer() { auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("selfie")); auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); _selfieFramebuffer->setRenderBuffer(0, tex); @@ -47,7 +47,7 @@ void FramebufferCache::createPrimaryFramebuffer() { gpu::FramebufferPointer FramebufferCache::getFramebuffer() { std::unique_lock lock(_mutex); if (_cachedFramebuffers.empty()) { - _cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_SRGBA_32, _frameBufferSize.width(), _frameBufferSize.height()))); + _cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create("cached", gpu::Element::COLOR_SRGBA_32, _frameBufferSize.width(), _frameBufferSize.height()))); } gpu::FramebufferPointer result = _cachedFramebuffers.front(); _cachedFramebuffers.pop_front(); diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 3e4ec50dee..83f1d4cb23 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -319,7 +319,7 @@ void diffuseProfileGPU(gpu::TexturePointer& profileMap, RenderArgs* args) { makePipeline = gpu::Pipeline::create(program, state); } - auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("diffuseProfile")); makeFramebuffer->setRenderBuffer(0, profileMap); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { @@ -356,7 +356,7 @@ void diffuseScatterGPU(const gpu::TexturePointer& profileMap, gpu::TexturePointe makePipeline = gpu::Pipeline::create(program, state); } - auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("diffuseScatter")); makeFramebuffer->setRenderBuffer(0, lut); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { @@ -393,7 +393,7 @@ void computeSpecularBeckmannGPU(gpu::TexturePointer& beckmannMap, RenderArgs* ar makePipeline = gpu::Pipeline::create(program, state); } - auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + auto makeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("computeSpecularBeckmann")); makeFramebuffer->setRenderBuffer(0, beckmannMap); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index e43afd94a9..b461e46c04 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -74,22 +74,19 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _linearDepthTexture->setSource("LinearDepthFramebuffer::_linearDepthTexture"); - _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); // For Downsampling: _halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _halfLinearDepthTexture->setSource("LinearDepthFramebuffer::_halfLinearDepthTexture"); _halfLinearDepthTexture->autoGenerateMips(5); _halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _halfNormalTexture->setSource("LinearDepthFramebuffer::_halfNormalTexture"); - _downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("halfLinearDepth")); _downsampleFramebuffer->setRenderBuffer(0, _halfLinearDepthTexture); _downsampleFramebuffer->setRenderBuffer(1, _halfNormalTexture); } @@ -304,18 +301,15 @@ void SurfaceGeometryFramebuffer::allocate() { auto height = _frameSize.y; _curvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _curvatureTexture->setSource("SurfaceGeometryFramebuffer::_curvatureTexture"); - _curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::curvature")); _curvatureFramebuffer->setRenderBuffer(0, _curvatureTexture); _lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _lowCurvatureTexture->setSource("SurfaceGeometryFramebuffer::_lowCurvatureTexture"); - _lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::lowCurvature")); _lowCurvatureFramebuffer->setRenderBuffer(0, _lowCurvatureTexture); _blurringTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _blurringTexture->setSource("SurfaceGeometryFramebuffer::_blurringTexture"); - _blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::blurring")); _blurringFramebuffer->setRenderBuffer(0, _blurringTexture); } diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 144e1e0058..f8b5546b92 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -101,7 +101,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra } if (!_blurredFramebuffer) { - _blurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _blurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("blur")); // attach depthStencil if present in source //if (sourceFramebuffer->hasDepthStencil()) { @@ -124,7 +124,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra // The job output the blur result in a new Framebuffer spawning here. // Let s make sure it s ready for this if (!_outputFramebuffer) { - _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("blurOutput")); // attach depthStencil if present in source /* if (sourceFramebuffer->hasDepthStencil()) { diff --git a/plugins/hifiNeuron/src/NeuronProvider.cpp b/plugins/hifiNeuron/src/NeuronProvider.cpp index b171c5150d..5315ff105e 100644 --- a/plugins/hifiNeuron/src/NeuronProvider.cpp +++ b/plugins/hifiNeuron/src/NeuronProvider.cpp @@ -38,6 +38,10 @@ public: return _inputPlugins; } + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } + private: InputPluginList _inputPlugins; }; diff --git a/plugins/hifiSdl2/src/SDL2Provider.cpp b/plugins/hifiSdl2/src/SDL2Provider.cpp index 1c387a9886..c3315dee07 100644 --- a/plugins/hifiSdl2/src/SDL2Provider.cpp +++ b/plugins/hifiSdl2/src/SDL2Provider.cpp @@ -37,6 +37,10 @@ public: return _inputPlugins; } + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } + private: InputPluginList _inputPlugins; }; diff --git a/plugins/hifiSixense/src/SixenseProvider.cpp b/plugins/hifiSixense/src/SixenseProvider.cpp index 2958e47848..aded33db24 100644 --- a/plugins/hifiSixense/src/SixenseProvider.cpp +++ b/plugins/hifiSixense/src/SixenseProvider.cpp @@ -38,6 +38,9 @@ public: return _inputPlugins; } + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } private: InputPluginList _inputPlugins; }; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 377050064a..7209104a85 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -126,3 +126,7 @@ void OculusBaseDisplayPlugin::updatePresentPose() { //_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose); _currentPresentFrameInfo.presentPose = _currentPresentFrameInfo.renderPose; } + +OculusBaseDisplayPlugin::~OculusBaseDisplayPlugin() { + qDebug() << "Destroying OculusBaseDisplayPlugin"; +} diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index 25629f004a..023f933acf 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -16,6 +16,7 @@ class OculusBaseDisplayPlugin : public HmdDisplayPlugin { using Parent = HmdDisplayPlugin; public: + ~OculusBaseDisplayPlugin(); bool isSupported() const override; // Stereo specific methods diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 838a4121cd..b5f4d79042 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -46,7 +46,7 @@ void OculusDisplayPlugin::cycleDebugOutput() { void OculusDisplayPlugin::customizeContext() { Parent::customizeContext(); - _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y)); + _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OculusOutput", gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y)); ovrTextureSwapChainDesc desc = { }; desc.Type = ovrTexture_2D; desc.ArraySize = 1; @@ -97,6 +97,7 @@ void OculusDisplayPlugin::uncustomizeContext() { ovr_DestroyTextureSwapChain(_session, _textureSwapChain); _textureSwapChain = nullptr; + _outputFramebuffer.reset(); Parent::uncustomizeContext(); } @@ -163,3 +164,7 @@ QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { } return AudioClient::friendlyNameForAudioDevice(buffer); } + +OculusDisplayPlugin::~OculusDisplayPlugin() { + qDebug() << "Destroying OculusDisplayPlugin"; +} diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index 80705319c6..4d10fd38a5 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -12,6 +12,7 @@ class OculusDisplayPlugin : public OculusBaseDisplayPlugin { using Parent = OculusBaseDisplayPlugin; public: + ~OculusDisplayPlugin(); const QString& getName() const override { return NAME; } void init() override; diff --git a/plugins/oculus/src/OculusProvider.cpp b/plugins/oculus/src/OculusProvider.cpp index e723fa839a..47ccc5304e 100644 --- a/plugins/oculus/src/OculusProvider.cpp +++ b/plugins/oculus/src/OculusProvider.cpp @@ -62,6 +62,14 @@ public: return _inputPlugins; } + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } + + virtual void destroyDisplayPlugins() override { + _displayPlugins.clear(); + } + private: DisplayPluginList _displayPlugins; InputPluginList _inputPlugins; diff --git a/plugins/oculusLegacy/src/OculusProvider.cpp b/plugins/oculusLegacy/src/OculusProvider.cpp index 606563e0ad..fbfc66b432 100644 --- a/plugins/oculusLegacy/src/OculusProvider.cpp +++ b/plugins/oculusLegacy/src/OculusProvider.cpp @@ -38,6 +38,10 @@ public: return _displayPlugins; } + virtual void destroyDisplayPlugins() override { + _displayPlugins.clear(); + } + private: DisplayPluginList _displayPlugins; }; diff --git a/plugins/openvr/src/OpenVrProvider.cpp b/plugins/openvr/src/OpenVrProvider.cpp index 66227a9543..944322373a 100644 --- a/plugins/openvr/src/OpenVrProvider.cpp +++ b/plugins/openvr/src/OpenVrProvider.cpp @@ -51,6 +51,13 @@ public: return _inputPlugins; } + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } + + virtual void destroyDisplayPlugins() override { + _displayPlugins.clear(); + } private: DisplayPluginList _displayPlugins; From a44653db5717322ec709817ae4b48d2bd9650681 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 12 Oct 2016 10:47:42 -0700 Subject: [PATCH 13/27] Update ds path queries to be reliable --- domain-server/src/DomainServer.cpp | 2 +- libraries/networking/src/NodeList.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d7bcaa838e..32d09c517a 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2239,7 +2239,7 @@ void DomainServer::processPathQueryPacket(QSharedPointer messag QByteArray viewpointUTF8 = responseViewpoint.toUtf8(); // prepare a packet for the response - auto pathResponsePacket = NLPacket::create(PacketType::DomainServerPathResponse); + auto pathResponsePacket = NLPacket::create(PacketType::DomainServerPathResponse, -1, true); // check the number of bytes the viewpoint is quint16 numViewpointBytes = viewpointUTF8.size(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 617ba85bad..27e6f17c33 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -389,7 +389,7 @@ void NodeList::sendDSPathQuery(const QString& newPath) { // only send a path query if we know who our DS is or is going to be if (_domainHandler.isSocketKnown()) { // construct the path query packet - auto pathQueryPacket = NLPacket::create(PacketType::DomainServerPathQuery); + auto pathQueryPacket = NLPacket::create(PacketType::DomainServerPathQuery, -1, true); // get the UTF8 representation of path query QByteArray pathQueryUTF8 = newPath.toUtf8(); From ba4c356d7f0bdcd4d318d6283c50bdb1f8359c02 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 12 Oct 2016 11:05:19 -0700 Subject: [PATCH 14/27] Deadlock fix in avatar grab action. Reverse the order we acquire the entityTree & holdActions locks, to avoid deadlocks when the network thread also acquires them. The network thread does this when hold actions from other avatars are received. --- interface/src/avatar/MyAvatar.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 19346e51db..27e827cb68 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2283,12 +2283,13 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose& EntityTreeRenderer* entityTreeRenderer = qApp->getEntities(); EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr; if (entityTree) { - // to prevent actions from adding or removing themselves from the _holdActions vector - // while we are iterating, we need to enter a critical section. - std::lock_guard guard(_holdActionsMutex); - // lateAvatarUpdate will modify entity position & orientation, so we need an entity write lock entityTree->withWriteLock([&] { + + // to prevent actions from adding or removing themselves from the _holdActions vector + // while we are iterating, we need to enter a critical section. + std::lock_guard guard(_holdActionsMutex); + for (auto& holdAction : _holdActions) { holdAction->lateAvatarUpdate(prePhysicsPose, postUpdatePose); } From 0099a4e549e985b29844eadcf993c521eeb11516 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 12 Oct 2016 11:23:06 -0700 Subject: [PATCH 15/27] allow hand controller operations when Interface doesn't have focus, but ONLY when in hmd. --- scripts/system/controllers/handControllerPointer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 5bb8ea8a90..fb256413ae 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -471,7 +471,12 @@ function update() { if (!Menu.isOptionChecked("First Person")) { return off(); // What to do? menus can be behind hand! } - if (!Window.hasFocus() || !Reticle.allowMouseCapture) { + if ((!Window.hasFocus() && !HMD.active) || !Reticle.allowMouseCapture) { + // In desktop it's pretty clear when another app is on top. In that case we bail, because + // hand controllers might be sputtering "valid" data and that will keep someone from deliberately + // using the mouse on another app. (Fogbugz case 546.) + // However, in HMD, you might not realize you're not on top, and you wouldn't be able to operate + // other apps anyway. So in that case, we DO keep going even though we're not on top. (Fogbugz 1831.) return off(); // Don't mess with other apps or paused mouse activity } leftTrigger.update(); From c8850a8b8e22c12d5dafb7ed6d3d42423b766f32 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 12 Oct 2016 12:44:24 -0700 Subject: [PATCH 16/27] PR feedback AgentAvatarTimer now in its own files. The thread still is created the same way, and started only when you are an avatar, but now I remember to stop it when you no longer are one. Audio is still at 100Hz, but avatar messages go at 60Hz as before. Unsure it matters, but easy to do. Looking at that buzz now. --- assignment-client/src/Agent.cpp | 188 ++++++++++----------- assignment-client/src/Agent.h | 19 +-- assignment-client/src/AvatarAudioTimer.cpp | 33 ++++ assignment-client/src/AvatarAudioTimer.h | 31 ++++ 4 files changed, 157 insertions(+), 114 deletions(-) create mode 100644 assignment-client/src/AvatarAudioTimer.cpp create mode 100644 assignment-client/src/AvatarAudioTimer.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9be55c15a7..14b3c0e90f 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -46,26 +46,10 @@ #include "AbstractAudioInterface.h" #include "Agent.h" +#include "AvatarAudioTimer.h" static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; -// this should send a signal every 10ms, with pretty good precision -void AvatarAudioTimer::start() { - qDebug() << "AvatarAudioTimer::start called"; - auto startTime = usecTimestampNow(); - quint64 frameCounter = 0; - const int TARGET_INTERVAL_USEC = 10000; // 10ms - while (!_quit) { - frameCounter++; - // simplest possible timer - quint64 targetTime = startTime + frameCounter * TARGET_INTERVAL_USEC; - quint64 interval = std::max((quint64)0, targetTime - usecTimestampNow()); - usleep(interval); - emit avatarTick(); - } - qDebug() << "AvatarAudioTimer is finished"; -} - Agent::Agent(ReceivedMessage& message) : ThreadedAssignment(message), _entityEditSender(), @@ -399,14 +383,17 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); + // 100Hz timer for audio AvatarAudioTimer* audioTimerWorker = new AvatarAudioTimer(); audioTimerWorker->moveToThread(&_avatarAudioTimerThread); - connect(audioTimerWorker, &AvatarAudioTimer::avatarTick, this, &Agent::processAgentAvatarAndAudio); + connect(audioTimerWorker, &AvatarAudioTimer::avatarTick, this, &Agent::processAgentAvatarAudio); connect(this, &Agent::startAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::start); connect(this, &Agent::stopAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::stop); connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater); _avatarAudioTimerThread.start(); - + + // 60Hz timer for avatar + QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatar); _scriptEngine->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); @@ -460,6 +447,7 @@ void Agent::setIsAvatar(bool isAvatar) { nodeList->sendPacketList(std::move(packetList), *node); }); } + emit stopAvatarAudioTimer(); } } @@ -470,7 +458,7 @@ void Agent::sendAvatarIdentityPacket() { } } -void Agent::processAgentAvatarAndAudio() { +void Agent::processAgentAvatar() { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); @@ -486,102 +474,106 @@ void Agent::processAgentAvatarAndAudio() { auto nodeList = DependencyManager::get(); nodeList->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); + } +} - if (_isListeningToAudioStream || _avatarSound) { - // if we have an avatar audio stream then send it out to our audio-mixer - bool silentFrame = true; +void Agent::processAgentAvatarAudio() { + if (_isAvatar && (_isListeningToAudioStream || _avatarSound)) { + // if we have an avatar audio stream then send it out to our audio-mixer + auto scriptedAvatar = DependencyManager::get(); + bool silentFrame = true; - int16_t numAvailableSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; - const int16_t* nextSoundOutput = NULL; + int16_t numAvailableSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; + const int16_t* nextSoundOutput = NULL; - if (_avatarSound) { - const QByteArray& soundByteArray = _avatarSound->getByteArray(); - nextSoundOutput = reinterpret_cast(soundByteArray.data() + if (_avatarSound) { + const QByteArray& soundByteArray = _avatarSound->getByteArray(); + nextSoundOutput = reinterpret_cast(soundByteArray.data() + _numAvatarSoundSentBytes); - int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL - ? AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL - : soundByteArray.size() - _numAvatarSoundSentBytes; - numAvailableSamples = (int16_t)numAvailableBytes / sizeof(int16_t); + int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL + ? AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL + : soundByteArray.size() - _numAvatarSoundSentBytes; + numAvailableSamples = (int16_t)numAvailableBytes / sizeof(int16_t); - // check if the all of the _numAvatarAudioBufferSamples to be sent are silence - for (int i = 0; i < numAvailableSamples; ++i) { - if (nextSoundOutput[i] != 0) { - silentFrame = false; - break; - } - } - - _numAvatarSoundSentBytes += numAvailableBytes; - if (_numAvatarSoundSentBytes == soundByteArray.size()) { - // we're done with this sound object - so set our pointer back to NULL - // and our sent bytes back to zero - _avatarSound.clear(); - _numAvatarSoundSentBytes = 0; + // check if the all of the _numAvatarAudioBufferSamples to be sent are silence + for (int i = 0; i < numAvailableSamples; ++i) { + if (nextSoundOutput[i] != 0) { + silentFrame = false; + break; } } - auto audioPacket = NLPacket::create(silentFrame + _numAvatarSoundSentBytes += numAvailableBytes; + if (_numAvatarSoundSentBytes == soundByteArray.size()) { + // we're done with this sound object - so set our pointer back to NULL + // and our sent bytes back to zero + _avatarSound.clear(); + _numAvatarSoundSentBytes = 0; + } + } + + auto audioPacket = NLPacket::create(silentFrame ? PacketType::SilentAudioFrame : PacketType::MicrophoneAudioNoEcho); - // seek past the sequence number, will be packed when destination node is known - audioPacket->seek(sizeof(quint16)); - - if (silentFrame) { - if (!_isListeningToAudioStream) { - // if we have a silent frame and we're not listening then just send nothing and break out of here - return; - } - - // write the number of silent samples so the audio-mixer can uphold timing - audioPacket->writePrimitive(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); - - // use the orientation and position of this avatar for the source of this audio - audioPacket->writePrimitive(scriptedAvatar->getPosition()); - glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); - audioPacket->writePrimitive(headOrientation); - - } else if (nextSoundOutput) { - // write the codec - audioPacket->writeString(_selectedCodecName); - - // assume scripted avatar audio is mono and set channel flag to zero - audioPacket->writePrimitive((quint8)0); - - // use the orientation and position of this avatar for the source of this audio - audioPacket->writePrimitive(scriptedAvatar->getPosition()); - glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); - audioPacket->writePrimitive(headOrientation); - - // encode it - if(_encoder) { - QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); - QByteArray encodedBuffer; - _encoder->encode(decodedBuffer, encodedBuffer); - audioPacket->write(encodedBuffer.data(), encodedBuffer.size()); - } else { - audioPacket->write(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); - } + // seek past the sequence number, will be packed when destination node is known + audioPacket->seek(sizeof(quint16)); + if (silentFrame) { + if (!_isListeningToAudioStream) { + // if we have a silent frame and we're not listening then just send nothing and break out of here + return; } - // write audio packet to AudioMixer nodes - auto nodeList = DependencyManager::get(); - nodeList->eachNode([this, &nodeList, &audioPacket](const SharedNodePointer& node){ - // only send to nodes of type AudioMixer - if (node->getType() == NodeType::AudioMixer) { - // pack sequence number - quint16 sequence = _outgoingScriptAudioSequenceNumbers[node->getUUID()]++; - audioPacket->seek(0); - audioPacket->writePrimitive(sequence); + // write the number of silent samples so the audio-mixer can uphold timing + audioPacket->writePrimitive(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + + // use the orientation and position of this avatar for the source of this audio + audioPacket->writePrimitive(scriptedAvatar->getPosition()); + glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); + audioPacket->writePrimitive(headOrientation); + + } else if (nextSoundOutput) { + + // write the codec + audioPacket->writeString(_selectedCodecName); + + // assume scripted avatar audio is mono and set channel flag to zero + audioPacket->writePrimitive((quint8)0); + + // use the orientation and position of this avatar for the source of this audio + audioPacket->writePrimitive(scriptedAvatar->getPosition()); + glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); + audioPacket->writePrimitive(headOrientation); + + // encode it + if(_encoder) { + QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); + QByteArray encodedBuffer; + _encoder->encode(decodedBuffer, encodedBuffer); + audioPacket->write(encodedBuffer.data(), encodedBuffer.size()); + } else { + audioPacket->write(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); + } - // send audio packet - nodeList->sendUnreliablePacket(*audioPacket, *node); - } - }); } + + // write audio packet to AudioMixer nodes + auto nodeList = DependencyManager::get(); + nodeList->eachNode([this, &nodeList, &audioPacket](const SharedNodePointer& node) { + // only send to nodes of type AudioMixer + if (node->getType() == NodeType::AudioMixer) { + // pack sequence number + quint16 sequence = _outgoingScriptAudioSequenceNumbers[node->getUUID()]++; + audioPacket->seek(0); + audioPacket->writePrimitive(sequence); + + // send audio packet + nodeList->sendUnreliablePacket(*audioPacket, *node); + } + }); } } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index cbb1af2e33..67dba10de2 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -31,21 +31,6 @@ #include "MixedAudioStream.h" - -class AvatarAudioTimer : public QObject { - Q_OBJECT - -signals: - void avatarTick(); - -public slots: - void start(); - void stop() { _quit = true; } - -private: - bool _quit { false }; -}; - class Agent : public ThreadedAssignment { Q_OBJECT @@ -74,7 +59,6 @@ public: public slots: void run() override; void playAvatarSound(SharedSoundPointer avatarSound); - void processAgentAvatarAndAudio(); private slots: void requestScript(); @@ -87,6 +71,9 @@ private slots: void handleSelectedAudioFormat(QSharedPointer message); void nodeActivated(SharedNodePointer activatedNode); + + void processAgentAvatar(); + void processAgentAvatarAudio(); signals: void startAvatarAudioTimer(); diff --git a/assignment-client/src/AvatarAudioTimer.cpp b/assignment-client/src/AvatarAudioTimer.cpp new file mode 100644 index 0000000000..857209df7c --- /dev/null +++ b/assignment-client/src/AvatarAudioTimer.cpp @@ -0,0 +1,33 @@ +// +// AvatarAudioTimer.cpp +// assignment-client/src +// +// Created by David Kelly on 10/12/13. +// Copyright 2016 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 +#include +#include "AvatarAudioTimer.h" + +// this should send a signal every 10ms, with pretty good precision. Hardcoding +// to 10ms since that's what you'd want for audio. +void AvatarAudioTimer::start() { + qDebug() << "AvatarAudioTimer::start called"; + auto startTime = usecTimestampNow(); + quint64 frameCounter = 0; + const int TARGET_INTERVAL_USEC = 10000; // 10ms + while (!_quit) { + frameCounter++; + // simplest possible timer + quint64 targetTime = startTime + frameCounter * TARGET_INTERVAL_USEC; + quint64 interval = std::max((quint64)0, targetTime - usecTimestampNow()); + usleep(interval); + emit avatarTick(); + } + qDebug() << "AvatarAudioTimer is finished"; +} + + diff --git a/assignment-client/src/AvatarAudioTimer.h b/assignment-client/src/AvatarAudioTimer.h new file mode 100644 index 0000000000..1f6381b030 --- /dev/null +++ b/assignment-client/src/AvatarAudioTimer.h @@ -0,0 +1,31 @@ +// +// AvatarAudioTimer.h +// assignment-client/src +// +// Created by David Kelly on 10/12/13. +// Copyright 2016 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_AvatarAudioTimer_h +#define hifi_AvatarAudioTimer_h + +#include + +class AvatarAudioTimer : public QObject { + Q_OBJECT + +signals: + void avatarTick(); + +public slots: + void start(); + void stop() { _quit = true; } + +private: + bool _quit { false }; +}; + +#endif //hifi_AvatarAudioTimer_h From aa52963e5d12156bf15c27c76190be5edc25031c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 12 Oct 2016 12:59:43 -0700 Subject: [PATCH 17/27] Made the Grip buttons less sensitive to inadvertent squeezes. --- interface/resources/controllers/oculus_touch.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/controllers/oculus_touch.json b/interface/resources/controllers/oculus_touch.json index 455f9c304b..3edad8be55 100644 --- a/interface/resources/controllers/oculus_touch.json +++ b/interface/resources/controllers/oculus_touch.json @@ -22,7 +22,7 @@ }, { "from": "OculusTouch.LT", "to": "Standard.LT" }, { "from": "OculusTouch.LS", "to": "Standard.LS" }, - { "from": "OculusTouch.LeftGrip", "filters": { "type": "deadZone", "min": 0.3 }, "to": "Standard.LeftGrip" }, + { "from": "OculusTouch.LeftGrip", "filters": { "type": "deadZone", "min": 0.5 }, "to": "Standard.LeftGrip" }, { "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" }, { "from": "OculusTouch.RY", "to": "Standard.RY", @@ -38,7 +38,7 @@ }, { "from": "OculusTouch.RT", "to": "Standard.RT" }, { "from": "OculusTouch.RS", "to": "Standard.RS" }, - { "from": "OculusTouch.RightGrip", "filters": { "type": "deadZone", "min": 0.3 }, "to": "Standard.RightGrip" }, + { "from": "OculusTouch.RightGrip", "filters": { "type": "deadZone", "min": 0.5 }, "to": "Standard.RightGrip" }, { "from": "OculusTouch.RightHand", "to": "Standard.RightHand" }, { "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" }, From 867fc3ccbf5946f7c96e1941c0339a7cce252e31 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Oct 2016 16:37:29 -0700 Subject: [PATCH 18/27] prevent avatar from recentering below ground --- interface/src/avatar/MyAvatar.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 19346e51db..3f906cfff7 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -247,6 +247,15 @@ void MyAvatar::centerBody() { auto worldBodyPos = extractTranslation(worldBodyMatrix); auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); + if (_characterController.getState() == CharacterController::State::Ground) { + // the avatar's physical aspect thinks it is standing on something + // therefore need to be careful to not "center" the body below the floor + float downStep = glm::dot(worldBodyPos - getPosition(), _worldUpDirection); + if (downStep < -0.5f * _characterController.getCapsuleHalfHeight() + _characterController.getCapsuleRadius()) { + worldBodyPos -= downStep * _worldUpDirection; + } + } + // this will become our new position. setPosition(worldBodyPos); setOrientation(worldBodyRot); From 579c95b5dd9074f3745668d244edf9faac919c17 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 12 Oct 2016 14:42:41 -0700 Subject: [PATCH 19/27] pr feedback --- scripts/developer/tests/performance/summon.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/developer/tests/performance/summon.js b/scripts/developer/tests/performance/summon.js index 25ecd4860b..3eecba8413 100644 --- a/scripts/developer/tests/performance/summon.js +++ b/scripts/developer/tests/performance/summon.js @@ -23,9 +23,9 @@ var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's lengt var SOUND_DATA = {url: "http://howard-stearns.github.io/models/sounds/piano1.wav"}; var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND at once. var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next -var ANIMATION_DATA = { // T-pose until we get animations working again. +var ANIMATION_DATA = { "url": "http://howard-stearns.github.io/models/resources/avatar/animations/idle.fbx", - //"url": "http://howard-stearns.github.io/models/resources/avatar/animations/walk_fwd.fbx", + // "url": "http://howard-stearns.github.io/models/resources/avatar/animations/walk_fwd.fbx", // alternative example "startFrame": 0.0, "endFrame": 300.0, "timeScale": 1.0, @@ -80,8 +80,6 @@ function messageHandler(channel, messageString, senderID) { position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}), orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0), soundData: chatter && SOUND_DATA, - // No need to specify skeletonModelURL - //skeletonModelURL: "file:///c:/Program Files/High Fidelity Release/resources/meshes/defaultAvatar_full.fst"/, animationData: ANIMATION_DATA }); } From 4bea6f29318ac1a33563147aa77a27139ca7ffd4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Oct 2016 15:16:41 -0700 Subject: [PATCH 20/27] Update window size automaticatlly --- server-console/src/content-update.html | 8 ++++---- server-console/src/content-update.js | 5 +++++ server-console/src/main.js | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/server-console/src/content-update.html b/server-console/src/content-update.html index c4ed14473a..279b72fbc0 100644 --- a/server-console/src/content-update.html +++ b/server-console/src/content-update.html @@ -6,7 +6,7 @@ -
+

We backed up your old Sandbox content, just in case.

To restore it, follow these steps: @@ -45,9 +45,9 @@

- diff --git a/server-console/src/content-update.js b/server-console/src/content-update.js index c77cfc92c6..2835444841 100644 --- a/server-console/src/content-update.js +++ b/server-console/src/content-update.js @@ -6,6 +6,11 @@ function ready() { electron.ipcRenderer.on('update', function(event, message) { $('#directory').html(message); + + electron.ipcRenderer.send('setSize', { + width: $(window).width(), + height: $('#content').height() + 50 + }); }); electron.ipcRenderer.send('ready'); diff --git a/server-console/src/main.js b/server-console/src/main.js index 92bb549fbb..2d9320da15 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -530,6 +530,9 @@ function openBackupInstructions(folder) { } window.show(); + electron.ipcMain.on('setSize', function(event, obj) { + window.setSize(obj.width, obj.height); + }); electron.ipcMain.on('ready', function() { console.log("got ready"); window.webContents.send('update', folder); From f0dba9e76691456da79dffc724bf70fb658e4119 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 12 Oct 2016 16:29:05 -0700 Subject: [PATCH 21/27] Prevent crash on exit. If you or another user begins to near-grab an object while you exit the application, you might run into this crash. The PhysicalEntitySimulation has a list of AvatarHoldActions shared_ptr's. When it is destroyed, via the Application destructor, it will release these pointers. This in turn will invoke a AvatarHoldAction destructor, which attempts to reference the AvatarManager via the DependencyManager. However at this point the AvatarManager has already been destroyed, leading to a null dereference. The fix is to check the AvatarManager pointer first. --- interface/src/avatar/AvatarActionHold.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index e85cb8913c..85ff485d7a 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -37,9 +37,13 @@ AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntit } AvatarActionHold::~AvatarActionHold() { - auto myAvatar = DependencyManager::get()->getMyAvatar(); - if (myAvatar) { - myAvatar->removeHoldAction(this); + // Sometimes actions are destroyed after the AvatarManager is destroyed by the Application. + auto avatarManager = DependencyManager::get(); + if (avatarManager) { + auto myAvatar = avatarManager->getMyAvatar(); + if (myAvatar) { + myAvatar->removeHoldAction(this); + } } #if WANT_DEBUG From 0e567da8d2d599034337b0e7bf602b11fb57dfc0 Mon Sep 17 00:00:00 2001 From: Mat Tyndall Date: Thu, 13 Oct 2016 00:01:17 -0700 Subject: [PATCH 22/27] changed USE_STABLE_GLOBAL_SERVICES to use 1 --- cmake/macros/SetPackagingParameters.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 531f9a1da2..67aee72738 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -43,7 +43,7 @@ macro(SET_PACKAGING_PARAMETERS) if (BUILD_BRANCH STREQUAL "stable") message(STATUS "The RELEASE_TYPE is PRODUCTION and the BUILD_BRANCH is stable...") set(BUILD_GLOBAL_SERVICES "STABLE") - set(USE_STABLE_GLOBAL_SERVICES TRUE) + set(USE_STABLE_GLOBAL_SERVICES 1) endif() elseif (RELEASE_TYPE STREQUAL "PR") From 1966a710b58c64d5b91ad455c6ee27522395c302 Mon Sep 17 00:00:00 2001 From: Mat Tyndall Date: Thu, 13 Oct 2016 00:12:05 -0700 Subject: [PATCH 23/27] set inital USE_STABLE_GLOBAL_SERVICES to 0 --- cmake/macros/SetPackagingParameters.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 67aee72738..6ce3c95cdd 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -20,7 +20,7 @@ macro(SET_PACKAGING_PARAMETERS) set(RELEASE_NUMBER $ENV{RELEASE_NUMBER}) string(TOLOWER "$ENV{BRANCH}" BUILD_BRANCH) set(BUILD_GLOBAL_SERVICES "DEVELOPMENT") - set(USE_STABLE_GLOBAL_SERVICES FALSE) + set(USE_STABLE_GLOBAL_SERVICES 0) message(STATUS "The BUILD_BRANCH variable is: ${BUILD_BRANCH}") message(STATUS "The BRANCH environment variable is: $ENV{BRANCH}") From 55d4695489b0ca2f6d001976c3c66d5bed7e6be1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Oct 2016 11:51:54 -0700 Subject: [PATCH 24/27] Fix edit.js not allowing imports when you only have temp rez permissions --- scripts/system/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index d673bb4653..1382c94f9c 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1155,7 +1155,7 @@ function getPositionToImportEntity() { return position; } function importSVO(importURL) { - if (!Entities.canAdjustLocks()) { + if (!Entities.canRez() && !Entities.canRezTmp()) { Window.notifyEditError(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG); return; } From decb94b719311dba73338538f73216214c6fc37b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Oct 2016 14:01:45 -0700 Subject: [PATCH 25/27] Update ScriptCache to clear ATP assets when disconnected from a domain --- interface/src/Application.cpp | 4 ++++ libraries/script-engine/src/ScriptCache.cpp | 13 +++++++++++++ libraries/script-engine/src/ScriptCache.h | 1 + 3 files changed, 18 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80e444462f..5658ed8b64 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -668,6 +668,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused); + // We could clear ATP assets only when changing domains, but it's possible that the domain you are connected + // to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid. + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get().data(), &ScriptCache::clearATPScriptsFromCache); + // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SECOND; diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index e9f20b5164..a2a6a9ecf1 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -36,6 +36,19 @@ void ScriptCache::clearCache() { _scriptCache.clear(); } +void ScriptCache::clearATPScriptsFromCache() { + Lock lock(_containerLock); + qDebug(scriptengine) << "Clearing ATP scripts from ScriptCache"; + for (auto it = _scriptCache.begin(); it != _scriptCache.end();) { + if (it.key().scheme() == "atp") { + qDebug(scriptengine) << "Removing: " << it.key(); + it = _scriptCache.erase(it); + } else { + ++it; + } + } +} + QString ScriptCache::getScript(const QUrl& unnormalizedURL, ScriptUser* scriptUser, bool& isPending, bool reload) { QUrl url = ResourceManager::normalizeURL(unnormalizedURL); QString scriptContents; diff --git a/libraries/script-engine/src/ScriptCache.h b/libraries/script-engine/src/ScriptCache.h index 17ba5c4b0a..5aac62b08b 100644 --- a/libraries/script-engine/src/ScriptCache.h +++ b/libraries/script-engine/src/ScriptCache.h @@ -39,6 +39,7 @@ class ScriptCache : public QObject, public Dependency { public: void clearCache(); + Q_INVOKABLE void clearATPScriptsFromCache(); void getScriptContents(const QString& scriptOrURL, contentAvailableCallback contentAvailable, bool forceDownload = false); From 7626f49ddc964b4a1d69609f87fd4280f33b35ee Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Oct 2016 15:43:28 -0700 Subject: [PATCH 26/27] Replace qDebug with qCDebug in ScriptCache --- libraries/script-engine/src/ScriptCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index a2a6a9ecf1..96e3d7e914 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -38,10 +38,10 @@ void ScriptCache::clearCache() { void ScriptCache::clearATPScriptsFromCache() { Lock lock(_containerLock); - qDebug(scriptengine) << "Clearing ATP scripts from ScriptCache"; + qCDebug(scriptengine) << "Clearing ATP scripts from ScriptCache"; for (auto it = _scriptCache.begin(); it != _scriptCache.end();) { if (it.key().scheme() == "atp") { - qDebug(scriptengine) << "Removing: " << it.key(); + qCDebug(scriptengine) << "Removing: " << it.key(); it = _scriptCache.erase(it); } else { ++it; From 6cf4802cc22e157007692e18e1911ad7bb2be099 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Oct 2016 16:06:07 -0700 Subject: [PATCH 27/27] Change default hifi address from dev-welcome to welcome --- libraries/networking/src/AddressManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index f753bb0548..ab7b53a6d9 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -23,7 +23,7 @@ #include "AccountManager.h" const QString HIFI_URL_SCHEME = "hifi"; -const QString DEFAULT_HIFI_ADDRESS = "hifi://dev-welcome"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome"; const QString SANDBOX_HIFI_ADDRESS = "hifi://localhost"; const QString SANDBOX_STATUS_URL = "http://localhost:60332/status"; const QString INDEX_PATH = "/";