From e1cb041576433ffada4d550ac99acc224fc82c18 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 16 Sep 2015 15:00:42 -0700 Subject: [PATCH 01/32] first cut at adding desiredProperties to getProperties --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- .../entities-renderer/src/RenderableModelEntityItem.h | 2 +- libraries/entities/src/BoxEntityItem.cpp | 4 ++-- libraries/entities/src/BoxEntityItem.h | 4 ++-- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 9 +++++++-- libraries/entities/src/EntityScriptingInterface.h | 1 + libraries/entities/src/LightEntityItem.cpp | 4 ++-- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/LineEntityItem.cpp | 4 ++-- libraries/entities/src/LineEntityItem.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 4 ++-- libraries/entities/src/ModelEntityItem.h | 2 +- libraries/entities/src/ParticleEffectEntityItem.cpp | 4 ++-- libraries/entities/src/ParticleEffectEntityItem.h | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 4 ++-- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 4 ++-- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/entities/src/SphereEntityItem.cpp | 4 ++-- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 4 ++-- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 4 ++-- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 4 ++-- libraries/entities/src/ZoneEntityItem.h | 2 +- 28 files changed, 47 insertions(+), 41 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e0cc5f644f..9f0ce93721 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -358,8 +358,8 @@ bool RenderableModelEntityItem::needsToCallUpdate() const { return _needsInitialSimulation || ModelEntityItem::needsToCallUpdate(); } -EntityItemProperties RenderableModelEntityItem::getProperties() const { - EntityItemProperties properties = ModelEntityItem::getProperties(); // get the properties from our base class +EntityItemProperties RenderableModelEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties); // get the properties from our base class if (_originalTexturesRead) { properties.setTextureNames(_originalTextures); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index d2c9370553..a893cf98f9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -35,7 +35,7 @@ public: virtual ~RenderableModelEntityItem(); - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index ce05bd93f0..88b4fec9e6 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -32,8 +32,8 @@ BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemP setProperties(properties); } -EntityItemProperties BoxEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties BoxEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties._color = getXColor(); properties._colorChanged = false; diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index 49ce67f361..e1bb284980 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -23,8 +23,8 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; - virtual bool setProperties(const EntityItemProperties& properties); + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 60a3004635..3bebbed527 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1019,7 +1019,7 @@ quint64 EntityItem::getExpiry() const { return _created + (quint64)(_lifetime * (float)USECS_PER_SECOND); } -EntityItemProperties EntityItem::getProperties() const { +EntityItemProperties EntityItem::getProperties(QScriptValue desiredProperties) const { EntityItemProperties properties; properties._id = getID(); properties._idSet = true; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 14f06f9f18..bb736a40a2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -131,7 +131,7 @@ public: EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; /// returns true if something changed virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4b8b4e2903..5d4934ca7e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -100,12 +100,17 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { - EntityItemProperties results; + QScriptValue allProperties; + return getEntityProperties(identity, allProperties); +} + +EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, QScriptValue desiredProperties) { + EntityItemProperties results; if (_entityTree) { _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); if (entity) { - results = entity->getProperties(); + results = entity->getProperties(desiredProperties); // TODO: improve sitting points and naturalDimensions in the future, // for now we've included the old sitting points model behavior for entity types that are models diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8d2b0b6892..fe91535e04 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -78,6 +78,7 @@ public slots: /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID); + Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, QScriptValue desiredProperties); /// edits a model updating only the included properties, will return the identified EntityItemID in case of /// successful edit, if the input entityID is for an unknown model this function will have no effect diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index d67d09e4b1..cb4130ead3 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -56,8 +56,8 @@ void LightEntityItem::setDimensions(const glm::vec3& value) { } -EntityItemProperties LightEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties LightEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight); COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 3ed28a252a..fd94e6ef5c 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -26,7 +26,7 @@ public: virtual void setDimensions(const glm::vec3& value); // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 222aee1a8f..0fb2ea9e01 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -43,9 +43,9 @@ LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityIte } -EntityItemProperties LineEntityItem::getProperties() const { +EntityItemProperties LineEntityItem::getProperties(QScriptValue desiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties._color = getXColor(); diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 3b7590a460..d06e2393b3 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -23,7 +23,7 @@ class LineEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 4c03f4a7da..deb7db279b 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -43,8 +43,8 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI _color[0] = _color[1] = _color[2] = 0; } -EntityItemProperties ModelEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties ModelEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 950a95bae2..281487f810 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -25,7 +25,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index b1229b8bb6..f032a988a2 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -147,8 +147,8 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() { } -EntityItemProperties ParticleEffectEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties ParticleEffectEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 802ff25af3..dea8e0e8c8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -25,7 +25,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of this entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 196fde47fb..0b8593fdf2 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -45,9 +45,9 @@ _strokeWidths(QVector(0.0f)) setProperties(properties); } -EntityItemProperties PolyLineEntityItem::getProperties() const { +EntityItemProperties PolyLineEntityItem::getProperties(QScriptValue desiredProperties) const { QWriteLocker lock(&_quadReadWriteLock); - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties._color = getXColor(); diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index e5fdcf9b78..efbadd73b4 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -23,7 +23,7 @@ class PolyLineEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 6c53dbfa16..a19430b245 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -104,8 +104,8 @@ const glm::vec3& PolyVoxEntityItem::getVoxelVolumeSize() const { } -EntityItemProperties PolyVoxEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties PolyVoxEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize); COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData); COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 31906a9cc0..e34a99c1e1 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -23,7 +23,7 @@ class PolyVoxEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 48eb5e01f7..03d0f223f0 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -37,8 +37,8 @@ SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const Entit _volumeMultiplier *= PI / 6.0f; } -EntityItemProperties SphereEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties SphereEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties.setColor(getXColor()); return properties; } diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 3b29a3a1f5..af1c87c57e 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 61730b208c..f67cc8375b 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -47,8 +47,8 @@ void TextEntityItem::setDimensions(const glm::vec3& value) { EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } -EntityItemProperties TextEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties TextEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText); COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight); diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index a659f3c39b..1254330dc6 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -27,7 +27,7 @@ public: virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 041022a916..10d0101771 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -40,8 +40,8 @@ void WebEntityItem::setDimensions(const glm::vec3& value) { EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); } -EntityItemProperties WebEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties WebEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl); return properties; } diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 24e19e1cb1..58464e8f25 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -26,7 +26,7 @@ public: virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index fed85bf6a5..c7c387d77e 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -73,8 +73,8 @@ EnvironmentData ZoneEntityItem::getEnvironmentData() const { return result; } -EntityItemProperties ZoneEntityItem::getProperties() const { - EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class +EntityItemProperties ZoneEntityItem::getProperties(QScriptValue desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightColor, getKeyLightColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightIntensity, getKeyLightIntensity); diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 41af2f14d8..91a194e2e3 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -27,7 +27,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties() const; + virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time From 248107c468521497a0062c7a1dabf1e58d264b77 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 16 Sep 2015 16:45:26 -0700 Subject: [PATCH 02/32] add reload all support for entity scripts --- interface/src/Application.cpp | 2 ++ libraries/entities-renderer/src/EntityTreeRenderer.cpp | 10 ++++++++++ libraries/entities-renderer/src/EntityTreeRenderer.h | 4 ++++ libraries/script-engine/src/ScriptCache.cpp | 7 +++++++ libraries/script-engine/src/ScriptCache.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 5 ++++- libraries/script-engine/src/ScriptEngine.h | 4 ++-- 7 files changed, 30 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3cb75b55ec..a313308023 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4347,6 +4347,8 @@ void Application::stopScript(const QString &scriptName, bool restart) { } void Application::reloadAllScripts() { + DependencyManager::get()->clearCache(); + getEntities()->reloadEntityScripts(); stopAllScripts(true); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 2fd760bbd3..fa186b15f8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -93,6 +93,15 @@ void EntityTreeRenderer::clear() { OctreeRenderer::clear(); } +void EntityTreeRenderer::reloadEntityScripts() { + _entitiesScriptEngine->unloadAllEntityScripts(); + foreach(auto entity, _entitiesInScene) { + if (!entity->getScript().isEmpty()) { + _entitiesScriptEngine->loadEntityScript(entity->getEntityItemID(), entity->getScript(), true); + } + } +} + void EntityTreeRenderer::init() { OctreeRenderer::init(); EntityTreePointer entityTree = std::static_pointer_cast(_tree); @@ -769,6 +778,7 @@ void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) { void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID, const bool reload) { + qDebug() << "entitySciptChanging() entityID:" << entityID << "reload:" << reload; if (_tree && !_shuttingDown) { _entitiesScriptEngine->unloadEntityScript(entityID); checkAndCallPreload(entityID, reload); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index a2f343efd2..6bacb23a3f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -62,6 +62,10 @@ public: /// clears the tree virtual void clear(); + /// reloads the entity scripts, calling unload and preload + void reloadEntityScripts(); + + /// if a renderable entity item needs a model, we will allocate it for them Q_INVOKABLE Model* allocateModel(const QString& url, const QString& collisionUrl); diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index e2c07c05d0..fb0edb1e49 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -27,6 +27,11 @@ ScriptCache::ScriptCache(QObject* parent) { // nothing to do here... } +void ScriptCache::clearCache() { + _scriptCache.clear(); +} + + QString ScriptCache::getScript(const QUrl& unnormalizedURL, ScriptUser* scriptUser, bool& isPending, bool reload) { QUrl url = ResourceManager::normalizeURL(unnormalizedURL); QString scriptContents; @@ -95,6 +100,8 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable return; } + qCDebug(scriptengine) << "ScriptCache::getScriptContents() scriptOrURL:" << scriptOrURL << " forceDownload:" << forceDownload << " on thread[" << QThread::currentThread() << "] expected thread[" << thread() << "]"; + if (_scriptCache.contains(url) && !forceDownload) { qCDebug(scriptengine) << "Found script in cache:" << url.toString(); #if 1 // def THREAD_DEBUGGING diff --git a/libraries/script-engine/src/ScriptCache.h b/libraries/script-engine/src/ScriptCache.h index 7de14a09f7..b786422b3f 100644 --- a/libraries/script-engine/src/ScriptCache.h +++ b/libraries/script-engine/src/ScriptCache.h @@ -28,6 +28,7 @@ class ScriptCache : public QObject, public Dependency { SINGLETON_DEPENDENCY public: + void clearCache(); void getScriptContents(const QString& scriptOrURL, contentAvailableCallback contentAvailable, bool forceDownload = false); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cd9e9d2e6c..1b341edbb5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -909,7 +909,10 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif - DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { + + qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() scriptOrURL:" << entityScript << "forceDownload:" << forceRedownload << "on thread[" << QThread::currentThread() << "] expected thread[" << thread() << "]"; + + DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 83e65823a5..001f54221b 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -109,8 +109,8 @@ public: // Entity Script Related methods Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload = false); // will call the preload method once loaded Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID); // will call unload method - Q_INVOKABLE void unloadAllEntityScripts(); - Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName); + Q_INVOKABLE void unloadAllEntityScripts(); + Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision); From 4e2cb00ec342301e4789e6367d1adf503f15120f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 17:33:53 -0700 Subject: [PATCH 03/32] first cut at only returning type specific properties in getEntityProperties --- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.h | 2 +- libraries/entities/src/BoxEntityItem.cpp | 2 +- libraries/entities/src/BoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 6 +- libraries/entities/src/EntityItem.h | 2 +- .../entities/src/EntityItemProperties.cpp | 205 ++++++++++-------- libraries/entities/src/EntityItemProperties.h | 12 +- .../entities/src/EntityItemPropertiesMacros.h | 16 +- libraries/entities/src/EntityPropertyFlags.h | 25 --- .../entities/src/EntityScriptingInterface.cpp | 6 +- .../entities/src/EntityScriptingInterface.h | 2 +- libraries/entities/src/EntityTree.cpp | 8 +- libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/LineEntityItem.cpp | 2 +- libraries/entities/src/LineEntityItem.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/ModelEntityItem.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 2 +- .../entities/src/ParticleEffectEntityItem.h | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 2 +- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 2 +- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/entities/src/SphereEntityItem.cpp | 2 +- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 2 +- libraries/entities/src/ZoneEntityItem.h | 2 +- libraries/shared/src/PropertyFlags.h | 1 + 34 files changed, 171 insertions(+), 160 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 9f0ce93721..74317b7eff 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -358,7 +358,7 @@ bool RenderableModelEntityItem::needsToCallUpdate() const { return _needsInitialSimulation || ModelEntityItem::needsToCallUpdate(); } -EntityItemProperties RenderableModelEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties); // get the properties from our base class if (_originalTexturesRead) { properties.setTextureNames(_originalTextures); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index a893cf98f9..5b61046816 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -35,7 +35,7 @@ public: virtual ~RenderableModelEntityItem(); - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 88b4fec9e6..4f30060207 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -32,7 +32,7 @@ BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemP setProperties(properties); } -EntityItemProperties BoxEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties._color = getXColor(); diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index e1bb284980..21e36c7031 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3bebbed527..ce719ee976 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1019,8 +1019,10 @@ quint64 EntityItem::getExpiry() const { return _created + (quint64)(_lifetime * (float)USECS_PER_SECOND); } -EntityItemProperties EntityItem::getProperties(QScriptValue desiredProperties) const { - EntityItemProperties properties; +EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProperties) const { + EncodeBitstreamParams params; // unknown + EntityPropertyFlags propertyFlags = desiredProperties.isEmpty() ? getEntityProperties(params) : desiredProperties; + EntityItemProperties properties(propertyFlags); properties._id = getID(); properties._idSet = true; properties._created = _created; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bb736a40a2..a50e32aaee 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -131,7 +131,7 @@ public: EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; /// returns true if something changed virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index dbcad8a328..5acc6158aa 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -36,7 +36,7 @@ StagePropertyGroup EntityItemProperties::_staticStage; EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1); -EntityItemProperties::EntityItemProperties() : +EntityItemProperties::EntityItemProperties(EntityPropertyFlags desiredProperties) : CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE), CONSTRUCT_PROPERTY(position, 0.0f), @@ -140,7 +140,8 @@ _localRenderAlphaChanged(false), _defaultSettings(true), _naturalDimensions(1.0f, 1.0f, 1.0f), -_naturalPosition(0.0f, 0.0f, 0.0f) +_naturalPosition(0.0f, 0.0f, 0.0f), +_desiredProperties(desiredProperties) { } @@ -423,25 +424,25 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool EntityItemProperties defaultEntityProperties; if (_idSet) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(id, _id.toString()); } - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type)); - COPY_PROPERTY_TO_QSCRIPTVALUE(position); - COPY_PROPERTY_TO_QSCRIPTVALUE(dimensions); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type)); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, position); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, dimensions); if (!skipDefaults) { - COPY_PROPERTY_TO_QSCRIPTVALUE(naturalDimensions); // gettable, but not settable - COPY_PROPERTY_TO_QSCRIPTVALUE(naturalPosition); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, naturalDimensions); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, naturalPosition); } - COPY_PROPERTY_TO_QSCRIPTVALUE(rotation); - COPY_PROPERTY_TO_QSCRIPTVALUE(velocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(gravity); - COPY_PROPERTY_TO_QSCRIPTVALUE(acceleration); - COPY_PROPERTY_TO_QSCRIPTVALUE(damping); - COPY_PROPERTY_TO_QSCRIPTVALUE(restitution); - COPY_PROPERTY_TO_QSCRIPTVALUE(friction); - COPY_PROPERTY_TO_QSCRIPTVALUE(density); - COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ROTATION, rotation); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY, velocity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAVITY, gravity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION, acceleration); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DAMPING, damping); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RESTITUTION, restitution); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FRICTION, friction); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFETIME, lifetime); if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) { COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable @@ -450,78 +451,76 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec created.setTimeSpec(Qt::OffsetFromUTC); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created.toString(Qt::ISODate)); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(created, created.toString(Qt::ISODate)); - COPY_PROPERTY_TO_QSCRIPTVALUE(script); - COPY_PROPERTY_TO_QSCRIPTVALUE(scriptTimestamp); - COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint); - COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping); - COPY_PROPERTY_TO_QSCRIPTVALUE(visible); - COPY_PROPERTY_TO_QSCRIPTVALUE(color); - COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(alpha); - COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); - COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); - COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(animationSettings, getAnimationSettings()); - COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); - COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); - COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); - COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove); - COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight); - COPY_PROPERTY_TO_QSCRIPTVALUE(intensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(exponent); - COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff); - COPY_PROPERTY_TO_QSCRIPTVALUE(locked); - COPY_PROPERTY_TO_QSCRIPTVALUE(textures); - COPY_PROPERTY_TO_QSCRIPTVALUE(userData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT, script); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_REGISTRATION_POINT, registrationPoint); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_SPREAD, colorSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_START, colorStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_FINISH, colorFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, animationURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, animationIsPlaying); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, animationFPS); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_SETTINGS, animationSettings, getAnimationSettings()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); //COPY_PROPERTY_TO_QSCRIPTVALUE(simulationOwner); // TODO: expose this for JSON saves? - COPY_PROPERTY_TO_QSCRIPTVALUE(text); - COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textColor, getTextColor()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundColor, getBackgroundColor()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(shapeType, getShapeTypeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(maxParticles); - COPY_PROPERTY_TO_QSCRIPTVALUE(lifespan); - COPY_PROPERTY_TO_QSCRIPTVALUE(emitRate); - COPY_PROPERTY_TO_QSCRIPTVALUE(emitVelocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(velocitySpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration); - COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); - COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); - COPY_PROPERTY_TO_QSCRIPTVALUE(name); - COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_COLOR, textColor, getTextColor()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_COLOR, backgroundColor, getBackgroundColor()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_PARTICLES, maxParticles); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFESPAN, lifespan); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RATE, emitRate); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_VELOCITY, emitVelocity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY_SPREAD, velocitySpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ACCELERATION, emitAcceleration); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION_SPREAD, accelerationSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_RADIUS, particleRadius); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_SPREAD, radiusSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_START, radiusStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_FINISH, radiusFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightColor); - COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl); - COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize); - COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData); - COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle); - COPY_PROPERTY_TO_QSCRIPTVALUE(lineWidth); - COPY_PROPERTY_TO_QSCRIPTVALUE(linePoints); - COPY_PROPERTY_TO_QSCRIPTVALUE(href); - COPY_PROPERTY_TO_QSCRIPTVALUE(description); - COPY_PROPERTY_TO_QSCRIPTVALUE(faceCamera); - COPY_PROPERTY_TO_QSCRIPTVALUE(actionData); - COPY_PROPERTY_TO_QSCRIPTVALUE(normals); - COPY_PROPERTY_TO_QSCRIPTVALUE(strokeWidths); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_COLOR, keyLightColor); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, keyLightDirection); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_MODE, backgroundMode, getBackgroundModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_DATA, voxelData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); // Sitting properties support if (!skipDefaults) { @@ -534,7 +533,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool sittingPoints.setProperty(i, sittingPoint); } sittingPoints.setProperty("length", _sittingPoints.size()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(sittingPoints, sittingPoints); // gettable, but not settable } if (!skipDefaults) { @@ -560,17 +559,21 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool _atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); _skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); - COPY_PROPERTY_TO_QSCRIPTVALUE(xTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(zTextureURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_TEXTURE_URL, xTextureURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_TEXTURE_URL, yTextureURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_TEXTURE_URL, zTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(xNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(yNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(zNNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_N_NEIGHBOR_ID, xNNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(xPNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(yPNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(zPNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); + + // FIXME - I don't think these properties are supported any more + //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); + //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); return properties; } @@ -709,6 +712,16 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object } +QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) { + QScriptValue result = engine->newObject(); + return result; +} + +void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) { + +} + + // TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the // encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar // to how we handle this in the Octree streaming case. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index cec6b456a7..9e7eb80b49 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -58,7 +58,7 @@ class EntityItemProperties { friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods friend class PolyLineEntityItem; // TODO: consider removing this friend relationship and use public methods public: - EntityItemProperties(); + EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); virtual ~EntityItemProperties(); EntityTypes::EntityType getType() const { return _type; } @@ -259,13 +259,19 @@ private: QStringList _textureNames; glm::vec3 _naturalDimensions; glm::vec3 _naturalPosition; + + EntityPropertyFlags _desiredProperties; // if set will narrow scopes of copy/to/from to just these properties }; Q_DECLARE_METATYPE(EntityItemProperties); QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue& object, EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue& object, EntityItemProperties& properties); + +Q_DECLARE_METATYPE(EntityPropertyFlags); +QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags); +void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags); // define these inline here so the macros work diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index a3e31024d1..22b07a9abc 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -122,8 +122,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) properties.setProperty(#g, groupProperties); \ } -#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \ - if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ +#define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \ + if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ + (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ QScriptValue V = convertScriptValue(engine, _##P); \ properties.setProperty(#P, V); \ } @@ -131,12 +132,19 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \ properties.setProperty(#P, G); -#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \ - if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ +#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \ + if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ + (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ QScriptValue V = convertScriptValue(engine, G); \ properties.setProperty(#P, V); \ } +#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \ + if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ + QScriptValue V = convertScriptValue(engine, G); \ + properties.setProperty(#P, V); \ + } + typedef glm::vec3 glmVec3; typedef glm::quat glmQuat; typedef QVector qVectorVec3; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index d4f880ed8f..df0aec01bf 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -12,33 +12,8 @@ #ifndef hifi_EntityPropertyFlags_h #define hifi_EntityPropertyFlags_h -/* -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include // for SittingPoint -*/ - #include -/* -#include -#include - -#include "AtmospherePropertyGroup.h" -#include "EntityItemID.h" -#include "EntityItemPropertiesMacros.h" -#include "EntityTypes.h" -*/ - enum EntityPropertyList { PROP_PAGED_PROPERTY, PROP_CUSTOM_PROPERTIES_INCLUDED, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 5d4934ca7e..936e57eec4 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -100,11 +100,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { - QScriptValue allProperties; - return getEntityProperties(identity, allProperties); + EntityPropertyFlags noSpecificProperties; + return getEntityProperties(identity, noSpecificProperties); } -EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, QScriptValue desiredProperties) { +EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) { EntityItemProperties results; if (_entityTree) { _entityTree->withReadLock([&] { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fe91535e04..e344154fb4 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -78,7 +78,7 @@ public slots: /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID); - Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, QScriptValue desiredProperties); + Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties); /// edits a model updating only the included properties, will return the identified EntityItemID in case of /// successful edit, if the input entityID is for an unknown model this function will have no effect diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c4c02d364f..85ae6233e1 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -119,6 +119,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI EntityTreeElementPointer containingElement, const SharedNodePointer& senderNode) { EntityItemProperties properties = origProperties; + qDebug() << "EntityTree::updateEntityWithElement() entity:" << entity->getEntityItemID(); + bool allowLockChange; QUuid senderID; if (senderNode.isNull()) { @@ -224,7 +226,10 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI QString entityScriptAfter = entity->getScript(); quint64 entityScriptTimestampAfter = entity->getScriptTimestamp(); bool reload = entityScriptTimestampBefore != entityScriptTimestampAfter; - if (entityScriptBefore != entityScriptAfter || reload) { + qDebug() << "EntityTree::updateEntityWithElement() entityScriptTimestampBefore:" << entityScriptTimestampBefore; + qDebug() << "EntityTree::updateEntityWithElement() entityScriptTimestampAfter:" << entityScriptTimestampAfter; + qDebug() << "EntityTree::updateEntityWithElement() reload:" << reload; + if (entityScriptBefore != entityScriptAfter || reload) { emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed } maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL()); @@ -285,6 +290,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti } void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID, const bool reload) { + qDebug() << "EntityTree::emitEntityScriptChanging(entityItemID:" << entityItemID << ", reload:" << reload<<")"; emit entityScriptChanging(entityItemID, reload); } diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index cb4130ead3..1d2e358799 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -56,7 +56,7 @@ void LightEntityItem::setDimensions(const glm::vec3& value) { } -EntityItemProperties LightEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight); diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index fd94e6ef5c..0590955700 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -26,7 +26,7 @@ public: virtual void setDimensions(const glm::vec3& value); // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 0fb2ea9e01..856d443a44 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -43,7 +43,7 @@ LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityIte } -EntityItemProperties LineEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index d06e2393b3..faa14d788e 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -23,7 +23,7 @@ class LineEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index deb7db279b..70747937d8 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -43,7 +43,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI _color[0] = _color[1] = _color[2] = 0; } -EntityItemProperties ModelEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 281487f810..bf6d7a9785 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -25,7 +25,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f032a988a2..b493cbfa48 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -147,7 +147,7 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() { } -EntityItemProperties ParticleEffectEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index dea8e0e8c8..053301206a 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -25,7 +25,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of this entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 0b8593fdf2..29a44547ff 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -45,7 +45,7 @@ _strokeWidths(QVector(0.0f)) setProperties(properties); } -EntityItemProperties PolyLineEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { QWriteLocker lock(&_quadReadWriteLock); EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index efbadd73b4..27a116e1b1 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -23,7 +23,7 @@ class PolyLineEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index a19430b245..70ae25c65c 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -104,7 +104,7 @@ const glm::vec3& PolyVoxEntityItem::getVoxelVolumeSize() const { } -EntityItemProperties PolyVoxEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties PolyVoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize); COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index e34a99c1e1..4cacf22457 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -23,7 +23,7 @@ class PolyVoxEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 03d0f223f0..b00544e979 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -37,7 +37,7 @@ SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const Entit _volumeMultiplier *= PI / 6.0f; } -EntityItemProperties SphereEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties SphereEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties.setColor(getXColor()); return properties; diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index af1c87c57e..46798d6b10 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index f67cc8375b..a4ce27f8b2 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -47,7 +47,7 @@ void TextEntityItem::setDimensions(const glm::vec3& value) { EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } -EntityItemProperties TextEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties TextEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText); diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 1254330dc6..101cef50b5 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -27,7 +27,7 @@ public: virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 10d0101771..a4f60d5150 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -40,7 +40,7 @@ void WebEntityItem::setDimensions(const glm::vec3& value) { EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); } -EntityItemProperties WebEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties WebEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl); return properties; diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 58464e8f25..a2ca955916 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -26,7 +26,7 @@ public: virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index c7c387d77e..8d843bd0b9 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -73,7 +73,7 @@ EnvironmentData ZoneEntityItem::getEnvironmentData() const { return result; } -EntityItemProperties ZoneEntityItem::getProperties(QScriptValue desiredProperties) const { +EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightColor, getKeyLightColor); diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 91a194e2e3..dbc3cede63 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -27,7 +27,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(QScriptValue desiredProperties = QScriptValue()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index 8e74fd728b..2d512ece61 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -45,6 +45,7 @@ public: _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false), _encodedLength(0) { decode(fromEncoded); } void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped = false; _encodedLength = 0; } + bool isEmpty() const { return _maxFlag == INT_MIN && _minFlag == INT_MAX && _trailingFlipped == false && _encodedLength == 0; } Enum firstFlag() const { return (Enum)_minFlag; } Enum lastFlag() const { return (Enum)_maxFlag; } From 81255c8379b0cabd4ad26fd2cd901eac21539c77 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 17:40:41 -0700 Subject: [PATCH 04/32] whitespace repair --- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 4 ++-- libraries/entities/src/EntityTree.cpp | 8 +------- libraries/script-engine/src/ScriptCache.cpp | 4 +--- libraries/script-engine/src/ScriptEngine.cpp | 4 +--- libraries/script-engine/src/ScriptEngine.h | 4 ++-- 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a50e32aaee..deebfc400d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -131,7 +131,7 @@ public: EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; /// returns true if something changed virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 936e57eec4..0b54572c7f 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -105,12 +105,12 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit } EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) { - EntityItemProperties results; + EntityItemProperties results; if (_entityTree) { _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); if (entity) { - results = entity->getProperties(desiredProperties); + results = entity->getProperties(desiredProperties); // TODO: improve sitting points and naturalDimensions in the future, // for now we've included the old sitting points model behavior for entity types that are models diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 85ae6233e1..c4c02d364f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -119,8 +119,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI EntityTreeElementPointer containingElement, const SharedNodePointer& senderNode) { EntityItemProperties properties = origProperties; - qDebug() << "EntityTree::updateEntityWithElement() entity:" << entity->getEntityItemID(); - bool allowLockChange; QUuid senderID; if (senderNode.isNull()) { @@ -226,10 +224,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI QString entityScriptAfter = entity->getScript(); quint64 entityScriptTimestampAfter = entity->getScriptTimestamp(); bool reload = entityScriptTimestampBefore != entityScriptTimestampAfter; - qDebug() << "EntityTree::updateEntityWithElement() entityScriptTimestampBefore:" << entityScriptTimestampBefore; - qDebug() << "EntityTree::updateEntityWithElement() entityScriptTimestampAfter:" << entityScriptTimestampAfter; - qDebug() << "EntityTree::updateEntityWithElement() reload:" << reload; - if (entityScriptBefore != entityScriptAfter || reload) { + if (entityScriptBefore != entityScriptAfter || reload) { emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed } maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL()); @@ -290,7 +285,6 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti } void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID, const bool reload) { - qDebug() << "EntityTree::emitEntityScriptChanging(entityItemID:" << entityItemID << ", reload:" << reload<<")"; emit entityScriptChanging(entityItemID, reload); } diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 70076dd28f..96e624c187 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -28,7 +28,7 @@ ScriptCache::ScriptCache(QObject* parent) { } void ScriptCache::clearCache() { - _scriptCache.clear(); + _scriptCache.clear(); } QString ScriptCache::getScript(const QUrl& unnormalizedURL, ScriptUser* scriptUser, bool& isPending, bool reload) { @@ -99,8 +99,6 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable return; } - qCDebug(scriptengine) << "ScriptCache::getScriptContents() scriptOrURL:" << scriptOrURL << " forceDownload:" << forceDownload << " on thread[" << QThread::currentThread() << "] expected thread[" << thread() << "]"; - if (_scriptCache.contains(url) && !forceDownload) { qCDebug(scriptengine) << "Found script in cache:" << url.toString(); #if 1 // def THREAD_DEBUGGING diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index d8392f1598..771906aa95 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -910,9 +910,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif - qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() scriptOrURL:" << entityScript << "forceDownload:" << forceRedownload << "on thread[" << QThread::currentThread() << "] expected thread[" << thread() << "]"; - - DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { + DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 001f54221b..83e65823a5 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -109,8 +109,8 @@ public: // Entity Script Related methods Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload = false); // will call the preload method once loaded Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID); // will call unload method - Q_INVOKABLE void unloadAllEntityScripts(); - Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName); + Q_INVOKABLE void unloadAllEntityScripts(); + Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event); Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision); From b16dfb8a9e624adbe702d90a64327246dd0675dc Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 17:41:54 -0700 Subject: [PATCH 05/32] whitespace repair --- libraries/script-engine/src/ScriptEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 771906aa95..692a320b4e 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -909,7 +909,6 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif - DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; From 08babecb75305cc4d44d53a0c728620d527703c3 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 19:51:21 -0700 Subject: [PATCH 06/32] add support for mapping EntityPropertyFlags to QScriptValues and wire in desiredProps --- .../entities/src/EntityItemProperties.cpp | 127 +++++++++++++++++- libraries/entities/src/EntityItemProperties.h | 3 + .../entities/src/EntityItemPropertiesMacros.h | 5 + .../entities/src/EntityScriptingInterface.cpp | 4 +- .../entities/src/EntityScriptingInterface.h | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 1 + 6 files changed, 137 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5acc6158aa..61329e61a9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -713,15 +713,138 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) { - QScriptValue result = engine->newObject(); + return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags); + QScriptValue result = engine->newObject(); return result; } void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) { - + EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); } +QScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) { + QScriptValue result = engine->newObject(); + return result; +} + +static QHash _propertyStringsToEnums; + +void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) { + static std::once_flag initMap; + + std::call_once(initMap, [](){ + ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool); + ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_ROTATION, Rotation, rotation, glm::quat); + ADD_PROPERTY_TO_MAP(PROP_DENSITY, Density, density, float); + ADD_PROPERTY_TO_MAP(PROP_VELOCITY, Velocity, velocity, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_GRAVITY, Gravity, gravity, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_ACCELERATION, Acceleration, acceleration, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_DAMPING, Damping, damping, float); + ADD_PROPERTY_TO_MAP(PROP_RESTITUTION, Restitution, restitution, float); + ADD_PROPERTY_TO_MAP(PROP_FRICTION, Friction, friction, float); + ADD_PROPERTY_TO_MAP(PROP_LIFETIME, Lifetime, lifetime, float); + ADD_PROPERTY_TO_MAP(PROP_SCRIPT, Script, script, QString); + ADD_PROPERTY_TO_MAP(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); + ADD_PROPERTY_TO_MAP(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); + ADD_PROPERTY_TO_MAP(PROP_COLOR, Color, color, xColor); + ADD_PROPERTY_TO_MAP(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor); + ADD_PROPERTY_TO_MAP(PROP_COLOR_START, ColorStart, colorStart, xColor); + ADD_PROPERTY_TO_MAP(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor); + ADD_PROPERTY_TO_MAP(PROP_ALPHA, Alpha, alpha, float); + ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); + ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float); + ADD_PROPERTY_TO_MAP(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); + ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString); + ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); + ADD_PROPERTY_TO_MAP(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); + ADD_PROPERTY_TO_MAP(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float); + ADD_PROPERTY_TO_MAP(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float); + ADD_PROPERTY_TO_MAP(PROP_ANIMATION_PLAYING, AnimationIsPlaying, animationIsPlaying, bool); + ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float); + ADD_PROPERTY_TO_MAP(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool); + ADD_PROPERTY_TO_MAP(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool); + ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool); + ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float); + ADD_PROPERTY_TO_MAP(PROP_EXPONENT, Exponent, exponent, float); + ADD_PROPERTY_TO_MAP(PROP_CUTOFF, Cutoff, cutoff, float); + ADD_PROPERTY_TO_MAP(PROP_LOCKED, Locked, locked, bool); + ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString); + ADD_PROPERTY_TO_MAP(PROP_ANIMATION_SETTINGS, AnimationSettings, animationSettings, QString); + ADD_PROPERTY_TO_MAP(PROP_USER_DATA, UserData, userData, QString); + ADD_PROPERTY_TO_MAP(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner); + ADD_PROPERTY_TO_MAP(PROP_TEXT, Text, text, QString); + ADD_PROPERTY_TO_MAP(PROP_LINE_HEIGHT, LineHeight, lineHeight, float); + ADD_PROPERTY_TO_MAP(PROP_TEXT_COLOR, TextColor, textColor, xColor); + ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor); + ADD_PROPERTY_TO_MAP(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); + ADD_PROPERTY_TO_MAP(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32); + ADD_PROPERTY_TO_MAP(PROP_LIFESPAN, Lifespan, lifespan, float); + ADD_PROPERTY_TO_MAP(PROP_EMIT_RATE, EmitRate, emitRate, float); + ADD_PROPERTY_TO_MAP(PROP_EMIT_VELOCITY, EmitVelocity, emitVelocity, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_VELOCITY_SPREAD, VelocitySpread, velocitySpread, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); + ADD_PROPERTY_TO_MAP(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float); + ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float); + ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); + ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); + ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); + ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); + ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float); + ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray); + ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); + ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); + ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_MODE, BackgroundMode, backgroundMode, BackgroundMode); + ADD_PROPERTY_TO_MAP(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString); + ADD_PROPERTY_TO_MAP(PROP_LINE_WIDTH, LineWidth, lineWidth, float); + ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); + ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); + ADD_PROPERTY_TO_MAP(PROP_DESCRIPTION, Description, description, QString); + ADD_PROPERTY_TO_MAP(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool); + ADD_PROPERTY_TO_MAP(PROP_ACTION_DATA, ActionData, actionData, QByteArray); + ADD_PROPERTY_TO_MAP(PROP_NORMALS, Normals, normals, QVector); + ADD_PROPERTY_TO_MAP(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector); + ADD_PROPERTY_TO_MAP(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString); + ADD_PROPERTY_TO_MAP(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString); + ADD_PROPERTY_TO_MAP(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString); + ADD_PROPERTY_TO_MAP(PROP_X_N_NEIGHBOR_ID, XNNeighborID, xNNeighborID, EntityItemID); + ADD_PROPERTY_TO_MAP(PROP_Y_N_NEIGHBOR_ID, YNNeighborID, yNNeighborID, EntityItemID); + ADD_PROPERTY_TO_MAP(PROP_Z_N_NEIGHBOR_ID, ZNNeighborID, zNNeighborID, EntityItemID); + ADD_PROPERTY_TO_MAP(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID); + ADD_PROPERTY_TO_MAP(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID); + ADD_PROPERTY_TO_MAP(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID); + + // FIXME - these are not yet handled + //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); + //DEFINE_PROPERTY_GROUP(Stage, stage, StagePropertyGroup); + //DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup); + //DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); + + }); + + if (object.isString()) { + if (_propertyStringsToEnums.contains(object.toString())) { + flags << _propertyStringsToEnums[object.toString()]; + } + } else if (object.isArray()) { + quint32 length = object.property("length").toInt32(); + for (quint32 i = 0; i < length; i++) { + QString propertyName = object.property(i).toString(); + if (_propertyStringsToEnums.contains(propertyName)) { + flags << _propertyStringsToEnums[propertyName]; + } + } + } +} + // TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the // encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar // to how we handle this in the Octree streaming case. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9e7eb80b49..9856911207 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -67,6 +67,9 @@ public: virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const; virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly); + static QScriptValue entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags); + static void entityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags); + // editing related features supported by all entities quint64 getLastEdited() const { return _lastEdited; } float getEditedAgo() const /// Elapsed seconds since this entity was last edited diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 22b07a9abc..358606ef6a 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -304,6 +304,11 @@ inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid T _##n; \ static T _static##N; +//(PROP_VISIBLE, Visible, visible, bool); + +#define ADD_PROPERTY_TO_MAP(P, N, n, T) \ + _propertyStringsToEnums[#n] = P; + #define DEFINE_PROPERTY(P, N, n, T) \ public: \ T get##N() const { return _##n; } \ diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 0b54572c7f..5d00e51fd1 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -100,8 +100,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { - EntityPropertyFlags noSpecificProperties; - return getEntityProperties(identity, noSpecificProperties); + EntityPropertyFlags noSpecificProperties; + return getEntityProperties(identity, noSpecificProperties); } EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index e344154fb4..485df5cb03 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -78,7 +78,7 @@ public slots: /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID); - Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties); + Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties); /// edits a model updating only the included properties, will return the identified EntityItemID in case of /// successful edit, if the input entityID is for an unknown model this function will have no effect diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 692a320b4e..b8a97f0902 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -280,6 +280,7 @@ void ScriptEngine::init() { _controllerScriptingInterface->registerControllerTypes(this); } + qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); From 6de424237ff107e6bc7d66ec3e2ac8053b56343d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 20:24:15 -0700 Subject: [PATCH 07/32] add support for property groups in the desired properties logic --- .../entities/src/AtmospherePropertyGroup.cpp | 16 +++++----- .../entities/src/AtmospherePropertyGroup.h | 2 +- .../entities/src/EntityItemProperties.cpp | 30 ++++++++++++++----- .../entities/src/EntityItemPropertiesMacros.h | 10 ++++--- libraries/entities/src/EntityPropertyFlags.h | 2 +- libraries/entities/src/PropertyGroup.h | 2 +- .../entities/src/SkyboxPropertyGroup.cpp | 6 ++-- libraries/entities/src/SkyboxPropertyGroup.h | 2 +- libraries/entities/src/StagePropertyGroup.cpp | 16 +++++----- libraries/entities/src/StagePropertyGroup.h | 2 +- 10 files changed, 53 insertions(+), 35 deletions(-) diff --git a/libraries/entities/src/AtmospherePropertyGroup.cpp b/libraries/entities/src/AtmospherePropertyGroup.cpp index 364612d4db..f8117dbb62 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.cpp +++ b/libraries/entities/src/AtmospherePropertyGroup.cpp @@ -32,14 +32,14 @@ AtmospherePropertyGroup::AtmospherePropertyGroup() { _hasStars = true; } -void AtmospherePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, Center, center); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, InnerRadius, innerRadius); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, OuterRadius, outerRadius); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, MieScattering, mieScattering); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, RayleighScattering, rayleighScattering); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, HasStars, hasStars); +void AtmospherePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_CENTER, Atmosphere, atmosphere, Center, center); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_INNER_RADIUS, Atmosphere, atmosphere, InnerRadius, innerRadius); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_OUTER_RADIUS, Atmosphere, atmosphere, OuterRadius, outerRadius); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_MIE_SCATTERING, Atmosphere, atmosphere, MieScattering, mieScattering); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, Atmosphere, atmosphere, RayleighScattering, rayleighScattering); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_HAS_STARS, Atmosphere, atmosphere, HasStars, hasStars); } void AtmospherePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { diff --git a/libraries/entities/src/AtmospherePropertyGroup.h b/libraries/entities/src/AtmospherePropertyGroup.h index e081033cd6..c4b50822fa 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.h +++ b/libraries/entities/src/AtmospherePropertyGroup.h @@ -53,7 +53,7 @@ public: virtual ~AtmospherePropertyGroup() {} // EntityItemProperty related helpers - virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings); virtual void debugDump() const; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 61329e61a9..102611dc2f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -555,10 +555,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable } - _stage.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); - _atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); - _skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_TEXTURE_URL, xTextureURL); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_TEXTURE_URL, yTextureURL); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_TEXTURE_URL, zTextureURL); @@ -571,6 +567,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); + _stage.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + _atmosphere.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -822,11 +822,27 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID); ADD_PROPERTY_TO_MAP(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID); + ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color); + ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url); + + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_CENTER, Atmosphere, atmosphere, Center, center); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_INNER_RADIUS, Atmosphere, atmosphere, InnerRadius, innerRadius); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_OUTER_RADIUS, Atmosphere, atmosphere, OuterRadius, outerRadius); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_MIE_SCATTERING, Atmosphere, atmosphere, MieScattering, mieScattering); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, Atmosphere, atmosphere, RayleighScattering, rayleighScattering); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_HAS_STARS, Atmosphere, atmosphere, HasStars, hasStars); + + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_SUN_MODEL_ENABLED, Stage, stage, SunModelEnabled, sunModelEnabled); + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_LATITUDE, Stage, stage, Latitude, latitude); + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_LONGITUDE, Stage, stage, Longitude, longitude); + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_ALTITUDE, Stage, stage, Altitude, altitude); + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_DAY, Stage, stage, Day, day); + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_HOUR, Stage, stage, Hour, hour); + ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_AUTOMATIC_HOURDAY, Stage, stage, AutomaticHourDay, automaticHourDay); + // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); - //DEFINE_PROPERTY_GROUP(Stage, stage, StagePropertyGroup); - //DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup); - //DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); }); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 358606ef6a..964529afca 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -111,8 +111,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); } -#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \ - if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \ +#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \ + if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ + (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ QScriptValue groupProperties = properties.property(#g); \ if (!groupProperties.isValid()) { \ groupProperties = engine->newObject(); \ @@ -304,11 +305,12 @@ inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid T _##n; \ static T _static##N; -//(PROP_VISIBLE, Visible, visible, bool); - #define ADD_PROPERTY_TO_MAP(P, N, n, T) \ _propertyStringsToEnums[#n] = P; +#define ADD_GROUP_PROPERTY_TO_MAP(P, G, g, N, n) \ + _propertyStringsToEnums[#g "." #n] = P; + #define DEFINE_PROPERTY(P, N, n, T) \ public: \ T get##N() const { return _##n; } \ diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index df0aec01bf..68c318a579 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -165,6 +165,7 @@ enum EntityPropertyList { PROP_STAGE_ALTITUDE = PROP_SPECULAR_COLOR_UNUSED, PROP_STAGE_DAY = PROP_LINEAR_ATTENUATION_UNUSED, PROP_STAGE_HOUR = PROP_QUADRATIC_ATTENUATION_UNUSED, + PROP_STAGE_AUTOMATIC_HOURDAY = PROP_ANIMATION_FRAME_INDEX, PROP_ATMOSPHERE_CENTER = PROP_MAX_PARTICLES, PROP_ATMOSPHERE_INNER_RADIUS = PROP_LIFESPAN, PROP_ATMOSPHERE_OUTER_RADIUS = PROP_EMIT_RATE, @@ -175,7 +176,6 @@ enum EntityPropertyList { PROP_BACKGROUND_MODE = PROP_MODEL_URL, PROP_SKYBOX_COLOR = PROP_ANIMATION_URL, PROP_SKYBOX_URL = PROP_ANIMATION_FPS, - PROP_STAGE_AUTOMATIC_HOURDAY = PROP_ANIMATION_FRAME_INDEX, // Aliases/Piggyback properties for Web. These properties intentionally reuse the enum values for // other properties which will never overlap with each other. diff --git a/libraries/entities/src/PropertyGroup.h b/libraries/entities/src/PropertyGroup.h index 7ac4b54a8e..f780907896 100644 --- a/libraries/entities/src/PropertyGroup.h +++ b/libraries/entities/src/PropertyGroup.h @@ -55,7 +55,7 @@ public: virtual ~PropertyGroup() {} // EntityItemProperty related helpers - virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0; + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0; virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) = 0; virtual void debugDump() const { } diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp index 5be7c1eb49..624a382d55 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.cpp +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp @@ -20,9 +20,9 @@ SkyboxPropertyGroup::SkyboxPropertyGroup() { _url = QString(); } -void SkyboxPropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, Color, color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, URL, url); +void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_SKYBOX_URL, Skybox, skybox, URL, url); } void SkyboxPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { diff --git a/libraries/entities/src/SkyboxPropertyGroup.h b/libraries/entities/src/SkyboxPropertyGroup.h index a92ec5abbb..25d982cbe7 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.h +++ b/libraries/entities/src/SkyboxPropertyGroup.h @@ -33,7 +33,7 @@ public: virtual ~SkyboxPropertyGroup() {} // EntityItemProperty related helpers - virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings); virtual void debugDump() const; diff --git a/libraries/entities/src/StagePropertyGroup.cpp b/libraries/entities/src/StagePropertyGroup.cpp index 937dc2412e..fb27f9a464 100644 --- a/libraries/entities/src/StagePropertyGroup.cpp +++ b/libraries/entities/src/StagePropertyGroup.cpp @@ -36,14 +36,14 @@ StagePropertyGroup::StagePropertyGroup() { _automaticHourDay = false; } -void StagePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, SunModelEnabled, sunModelEnabled); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Latitude, latitude); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Longitude, longitude); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Altitude, altitude); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Day, day); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Hour, hour); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, AutomaticHourDay, automaticHourDay); +void StagePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_SUN_MODEL_ENABLED, Stage, stage, SunModelEnabled, sunModelEnabled); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_LATITUDE, Stage, stage, Latitude, latitude); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_LONGITUDE, Stage, stage, Longitude, longitude); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_ALTITUDE, Stage, stage, Altitude, altitude); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_DAY, Stage, stage, Day, day); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_HOUR, Stage, stage, Hour, hour); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_AUTOMATIC_HOURDAY, Stage, stage, AutomaticHourDay, automaticHourDay); } void StagePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { diff --git a/libraries/entities/src/StagePropertyGroup.h b/libraries/entities/src/StagePropertyGroup.h index c5df4fe0bd..32eb3462a3 100644 --- a/libraries/entities/src/StagePropertyGroup.h +++ b/libraries/entities/src/StagePropertyGroup.h @@ -33,7 +33,7 @@ public: virtual ~StagePropertyGroup() {} // EntityItemProperty related helpers - virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings); virtual void debugDump() const; From 7f9a6d7b8ef1747119a996840a9ec5a11b4bc551 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 20:26:50 -0700 Subject: [PATCH 08/32] whitespace fixes --- libraries/entities/src/BoxEntityItem.h | 4 ++-- libraries/entities/src/LineEntityItem.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index 21e36c7031..fdc66dd3e5 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -23,8 +23,8 @@ public: ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; - virtual bool setProperties(const EntityItemProperties& properties); + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; + virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index faa14d788e..7e0f49c984 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -22,8 +22,8 @@ class LineEntityItem : public EntityItem { ALLOW_INSTANTIATION // This class can be instantiated - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); // TODO: eventually only include properties changed since the params.lastViewFrustumSent time From 45c34e161736f42f047d8edc2ae0d15249a0bf9a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 20:55:19 -0700 Subject: [PATCH 09/32] only copy properties to the script values for properties that our type actually has --- .../entities/src/EntityItemProperties.cpp | 204 +++++++++++------- 1 file changed, 122 insertions(+), 82 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 102611dc2f..65b41b5734 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -428,6 +428,15 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool } COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type)); + auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec + created.setTimeSpec(Qt::OffsetFromUTC); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(created, created.toString(Qt::ISODate)); + + if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable + } + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, position); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, dimensions); if (!skipDefaults) { @@ -443,84 +452,131 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FRICTION, friction); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFETIME, lifetime); - - if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable - } - - auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec - created.setTimeSpec(Qt::OffsetFromUTC); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(created, created.toString(Qt::ISODate)); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT, script); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_REGISTRATION_POINT, registrationPoint); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_SPREAD, colorSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_START, colorStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_FINISH, colorFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, animationURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, animationIsPlaying); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, animationFPS); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_SETTINGS, animationSettings, getAnimationSettings()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); - //COPY_PROPERTY_TO_QSCRIPTVALUE(simulationOwner); // TODO: expose this for JSON saves? - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_COLOR, textColor, getTextColor()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_COLOR, backgroundColor, getBackgroundColor()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_PARTICLES, maxParticles); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFESPAN, lifespan); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RATE, emitRate); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_VELOCITY, emitVelocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY_SPREAD, velocitySpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ACCELERATION, emitAcceleration); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION_SPREAD, accelerationSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_RADIUS, particleRadius); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_SPREAD, radiusSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_START, radiusStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_FINISH, radiusFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_COLOR, keyLightColor); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, keyLightDirection); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_MODE, backgroundMode, getBackgroundModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_DATA, voxelData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL); + + // Boxes, Spheres, Light, Line, Model(??), Particle, PolyLine + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color); + + // Particles only + if (_type == EntityTypes::ParticleEffect) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_PARTICLES, maxParticles); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFESPAN, lifespan); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RATE, emitRate); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_VELOCITY, emitVelocity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY_SPREAD, velocitySpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ACCELERATION, emitAcceleration); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION_SPREAD, accelerationSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_RADIUS, particleRadius); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_SPREAD, radiusSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_START, radiusStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_FINISH, radiusFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_SPREAD, colorSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_START, colorStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_FINISH, colorFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); + } + + // Models only + if (_type == EntityTypes::Model) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, animationURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); + } + + + if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); + } + + // Models & Particles + if (_type == EntityTypes::Model || _type == EntityTypes::ParticleEffect) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, animationIsPlaying); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, animationFPS); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_SETTINGS, animationSettings, getAnimationSettings()); + } + + // Lights only + if (_type == EntityTypes::Light) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff); + } + + // Text only + if (_type == EntityTypes::Text) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_COLOR, textColor, getTextColor()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_COLOR, backgroundColor, getBackgroundColor()); + } + + // Zones only + if (_type == EntityTypes::Zone) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_COLOR, keyLightColor); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, keyLightDirection); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_MODE, backgroundMode, getBackgroundModeAsString()); + + _stage.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + _atmosphere.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + } + + // Web only + if (_type == EntityTypes::Web) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl); + } + + // PolyVoxel only + if (_type == EntityTypes::PolyVox) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_DATA, voxelData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_TEXTURE_URL, xTextureURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_TEXTURE_URL, yTextureURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_TEXTURE_URL, zTextureURL); + + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_N_NEIGHBOR_ID, xNNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID); + + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); + } + + // Lines & PolyLines + if (_type == EntityTypes::Line || _type == EntityTypes::PolyLine) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); + } + + //COPY_PROPERTY_TO_QSCRIPTVALUE(simulationOwner); // TODO: expose this for JSON saves? // Sitting properties support if (!skipDefaults) { @@ -555,22 +611,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable } - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_TEXTURE_URL, xTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_TEXTURE_URL, yTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_TEXTURE_URL, zTextureURL); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_N_NEIGHBOR_ID, xNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); - - _stage.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - _atmosphere.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); From d0a46224276fbb7e32c34941d06d07b96a76d461 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 21:01:56 -0700 Subject: [PATCH 10/32] removed some debug code --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 3e4569e70f..c55eaaeff9 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -778,7 +778,6 @@ void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) { void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID, const bool reload) { - qDebug() << "entitySciptChanging() entityID:" << entityID << "reload:" << reload; if (_tree && !_shuttingDown) { _entitiesScriptEngine->unloadEntityScript(entityID); checkAndCallPreload(entityID, reload); From 0811da14b88c21556b6a386db8b2ace12b6d795f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 21:14:07 -0700 Subject: [PATCH 11/32] use new feature for getEntityUserData --- examples/libraries/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index 1275975fd8..ea0bae745e 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -60,7 +60,7 @@ setEntityUserData = function(id, data) { // FIXME do non-destructive modification of the existing user data getEntityUserData = function(id) { var results = null; - var properties = Entities.getEntityProperties(id); + var properties = Entities.getEntityProperties(id, "userData"); if (properties.userData) { try { results = JSON.parse(properties.userData); From 4a34b142d1d2924127dc4f7efa03b66b9cdae7ef Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Sep 2015 22:05:14 -0700 Subject: [PATCH 12/32] remove render element proxies --- .../src/EntityTreeRenderer.cpp | 81 ------------------- .../src/EntityTreeRenderer.h | 5 -- 2 files changed, 86 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c55eaaeff9..ebdf0f0339 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -52,9 +52,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf _lastMouseEventValid(false), _viewState(viewState), _scriptingServices(scriptingServices), - _displayElementChildProxies(false), _displayModelBounds(false), - _displayModelElementProxy(false), _dontDoPrecisionPicking(false) { REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory) @@ -372,92 +370,13 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP return result; } -void EntityTreeRenderer::renderElementProxy(EntityTreeElementPointer entityTreeElement, RenderArgs* args) { - auto deferredLighting = DependencyManager::get(); - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - Transform transform; - - glm::vec3 elementCenter = entityTreeElement->getAACube().calcCenter(); - float elementSize = entityTreeElement->getScale(); - - auto drawWireCube = [&](glm::vec3 offset, float size, glm::vec4 color) { - transform.setTranslation(elementCenter + offset); - batch.setModelTransform(transform); - deferredLighting->renderWireCube(batch, size, color); - }; - - drawWireCube(glm::vec3(), elementSize, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f)); - - if (_displayElementChildProxies) { - // draw the children - float halfSize = elementSize / 2.0f; - float quarterSize = elementSize / 4.0f; - - drawWireCube(glm::vec3(-quarterSize, -quarterSize, -quarterSize), halfSize, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f)); - drawWireCube(glm::vec3(quarterSize, -quarterSize, -quarterSize), halfSize, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)); - drawWireCube(glm::vec3(-quarterSize, quarterSize, -quarterSize), halfSize, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f)); - drawWireCube(glm::vec3(-quarterSize, -quarterSize, quarterSize), halfSize, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f)); - drawWireCube(glm::vec3(quarterSize, quarterSize, quarterSize), halfSize, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); - drawWireCube(glm::vec3(-quarterSize, quarterSize, quarterSize), halfSize, glm::vec4(0.0f, 0.5f, 0.5f, 1.0f)); - drawWireCube(glm::vec3(quarterSize, -quarterSize, quarterSize), halfSize, glm::vec4(0.5f, 0.0f, 0.0f, 1.0f)); - drawWireCube(glm::vec3(quarterSize, quarterSize, -quarterSize), halfSize, glm::vec4(0.0f, 0.5f, 0.0f, 1.0f)); - } -} - -void EntityTreeRenderer::renderProxies(EntityItemPointer entity, RenderArgs* args) { - bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE; - if (!isShadowMode && _displayModelBounds) { - PerformanceTimer perfTimer("renderProxies"); - - AACube maxCube = entity->getMaximumAACube(); - AACube minCube = entity->getMinimumAACube(); - AABox entityBox = entity->getAABox(); - - glm::vec3 maxCenter = maxCube.calcCenter(); - glm::vec3 minCenter = minCube.calcCenter(); - glm::vec3 entityBoxCenter = entityBox.calcCenter(); - glm::vec3 entityBoxScale = entityBox.getScale(); - - auto deferredLighting = DependencyManager::get(); - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - Transform transform; - - // draw the max bounding cube - transform.setTranslation(maxCenter); - batch.setModelTransform(transform); - deferredLighting->renderWireCube(batch, maxCube.getScale(), glm::vec4(1.0f, 1.0f, 0.0f, 1.0f)); - - // draw the min bounding cube - transform.setTranslation(minCenter); - batch.setModelTransform(transform); - deferredLighting->renderWireCube(batch, minCube.getScale(), glm::vec4(0.0f, 1.0f, 0.0f, 1.0f)); - - // draw the entityBox bounding box - transform.setTranslation(entityBoxCenter); - transform.setScale(entityBoxScale); - batch.setModelTransform(transform); - deferredLighting->renderWireCube(batch, 1.0f, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f)); - - // Rotated bounding box - batch.setModelTransform(entity->getTransformToCenter()); - deferredLighting->renderWireCube(batch, 1.0f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)); - } -} - void EntityTreeRenderer::renderElement(OctreeElementPointer element, RenderArgs* args) { // actually render it here... // we need to iterate the actual entityItems of the element EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE; - if (!isShadowMode && _displayModelElementProxy && entityTreeElement->size() > 0) { - renderElementProxy(entityTreeElement, args); - } - entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { if (entityItem->isVisible()) { // NOTE: Zone Entities are a special case we handle here... diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 18874957fd..2691c3c66f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -114,9 +114,7 @@ public slots: void updateEntityRenderStatus(bool shouldRenderEntities); // optional slots that can be wired to menu items - void setDisplayElementChildProxies(bool value) { _displayElementChildProxies = value; } void setDisplayModelBounds(bool value) { _displayModelBounds = value; } - void setDisplayModelElementProxy(bool value) { _displayModelElementProxy = value; } void setDontDoPrecisionPicking(bool value) { _dontDoPrecisionPicking = value; } protected: @@ -134,7 +132,6 @@ private: void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); QList _releasedModels; - void renderProxies(EntityItemPointer entity, RenderArgs* args); RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, bool precisionPicking); @@ -157,9 +154,7 @@ private: MouseEvent _lastMouseEvent; AbstractViewStateInterface* _viewState; AbstractScriptingServicesInterface* _scriptingServices; - bool _displayElementChildProxies; bool _displayModelBounds; - bool _displayModelElementProxy; bool _dontDoPrecisionPicking; bool _shuttingDown = false; From 420acde72004d7299dd9a2c6739dbe54871b237a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 17 Sep 2015 22:07:52 -0700 Subject: [PATCH 13/32] blend IK effects between distinct end effectors --- .../animation/src/AnimInverseKinematics.cpp | 78 ++++++++++++------- .../animation/src/AnimInverseKinematics.h | 33 +++++++- 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 36b23c313e..409c243612 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -153,6 +153,11 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar ++constraintItr; } } else { + // clear the accumulators before we start the IK solver + for (auto& accumulatorPair: _accumulators) { + accumulatorPair.second.clear(); + } + // compute absolute poses that correspond to relative target poses AnimPoseVec absolutePoses; computeAbsolutePoses(absolutePoses); @@ -165,8 +170,8 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar quint64 expiry = usecTimestampNow() + MAX_IK_TIME; do { largestError = 0.0f; + int lowestMovedIndex = _relativePoses.size(); for (auto& target: targets) { - int lowestMovedIndex = _relativePoses.size() - 1; int tipIndex = target.index; AnimPose targetPose = target.pose; int rootIndex = target.rootIndex; @@ -226,7 +231,8 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar glm::inverse(absolutePoses[pivotIndex].rot); } } - _relativePoses[pivotIndex].rot = newRot; + // store the rotation change in the accumulator + _accumulators[pivotIndex].add(newRot); } // this joint has been changed so we check to see if it has the lowest index if (pivotIndex < lowestMovedIndex) { @@ -243,36 +249,49 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar if (largestError < error) { largestError = error; } - - if (lowestMovedIndex <= _maxTargetIndex && lowestMovedIndex < tipIndex) { - // only update the absolutePoses that matter: those between lowestMovedIndex and _maxTargetIndex - for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) { - int parentIndex = _skeleton->getParentIndex(i); - if (parentIndex != -1) { - absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i]; - } - } - } - - // finally set the relative rotation of the tip to agree with absolute target rotation - int parentIndex = _skeleton->getParentIndex(tipIndex); - if (parentIndex != -1) { - // compute tip's new parent-relative rotation - // Q = Qp * q --> q' = Qp^ * Q - glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot; - RotationConstraint* constraint = getConstraint(tipIndex); - if (constraint) { - constraint->apply(newRelativeRotation); - // TODO: ATM the final rotation target just fails but we need to provide - // feedback to the IK system so that it can adjust the bones up the skeleton - // to help this rotation target get met. - } - _relativePoses[tipIndex].rot = newRelativeRotation; - absolutePoses[tipIndex].rot = targetPose.rot; - } } ++numLoops; + + // harvest accumulated rotations and apply the average + for (auto& accumulatorPair: _accumulators) { + RotationAccumulator& accumulator = accumulatorPair.second; + if (accumulator.size() > 0) { + _relativePoses[accumulatorPair.first].rot = accumulator.getAverage(); + accumulator.clear(); + } + } + + // only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex + if (lowestMovedIndex < _maxTargetIndex) { + for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) { + int parentIndex = _skeleton->getParentIndex(i); + if (parentIndex != -1) { + absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i]; + } + } + } } while (largestError > ACCEPTABLE_RELATIVE_ERROR && numLoops < MAX_IK_LOOPS && usecTimestampNow() < expiry); + + // finally set the relative rotation of each tip to agree with absolute target rotation + for (auto& target: targets) { + int tipIndex = target.index; + int parentIndex = _skeleton->getParentIndex(tipIndex); + if (parentIndex != -1) { + AnimPose targetPose = target.pose; + // compute tip's new parent-relative rotation + // Q = Qp * q --> q' = Qp^ * Q + glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot; + RotationConstraint* constraint = getConstraint(tipIndex); + if (constraint) { + constraint->apply(newRelativeRotation); + // TODO: ATM the final rotation target just fails but we need to provide + // feedback to the IK system so that it can adjust the bones up the skeleton + // to help this rotation target get met. + } + _relativePoses[tipIndex].rot = newRelativeRotation; + absolutePoses[tipIndex].rot = targetPose.rot; + } + } } return _relativePoses; } @@ -628,6 +647,7 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele _maxTargetIndex = 0; + _accumulators.clear(); if (skeleton) { initConstraints(); } else { diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index b59fb4d5fc..ae8ab34bdc 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -16,6 +16,37 @@ class RotationConstraint; +class RotationAccumulator { +public: + RotationAccumulator() {} + + uint32_t size() const { return _rotations.size(); } + + void add(const glm::quat& rotation) { _rotations.push_back(rotation); } + + glm::quat getAverage() { + glm::quat average; + uint32_t numRotations = _rotations.size(); + if (numRotations > 0) { + average = _rotations[0]; + for (uint32_t i = 1; i < numRotations; ++i) { + glm::quat rotation = _rotations[i]; + if (glm::dot(average, rotation) < 0.0f) { + rotation = -rotation; + } + average += rotation; + } + average = glm::normalize(average); + } + return average; + } + + void clear() { _rotations.clear(); } + +private: + std::vector _rotations; +}; + class AnimInverseKinematics : public AnimNode { public: @@ -24,7 +55,6 @@ public: void loadDefaultPoses(const AnimPoseVec& poses); void loadPoses(const AnimPoseVec& poses); - const AnimPoseVec& getRelativePoses() const { return _relativePoses; } void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar); @@ -60,6 +90,7 @@ protected: }; std::map _constraints; + std::map _accumulators; std::vector _targetVarVec; AnimPoseVec _defaultRelativePoses; // poses of the relaxed state AnimPoseVec _relativePoses; // current relative poses From b6a153d92690a9a2b19f1adfd23ffb61d85b83c1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 17 Sep 2015 22:30:44 -0700 Subject: [PATCH 14/32] split RotationAccumulator into its own files --- .../animation/src/AnimInverseKinematics.h | 36 +++---------------- .../animation/src/RotationAccumulator.cpp | 29 +++++++++++++++ libraries/animation/src/RotationAccumulator.h | 34 ++++++++++++++++++ 3 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 libraries/animation/src/RotationAccumulator.cpp create mode 100644 libraries/animation/src/RotationAccumulator.h diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index ae8ab34bdc..c4bda1be89 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -12,41 +12,15 @@ #include +#include +#include + #include "AnimNode.h" +#include "RotationAccumulator.h" + class RotationConstraint; -class RotationAccumulator { -public: - RotationAccumulator() {} - - uint32_t size() const { return _rotations.size(); } - - void add(const glm::quat& rotation) { _rotations.push_back(rotation); } - - glm::quat getAverage() { - glm::quat average; - uint32_t numRotations = _rotations.size(); - if (numRotations > 0) { - average = _rotations[0]; - for (uint32_t i = 1; i < numRotations; ++i) { - glm::quat rotation = _rotations[i]; - if (glm::dot(average, rotation) < 0.0f) { - rotation = -rotation; - } - average += rotation; - } - average = glm::normalize(average); - } - return average; - } - - void clear() { _rotations.clear(); } - -private: - std::vector _rotations; -}; - class AnimInverseKinematics : public AnimNode { public: diff --git a/libraries/animation/src/RotationAccumulator.cpp b/libraries/animation/src/RotationAccumulator.cpp new file mode 100644 index 0000000000..22b84afc77 --- /dev/null +++ b/libraries/animation/src/RotationAccumulator.cpp @@ -0,0 +1,29 @@ +// +// RotationAccumulator.h +// +// Copyright 2015 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 "RotationAccumulator.h" + +#include + +glm::quat RotationAccumulator::getAverage() { + glm::quat average; + uint32_t numRotations = _rotations.size(); + if (numRotations > 0) { + average = _rotations[0]; + for (uint32_t i = 1; i < numRotations; ++i) { + glm::quat rotation = _rotations[i]; + if (glm::dot(average, rotation) < 0.0f) { + rotation = -rotation; + } + average += rotation; + } + average = glm::normalize(average); + } + return average; +} diff --git a/libraries/animation/src/RotationAccumulator.h b/libraries/animation/src/RotationAccumulator.h new file mode 100644 index 0000000000..d6854d9b01 --- /dev/null +++ b/libraries/animation/src/RotationAccumulator.h @@ -0,0 +1,34 @@ +// +// RotationAccumulator.h +// +// Copyright 2015 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_RotationAccumulator_h +#define hifi_RotationAccumulator_h + +#include + +#include +#include + +class RotationAccumulator { +public: + RotationAccumulator() {} + + uint32_t size() const { return _rotations.size(); } + + void add(const glm::quat& rotation) { _rotations.push_back(rotation); } + + glm::quat getAverage(); + + void clear() { _rotations.clear(); } + +private: + std::vector _rotations; +}; + +#endif // hifi_RotationAccumulator_h From 6d7b129b835ca0ee73da659a7d5369bdf36284a7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 17 Sep 2015 23:15:18 -0700 Subject: [PATCH 15/32] rework handControllerGrab.js --- examples/controllers/handControllerGrab.js | 519 +++++++++------------ 1 file changed, 231 insertions(+), 288 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f38d4a1008..7490a811c5 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -10,31 +10,22 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - Script.include("../libraries/utils.js"); +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var GRAB_RADIUS = 0.3; var RADIUS_FACTOR = 4; - -var RIGHT_HAND_CLICK = Controller.findAction("RIGHT_HAND_CLICK"); -var rightTriggerAction = RIGHT_HAND_CLICK; - -var GRAB_USER_DATA_KEY = "grabKey"; - -var LEFT_HAND_CLICK = Controller.findAction("LEFT_HAND_CLICK"); -var leftTriggerAction = LEFT_HAND_CLICK; - -var LIFETIME = 10; -var EXTRA_TIME = 5; -var POINTER_CHECK_TIME = 5000; - -var ZERO_VEC = { - x: 0, - y: 0, - z: 0 -} +var ZERO_VEC = {x: 0, y: 0, z: 0}; +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; var LINE_LENGTH = 500; -var THICK_LINE_WIDTH = 7; -var THIN_LINE_WIDTH = 2; + +var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK")); + +var startTime = Date.now(); +var LIFETIME = 10; var NO_INTERSECT_COLOR = { red: 10, @@ -47,35 +38,16 @@ var INTERSECT_COLOR = { blue: 10 }; -var GRAB_RADIUS = 0.3; -var GRAB_COLOR = { - red: 250, - green: 10, - blue: 250 -}; -var SHOW_LINE_THRESHOLD = 0.2; -var DISTANCE_HOLD_THRESHOLD = 0.8; +var STATE_SEARCHING = 0; +var STATE_DISTANCE_HOLDING = 1; +var STATE_CLOSE_GRABBING = 2; +var STATE_CONTINUE_CLOSE_GRABBING = 3; +var STATE_RELEASE = 4; -var right4Action = 18; -var left4Action = 17; - -var RIGHT = 1; -var LEFT = 0; -var rightController = new controller(RIGHT, rightTriggerAction, right4Action, "right"); -var leftController = new controller(LEFT, leftTriggerAction, left4Action, "left"); -var startTime = Date.now(); - - -//Need to wait before calling these methods for some reason... -Script.setTimeout(function() { - rightController.checkPointer(); - leftController.checkPointer(); -}, 100) - -function controller(side, triggerAction, pullAction, hand) { +function controller(hand, triggerAction) { this.hand = hand; - if (hand === "right") { + if (this.hand === RIGHT_HAND) { this.getHandPosition = MyAvatar.getRightPalmPosition; this.getHandRotation = MyAvatar.getRightPalmRotation; } else { @@ -83,309 +55,280 @@ function controller(side, triggerAction, pullAction, hand) { this.getHandRotation = MyAvatar.getLeftPalmRotation; } this.triggerAction = triggerAction; - this.pullAction = pullAction; - this.actionID = null; - this.distanceHolding = false; - this.closeGrabbing = false; - this.triggerValue = 0; - this.prevTriggerValue = 0; - this.palm = 2 * side; - this.tip = 2 * side + 1; - this.pointer = null; + this.palm = 2 * hand; + this.tip = 2 * hand + 1; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.grabbedVelocity = ZERO_VEC; + this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value } -controller.prototype.updateLine = function() { - if (this.pointer != null) { - if (Entities.getEntityProperties(this.pointer).id != this.pointer) { - this.pointer = null; - } +controller.prototype.update = function() { + switch(this.state) { + case STATE_SEARCHING: + search(this); + break; + case STATE_DISTANCE_HOLDING: + distanceHolding(this); + break; + case STATE_CLOSE_GRABBING: + closeGrabbing(this); + break; + case STATE_CONTINUE_CLOSE_GRABBING: + continueCloseGrabbing(this); + break; + case STATE_RELEASE: + release(this); + break; } +} - if (this.pointer == null) { - this.lineCreationTime = Date.now(); - this.pointer = Entities.addEntity({ + +function lineOn(self, closePoint, farPoint, color) { + // draw a line + if (self.pointer == null) { + self.pointer = Entities.addEntity({ type: "Line", name: "pointer", - color: NO_INTERSECT_COLOR, - dimensions: { - x: 1000, - y: 1000, - z: 1000 - }, + dimensions: {x: 1000, y: 1000, z: 1000}, visible: true, + position: closePoint, + linePoints: [ ZERO_VEC, farPoint ], + color: color, lifetime: LIFETIME }); - } - - var handPosition = this.getHandPosition(); - var direction = Quat.getUp(this.getHandRotation()); - - //only check if we havent already grabbed an object - if (this.distanceHolding) { - Entities.editEntity(this.pointer, { - position: handPosition, - linePoints: [ ZERO_VEC, Vec3.subtract(Entities.getEntityProperties(this.grabbedEntity).position, handPosition) ], + } else { + Entities.editEntity(self.pointer, { + position: closePoint, + linePoints: [ ZERO_VEC, farPoint ], + color: color, lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME }); + } +} + +function lineOff(self) { + if (self.pointer != null) { + Entities.deleteEntity(self.pointer); + } + self.pointer = null; +} + +function triggerSmoothedSqueezed(self) { + var triggerValue = Controller.getActionValue(self.triggerAction); + self.triggerValue = (self.triggerValue * 0.7) + (triggerValue * 0.3); // smooth out trigger value + return self.triggerValue > 0.2; +} + +function triggerSqueezed(self) { + var triggerValue = Controller.getActionValue(self.triggerAction); + return triggerValue > 0.2; +} + + +function search(self) { + if (!triggerSmoothedSqueezed(self)) { + self.state = STATE_RELEASE; return; } - Entities.editEntity(this.pointer, { - position: handPosition, - linePoints: [ ZERO_VEC, Vec3.multiply(direction, LINE_LENGTH) ], - lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME - }); - - if (this.checkForIntersections(handPosition, direction)) { - Entities.editEntity(this.pointer, { - color: INTERSECT_COLOR, - }); - } else { - Entities.editEntity(this.pointer, { - color: NO_INTERSECT_COLOR, - }); - } -} - - -controller.prototype.checkPointer = function() { - var self = this; - Script.setTimeout(function() { - var props = Entities.getEntityProperties(self.pointer); - Entities.editEntity(self.pointer, { - lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME - }); - self.checkPointer(); - }, POINTER_CHECK_TIME); -} - -controller.prototype.checkForIntersections = function(origin, direction) { - var pickRay = { - origin: origin, - direction: direction - }; - + // the trigger is being pressed, do a ray test + var handPosition = self.getHandPosition(); + var pickRay = {origin: handPosition, direction: Quat.getUp(self.getHandRotation())}; var intersection = Entities.findRayIntersection(pickRay, true); - if (intersection.intersects && intersection.properties.collisionsWillMove === 1) { - var handPosition = Controller.getSpatialControlPosition(this.palm); - this.distanceToEntity = Vec3.distance(handPosition, intersection.properties.position); - var intersectionDistance = Vec3.distance(handPosition, intersection.intersection); - + if (intersection.intersects && + intersection.properties.collisionsWillMove === 1 && + intersection.properties.locked === 0) { + // the ray is intersecting something we can move. + var handControllerPosition = Controller.getSpatialControlPosition(self.palm); + var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection); + self.grabbedEntity = intersection.entityID; if (intersectionDistance < 0.6) { - //We are grabbing an entity, so let it know we've grabbed it - this.grabbedEntity = intersection.entityID; - this.activateEntity(this.grabbedEntity); - this.hidePointer(); - this.shouldDisplayLine = false; - this.grabEntity(); - return true; + // the hand is very close to the intersected object. go into close-grabbing mode. + self.state = STATE_CLOSE_GRABBING; } else { - Entities.editEntity(this.pointer, { - linePoints: [ - ZERO_VEC, - Vec3.multiply(direction, this.distanceToEntity) - ] - }); - this.grabbedEntity = intersection.entityID; - return true; + // the hand is far from the intersected object. go into distance-holding mode + self.state = STATE_DISTANCE_HOLDING; + lineOn(self, pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } - } - return false; -} - - -controller.prototype.attemptMove = function() { - if (this.grabbedEntity || this.distanceHolding) { - var handPosition = Controller.getSpatialControlPosition(this.palm); - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - - this.distanceHolding = true; - if (this.actionID === null) { - this.currentObjectPosition = Entities.getEntityProperties(this.grabbedEntity).position; - this.currentObjectRotation = Entities.getEntityProperties(this.grabbedEntity).rotation; - - this.handPreviousPosition = handPosition; - this.handPreviousRotation = handRotation; - - this.actionID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: this.currentObjectPosition, - linearTimeScale: .1, - targetRotation: this.currentObjectRotation, - angularTimeScale: .1 - }); + } else { + // forward ray test failed, try sphere test. + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = GRAB_RADIUS; + var grabbedEntity = null; + for (var i = 0; i < nearbyEntities.length; i++) { + var props = Entities.getEntityProperties(nearbyEntities[i]); + var distance = Vec3.distance(props.position, handPosition); + if (distance < minDistance && props.name !== "pointer" && + props.collisionsWillMove === 1 && + props.locked === 0) { + self.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + } + } + if (self.grabbedEntity === null) { + lineOn(self, pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } else { - var radius = Math.max(Vec3.distance(this.currentObjectPosition, handPosition) * RADIUS_FACTOR, 1.0); - - var handMoved = Vec3.subtract(handPosition, this.handPreviousPosition); - this.handPreviousPosition = handPosition; - var superHandMoved = Vec3.multiply(handMoved, radius); - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - - // ---------------- this tracks hand rotation - // var handChange = Quat.multiply(handRotation, Quat.inverse(this.handPreviousRotation)); - // this.handPreviousRotation = handRotation; - // this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - // ---------------- - - // ---------------- this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, 2.0), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; - this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - // ---------------- - - - Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, linearTimeScale: .1, - targetRotation: this.currentObjectRotation, angularTimeScale: .1 - }); + self.state = STATE_CLOSE_GRABBING; } } } -controller.prototype.showPointer = function() { - Entities.editEntity(this.pointer, { - visible: true - }); -} - -controller.prototype.hidePointer = function() { - Entities.editEntity(this.pointer, { - visible: false - }); -} - - -controller.prototype.letGo = function() { - if (this.grabbedEntity && this.actionID) { - this.deactivateEntity(this.grabbedEntity); - Entities.deleteAction(this.grabbedEntity, this.actionID); +function distanceHolding(self) { + if (!triggerSmoothedSqueezed(self)) { + self.state = STATE_RELEASE; + return; } - this.grabbedEntity = null; - this.actionID = null; - this.distanceHolding = false; - this.closeGrabbing = false; -} -controller.prototype.update = function() { - this.triggerValue = Controller.getActionValue(this.triggerAction); - if (this.triggerValue > SHOW_LINE_THRESHOLD && this.prevTriggerValue < SHOW_LINE_THRESHOLD) { - //First check if an object is within close range and then run the close grabbing logic - if (this.checkForInRangeObject()) { - this.grabEntity(); - } else { - this.showPointer(); - this.shouldDisplayLine = true; + var handPosition = self.getHandPosition(); + var handControllerPosition = Controller.getSpatialControlPosition(self.palm); + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(self.palm)); + var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); + + lineOn(self, handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + + if (self.actionID === null) { + // first time here since trigger pulled -- add the action and initialize some variables + self.currentObjectPosition = grabbedProperties.position; + self.currentObjectRotation = grabbedProperties.rotation; + self.handPreviousPosition = handControllerPosition; + self.handPreviousRotation = handRotation; + + self.actionID = Entities.addAction("spring", self.grabbedEntity, { + targetPosition: self.currentObjectPosition, + linearTimeScale: .1, + targetRotation: self.currentObjectRotation, + angularTimeScale: .1 + }); + if (self.actionID == NULL_ACTION_ID) { + self.actionID = null; } - } else if (this.triggerValue < SHOW_LINE_THRESHOLD && this.prevTriggerValue > SHOW_LINE_THRESHOLD) { - this.hidePointer(); - this.letGo(); - this.shouldDisplayLine = false; - } + } else { + // the action was set up on a previous call. update the targets. + var radius = Math.max(Vec3.distance(self.currentObjectPosition, handControllerPosition) * RADIUS_FACTOR, RADIUS_FACTOR); - if (this.shouldDisplayLine) { - this.updateLine(); - } - if (this.triggerValue > DISTANCE_HOLD_THRESHOLD && !this.closeGrabbing) { - this.attemptMove(); - } + var handMoved = Vec3.subtract(handControllerPosition, self.handPreviousPosition); + self.handPreviousPosition = handControllerPosition; + var superHandMoved = Vec3.multiply(handMoved, radius); + self.currentObjectPosition = Vec3.sum(self.currentObjectPosition, superHandMoved); - this.prevTriggerValue = this.triggerValue; + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(self.handPreviousRotation, handRotation, 2.0), + Quat.inverse(self.handPreviousRotation)); + self.handPreviousRotation = handRotation; + self.currentObjectRotation = Quat.multiply(handChange, self.currentObjectRotation); + + Entities.updateAction(self.grabbedEntity, self.actionID, { + targetPosition: self.currentObjectPosition, linearTimeScale: .1, + targetRotation: self.currentObjectRotation, angularTimeScale: .1 + }); + } } -controller.prototype.grabEntity = function() { - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - this.closeGrabbing = true; - //check if our entity has instructions on how to be grabbed, otherwise, just use default relative position and rotation - var userData = getEntityUserData(this.grabbedEntity); - var objectRotation = Entities.getEntityProperties(this.grabbedEntity).rotation; +function closeGrabbing(self) { + if (!triggerSmoothedSqueezed(self)) { + self.state = STATE_RELEASE; + return; + } + + lineOff(self); + + var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); + + var handRotation = self.getHandRotation(); + var handPosition = self.getHandPosition(); + + var objectRotation = grabbedProperties.rotation; var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - var objectPosition = Entities.getEntityProperties(this.grabbedEntity).position; - var offset = Vec3.subtract(objectPosition, handPosition); + self.currentObjectPosition = grabbedProperties.position; + self.currentObjectTime = Date.now(); + var offset = Vec3.subtract(self.currentObjectPosition, handPosition); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); - var relativePosition = offsetPosition; - var relativeRotation = offsetRotation; - if (userData.grabFrame) { - if (userData.grabFrame.relativePosition) { - relativePosition = userData.grabFrame.relativePosition; - } - if (userData.grabFrame.relativeRotation) { - relativeRotation = userData.grabFrame.relativeRotation; - } - } - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand, + self.actionID = Entities.addAction("hold", self.grabbedEntity, { + hand: self.hand == RIGHT_HAND ? "right" : "left", timeScale: 0.05, - relativePosition: relativePosition, - relativeRotation: relativeRotation + relativePosition: offsetPosition, + relativeRotation: offsetRotation }); + if (self.actionID == NULL_ACTION_ID) { + self.actionID = null; + } else { + self.state = STATE_CONTINUE_CLOSE_GRABBING; + } } -controller.prototype.checkForInRangeObject = function() { - var handPosition = Controller.getSpatialControlPosition(this.palm); - var entities = Entities.findEntities(handPosition, GRAB_RADIUS); - var minDistance = GRAB_RADIUS; - var grabbedEntity = null; - //Get nearby entities and assign nearest - for (var i = 0; i < entities.length; i++) { - var props = Entities.getEntityProperties(entities[i]); - var distance = Vec3.distance(props.position, handPosition); - if (distance < minDistance && props.name !== "pointer" && props.collisionsWillMove === 1) { - grabbedEntity = entities[i]; - minDistance = distance; +function continueCloseGrabbing(self) { + if (!triggerSmoothedSqueezed(self)) { + self.state = STATE_RELEASE; + return; + } + + // keep track of the measured velocity of the held object + var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); + var now = Date.now(); + + var deltaPosition = Vec3.subtract(grabbedProperties.position, self.currentObjectPosition); + var deltaTime = (now - self.currentObjectTime) / 1000.0; // convert to seconds + + if (deltaTime > 0.0) { + var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); + // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger + // value would otherwise give the held object time to slow down. + if (triggerSqueezed(self)) { + self.grabbedVelocity = Vec3.sum(Vec3.multiply(self.grabbedVelocity, 0.1), + Vec3.multiply(grabbedVelocity, 0.9)); } } - if (grabbedEntity === null) { - return false; - } else { - //We are grabbing an entity, so let it know we've grabbed it - this.grabbedEntity = grabbedEntity; - this.activateEntity(this.grabbedEntity); - return true; + self.currentObjectPosition = grabbedProperties.position; + self.currentObjectTime = now; +} + + +function release(self) { + lineOff(self); + + if (self.grabbedEntity != null && self.actionID != null) { + Entities.deleteAction(self.grabbedEntity, self.actionID); } + + // the action will tend to quickly bring an object's velocity to zero. now that + // the action is gone, set the objects velocity to something the holder might expect. + Entities.editEntity(self.grabbedEntity, {velocity: self.grabbedVelocity}); + + self.grabbedVelocity = ZERO_VEC; + self.grabbedEntity = null; + self.actionID = null; + self.state = STATE_SEARCHING; } -controller.prototype.activateEntity = function(entity) { - var data = { - activated: true, - avatarId: MyAvatar.sessionUUID - }; - setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); -} - -controller.prototype.deactivateEntity = function(entity) { - var data = { - activated: false, - avatarId: null - }; - setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); -} controller.prototype.cleanup = function() { - Entities.deleteEntity(this.pointer); - if (this.grabbedEntity) { - Entities.deleteAction(this.grabbedEntity, this.actionID); - } + release(this); } + function update() { rightController.update(); leftController.update(); } + function cleanup() { rightController.cleanup(); leftController.cleanup(); } + Script.scriptEnding.connect(cleanup); Script.update.connect(update) From 9e94e7f1d0f6f96952eb1c98afde7db9dc6e9223 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Sep 2015 07:11:36 -0700 Subject: [PATCH 16/32] less complicated RotationAccumulator --- .../animation/src/RotationAccumulator.cpp | 25 +++++++++---------- libraries/animation/src/RotationAccumulator.h | 14 ++++------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/libraries/animation/src/RotationAccumulator.cpp b/libraries/animation/src/RotationAccumulator.cpp index 22b84afc77..fccb63fa35 100644 --- a/libraries/animation/src/RotationAccumulator.cpp +++ b/libraries/animation/src/RotationAccumulator.cpp @@ -11,19 +11,18 @@ #include -glm::quat RotationAccumulator::getAverage() { - glm::quat average; - uint32_t numRotations = _rotations.size(); - if (numRotations > 0) { - average = _rotations[0]; - for (uint32_t i = 1; i < numRotations; ++i) { - glm::quat rotation = _rotations[i]; - if (glm::dot(average, rotation) < 0.0f) { - rotation = -rotation; - } - average += rotation; +void RotationAccumulator::add(glm::quat rotation) { + if (_numRotations == 0) { + _rotationSum = rotation; + } else { + if (glm::dot(_rotationSum, rotation) < 0.0f) { + rotation = -rotation; } - average = glm::normalize(average); + _rotationSum += rotation; } - return average; + ++_numRotations; +} + +glm::quat RotationAccumulator::getAverage() { + return (_numRotations > 0) ? glm::normalize(_rotationSum) : glm::quat(); } diff --git a/libraries/animation/src/RotationAccumulator.h b/libraries/animation/src/RotationAccumulator.h index d6854d9b01..500f554271 100644 --- a/libraries/animation/src/RotationAccumulator.h +++ b/libraries/animation/src/RotationAccumulator.h @@ -10,25 +10,21 @@ #ifndef hifi_RotationAccumulator_h #define hifi_RotationAccumulator_h -#include - #include -#include class RotationAccumulator { public: - RotationAccumulator() {} + int size() const { return _numRotations; } - uint32_t size() const { return _rotations.size(); } - - void add(const glm::quat& rotation) { _rotations.push_back(rotation); } + void add(glm::quat rotation); glm::quat getAverage(); - void clear() { _rotations.clear(); } + void clear() { _numRotations = 0; } private: - std::vector _rotations; + glm::quat _rotationSum; + int _numRotations = 0; }; #endif // hifi_RotationAccumulator_h From b8c8ea2b53e3787e7e566326bcd061c4b7530a63 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 18 Sep 2015 07:20:35 -0700 Subject: [PATCH 17/32] move magic numbers to constant variables, add some comments --- examples/controllers/handControllerGrab.js | 100 ++++++++++++++------- 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 7490a811c5..c80084eec2 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -12,39 +12,67 @@ Script.include("../libraries/utils.js"); + +///////////////////////////////////////////////////////////////// +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.7; +var TRIGGER_ON_VALUE = 0.2; + +///////////////////////////////////////////////////////////////// +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 4; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var NO_INTERSECT_COLOR = {red: 10, green: 10, blue: 255}; // line color when pick misses +var INTERSECT_COLOR = {red: 250, green: 10, blue: 10}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = {x: 1000, y: 1000, z: 1000}; +var LINE_LENGTH = 500; + + +///////////////////////////////////////////////////////////////// +// +// close grabbing +// + +var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected +var CLOSE_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO = 0.9; // adjust time-averaging of held object's velocity +var CLOSE_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected + + +///////////////////////////////////////////////////////////////// +// +// other constants +// + var RIGHT_HAND = 1; var LEFT_HAND = 0; -var GRAB_RADIUS = 0.3; -var RADIUS_FACTOR = 4; var ZERO_VEC = {x: 0, y: 0, z: 0}; var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; -var LINE_LENGTH = 500; +var MSEC_PER_SEC = 1000.0; var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK")); var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK")); +// these control how long an abandoned pointer line will hang around var startTime = Date.now(); var LIFETIME = 10; -var NO_INTERSECT_COLOR = { - red: 10, - green: 10, - blue: 255 -}; -var INTERSECT_COLOR = { - red: 250, - green: 10, - blue: 10 -}; - - +// states for the state machine var STATE_SEARCHING = 0; var STATE_DISTANCE_HOLDING = 1; var STATE_CLOSE_GRABBING = 2; var STATE_CONTINUE_CLOSE_GRABBING = 3; var STATE_RELEASE = 4; + function controller(hand, triggerAction) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -56,11 +84,11 @@ function controller(hand, triggerAction) { } this.triggerAction = triggerAction; this.palm = 2 * hand; - this.tip = 2 * hand + 1; + // this.tip = 2 * hand + 1; // unused, but I'm leaving this here for fear it will be needed this.actionID = null; // action this script created... this.grabbedEntity = null; // on this entity. - this.grabbedVelocity = ZERO_VEC; + this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value @@ -94,7 +122,7 @@ function lineOn(self, closePoint, farPoint, color) { self.pointer = Entities.addEntity({ type: "Line", name: "pointer", - dimensions: {x: 1000, y: 1000, z: 1000}, + dimensions: LINE_ENTITY_DIMENSIONS, visible: true, position: closePoint, linePoints: [ ZERO_VEC, farPoint ], @@ -106,7 +134,7 @@ function lineOn(self, closePoint, farPoint, color) { position: closePoint, linePoints: [ ZERO_VEC, farPoint ], color: color, - lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME + lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME }); } } @@ -121,13 +149,14 @@ function lineOff(self) { function triggerSmoothedSqueezed(self) { var triggerValue = Controller.getActionValue(self.triggerAction); - self.triggerValue = (self.triggerValue * 0.7) + (triggerValue * 0.3); // smooth out trigger value - return self.triggerValue > 0.2; + // smooth out trigger value + self.triggerValue = (self.triggerValue * TRIGGER_SMOOTH_RATIO) + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + return self.triggerValue > TRIGGER_ON_VALUE; } function triggerSqueezed(self) { var triggerValue = Controller.getActionValue(self.triggerAction); - return triggerValue > 0.2; + return triggerValue > TRIGGER_ON_VALUE; } @@ -148,7 +177,7 @@ function search(self) { var handControllerPosition = Controller.getSpatialControlPosition(self.palm); var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection); self.grabbedEntity = intersection.entityID; - if (intersectionDistance < 0.6) { + if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) { // the hand is very close to the intersected object. go into close-grabbing mode. self.state = STATE_CLOSE_GRABBING; } else { @@ -202,16 +231,18 @@ function distanceHolding(self) { self.actionID = Entities.addAction("spring", self.grabbedEntity, { targetPosition: self.currentObjectPosition, - linearTimeScale: .1, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, targetRotation: self.currentObjectRotation, - angularTimeScale: .1 + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME }); if (self.actionID == NULL_ACTION_ID) { self.actionID = null; } } else { // the action was set up on a previous call. update the targets. - var radius = Math.max(Vec3.distance(self.currentObjectPosition, handControllerPosition) * RADIUS_FACTOR, RADIUS_FACTOR); + var radius = Math.max(Vec3.distance(self.currentObjectPosition, + handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, + DISTANCE_HOLDING_RADIUS_FACTOR); var handMoved = Vec3.subtract(handControllerPosition, self.handPreviousPosition); self.handPreviousPosition = handControllerPosition; @@ -219,14 +250,15 @@ function distanceHolding(self) { self.currentObjectPosition = Vec3.sum(self.currentObjectPosition, superHandMoved); // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(self.handPreviousRotation, handRotation, 2.0), + var handChange = Quat.multiply(Quat.slerp(self.handPreviousRotation, handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), Quat.inverse(self.handPreviousRotation)); self.handPreviousRotation = handRotation; self.currentObjectRotation = Quat.multiply(handChange, self.currentObjectRotation); Entities.updateAction(self.grabbedEntity, self.actionID, { - targetPosition: self.currentObjectPosition, linearTimeScale: .1, - targetRotation: self.currentObjectRotation, angularTimeScale: .1 + targetPosition: self.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: self.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME }); } } @@ -255,7 +287,7 @@ function closeGrabbing(self) { self.actionID = Entities.addAction("hold", self.grabbedEntity, { hand: self.hand == RIGHT_HAND ? "right" : "left", - timeScale: 0.05, + timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME, relativePosition: offsetPosition, relativeRotation: offsetRotation }); @@ -277,16 +309,16 @@ function continueCloseGrabbing(self) { var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); var now = Date.now(); - var deltaPosition = Vec3.subtract(grabbedProperties.position, self.currentObjectPosition); - var deltaTime = (now - self.currentObjectTime) / 1000.0; // convert to seconds + var deltaPosition = Vec3.subtract(grabbedProperties.position, self.currentObjectPosition); // meters + var deltaTime = (now - self.currentObjectTime) / MSEC_PER_SEC; // convert to seconds if (deltaTime > 0.0) { var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger // value would otherwise give the held object time to slow down. if (triggerSqueezed(self)) { - self.grabbedVelocity = Vec3.sum(Vec3.multiply(self.grabbedVelocity, 0.1), - Vec3.multiply(grabbedVelocity, 0.9)); + self.grabbedVelocity = Vec3.sum(Vec3.multiply(self.grabbedVelocity, (1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)), + Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)); } } From 0ba1e8c945144caded23fefb504ed0d3e777015d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Sep 2015 09:49:57 -0700 Subject: [PATCH 18/32] remove renderingInWorldInterface signals --- interface/src/Application.cpp | 8 -------- interface/src/Application.h | 3 --- .../src/scripting/GlobalServicesScriptingInterface.cpp | 6 ++++-- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a313308023..09abfbe01e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3648,14 +3648,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); } - if (!selfAvatarOnly) { - // give external parties a change to hook in - { - PerformanceTimer perfTimer("inWorldInterface"); - emit renderingInWorldInterface(); - } - } - activeRenderingThread = nullptr; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 6213dae4fa..0a591bf500 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -347,9 +347,6 @@ signals: /// Fired when we're simulating; allows external parties to hook in. void simulating(float deltaTime); - /// Fired when we're rendering in-world interface elements; allows external parties to hook in. - void renderingInWorldInterface(); - /// Fired when the import window is closed void importDone(); diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 26bee34d75..668bd92664 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -22,8 +22,10 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() { connect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut); _downloading = false; - connect(Application::getInstance(), &Application::renderingInWorldInterface, - this, &GlobalServicesScriptingInterface::checkDownloadInfo); + QTimer* checkDownloadTimer = new QTimer(this); + connect(checkDownloadTimer, &QTimer::timeout, this, &GlobalServicesScriptingInterface::checkDownloadInfo); + const int CHECK_DOWNLOAD_INTERVAL = MSECS_PER_SECOND / 2; + checkDownloadTimer->start(CHECK_DOWNLOAD_INTERVAL); auto discoverabilityManager = DependencyManager::get(); connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, From b08f5679998aedd4cdee3ec6989e33999f228f3d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 18 Sep 2015 09:56:45 -0700 Subject: [PATCH 19/32] put controller specific functions inside the controller object --- examples/controllers/handControllerGrab.js | 471 +++++++++++---------- 1 file changed, 238 insertions(+), 233 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index c80084eec2..ed69d1844d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -58,9 +58,6 @@ var ZERO_VEC = {x: 0, y: 0, z: 0}; var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; var MSEC_PER_SEC = 1000.0; -var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK")); -var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK")); - // these control how long an abandoned pointer line will hang around var startTime = Date.now(); var LIFETIME = 10; @@ -92,262 +89,270 @@ function controller(hand, triggerAction) { this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value -} - -controller.prototype.update = function() { - switch(this.state) { - case STATE_SEARCHING: - search(this); - break; - case STATE_DISTANCE_HOLDING: - distanceHolding(this); - break; - case STATE_CLOSE_GRABBING: - closeGrabbing(this); - break; - case STATE_CONTINUE_CLOSE_GRABBING: - continueCloseGrabbing(this); - break; - case STATE_RELEASE: - release(this); - break; - } -} - - -function lineOn(self, closePoint, farPoint, color) { - // draw a line - if (self.pointer == null) { - self.pointer = Entities.addEntity({ - type: "Line", - name: "pointer", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ ZERO_VEC, farPoint ], - color: color, - lifetime: LIFETIME - }); - } else { - Entities.editEntity(self.pointer, { - position: closePoint, - linePoints: [ ZERO_VEC, farPoint ], - color: color, - lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME - }); - } -} - - -function lineOff(self) { - if (self.pointer != null) { - Entities.deleteEntity(self.pointer); - } - self.pointer = null; -} - -function triggerSmoothedSqueezed(self) { - var triggerValue = Controller.getActionValue(self.triggerAction); - // smooth out trigger value - self.triggerValue = (self.triggerValue * TRIGGER_SMOOTH_RATIO) + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); - return self.triggerValue > TRIGGER_ON_VALUE; -} - -function triggerSqueezed(self) { - var triggerValue = Controller.getActionValue(self.triggerAction); - return triggerValue > TRIGGER_ON_VALUE; -} - - -function search(self) { - if (!triggerSmoothedSqueezed(self)) { - self.state = STATE_RELEASE; - return; - } - - // the trigger is being pressed, do a ray test - var handPosition = self.getHandPosition(); - var pickRay = {origin: handPosition, direction: Quat.getUp(self.getHandRotation())}; - var intersection = Entities.findRayIntersection(pickRay, true); - if (intersection.intersects && - intersection.properties.collisionsWillMove === 1 && - intersection.properties.locked === 0) { - // the ray is intersecting something we can move. - var handControllerPosition = Controller.getSpatialControlPosition(self.palm); - var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection); - self.grabbedEntity = intersection.entityID; - if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) { - // the hand is very close to the intersected object. go into close-grabbing mode. - self.state = STATE_CLOSE_GRABBING; - } else { - // the hand is far from the intersected object. go into distance-holding mode - self.state = STATE_DISTANCE_HOLDING; - lineOn(self, pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + this.update = function() { + switch(this.state) { + case STATE_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CLOSE_GRABBING: + this.closeGrabbing(); + break; + case STATE_CONTINUE_CLOSE_GRABBING: + this.continueCloseGrabbing(); + break; + case STATE_RELEASE: + this.release(); + break; } - } else { - // forward ray test failed, try sphere test. - var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); - var minDistance = GRAB_RADIUS; - var grabbedEntity = null; - for (var i = 0; i < nearbyEntities.length; i++) { - var props = Entities.getEntityProperties(nearbyEntities[i]); - var distance = Vec3.distance(props.position, handPosition); - if (distance < minDistance && props.name !== "pointer" && - props.collisionsWillMove === 1 && - props.locked === 0) { - self.grabbedEntity = nearbyEntities[i]; - minDistance = distance; + } + + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer == null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ ZERO_VEC, farPoint ], + color: color, + lifetime: LIFETIME + }); + } else { + Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ ZERO_VEC, farPoint ], + color: color, + lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME + }); + } + } + + + this.lineOff = function() { + if (this.pointer != null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + } + + + this.triggerSmoothedSqueezed = function() { + var triggerValue = Controller.getActionValue(this.triggerAction); + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + return this.triggerValue > TRIGGER_ON_VALUE; + } + + + this.triggerSqueezed = function() { + var triggerValue = Controller.getActionValue(this.triggerAction); + return triggerValue > TRIGGER_ON_VALUE; + } + + + this.search = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var pickRay = {origin: handPosition, direction: Quat.getUp(this.getHandRotation())}; + var intersection = Entities.findRayIntersection(pickRay, true); + if (intersection.intersects && + intersection.properties.collisionsWillMove === 1 && + intersection.properties.locked === 0) { + // the ray is intersecting something we can move. + var handControllerPosition = Controller.getSpatialControlPosition(this.palm); + var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection); + this.grabbedEntity = intersection.entityID; + if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + this.state = STATE_CLOSE_GRABBING; + } else { + // the hand is far from the intersected object. go into distance-holding mode + this.state = STATE_DISTANCE_HOLDING; + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + } else { + // forward ray test failed, try sphere test. + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = GRAB_RADIUS; + var grabbedEntity = null; + for (var i = 0; i < nearbyEntities.length; i++) { + var props = Entities.getEntityProperties(nearbyEntities[i]); + var distance = Vec3.distance(props.position, handPosition); + if (distance < minDistance && props.name !== "pointer" && + props.collisionsWillMove === 1 && + props.locked === 0) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + } + } + if (this.grabbedEntity === null) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } else { + this.state = STATE_CLOSE_GRABBING; } } - if (self.grabbedEntity === null) { - lineOn(self, pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + + this.distanceHolding = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } + + var handPosition = this.getHandPosition(); + var handControllerPosition = Controller.getSpatialControlPosition(this.palm); + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity); + + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + + if (this.actionID === null) { + // first time here since trigger pulled -- add the action and initialize some variables + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectRotation = grabbedProperties.rotation; + this.handPreviousPosition = handControllerPosition; + this.handPreviousRotation = handRotation; + + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + }); + if (this.actionID == NULL_ACTION_ID) { + this.actionID = null; + } } else { - self.state = STATE_CLOSE_GRABBING; + // the action was set up on a previous call. update the targets. + var radius = Math.max(Vec3.distance(this.currentObjectPosition, + handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, + DISTANCE_HOLDING_RADIUS_FACTOR); + + var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition); + this.handPreviousPosition = handControllerPosition; + var superHandMoved = Vec3.multiply(handMoved, radius); + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); + + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); + this.handPreviousRotation = handRotation; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + }); } } -} -function distanceHolding(self) { - if (!triggerSmoothedSqueezed(self)) { - self.state = STATE_RELEASE; - return; - } + this.closeGrabbing = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } - var handPosition = self.getHandPosition(); - var handControllerPosition = Controller.getSpatialControlPosition(self.palm); - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(self.palm)); - var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); + this.lineOff(); - lineOn(self, handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity); - if (self.actionID === null) { - // first time here since trigger pulled -- add the action and initialize some variables - self.currentObjectPosition = grabbedProperties.position; - self.currentObjectRotation = grabbedProperties.rotation; - self.handPreviousPosition = handControllerPosition; - self.handPreviousRotation = handRotation; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); - self.actionID = Entities.addAction("spring", self.grabbedEntity, { - targetPosition: self.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: self.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + var objectRotation = grabbedProperties.rotation; + var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectTime = Date.now(); + var offset = Vec3.subtract(this.currentObjectPosition, handPosition); + var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); + + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand == RIGHT_HAND ? "right" : "left", + timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME, + relativePosition: offsetPosition, + relativeRotation: offsetRotation }); - if (self.actionID == NULL_ACTION_ID) { - self.actionID = null; - } - } else { - // the action was set up on a previous call. update the targets. - var radius = Math.max(Vec3.distance(self.currentObjectPosition, - handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, - DISTANCE_HOLDING_RADIUS_FACTOR); - - var handMoved = Vec3.subtract(handControllerPosition, self.handPreviousPosition); - self.handPreviousPosition = handControllerPosition; - var superHandMoved = Vec3.multiply(handMoved, radius); - self.currentObjectPosition = Vec3.sum(self.currentObjectPosition, superHandMoved); - - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(self.handPreviousRotation, handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(self.handPreviousRotation)); - self.handPreviousRotation = handRotation; - self.currentObjectRotation = Quat.multiply(handChange, self.currentObjectRotation); - - Entities.updateAction(self.grabbedEntity, self.actionID, { - targetPosition: self.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: self.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - }); - } -} - - -function closeGrabbing(self) { - if (!triggerSmoothedSqueezed(self)) { - self.state = STATE_RELEASE; - return; - } - - lineOff(self); - - var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); - - var handRotation = self.getHandRotation(); - var handPosition = self.getHandPosition(); - - var objectRotation = grabbedProperties.rotation; - var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - self.currentObjectPosition = grabbedProperties.position; - self.currentObjectTime = Date.now(); - var offset = Vec3.subtract(self.currentObjectPosition, handPosition); - var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); - - self.actionID = Entities.addAction("hold", self.grabbedEntity, { - hand: self.hand == RIGHT_HAND ? "right" : "left", - timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME, - relativePosition: offsetPosition, - relativeRotation: offsetRotation - }); - if (self.actionID == NULL_ACTION_ID) { - self.actionID = null; - } else { - self.state = STATE_CONTINUE_CLOSE_GRABBING; - } -} - - -function continueCloseGrabbing(self) { - if (!triggerSmoothedSqueezed(self)) { - self.state = STATE_RELEASE; - return; - } - - // keep track of the measured velocity of the held object - var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); - var now = Date.now(); - - var deltaPosition = Vec3.subtract(grabbedProperties.position, self.currentObjectPosition); // meters - var deltaTime = (now - self.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - if (deltaTime > 0.0) { - var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); - // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger - // value would otherwise give the held object time to slow down. - if (triggerSqueezed(self)) { - self.grabbedVelocity = Vec3.sum(Vec3.multiply(self.grabbedVelocity, (1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)), - Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)); + if (this.actionID == NULL_ACTION_ID) { + this.actionID = null; + } else { + this.state = STATE_CONTINUE_CLOSE_GRABBING; } } - self.currentObjectPosition = grabbedProperties.position; - self.currentObjectTime = now; -} + this.continueCloseGrabbing = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } -function release(self) { - lineOff(self); + // keep track of the measured velocity of the held object + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity); + var now = Date.now(); - if (self.grabbedEntity != null && self.actionID != null) { - Entities.deleteAction(self.grabbedEntity, self.actionID); + var deltaPosition = Vec3.subtract(grabbedProperties.position, this.currentObjectPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + if (deltaTime > 0.0) { + var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); + // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger + // value would otherwise give the held object time to slow down. + if (this.triggerSqueezed()) { + this.grabbedVelocity = + Vec3.sum(Vec3.multiply(this.grabbedVelocity, + (1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)), + Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)); + } + } + + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectTime = now; } - // the action will tend to quickly bring an object's velocity to zero. now that - // the action is gone, set the objects velocity to something the holder might expect. - Entities.editEntity(self.grabbedEntity, {velocity: self.grabbedVelocity}); - self.grabbedVelocity = ZERO_VEC; - self.grabbedEntity = null; - self.actionID = null; - self.state = STATE_SEARCHING; + this.release = function() { + this.lineOff(); + + if (this.grabbedEntity != null && this.actionID != null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + + // the action will tend to quickly bring an object's velocity to zero. now that + // the action is gone, set the objects velocity to something the holder might expect. + Entities.editEntity(this.grabbedEntity, {velocity: this.grabbedVelocity}); + + this.grabbedVelocity = ZERO_VEC; + this.grabbedEntity = null; + this.actionID = null; + this.state = STATE_SEARCHING; + } + + + this.cleanup = function() { + release(); + } } -controller.prototype.cleanup = function() { - release(this); -} +var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK")); function update() { From 6ed0a57d9f9e314e55d51d832105feb8b7e52c4e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Sep 2015 10:09:23 -0700 Subject: [PATCH 20/32] avoid unecessary computation of last absolutePose --- libraries/animation/src/AnimInverseKinematics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 409c243612..084139747a 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -263,7 +263,7 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar // only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex if (lowestMovedIndex < _maxTargetIndex) { - for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) { + for (int i = lowestMovedIndex; i < _maxTargetIndex; ++i) { int parentIndex = _skeleton->getParentIndex(i); if (parentIndex != -1) { absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i]; From a85afb5280f0747786674bc9515d4f7fa50fe6ee Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Sep 2015 10:13:21 -0700 Subject: [PATCH 21/32] simplify logic of RotationAccumulator::add() --- libraries/animation/src/RotationAccumulator.cpp | 12 +++++------- libraries/animation/src/RotationAccumulator.h | 4 +++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/animation/src/RotationAccumulator.cpp b/libraries/animation/src/RotationAccumulator.cpp index fccb63fa35..b3ec790d20 100644 --- a/libraries/animation/src/RotationAccumulator.cpp +++ b/libraries/animation/src/RotationAccumulator.cpp @@ -12,14 +12,12 @@ #include void RotationAccumulator::add(glm::quat rotation) { - if (_numRotations == 0) { - _rotationSum = rotation; - } else { - if (glm::dot(_rotationSum, rotation) < 0.0f) { - rotation = -rotation; - } - _rotationSum += rotation; + // make sure both quaternions are on the same hyper-hemisphere before we add them + if (glm::dot(_rotationSum, rotation) < 0.0f) { + rotation = -rotation; } + // sum the rotation linearly (lerp) + _rotationSum += rotation; ++_numRotations; } diff --git a/libraries/animation/src/RotationAccumulator.h b/libraries/animation/src/RotationAccumulator.h index 500f554271..bb30c14363 100644 --- a/libraries/animation/src/RotationAccumulator.h +++ b/libraries/animation/src/RotationAccumulator.h @@ -14,6 +14,8 @@ class RotationAccumulator { public: + RotationAccumulator() : _rotationSum(0.0f, 0.0f, 0.0f, 0.0f), _numRotations(0) { } + int size() const { return _numRotations; } void add(glm::quat rotation); @@ -24,7 +26,7 @@ public: private: glm::quat _rotationSum; - int _numRotations = 0; + int _numRotations; }; #endif // hifi_RotationAccumulator_h From 4cb2249cda69af25bd8121e33a8043776ddeebc6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Sep 2015 10:16:19 -0700 Subject: [PATCH 22/32] premature optimization: remove another branch --- libraries/animation/src/RotationAccumulator.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/animation/src/RotationAccumulator.cpp b/libraries/animation/src/RotationAccumulator.cpp index b3ec790d20..e3de402ef8 100644 --- a/libraries/animation/src/RotationAccumulator.cpp +++ b/libraries/animation/src/RotationAccumulator.cpp @@ -12,12 +12,8 @@ #include void RotationAccumulator::add(glm::quat rotation) { - // make sure both quaternions are on the same hyper-hemisphere before we add them - if (glm::dot(_rotationSum, rotation) < 0.0f) { - rotation = -rotation; - } - // sum the rotation linearly (lerp) - _rotationSum += rotation; + // make sure both quaternions are on the same hyper-hemisphere before we add them linearly (lerp) + _rotationSum += copysignf(1.0f, glm::dot(_rotationSum, rotation)) * rotation; ++_numRotations; } From 6edc817bf26c66347db23940d50704098202299b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Sep 2015 11:35:50 -0700 Subject: [PATCH 23/32] move the best zone logic out of EntityTreeRenderer::render() --- .../src/EntityTreeRenderer.cpp | 85 +++++++------------ .../src/EntityTreeRenderer.h | 2 +- 2 files changed, 33 insertions(+), 54 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ebdf0f0339..4d42b79092 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -165,12 +165,41 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { _tree->withReadLock([&] { std::static_pointer_cast(_tree)->findEntities(avatarPosition, radius, foundEntities); + // Whenever you're in an intersection between zones, we will always choose the smallest zone. + _bestZone = NULL; // NOTE: Is this what we want? + _bestZoneVolume = std::numeric_limits::max(); + // create a list of entities that actually contain the avatar's position foreach(EntityItemPointer entity, foundEntities) { if (entity->contains(avatarPosition)) { entitiesContainingAvatar << entity->getEntityItemID(); + + // if this entity is a zone, use this time to determine the bestZone + if (entity->getType() == EntityTypes::Zone) { + float entityVolumeEstimate = entity->getVolumeEstimate(); + if (entityVolumeEstimate < _bestZoneVolume) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = std::dynamic_pointer_cast(entity); + } else if (entityVolumeEstimate == _bestZoneVolume) { + if (!_bestZone) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = std::dynamic_pointer_cast(entity); + } else { + // in the case of the volume being equal, we will use the + // EntityItemID to deterministically pick one entity over the other + if (entity->getEntityItemID() < _bestZone->getEntityItemID()) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = std::dynamic_pointer_cast(entity); + } + } + } + + } } } + + applyZonePropertiesToScene(_bestZone); + }); // Note: at this point we don't need to worry about the tree being locked, because we only deal with @@ -306,23 +335,9 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr_renderer = this; - _tree->withReadLock([&] { - // Whenever you're in an intersection between zones, we will always choose the smallest zone. - _bestZone = NULL; // NOTE: Is this what we want? - _bestZoneVolume = std::numeric_limits::max(); - - // FIX ME: right now the renderOperation does the following: - // 1) determining the best zone (not really rendering) - // 2) render the debug cell details - // we should clean this up - _tree->recurseTreeWithOperation(renderOperation, renderArgs); - - applyZonePropertiesToScene(_bestZone); - }); - } + // FIXME - currently the EntityItem rendering code still depends on knowing about the EntityTreeRenderer + // because it uses it as a model loading service. We don't actually do anything in rendering other than this. + renderArgs->_renderer = this; deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup } @@ -370,42 +385,6 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP return result; } -void EntityTreeRenderer::renderElement(OctreeElementPointer element, RenderArgs* args) { - // actually render it here... - // we need to iterate the actual entityItems of the element - EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - - bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE; - - entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - if (entityItem->isVisible()) { - // NOTE: Zone Entities are a special case we handle here... - if (entityItem->getType() == EntityTypes::Zone) { - if (entityItem->contains(_viewState->getAvatarPosition())) { - float entityVolumeEstimate = entityItem->getVolumeEstimate(); - if (entityVolumeEstimate < _bestZoneVolume) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entityItem); - } else if (entityVolumeEstimate == _bestZoneVolume) { - if (!_bestZone) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entityItem); - } else { - // in the case of the volume being equal, we will use the - // EntityItemID to deterministically pick one entity over the other - if (entityItem->getEntityItemID() < _bestZone->getEntityItemID()) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entityItem); - } - } - } - } - } - } - }); - -} - float EntityTreeRenderer::getSizeScale() const { return _viewState->getSizeScale(); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 2691c3c66f..1664920a1d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -40,7 +40,7 @@ public: virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; } - virtual void renderElement(OctreeElementPointer element, RenderArgs* args); + virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { } virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; virtual void setTree(OctreePointer newTree); From 07f3abfc911a83a5f2562f8019ab5690835194f9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Sep 2015 12:01:23 -0700 Subject: [PATCH 24/32] fix bugs --- libraries/animation/src/AnimInverseKinematics.cpp | 10 ++++------ libraries/animation/src/RotationAccumulator.cpp | 5 +++++ libraries/animation/src/RotationAccumulator.h | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 084139747a..6af58e89a1 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -262,12 +262,10 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar } // only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex - if (lowestMovedIndex < _maxTargetIndex) { - for (int i = lowestMovedIndex; i < _maxTargetIndex; ++i) { - int parentIndex = _skeleton->getParentIndex(i); - if (parentIndex != -1) { - absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i]; - } + for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) { + int parentIndex = _skeleton->getParentIndex(i); + if (parentIndex != -1) { + absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i]; } } } while (largestError > ACCEPTABLE_RELATIVE_ERROR && numLoops < MAX_IK_LOOPS && usecTimestampNow() < expiry); diff --git a/libraries/animation/src/RotationAccumulator.cpp b/libraries/animation/src/RotationAccumulator.cpp index e3de402ef8..58ce4b9f36 100644 --- a/libraries/animation/src/RotationAccumulator.cpp +++ b/libraries/animation/src/RotationAccumulator.cpp @@ -20,3 +20,8 @@ void RotationAccumulator::add(glm::quat rotation) { glm::quat RotationAccumulator::getAverage() { return (_numRotations > 0) ? glm::normalize(_rotationSum) : glm::quat(); } + +void RotationAccumulator::clear() { + _rotationSum *= 0.0f; + _numRotations = 0; +} diff --git a/libraries/animation/src/RotationAccumulator.h b/libraries/animation/src/RotationAccumulator.h index bb30c14363..634a3d0eac 100644 --- a/libraries/animation/src/RotationAccumulator.h +++ b/libraries/animation/src/RotationAccumulator.h @@ -22,7 +22,7 @@ public: glm::quat getAverage(); - void clear() { _numRotations = 0; } + void clear(); private: glm::quat _rotationSum; From 3c64db5c8629e7f3f691acc2bce42abdca8eeb24 Mon Sep 17 00:00:00 2001 From: Shared Vive Room Date: Fri, 18 Sep 2015 12:02:05 -0700 Subject: [PATCH 25/32] Adjust controller offset from 6 inches to 3 inches When using the vive controller the position of your wrist should match your actual wrist a bit better, unless your name is Shaquille O'Neal. --- .../input-plugins/src/input-plugins/ViveControllerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 5410db11a4..4af3dd97d0 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -42,7 +42,7 @@ const unsigned int GRIP_BUTTON = 1U << 2; const unsigned int TRACKPAD_BUTTON = 1U << 3; const unsigned int TRIGGER_BUTTON = 1U << 4; -const float CONTROLLER_LENGTH_OFFSET = 0.175f; +const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const QString ViveControllerManager::NAME = "OpenVR"; From 416acb1d4ad171bf2edb84d7f08fce09795b9ef2 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Sep 2015 12:03:58 -0700 Subject: [PATCH 26/32] remove call to _entities.render() in displaySide() --- interface/src/Application.cpp | 3 +-- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 8 +------- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 09abfbe01e..1b6be53e83 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1063,7 +1063,7 @@ void Application::paintGL() { auto lodManager = DependencyManager::get(); - RenderArgs renderArgs(_gpuContext, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), + RenderArgs renderArgs(_gpuContext, getEntities(), getViewFrustum(), lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); @@ -3562,7 +3562,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); } renderArgs->_debugFlags = renderDebugFlags; - _entities.render(renderArgs); //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges); } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4d42b79092..c6c08471e1 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -149,6 +149,7 @@ void EntityTreeRenderer::update() { } } + deleteReleasedModels(); } void EntityTreeRenderer::checkEnterLeaveEntities() { @@ -334,13 +335,6 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr_renderer = this; - deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup -} - const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) { const FBXGeometry* result = NULL; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 1664920a1d..59919de27d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -53,7 +53,7 @@ public: void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); virtual void init(); - virtual void render(RenderArgs* renderArgs) override; + virtual void render(RenderArgs* renderArgs) override { } virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem); virtual const Model* getModelForEntityItem(EntityItemPointer entityItem); From 0d375110710a70f85e5b0f9bc28993c028df51a5 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Sep 2015 14:06:38 -0700 Subject: [PATCH 27/32] add support for scripts to call methods on entity scripts --- examples/controllers/handControllerGrab.js | 38 ++++++++++++-- examples/entityScripts/detectGrabExample.js | 52 ++++--------------- .../src/EntityTreeRenderer.cpp | 1 + .../src/EntitiesScriptEngineProvider.h | 25 +++++++++ .../entities/src/EntityScriptingInterface.cpp | 9 ++++ .../entities/src/EntityScriptingInterface.h | 10 +++- libraries/script-engine/src/ScriptEngine.h | 3 +- 7 files changed, 92 insertions(+), 46 deletions(-) create mode 100644 libraries/entities/src/EntitiesScriptEngineProvider.h diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ed69d1844d..109a4ab57c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -69,6 +69,7 @@ var STATE_CLOSE_GRABBING = 2; var STATE_CONTINUE_CLOSE_GRABBING = 3; var STATE_RELEASE = 4; +var GRAB_USER_DATA_KEY = "grabKey"; function controller(hand, triggerAction) { this.hand = hand; @@ -89,6 +90,7 @@ function controller(hand, triggerAction) { this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value + this.alreadyDistanceHolding = false; // FIXME - I'll leave it to Seth to potentially make this another state this.update = function() { switch(this.state) { @@ -210,13 +212,20 @@ function controller(hand, triggerAction) { this.distanceHolding = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; + this.alreadyDistanceHolding = false; return; } + if (!this.alreadyDistanceHolding) { + this.activateEntity(this.grabbedEntity); + this.alreadyDistanceHolding = true; + } + var handPosition = this.getHandPosition(); var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]); + Entities.callEntityMethod(this.grabbedEntity, "distanceHolding"); this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); @@ -270,7 +279,9 @@ function controller(hand, triggerAction) { this.lineOff(); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity); + this.activateEntity(this.grabbedEntity); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, "position"); var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); @@ -294,6 +305,7 @@ function controller(hand, triggerAction) { } else { this.state = STATE_CONTINUE_CLOSE_GRABBING; } + Entities.callEntityMethod(this.grabbedEntity, "closeGrabbing"); } @@ -324,6 +336,7 @@ function controller(hand, triggerAction) { this.currentObjectPosition = grabbedProperties.position; this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueCloseGrabbing"); } @@ -336,7 +349,10 @@ function controller(hand, triggerAction) { // the action will tend to quickly bring an object's velocity to zero. now that // the action is gone, set the objects velocity to something the holder might expect. - Entities.editEntity(this.grabbedEntity, {velocity: this.grabbedVelocity}); + Entities.editEntity(this.grabbedEntity, { velocity: this.grabbedVelocity }); + + Entities.callEntityMethod(this.grabbedEntity, "release"); + this.deactivateEntity(this.grabbedEntity); this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; @@ -348,6 +364,22 @@ function controller(hand, triggerAction) { this.cleanup = function() { release(); } + + this.activateEntity = function(entity) { + var data = { + activated: true, + avatarId: MyAvatar.sessionUUID + }; + setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); + } + + this.deactivateEntity = function(entity) { + var data = { + activated: false, + avatarId: null + }; + setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); + } } diff --git a/examples/entityScripts/detectGrabExample.js b/examples/entityScripts/detectGrabExample.js index cdc79e119d..c84d3250cc 100644 --- a/examples/entityScripts/detectGrabExample.js +++ b/examples/entityScripts/detectGrabExample.js @@ -12,7 +12,6 @@ // (function() { - Script.include("../libraries/utils.js"); var _this; @@ -24,39 +23,18 @@ DetectGrabbed.prototype = { - // update() will be called regulary, because we've hooked the update signal in our preload() function - // we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us - // if we're currently being grabbed and if the person grabbing us is the current interfaces avatar. - // we will watch this for state changes and print out if we're being grabbed or released when it changes. - update: function() { - var GRAB_USER_DATA_KEY = "grabKey"; + distanceHolding: function () { + print("I am being distance held... entity:" + this.entityID); + }, - // because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID - var entityID = _this.entityID; - - // we want to assume that if there is no grab data, then we are not being grabbed - var defaultGrabData = { activated: false, avatarId: null }; - - // this handy function getEntityCustomData() is available in utils.js and it will return just the specific section - // of user data we asked for. If it's not available it returns our default data. - var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData); - - // if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface - if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) { - - // remember we're being grabbed so we can detect being released - _this.beingGrabbed = true; - - // print out that we're being grabbed - print("I'm being grabbed..."); - - } else if (_this.beingGrabbed) { - - // if we are not being grabbed, and we previously were, then we were just released, remember that - // and print out a message - _this.beingGrabbed = false; - print("I'm was released..."); - } + closeGrabbing: function () { + print("I was just grabbed... entity:" + this.entityID); + }, + continueCloseGrabbing: function () { + print("I am still being grabbed... entity:" + this.entityID); + }, + release: function () { + print("I was released... entity:" + this.entityID); }, // preload() will be called when the entity has become visible (or known) to the interface @@ -65,14 +43,6 @@ // * connecting to the update signal so we can check our grabbed state preload: function(entityID) { this.entityID = entityID; - Script.update.connect(this.update); - }, - - // unload() will be called when our entity is no longer available. It may be because we were deleted, - // or because we've left the domain or quit the application. In all cases we want to unhook our connection - // to the update signal - unload: function(entityID) { - Script.update.disconnect(this.update); }, }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c55eaaeff9..056aaab1a5 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -112,6 +112,7 @@ void EntityTreeRenderer::init() { _scriptingServices->getControllerScriptingInterface()); _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine); _entitiesScriptEngine->runInThread(); + DependencyManager::get()->setEntitiesScriptEngine(_entitiesScriptEngine); } // make sure our "last avatar position" is something other than our current position, so that on our diff --git a/libraries/entities/src/EntitiesScriptEngineProvider.h b/libraries/entities/src/EntitiesScriptEngineProvider.h new file mode 100644 index 0000000000..d112a6c0f9 --- /dev/null +++ b/libraries/entities/src/EntitiesScriptEngineProvider.h @@ -0,0 +1,25 @@ +// +// EntitiesScriptEngineProvider.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on Sept. 18, 2015 +// Copyright 2015 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 +// +// TODO: How will we handle collision callbacks with Entities +// + +#ifndef hifi_EntitiesScriptEngineProvider_h +#define hifi_EntitiesScriptEngineProvider_h + +#include +#include "EntityItemID.h" + +class EntitiesScriptEngineProvider { +public: + virtual void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName) = 0; +}; + +#endif // hifi_EntitiesScriptEngineProvider_h \ No newline at end of file diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4b8b4e2903..1d403e37cd 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -11,6 +11,7 @@ #include "EntityScriptingInterface.h" +#include "EntityItemID.h" #include #include "EntitiesLogging.h" @@ -211,6 +212,14 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { } } +void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method) { + if (_entitiesScriptEngine) { + EntityItemID entityID{ id }; + _entitiesScriptEngine->callEntityScriptMethod(entityID, method); + } +} + + QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { EntityItemID result; if (_entityTree) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8d2b0b6892..8484b7189a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -20,18 +20,19 @@ #include #include #include + #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" #include "PolyLineEntityItem.h" #include "EntityTree.h" #include "EntityEditPacketSender.h" +#include "EntitiesScriptEngineProvider.h" class EntityTree; class MouseEvent; - class RayToEntityIntersectionResult { public: RayToEntityIntersectionResult(); @@ -63,6 +64,7 @@ public: void setEntityTree(EntityTreePointer modelTree); EntityTreePointer getEntityTree() { return _entityTree; } + void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine) { _entitiesScriptEngine = engine; } public slots: @@ -86,6 +88,11 @@ public slots: /// deletes a model Q_INVOKABLE void deleteEntity(QUuid entityID); + /// Allows a script to call a method on an entity's script. The method will execute in the entity script + /// engine. If the entity does not have an entity script or the method does not exist, this call will have + /// no effect. + Q_INVOKABLE void callEntityMethod(QUuid entityID, const QString& method); + /// finds the closest model to the center point, within the radius /// will return a EntityItemID.isKnownID = false if no models are in the radius /// this function will not find any models in script engine contexts which don't have access to models @@ -180,6 +187,7 @@ private: bool precisionPicking); EntityTreePointer _entityTree; + EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr; }; #endif // hifi_EntityScriptingInterface_h diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 83e65823a5..3cfeb3447e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "AbstractControllerScriptingInterface.h" #include "ArrayBufferClass.h" @@ -46,7 +47,7 @@ public: QScriptValue scriptObject; }; -class ScriptEngine : public QScriptEngine, public ScriptUser { +class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider { Q_OBJECT public: ScriptEngine(const QString& scriptContents = NO_SCRIPT, From 7a8cee4cc3001650e02fc41a9254257551aa1a99 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 18 Sep 2015 14:13:08 -0700 Subject: [PATCH 28/32] fix release velocity so throwing things works reliably --- examples/controllers/handControllerGrab.js | 26 +++++++++++++--------- examples/libraries/utils.js | 7 ++++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ed69d1844d..df90de1b67 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -18,7 +18,7 @@ Script.include("../libraries/utils.js"); // these tune time-averaging and "on" value for analog trigger // -var TRIGGER_SMOOTH_RATIO = 0.7; +var TRIGGER_SMOOTH_RATIO = 0.0; // 0.0 disables smoothing of trigger value var TRIGGER_ON_VALUE = 0.2; ///////////////////////////////////////////////////////////////// @@ -42,9 +42,9 @@ var LINE_LENGTH = 500; var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected var CLOSE_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO = 0.9; // adjust time-averaging of held object's velocity +var CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. var CLOSE_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected - +var RELEASE_VELOCITY_MULTIPLIER = 2.0; // affects throwing things ///////////////////////////////////////////////////////////////// // @@ -278,9 +278,8 @@ function controller(hand, triggerAction) { var objectRotation = grabbedProperties.rotation; var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectTime = Date.now(); - var offset = Vec3.subtract(this.currentObjectPosition, handPosition); + currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); this.actionID = Entities.addAction("hold", this.grabbedEntity, { @@ -294,6 +293,9 @@ function controller(hand, triggerAction) { } else { this.state = STATE_CONTINUE_CLOSE_GRABBING; } + + this.currentHandControllerPosition = Controller.getSpatialControlPosition(this.palm); + this.currentObjectTime = Date.now(); } @@ -304,13 +306,13 @@ function controller(hand, triggerAction) { } // keep track of the measured velocity of the held object - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity); + var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var now = Date.now(); - var deltaPosition = Vec3.subtract(grabbedProperties.position, this.currentObjectPosition); // meters + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerPosition); // meters var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - if (deltaTime > 0.0) { + if (deltaTime > 0.0 && !vec3equal(this.currentHandControllerPosition, handControllerPosition)) { var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger // value would otherwise give the held object time to slow down. @@ -322,7 +324,7 @@ function controller(hand, triggerAction) { } } - this.currentObjectPosition = grabbedProperties.position; + this.currentHandControllerPosition = handControllerPosition; this.currentObjectTime = now; } @@ -336,7 +338,9 @@ function controller(hand, triggerAction) { // the action will tend to quickly bring an object's velocity to zero. now that // the action is gone, set the objects velocity to something the holder might expect. - Entities.editEntity(this.grabbedEntity, {velocity: this.grabbedVelocity}); + Entities.editEntity(this.grabbedEntity, + {velocity: Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER)} + ); this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index 1275975fd8..865a5a55b1 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -6,11 +6,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -vec3toStr = function (v, digits) { +vec3toStr = function(v, digits) { if (!digits) { digits = 3; } return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }"; } +vec3equal = function(v0, v1) { + return (v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z); +} colorMix = function(colorA, colorB, mix) { var result = {}; @@ -175,4 +178,4 @@ pointInExtents = function(point, minPoint, maxPoint) { return (point.x >= minPoint.x && point.x <= maxPoint.x) && (point.y >= minPoint.y && point.y <= maxPoint.y) && (point.z >= minPoint.z && point.z <= maxPoint.z); -} \ No newline at end of file +} From 020fb25ace3dfb179fbdddd8aced64d5521a15eb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Sep 2015 14:24:01 -0700 Subject: [PATCH 29/32] CR feedback --- libraries/entities-renderer/src/EntityTreeRenderer.h | 3 --- libraries/octree/src/OctreeRenderer.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 59919de27d..d100597969 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -40,7 +40,6 @@ public: virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; } - virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { } virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; virtual void setTree(OctreePointer newTree); @@ -53,7 +52,6 @@ public: void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); virtual void init(); - virtual void render(RenderArgs* renderArgs) override { } virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem); virtual const Model* getModelForEntityItem(EntityItemPointer entityItem); @@ -128,7 +126,6 @@ private: void addEntityToScene(EntityItemPointer entity); void applyZonePropertiesToScene(std::shared_ptr zone); - void renderElementProxy(EntityTreeElementPointer entityTreeElement, RenderArgs* args); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); QList _releasedModels; diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 5fda4c9f4a..e2d97f0484 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -38,7 +38,7 @@ public: virtual char getMyNodeType() const = 0; virtual PacketType getMyQueryMessageType() const = 0; virtual PacketType getExpectedPacketType() const = 0; - virtual void renderElement(OctreeElementPointer element, RenderArgs* args) = 0; + virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { } virtual float getSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; } virtual int getBoundaryLevelAdjust() const { return 0; } From d1a7aca7f091c38266b1924df4f05286e323b11c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 18 Sep 2015 14:45:49 -0700 Subject: [PATCH 30/32] add continue-distance-holding state. don't call callEntityMethod unless action creation works. increase distance-holding multiplier. --- examples/controllers/handControllerGrab.js | 105 +++++++++++---------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 554d5117ea..fc82e0c065 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -26,7 +26,7 @@ var TRIGGER_ON_VALUE = 0.2; // distant manipulation // -var DISTANCE_HOLDING_RADIUS_FACTOR = 4; // multiplied by distance between hand and object +var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did var NO_INTERSECT_COLOR = {red: 10, green: 10, blue: 255}; // line color when pick misses @@ -65,9 +65,10 @@ var LIFETIME = 10; // states for the state machine var STATE_SEARCHING = 0; var STATE_DISTANCE_HOLDING = 1; -var STATE_CLOSE_GRABBING = 2; -var STATE_CONTINUE_CLOSE_GRABBING = 3; -var STATE_RELEASE = 4; +var STATE_CONTINUE_DISTANCE_HOLDING = 2; +var STATE_CLOSE_GRABBING = 3; +var STATE_CONTINUE_CLOSE_GRABBING = 4; +var STATE_RELEASE = 5; var GRAB_USER_DATA_KEY = "grabKey"; @@ -90,7 +91,6 @@ function controller(hand, triggerAction) { this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value - this.alreadyDistanceHolding = false; // FIXME - I'll leave it to Seth to potentially make this another state this.update = function() { switch(this.state) { @@ -100,6 +100,9 @@ function controller(hand, triggerAction) { case STATE_DISTANCE_HOLDING: this.distanceHolding(); break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; case STATE_CLOSE_GRABBING: this.closeGrabbing(); break; @@ -210,64 +213,68 @@ function controller(hand, triggerAction) { this.distanceHolding = function() { - if (!this.triggerSmoothedSqueezed()) { - this.state = STATE_RELEASE; - this.alreadyDistanceHolding = false; - return; + var handControllerPosition = Controller.getSpatialControlPosition(this.palm); + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]); + + // add the action and initialize some variables + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectRotation = grabbedProperties.rotation; + this.handPreviousPosition = handControllerPosition; + this.handPreviousRotation = handRotation; + + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + }); + if (this.actionID == NULL_ACTION_ID) { + this.actionID = null; } - if (!this.alreadyDistanceHolding) { + if (this.actionID != null) { + this.state = STATE_CONTINUE_DISTANCE_HOLDING; this.activateEntity(this.grabbedEntity); - this.alreadyDistanceHolding = true; + Entities.callEntityMethod(this.grabbedEntity, "distanceHolding"); + } + } + + + this.continueDistanceHolding = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; } var handPosition = this.getHandPosition(); var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]); - Entities.callEntityMethod(this.grabbedEntity, "distanceHolding"); this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - if (this.actionID === null) { - // first time here since trigger pulled -- add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.handPreviousPosition = handControllerPosition; - this.handPreviousRotation = handRotation; + // the action was set up on a previous call. update the targets. + var radius = Math.max(Vec3.distance(this.currentObjectPosition, + handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, + DISTANCE_HOLDING_RADIUS_FACTOR); - this.actionID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - }); - if (this.actionID == NULL_ACTION_ID) { - this.actionID = null; - } - } else { - // the action was set up on a previous call. update the targets. - var radius = Math.max(Vec3.distance(this.currentObjectPosition, - handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, - DISTANCE_HOLDING_RADIUS_FACTOR); + var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition); + this.handPreviousPosition = handControllerPosition; + var superHandMoved = Vec3.multiply(handMoved, radius); + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition); - this.handPreviousPosition = handControllerPosition; - var superHandMoved = Vec3.multiply(handMoved, radius); - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); + this.handPreviousRotation = handRotation; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; - this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - - Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - }); - } + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + }); } @@ -303,11 +310,11 @@ function controller(hand, triggerAction) { this.actionID = null; } else { this.state = STATE_CONTINUE_CLOSE_GRABBING; + Entities.callEntityMethod(this.grabbedEntity, "closeGrabbing"); } this.currentHandControllerPosition = Controller.getSpatialControlPosition(this.palm); this.currentObjectTime = Date.now(); - Entities.callEntityMethod(this.grabbedEntity, "closeGrabbing"); } From 612e906a443a7fc0f317252792210f78b28fcadb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 18 Sep 2015 15:09:05 -0700 Subject: [PATCH 31/32] change the names of entityMethods which the grab script will call. adjust the release velocity multiplier --- examples/controllers/handControllerGrab.js | 63 +++++++++++++--------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index fc82e0c065..20b0003cc7 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -37,14 +37,14 @@ var LINE_LENGTH = 500; ///////////////////////////////////////////////////////////////// // -// close grabbing +// near grabbing // var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected -var CLOSE_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. -var CLOSE_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected -var RELEASE_VELOCITY_MULTIPLIER = 2.0; // affects throwing things +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things ///////////////////////////////////////////////////////////////// // @@ -66,8 +66,8 @@ var LIFETIME = 10; var STATE_SEARCHING = 0; var STATE_DISTANCE_HOLDING = 1; var STATE_CONTINUE_DISTANCE_HOLDING = 2; -var STATE_CLOSE_GRABBING = 3; -var STATE_CONTINUE_CLOSE_GRABBING = 4; +var STATE_NEAR_GRABBING = 3; +var STATE_CONTINUE_NEAR_GRABBING = 4; var STATE_RELEASE = 5; var GRAB_USER_DATA_KEY = "grabKey"; @@ -88,7 +88,7 @@ function controller(hand, triggerAction) { this.actionID = null; // action this script created... this.grabbedEntity = null; // on this entity. this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity - this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing + this.state = 0; this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value @@ -103,11 +103,11 @@ function controller(hand, triggerAction) { case STATE_CONTINUE_DISTANCE_HOLDING: this.continueDistanceHolding(); break; - case STATE_CLOSE_GRABBING: - this.closeGrabbing(); + case STATE_NEAR_GRABBING: + this.nearGrabbing(); break; - case STATE_CONTINUE_CLOSE_GRABBING: - this.continueCloseGrabbing(); + case STATE_CONTINUE_NEAR_GRABBING: + this.continueNearGrabbing(); break; case STATE_RELEASE: this.release(); @@ -180,9 +180,9 @@ function controller(hand, triggerAction) { var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection); this.grabbedEntity = intersection.entityID; - if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) { + if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) { // the hand is very close to the intersected object. go into close-grabbing mode. - this.state = STATE_CLOSE_GRABBING; + this.state = STATE_NEAR_GRABBING; } else { // the hand is far from the intersected object. go into distance-holding mode this.state = STATE_DISTANCE_HOLDING; @@ -206,7 +206,7 @@ function controller(hand, triggerAction) { if (this.grabbedEntity === null) { this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } else { - this.state = STATE_CLOSE_GRABBING; + this.state = STATE_NEAR_GRABBING; } } } @@ -236,7 +236,13 @@ function controller(hand, triggerAction) { if (this.actionID != null) { this.state = STATE_CONTINUE_DISTANCE_HOLDING; this.activateEntity(this.grabbedEntity); - Entities.callEntityMethod(this.grabbedEntity, "distanceHolding"); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } } } @@ -271,6 +277,8 @@ function controller(hand, triggerAction) { this.handPreviousRotation = handRotation; this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME @@ -278,7 +286,7 @@ function controller(hand, triggerAction) { } - this.closeGrabbing = function() { + this.nearGrabbing = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -302,15 +310,20 @@ function controller(hand, triggerAction) { this.actionID = Entities.addAction("hold", this.grabbedEntity, { hand: this.hand == RIGHT_HAND ? "right" : "left", - timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME, + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: offsetPosition, relativeRotation: offsetRotation }); if (this.actionID == NULL_ACTION_ID) { this.actionID = null; } else { - this.state = STATE_CONTINUE_CLOSE_GRABBING; - Entities.callEntityMethod(this.grabbedEntity, "closeGrabbing"); + this.state = STATE_CONTINUE_NEAR_GRABBING; + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } } this.currentHandControllerPosition = Controller.getSpatialControlPosition(this.palm); @@ -318,7 +331,7 @@ function controller(hand, triggerAction) { } - this.continueCloseGrabbing = function() { + this.continueNearGrabbing = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -338,14 +351,14 @@ function controller(hand, triggerAction) { if (this.triggerSqueezed()) { this.grabbedVelocity = Vec3.sum(Vec3.multiply(this.grabbedVelocity, - (1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)), - Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)); + (1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)), + Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)); } } this.currentHandControllerPosition = handControllerPosition; this.currentObjectTime = now; - Entities.callEntityMethod(this.grabbedEntity, "continueCloseGrabbing"); + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); } @@ -361,7 +374,7 @@ function controller(hand, triggerAction) { Entities.editEntity(this.grabbedEntity, {velocity: Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER)} ); - Entities.callEntityMethod(this.grabbedEntity, "release"); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); this.deactivateEntity(this.grabbedEntity); this.grabbedVelocity = ZERO_VEC; From 3d18edd9d10f646d08ae954a367a2e2b2b1272cf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 18 Sep 2015 15:13:09 -0700 Subject: [PATCH 32/32] update detectGrabExample.js --- examples/entityScripts/detectGrabExample.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/entityScripts/detectGrabExample.js b/examples/entityScripts/detectGrabExample.js index c84d3250cc..7e97572159 100644 --- a/examples/entityScripts/detectGrabExample.js +++ b/examples/entityScripts/detectGrabExample.js @@ -23,16 +23,27 @@ DetectGrabbed.prototype = { - distanceHolding: function () { - print("I am being distance held... entity:" + this.entityID); + setRightHand: function () { + print("I am being held in a right hand... entity:" + this.entityID); + }, + setLeftHand: function () { + print("I am being held in a left hand... entity:" + this.entityID); }, - closeGrabbing: function () { + startDistantGrab: function () { + print("I am being distance held... entity:" + this.entityID); + }, + continueDistantGrab: function () { + print("I continue to be distance held... entity:" + this.entityID); + }, + + startNearGrab: function () { print("I was just grabbed... entity:" + this.entityID); }, - continueCloseGrabbing: function () { + continueNearGrab: function () { print("I am still being grabbed... entity:" + this.entityID); }, + release: function () { print("I was released... entity:" + this.entityID); },