diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 4d0e1bf19c..4173cacfc7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -61,7 +61,7 @@ const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18; -const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.001f; +const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f; const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; const QString AUDIO_ENV_GROUP_KEY = "audio_env"; const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer"; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index a49e1072eb..ba4cfe8dfd 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -93,8 +93,8 @@ "name": "noise_muting_threshold", "label": "Noise Muting Threshold", "help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)", - "placeholder": "0.001", - "default": "0.001", + "placeholder": "0.003", + "default": "0.003", "advanced": false }, { diff --git a/examples/entityScripts/changeColorOnHover.js b/examples/entityScripts/changeColorOnHover.js index de3f5f3784..638c1bece4 100644 --- a/examples/entityScripts/changeColorOnHover.js +++ b/examples/entityScripts/changeColorOnHover.js @@ -22,13 +22,21 @@ this.oldColorKnown = true; print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); }; + + this.preload = function(entityID) { + print("preload"); + this.storeOldColor(entityID); + }; + this.hoverEnterEntity = function(entityID, mouseEvent) { + print("hoverEnterEntity"); if (!this.oldColorKnown) { this.storeOldColor(entityID); } Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} }); }; this.hoverLeaveEntity = function(entityID, mouseEvent) { + print("hoverLeaveEntity"); if (this.oldColorKnown) { print("leave restoring old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); diff --git a/examples/entityScripts/playSoundOnClick.js b/examples/entityScripts/playSoundOnClick.js index b261bb269a..4bc523a7aa 100644 --- a/examples/entityScripts/playSoundOnClick.js +++ b/examples/entityScripts/playSoundOnClick.js @@ -12,13 +12,23 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function(){ - var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + var bird; + + function playSound(entityID) { + var options = new AudioInjectionOptions(); + var position = MyAvatar.position; + options.position = position; + options.volume = 0.5; + Audio.playSound(bird, options); + }; + + this.preload = function(entityID) { + print("preload("+entityID.id+")"); + bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + }; + this.clickDownOnEntity = function(entityID, mouseEvent) { print("clickDownOnEntity()..."); - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + playSound(); }; }) diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index 228a8a36d0..98702dcfdd 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -12,9 +12,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function(){ - var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + var bird; - function playSound(entityID) { + function playSound() { var options = new AudioInjectionOptions(); var position = MyAvatar.position; options.position = position; @@ -22,6 +22,11 @@ Audio.playSound(bird, options); }; + this.preload = function(entityID) { + print("preload("+entityID.id+")"); + bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + }; + this.enterEntity = function(entityID) { playSound(); }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b1c969b66f..bb19ce3ca5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -837,14 +837,12 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod } bool Application::event(QEvent* event) { - // handle custom URL if (event->type() == QEvent::FileOpen) { QFileOpenEvent* fileEvent = static_cast(event); - - if (!fileEvent->url().isEmpty()) { - AddressManager::getInstance().handleLookupString(fileEvent->url().toLocalFile()); + if (fileEvent->url().isValid()) { + openUrl(fileEvent->url()); } return false; diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 2f8ddb1095..1876b6c624 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -81,6 +81,9 @@ void EntityTreeRenderer::init() { _lastAvatarPosition = avatarPosition + glm::vec3(1.f, 1.f, 1.f); connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity); + connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::checkAndCallPreload); + connect(entityTree, &EntityTree::entityScriptChanging, this, &EntityTreeRenderer::checkAndCallPreload); + connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID); } QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) { @@ -770,3 +773,20 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { _entityScripts.remove(entityID); } +void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) { + // load the entity script if needed... + QScriptValue entityScript = loadEntityScript(entityID); + if (entityScript.property("preload").isValid()) { + QScriptValueList entityArgs = createEntityArgs(entityID); + entityScript.property("preload").call(entityScript, entityArgs); + } +} + +void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID) { + if (_entityScripts.contains(oldEntityID)) { + EntityScriptDetails details = _entityScripts[oldEntityID]; + _entityScripts.remove(oldEntityID); + _entityScripts[newEntityID] = details; + } +} + diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index ff9066dd6d..7c1c81b6c9 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -104,6 +104,8 @@ signals: public slots: void deletingEntity(const EntityItemID& entityID); + void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID); + void checkAndCallPreload(const EntityItemID& entityID); private: QList _releasedModels; diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 1742afba05..9052ec910f 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -547,7 +547,8 @@ NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer& owner) { } void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) { - for (int i = 0; i < _meshes.size(); i++) { - NetworkMesh& mesh = _meshes[i]; - for (int j = 0; j < mesh.parts.size(); j++) { - NetworkMeshPart& part = mesh.parts[j]; - - QSharedPointer matchingTexture = QSharedPointer(); - if (part.diffuseTextureName == name) { - part.diffuseTexture = + if (_meshes.size() > 0) { + for (int i = 0; i < _meshes.size(); i++) { + NetworkMesh& mesh = _meshes[i]; + for (int j = 0; j < mesh.parts.size(); j++) { + NetworkMeshPart& part = mesh.parts[j]; + + QSharedPointer matchingTexture = QSharedPointer(); + if (part.diffuseTextureName == name) { + part.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, _geometry.meshes[i].isEye, QByteArray()); - part.diffuseTexture->setLoadPriorities(_loadPriorities); - } else if (part.normalTextureName == name) { - part.normalTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, - false, QByteArray()); - part.normalTexture->setLoadPriorities(_loadPriorities); - } else if (part.specularTextureName == name) { - part.specularTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, - false, QByteArray()); - part.specularTexture->setLoadPriorities(_loadPriorities); + part.diffuseTexture->setLoadPriorities(_loadPriorities); + } else if (part.normalTextureName == name) { + part.normalTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, + false, QByteArray()); + part.normalTexture->setLoadPriorities(_loadPriorities); + } else if (part.specularTextureName == name) { + part.specularTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, + false, QByteArray()); + part.specularTexture->setLoadPriorities(_loadPriorities); + } } } + } else { + qDebug() << "Adding a name url pair to pending" << name << url; + // we don't have meshes downloaded yet, so hold this texture as pending + _pendingTextureChanges.insert(name, url); } } @@ -760,6 +769,15 @@ QStringList NetworkGeometry::getTextureNames() const { return result; } +void NetworkGeometry::replaceTexturesWithPendingChanges() { + QHash::Iterator it = _pendingTextureChanges.begin(); + + while (it != _pendingTextureChanges.end()) { + setTextureWithNameToURL(it.key(), it.value()); + it = _pendingTextureChanges.erase(it); + } +} + /// Reads geometry in a worker thread. class GeometryReader : public QRunnable { public: @@ -807,6 +825,7 @@ void NetworkGeometry::init() { _geometry = FBXGeometry(); _meshes.clear(); _lods.clear(); + _pendingTextureChanges.clear(); _request.setUrl(_url); Resource::init(); } diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 28f1341b5f..e58177533c 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -113,7 +113,7 @@ public: void setTextureWithNameToURL(const QString& name, const QUrl& url); QStringList getTextureNames() const; - + protected: virtual void init(); @@ -122,6 +122,8 @@ protected: Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); +private slots: + void replaceTexturesWithPendingChanges(); private: friend class GeometryCache; @@ -139,6 +141,8 @@ private: QWeakPointer _lodParent; QHash, QVector > _jointMappings; + + QHash _pendingTextureChanges; }; /// The state associated with a single mesh part. diff --git a/interface/src/scripting/JoystickScriptingInterface.cpp b/interface/src/scripting/JoystickScriptingInterface.cpp index 68affeda5b..40109703d6 100644 --- a/interface/src/scripting/JoystickScriptingInterface.cpp +++ b/interface/src/scripting/JoystickScriptingInterface.cpp @@ -52,9 +52,12 @@ JoystickScriptingInterface::JoystickScriptingInterface() : for (int i = 0; i < joystickCount; i++) { SDL_GameController* controller = SDL_GameControllerOpen(i); - SDL_JoystickID id = getInstanceId(controller); - Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); - _openJoysticks[id] = joystick; + + if (controller) { + SDL_JoystickID id = getInstanceId(controller); + Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); + _openJoysticks[id] = joystick; + } } _isInitialized = true; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ae44e3931b..adf72198be 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -145,14 +145,14 @@ public: float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - void setDimensions(const glm::vec3& value) { _dimensions = value; ; recalculateCollisionShape(); } + void setDimensions(const glm::vec3& value) { _dimensions = value; recalculateCollisionShape(); } /// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); } static const glm::quat DEFAULT_ROTATION; const glm::quat& getRotation() const { return _rotation; } - void setRotation(const glm::quat& rotation) { _rotation = rotation; ; recalculateCollisionShape(); } + void setRotation(const glm::quat& rotation) { _rotation = rotation; recalculateCollisionShape(); } static const float DEFAULT_GLOW_LEVEL; float getGlowLevel() const { return _glowLevel; } @@ -169,7 +169,7 @@ public: static const glm::vec3 DEFAULT_VELOCITY; static const glm::vec3 NO_VELOCITY; static const float EPSILON_VELOCITY_LENGTH; - const glm::vec3 getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second + const glm::vec3& getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 199bd92030..bc2823e15c 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -124,6 +124,7 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp } else { // check to see if we need to simulate this entity... EntityItem::SimulationState oldState = existingEntity->getSimulationState(); + QString entityScriptBefore = existingEntity->getScript(); UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); recurseTreeWithOperator(&theOperator); @@ -131,6 +132,12 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp EntityItem::SimulationState newState = existingEntity->getSimulationState(); changeEntityState(existingEntity, oldState, newState); + + QString entityScriptAfter = existingEntity->getScript(); + if (entityScriptBefore != entityScriptAfter) { + emitEntityScriptChanging(entityID); // the entity script has changed + } + } containingElement = getContainingElement(entityID); @@ -168,6 +175,7 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem if (result) { // this does the actual adding of the entity addEntityItem(result); + emitAddingEntity(entityID); } return result; } @@ -184,6 +192,14 @@ void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { } } +void EntityTree::emitAddingEntity(const EntityItemID& entityItemID) { + emit addingEntity(entityItemID); +} + +void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) { + emit entityScriptChanging(entityItemID); +} + void EntityTree::deleteEntity(const EntityItemID& entityID) { emit deletingEntity(entityID); @@ -290,6 +306,7 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) { EntityItemID creatorTokenVersion = searchEntityID.convertToCreatorTokenVersion(); EntityItemID knownIDVersion = searchEntityID.convertToKnownIDVersion(); + // First look for and find the "viewed version" of this entity... it's possible we got // the known ID version sent to us between us creating our local version, and getting this // remapping message. If this happened, we actually want to find and delete that version of @@ -310,6 +327,10 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) { creatorTokenContainingElement->updateEntityItemID(creatorTokenVersion, knownIDVersion); setContainingElement(creatorTokenVersion, NULL); setContainingElement(knownIDVersion, creatorTokenContainingElement); + + // because the ID of the entity is switching, we need to emit these signals for any + // listeners who care about the changing of IDs + emit changingEntityID(creatorTokenVersion, knownIDVersion); } } unlock(); @@ -981,7 +1002,6 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons return processedBytes; } - EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ { // TODO: do we need to make this thread safe? Or is it acceptable as is if (_entityToElementMap.contains(entityItemID)) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8d1acc0d01..6fe2d256c2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -140,10 +140,16 @@ public: void trackDeletedEntity(const EntityItemID& entityID); + void emitAddingEntity(const EntityItemID& entityItemID); + void emitEntityScriptChanging(const EntityItemID& entityItemID); + QList& getMovingEntities() { return _movingEntities; } signals: void deletingEntity(const EntityItemID& entityID); + void addingEntity(const EntityItemID& entityID); + void entityScriptChanging(const EntityItemID& entityItemID); + void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID); private: diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 079fb1bba7..1dea2bcd85 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -726,7 +726,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int entityItemID = EntityItemID::readEntityItemIDFromBuffer(dataAt, bytesLeftToRead); entityItem = _myTree->findEntityByEntityItemID(entityItemID); } - + // If the item already exists in our tree, we want do the following... // 1) allow the existing item to read from the databuffer // 2) check to see if after reading the item, the containing element is still correct, fix it if needed @@ -734,10 +734,13 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty if (entityItem) { + QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); EntityItem::SimulationState oldState = entityItem->getSimulationState(); + bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); + EntityItem::SimulationState newState = entityItem->getSimulationState(); if (oldState != newState) { _myTree->changeEntityState(entityItem, oldState, newState); @@ -755,6 +758,12 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } } } + + QString entityScriptAfter = entityItem->getScript(); + if (entityScriptBefore != entityScriptAfter) { + _myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed + } + } else { entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args); if (entityItem) { @@ -762,6 +771,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int addEntityItem(entityItem); // add this new entity to this elements entities entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); + _myTree->emitAddingEntity(entityItemID); // we just added an entity EntityItem::SimulationState newState = entityItem->getSimulationState(); _myTree->changeEntityState(entityItem, EntityItem::Static, newState); }