From 172fab6789d6caba4d8ae1c8e080d8897f3e7435 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 30 Mar 2017 17:53:54 -0700 Subject: [PATCH 01/18] Thread safety for property getter/setters on entities --- libraries/entities/src/EntityItem.cpp | 543 ++++++++++++++++++++-- libraries/entities/src/EntityItem.h | 139 +++--- libraries/entities/src/TextEntityItem.cpp | 95 ++++ libraries/entities/src/TextEntityItem.h | 38 +- 4 files changed, 682 insertions(+), 133 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0bb085459e..9ba740728b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -909,19 +909,23 @@ void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSk float EntityItem::computeMass() const { glm::vec3 dimensions = getDimensions(); - return _density * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; + return getDensity() * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; } void EntityItem::setDensity(float density) { - _density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); + withWriteLock([&] { + _density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); + }); } void EntityItem::updateDensity(float density) { float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); - if (_density != clampedDensity) { - _density = clampedDensity; - _dirtyFlags |= Simulation::DIRTY_MASS; - } + withWriteLock([&] { + if (_density != clampedDensity) { + _density = clampedDensity; + _dirtyFlags |= Simulation::DIRTY_MASS; + } + }); } void EntityItem::setMass(float mass) { @@ -941,10 +945,12 @@ void EntityItem::setMass(float mass) { } else { newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); } - if (_density != newDensity) { - _density = newDensity; - _dirtyFlags |= Simulation::DIRTY_MASS; - } + withWriteLock([&] { + if (_density != newDensity) { + _density = newDensity; + _dirtyFlags |= Simulation::DIRTY_MASS; + } + }); } void EntityItem::setHref(QString value) { @@ -952,32 +958,47 @@ void EntityItem::setHref(QString value) { if (! (value.toLower().startsWith("hifi://")) ) { return; } - _href = value; + withWriteLock([&] { + _href = value; + }); } void EntityItem::setCollisionSoundURL(const QString& value) { - if (_collisionSoundURL != value) { - _collisionSoundURL = value; - + bool modified = false; + withWriteLock([&] { + if (_collisionSoundURL != value) { + _collisionSoundURL = value; + modified = true; + } + }); + if (modified) { if (auto myTree = getTree()) { - myTree->notifyNewCollisionSoundURL(_collisionSoundURL, getEntityItemID()); + myTree->notifyNewCollisionSoundURL(value, getEntityItemID()); } } } SharedSoundPointer EntityItem::getCollisionSound() { - if (!_collisionSound) { - _collisionSound = DependencyManager::get()->getSound(_collisionSoundURL); + SharedSoundPointer result; + withReadLock([&] { + result = _collisionSound; + }); + + if (!result) { + result = DependencyManager::get()->getSound(_collisionSoundURL); + withWriteLock([&] { + _collisionSound = result; + }); } - return _collisionSound; + return result; } void EntityItem::simulate(const quint64& now) { - if (_lastSimulated == 0) { - _lastSimulated = now; + if (0 == getLastSimulated()) { + setLastSimulated(now); } - float timeElapsed = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); + float timeElapsed = (float)(now - getLastSimulated()) / (float)(USECS_PER_SECOND); #ifdef WANT_DEBUG qCDebug(entities) << "********** EntityItem::simulate()"; @@ -1024,7 +1045,7 @@ void EntityItem::simulate(const quint64& now) { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; setAcceleration(Vectors::ZERO); } - _lastSimulated = now; + setLastSimulated(now); } bool EntityItem::stepKinematicMotion(float timeElapsed) { @@ -1056,9 +1077,10 @@ bool EntityItem::stepKinematicMotion(float timeElapsed) { timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED); if (isSpinning) { + float angularDamping = getAngularDamping(); // angular damping - if (_angularDamping > 0.0f) { - angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); + if (angularDamping > 0.0f) { + angularVelocity *= powf(1.0f - angularDamping, timeElapsed); } const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED = @@ -1086,15 +1108,17 @@ bool EntityItem::stepKinematicMotion(float timeElapsed) { glm::vec3 deltaVelocity = Vectors::ZERO; // linear damping - if (_damping > 0.0f) { - deltaVelocity = (powf(1.0f - _damping, timeElapsed) - 1.0f) * linearVelocity; + float damping = getDamping(); + if (damping > 0.0f) { + deltaVelocity = (powf(1.0f - damping, timeElapsed) - 1.0f) * linearVelocity; } const float MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED = 1.0e-4f; // 0.01 m/sec^2 - if (glm::length2(_acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) { + vec3 acceleration = getAcceleration(); + if (glm::length2(acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) { // yes acceleration // acceleration is in world-frame but we need it in local-frame - glm::vec3 linearAcceleration = _acceleration; + glm::vec3 linearAcceleration = acceleration; bool success; Transform parentTransform = getParentTransform(success); if (success) { @@ -1180,7 +1204,7 @@ bool EntityItem::lifetimeHasExpired() const { } quint64 EntityItem::getExpiry() const { - return _created + (quint64)(_lifetime * (float)USECS_PER_SECOND); + return getCreated() + (quint64)(getLifetime() * (float)USECS_PER_SECOND); } EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProperties) const { @@ -1189,10 +1213,10 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper EntityItemProperties properties(propertyFlags); properties._id = getID(); properties._idSet = true; - properties._created = _created; - properties._lastEdited = _lastEdited; - properties.setClientOnly(_clientOnly); - properties.setOwningAvatarID(_owningAvatarID); + properties._created = getCreated(); + properties._lastEdited = getLastEdited(); + properties.setClientOnly(getClientOnly()); + properties.setOwningAvatarID(getOwningAvatarID()); properties._type = getType(); @@ -1259,7 +1283,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c properties._angularVelocity = getLocalAngularVelocity(); } if (!properties._accelerationChanged) { - properties._acceleration = _acceleration; + properties._acceleration = getAcceleration(); } properties._positionChanged = true; @@ -1777,20 +1801,26 @@ void EntityItem::updateRestitution(float value) { void EntityItem::updateFriction(float value) { float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION); - if (_friction != clampedValue) { - _friction = clampedValue; - _dirtyFlags |= Simulation::DIRTY_MATERIAL; - } + withWriteLock([&] { + if (_friction != clampedValue) { + _friction = clampedValue; + _dirtyFlags |= Simulation::DIRTY_MATERIAL; + } + }); } void EntityItem::setRestitution(float value) { float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION); - _restitution = clampedValue; + withWriteLock([&] { + _restitution = clampedValue; + }); } void EntityItem::setFriction(float value) { float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION); - _friction = clampedValue; + withWriteLock([&] { + _friction = clampedValue; + }); } void EntityItem::updateLifetime(float value) { @@ -2327,3 +2357,436 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { // the json filter syntax did not match what we expected, return a match return true; } + +quint64 EntityItem::getLastSimulated() const { + quint64 result; + withReadLock([&] { + result = _lastSimulated; + }); + return result; +} + +void EntityItem::setLastSimulated(quint64 now) { + withWriteLock([&] { + _lastSimulated = now; + }); +} + +quint64 EntityItem::getLastEdited() const { + quint64 result; + withReadLock([&] { + result = _lastEdited; + }); + return result; +} + +void EntityItem::setLastEdited(quint64 lastEdited) { + withWriteLock([&] { + _lastEdited = _lastUpdated = lastEdited; + _changedOnServer = glm::max(lastEdited, _changedOnServer); + }); +} + +quint64 EntityItem::getLastBroadcast() const { + quint64 result; + withReadLock([&] { + result = _lastBroadcast; + }); + return result; +} + +void EntityItem::setLastBroadcast(quint64 lastBroadcast) { + withWriteLock([&] { + _lastBroadcast = lastBroadcast; + }); +} + +void EntityItem::markAsChangedOnServer() { + withWriteLock([&] { + _changedOnServer = usecTimestampNow(); + }); +} + +quint64 EntityItem::getLastChangedOnServer() const { + quint64 result; + withReadLock([&] { + result = _changedOnServer; + }); + return result; +} + +void EntityItem::update(const quint64& now) { + withWriteLock([&] { + _lastUpdated = now; + }); +} + +quint64 EntityItem::getLastUpdated() const { + quint64 result; + withReadLock([&] { + result = _lastUpdated; + }); + return result; +} + +void EntityItem::requiresRecalcBoxes() { + withWriteLock([&] { + _recalcAABox = true; + _recalcMinAACube = true; + _recalcMaxAACube = true; + }); +} + +QString EntityItem::getHref() const { + QString result; + withReadLock([&] { + result = _href; + }); + return result; +} + +QString EntityItem::getDescription() const { + QString result; + withReadLock([&] { + result = _description; + }); + return result; +} + +void EntityItem::setDescription(const QString& value) { + withWriteLock([&] { + _description = value; + }); +} + +float EntityItem::getLocalRenderAlpha() const { + float result; + withReadLock([&] { + result = _localRenderAlpha; + }); + return result; +} + +void EntityItem::setLocalRenderAlpha(float localRenderAlpha) { + withWriteLock([&] { + _localRenderAlpha = localRenderAlpha; + }); +} + +glm::vec3 EntityItem::getGravity() const { + glm::vec3 result; + withReadLock([&] { + result = _gravity; + }); + return result; +} + +void EntityItem::setGravity(const glm::vec3& value) { + withWriteLock([&] { + _gravity = value; + }); +} + +glm::vec3 EntityItem::getAcceleration() const { + glm::vec3 result; + withReadLock([&] { + result = _acceleration; + }); + return result; +} + +void EntityItem::setAcceleration(const glm::vec3& value) { + withWriteLock([&] { + _acceleration = value; + }); +} + +float EntityItem::getDamping() const { + float result; + withReadLock([&] { + result = _damping; + }); + return result; +} +void EntityItem::setDamping(float value) { + withWriteLock([&] { + _damping = value; + }); +} + +float EntityItem::getRestitution() const { + float result; + withReadLock([&] { + result = _restitution; + }); + return result; +} + +float EntityItem::getFriction() const { + float result; + withReadLock([&] { + result = _friction; + }); + return result; +} + +// lifetime related properties. +float EntityItem::getLifetime() const { + float result; + withReadLock([&] { + result = _lifetime; + }); + return result; +} + +void EntityItem::setLifetime(float value) { + withWriteLock([&] { + _lifetime = value; + }); +} + +quint64 EntityItem::getCreated() const { + quint64 result; + withReadLock([&] { + result = _created; + }); + return result; +} + +void EntityItem::setCreated(quint64 value) { + withWriteLock([&] { + _created = value; + }); +} + +QString EntityItem::getScript() const { + QString result; + withReadLock([&] { + result = _script; + }); + return result; +} + +void EntityItem::setScript(const QString& value) { + withWriteLock([&] { + _script = value; + }); +} + +quint64 EntityItem::getScriptTimestamp() const { + quint64 result; + withReadLock([&] { + result = _scriptTimestamp; + }); + return result; +} + +void EntityItem::setScriptTimestamp(const quint64 value) { + withWriteLock([&] { + _scriptTimestamp = value; + }); +} + +QString EntityItem::getServerScripts() const { + QString result; + withReadLock([&] { + result = _serverScripts; + }); + return result; +} + +void EntityItem::setServerScripts(const QString& serverScripts) { + withWriteLock([&] { + _serverScripts = serverScripts; + _serverScriptsChangedTimestamp = usecTimestampNow(); + }); +} + +QString EntityItem::getCollisionSoundURL() const { + QString result; + withReadLock([&] { + result = _collisionSoundURL; + }); + return result; +} + +void EntityItem::setCollisionSound(SharedSoundPointer sound) { + withWriteLock([&] { + _collisionSound = sound; + }); +} + +glm::vec3 EntityItem::getRegistrationPoint() const { + glm::vec3 result; + withReadLock([&] { + result = _registrationPoint; + }); + return result; +} + +void EntityItem::setRegistrationPoint(const glm::vec3& value) { + withWriteLock([&] { + _registrationPoint = glm::clamp(value, 0.0f, 1.0f); + }); + dimensionsChanged(); // Registration Point affects the bounding box +} + +float EntityItem::getAngularDamping() const { + float result; + withReadLock([&] { + result = _angularDamping; + }); + return result; +} + +void EntityItem::setAngularDamping(float value) { + withWriteLock([&] { + _angularDamping = value; + }); +} + +QString EntityItem::getName() const { + QString result; + withReadLock([&] { + result = _name; + }); + return result; +} + +void EntityItem::setName(const QString& value) { + withWriteLock([&] { + _name = value; + }); +} + +QString EntityItem::getDebugName() { + QString result = getName(); + if (result.isEmpty()) { + result = getID().toString(); + } + return result; +} + +bool EntityItem::getVisible() const { + bool result; + withReadLock([&] { + result = _visible; + }); + return result; +} + +void EntityItem::setVisible(bool value) { + withWriteLock([&] { + _visible = value; + }); +} + +bool EntityItem::getCollisionless() const { + bool result; + withReadLock([&] { + result = _collisionless; + }); + return result; +} + +void EntityItem::setCollisionless(bool value) { + withWriteLock([&] { + _collisionless = value; + }); +} + +uint8_t EntityItem::getCollisionMask() const { + uint8_t result; + withReadLock([&] { + result = _collisionMask; + }); + return result; +} + +void EntityItem::setCollisionMask(uint8_t value) { + withWriteLock([&] { + _collisionMask = value; + }); +} + +bool EntityItem::getDynamic() const { + if (SHAPE_TYPE_STATIC_MESH == getShapeType()) { + return false; + } + bool result; + withReadLock([&] { + result = _dynamic; + }); + return result; +} + +void EntityItem::setDynamic(bool value) { + withWriteLock([&] { + _dynamic = value; + }); +} + +bool EntityItem::getLocked() const { + bool result; + withReadLock([&] { + result = _locked; + }); + return result; +} + +void EntityItem::setLocked(bool value) { + withWriteLock([&] { + _locked = value; + }); +} + +QString EntityItem::getUserData() const { + QString result; + withReadLock([&] { + result = _userData; + }); + return result; +} + +void EntityItem::setUserData(const QString& value) { + withWriteLock([&] { + _userData = value; + }); +} + +QString EntityItem::getMarketplaceID() const { + QString result; + withReadLock([&] { + result = _marketplaceID; + }); + return result; +} + +void EntityItem::setMarketplaceID(const QString& value) { + withWriteLock([&] { + _marketplaceID = value; + }); +} + +uint32_t EntityItem::getDirtyFlags() const { + uint32_t result; + withReadLock([&] { + result = _dirtyFlags; + }); + return result; +} + +void EntityItem::clearDirtyFlags(uint32_t mask) { + withWriteLock([&] { + _dirtyFlags &= ~mask; + }); +} + +float EntityItem::getDensity() const { + float result; + withReadLock([&] { + result = _density; + }); + return result; +} + diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b973d916e6..929fe8a698 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -110,22 +110,21 @@ public: virtual void somethingChangedNotification() { } void recordCreationTime(); // set _created to 'now' - quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs - void setLastSimulated(quint64 now) { _lastSimulated = now; } + quint64 getLastSimulated() const; /// Last simulated time of this entity universal usecs + void setLastSimulated(quint64 now); /// Last edited time of this entity universal usecs - quint64 getLastEdited() const { return _lastEdited; } - void setLastEdited(quint64 lastEdited) - { _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } + quint64 getLastEdited() const; + void setLastEdited(quint64 lastEdited); float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } /// Last time we sent out an edit packet for this entity - quint64 getLastBroadcast() const { return _lastBroadcast; } - void setLastBroadcast(quint64 lastBroadcast) { _lastBroadcast = lastBroadcast; } + quint64 getLastBroadcast() const; + void setLastBroadcast(quint64 lastBroadcast); - void markAsChangedOnServer() { _changedOnServer = usecTimestampNow(); } - quint64 getLastChangedOnServer() const { return _changedOnServer; } + void markAsChangedOnServer(); + quint64 getLastChangedOnServer() const; // TODO: eventually only include properties changed since the params.lastQuerySent time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; @@ -163,8 +162,8 @@ public: static void adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSkew); // perform update - virtual void update(const quint64& now) { _lastUpdated = now; } - quint64 getLastUpdated() const { return _lastUpdated; } + virtual void update(const quint64& now); + quint64 getLastUpdated() const; // perform linear extrapolation for SimpleEntitySimulation void simulate(const quint64& now); @@ -188,63 +187,63 @@ public: const Transform getTransformToCenter(bool& success) const; - inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; } + inline void requiresRecalcBoxes(); // Hyperlink related getters and setters - QString getHref() const { return _href; } + QString getHref() const; void setHref(QString value); - QString getDescription() const { return _description; } - void setDescription(QString value) { _description = value; } + QString getDescription() const; + void setDescription(const QString& value); /// Dimensions in meters (0.0 - TREE_SCALE) inline const glm::vec3 getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); - float getLocalRenderAlpha() const { return _localRenderAlpha; } - void setLocalRenderAlpha(float localRenderAlpha) { _localRenderAlpha = localRenderAlpha; } + float getLocalRenderAlpha() const; + void setLocalRenderAlpha(float localRenderAlpha); void setDensity(float density); float computeMass() const; void setMass(float mass); - float getDensity() const { return _density; } + float getDensity() const; bool hasVelocity() const { return getVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalVelocity() const { return getLocalVelocity() != ENTITY_ITEM_ZERO_VEC3; } - const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters - void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters - bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; } + glm::vec3 getGravity() const; /// get gravity in meters + void setGravity(const glm::vec3& value); /// gravity in meters + bool hasGravity() const { return getGravity() != ENTITY_ITEM_ZERO_VEC3; } - const glm::vec3& getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second - void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second - bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; } + glm::vec3 getAcceleration() const; /// get acceleration in meters/second/second + void setAcceleration(const glm::vec3& value); /// acceleration in meters/second/second + bool hasAcceleration() const { return getAcceleration() != ENTITY_ITEM_ZERO_VEC3; } - float getDamping() const { return _damping; } - void setDamping(float value) { _damping = value; } + float getDamping() const; + void setDamping(float value); - float getRestitution() const { return _restitution; } + float getRestitution() const; void setRestitution(float value); - float getFriction() const { return _friction; } + float getFriction() const; void setFriction(float value); // lifetime related properties. - float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity - void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity + float getLifetime() const; /// get the lifetime in seconds for the entity + void setLifetime(float value); /// set the lifetime in seconds for the entity - quint64 getCreated() const { return _created; } /// get the created-time in useconds for the entity - void setCreated(quint64 value) { _created = value; } /// set the created-time in useconds for the entity + quint64 getCreated() const; /// get the created-time in useconds for the entity + void setCreated(quint64 value); /// set the created-time in useconds for the entity /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted - bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; } + bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; } /// is this entity mortal, in that it has a lifetime set, and will automatically be deleted when that lifetime expires - bool isMortal() const { return _lifetime != ENTITY_ITEM_IMMORTAL_LIFETIME; } + bool isMortal() const { return getLifetime() != ENTITY_ITEM_IMMORTAL_LIFETIME; } /// age of this entity in seconds - float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } + float getAge() const { return (float)(usecTimestampNow() - getCreated()) / (float)USECS_PER_SECOND; } bool lifetimeHasExpired() const; quint64 getExpiry() const; @@ -256,63 +255,61 @@ public: using SpatiallyNestable::getQueryAACube; virtual AACube getQueryAACube(bool& success) const override; - QString getScript() const { return _script; } - void setScript(const QString& value) { _script = value; } + QString getScript() const; + void setScript(const QString& value); - quint64 getScriptTimestamp() const { return _scriptTimestamp; } - void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; } + quint64 getScriptTimestamp() const; + void setScriptTimestamp(const quint64 value); - QString getServerScripts() const { return _serverScripts; } - void setServerScripts(const QString& serverScripts) - { _serverScripts = serverScripts; _serverScriptsChangedTimestamp = usecTimestampNow(); } + QString getServerScripts() const; + void setServerScripts(const QString& serverScripts); - const QString& getCollisionSoundURL() const { return _collisionSoundURL; } + QString getCollisionSoundURL() const; void setCollisionSoundURL(const QString& value); SharedSoundPointer getCollisionSound(); - void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; } + void setCollisionSound(SharedSoundPointer sound); - const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity + glm::vec3 getRegistrationPoint() const; /// registration point as ratio of entity /// registration point as ratio of entity - void setRegistrationPoint(const glm::vec3& value) { - _registrationPoint = glm::clamp(value, 0.0f, 1.0f); dimensionsChanged(); // Registration Point affects the bounding box - } + void setRegistrationPoint(const glm::vec3& value); bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalAngularVelocity() const { return getLocalAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } - float getAngularDamping() const { return _angularDamping; } - void setAngularDamping(float value) { _angularDamping = value; } + float getAngularDamping() const; + void setAngularDamping(float value); - QString getName() const { return _name; } - void setName(const QString& value) { _name = value; } - QString getDebugName() { return _name != "" ? _name : getID().toString(); } + QString getName() const; + void setName(const QString& value); + QString getDebugName(); - bool getVisible() const { return _visible; } - void setVisible(bool value) { _visible = value; } - bool isVisible() const { return _visible; } - bool isInvisible() const { return !_visible; } + bool getVisible() const; + void setVisible(bool value); + inline bool isVisible() const { return getVisible(); } + inline bool isInvisible() const { return !getVisible(); } - bool getCollisionless() const { return _collisionless; } - void setCollisionless(bool value) { _collisionless = value; } + bool getCollisionless() const; + void setCollisionless(bool value); - uint8_t getCollisionMask() const { return _collisionMask; } - void setCollisionMask(uint8_t value) { _collisionMask = value; } + uint8_t getCollisionMask() const; + void setCollisionMask(uint8_t value); void computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const; - bool getDynamic() const { return SHAPE_TYPE_STATIC_MESH == getShapeType() ? false : _dynamic; } - void setDynamic(bool value) { _dynamic = value; } + bool getDynamic() const; + void setDynamic(bool value); virtual bool shouldBePhysical() const { return false; } - bool getLocked() const { return _locked; } - void setLocked(bool value) { _locked = value; } + bool getLocked() const; + void setLocked(bool value); - const QString& getUserData() const { return _userData; } - virtual void setUserData(const QString& value) { _userData = value; } + QString getUserData() const; + virtual void setUserData(const QString& value); + // FIXME not thread safe? const SimulationOwner& getSimulationOwner() const { return _simulationOwner; } void setSimulationOwner(const QUuid& id, quint8 priority); void setSimulationOwner(const SimulationOwner& owner); @@ -325,8 +322,8 @@ public: void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp); void rememberHasSimulationOwnershipBid() const; - const QString& getMarketplaceID() const { return _marketplaceID; } - void setMarketplaceID(const QString& value) { _marketplaceID = value; } + QString getMarketplaceID() const; + void setMarketplaceID(const QString& value); // TODO: get rid of users of getRadius()... float getRadius() const; @@ -369,8 +366,8 @@ public: void updateCreated(uint64_t value); virtual void setShapeType(ShapeType type) { /* do nothing */ } - uint32_t getDirtyFlags() const { return _dirtyFlags; } - void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } + uint32_t getDirtyFlags() const; + void clearDirtyFlags(uint32_t mask = 0xffffffff); bool isMoving() const; bool isMovingRelativeToParent() const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index fbb0bdc9cf..c6b857f6e7 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -141,3 +141,98 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const // FIXME - should set face and surfaceNormal return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance); } + +void TextEntityItem::setText(const QString& value) { + withWriteLock([&] { + _text = value; + }); +} + +QString TextEntityItem::getText() const { + QString result; + withReadLock([&] { + result = _text; + }); + return result; +} + +void TextEntityItem::setLineHeight(float value) { + withWriteLock([&] { + _lineHeight = value; + }); +} + +float TextEntityItem::getLineHeight() const { + float result; + withReadLock([&] { + result = _lineHeight; + }); + return result; +} + +const rgbColor& TextEntityItem::getTextColor() const { + return _textColor; +} + +const rgbColor& TextEntityItem::getBackgroundColor() const { + return _backgroundColor; +} + +xColor TextEntityItem::getTextColorX() const { + xColor result; + withReadLock([&] { + result = { _textColor[RED_INDEX], _textColor[GREEN_INDEX], _textColor[BLUE_INDEX] }; + }); + return result; +} + +void TextEntityItem::setTextColor(const rgbColor& value) { + withWriteLock([&] { + memcpy(_textColor, value, sizeof(_textColor)); + }); +} + +void TextEntityItem::setTextColor(const xColor& value) { + withWriteLock([&] { + _textColor[RED_INDEX] = value.red; + _textColor[GREEN_INDEX] = value.green; + _textColor[BLUE_INDEX] = value.blue; + }); +} + +xColor TextEntityItem::getBackgroundColorX() const { + xColor result; + withReadLock([&] { + result = { _backgroundColor[RED_INDEX], _backgroundColor[GREEN_INDEX], _backgroundColor[BLUE_INDEX] }; + }); + return result; +} + +void TextEntityItem::setBackgroundColor(const rgbColor& value) { + withWriteLock([&] { + memcpy(_backgroundColor, value, sizeof(_backgroundColor)); + }); +} + +void TextEntityItem::setBackgroundColor(const xColor& value) { + withWriteLock([&] { + _backgroundColor[RED_INDEX] = value.red; + _backgroundColor[GREEN_INDEX] = value.green; + _backgroundColor[BLUE_INDEX] = value.blue; + }); +} + +bool TextEntityItem::getFaceCamera() const { + bool result; + withReadLock([&] { + result = _faceCamera; + }); + return result; +} + +void TextEntityItem::setFaceCamera(bool value) { + withWriteLock([&] { + _faceCamera = value; + }); +} + diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 633aa96bfa..4e49bb8ef0 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -53,38 +53,32 @@ public: void** intersectedObject, bool precisionPicking) const override; static const QString DEFAULT_TEXT; - void setText(const QString& value) { _text = value; } - const QString& getText() const { return _text; } + void setText(const QString& value); + QString getText() const; static const float DEFAULT_LINE_HEIGHT; - void setLineHeight(float value) { _lineHeight = value; } - float getLineHeight() const { return _lineHeight; } + void setLineHeight(float value); + float getLineHeight() const; static const xColor DEFAULT_TEXT_COLOR; - const rgbColor& getTextColor() const { return _textColor; } - xColor getTextColorX() const { xColor color = { _textColor[RED_INDEX], _textColor[GREEN_INDEX], _textColor[BLUE_INDEX] }; return color; } + // FIXME should not return a reference because of thread safety, but can't return an array + const rgbColor& getTextColor() const; + xColor getTextColorX() const; - void setTextColor(const rgbColor& value) { memcpy(_textColor, value, sizeof(_textColor)); } - void setTextColor(const xColor& value) { - _textColor[RED_INDEX] = value.red; - _textColor[GREEN_INDEX] = value.green; - _textColor[BLUE_INDEX] = value.blue; - } + void setTextColor(const rgbColor& value); + void setTextColor(const xColor& value); static const xColor DEFAULT_BACKGROUND_COLOR; - const rgbColor& getBackgroundColor() const { return _backgroundColor; } - xColor getBackgroundColorX() const { xColor color = { _backgroundColor[RED_INDEX], _backgroundColor[GREEN_INDEX], _backgroundColor[BLUE_INDEX] }; return color; } + // FIXME should not return a reference because of thread safety, but can't return an array + const rgbColor& getBackgroundColor() const; + xColor getBackgroundColorX() const; - void setBackgroundColor(const rgbColor& value) { memcpy(_backgroundColor, value, sizeof(_backgroundColor)); } - void setBackgroundColor(const xColor& value) { - _backgroundColor[RED_INDEX] = value.red; - _backgroundColor[GREEN_INDEX] = value.green; - _backgroundColor[BLUE_INDEX] = value.blue; - } + void setBackgroundColor(const rgbColor& value); + void setBackgroundColor(const xColor& value); static const bool DEFAULT_FACE_CAMERA; - bool getFaceCamera() const { return _faceCamera; } - void setFaceCamera(bool value) { _faceCamera = value; } + bool getFaceCamera() const; + void setFaceCamera(bool value); protected: QString _text; From 03c6275268fa32e2806afad7f8356d035a61b241 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 3 Apr 2017 08:44:27 -0700 Subject: [PATCH 02/18] more thread safety --- libraries/entities/src/EntityItem.cpp | 43 ++++--- libraries/entities/src/EntityItem.h | 3 +- libraries/entities/src/LightEntityItem.cpp | 140 ++++++++++++++++++--- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/LineEntityItem.cpp | 61 ++++++++- libraries/entities/src/LineEntityItem.h | 20 ++- libraries/entities/src/ModelEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- 8 files changed, 216 insertions(+), 57 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9ba740728b..891196862a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -683,7 +683,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // However, for now, when the server uses a newer time than what we sent, listen to what we're told. if (overwriteLocalData) weOwnSimulation = false; } else if (_simulationOwner.set(newSimOwner)) { - _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; // recompute weOwnSimulation for later weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); @@ -695,19 +695,19 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef weOwnSimulation = true; if (!_simulationOwner.isNull()) { // someone else really did own it - _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; _simulationOwner.clearCurrentOwner(); } } else if (newSimOwner.matchesValidID(myNodeID) && !_hasBidOnSimulation) { // entity-server tells us that we have simulation ownership while we never requested this for this EntityItem, // this could happen when the user reloads the cache and entity tree. - _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; _simulationOwner.clearCurrentOwner(); weOwnSimulation = false; } else if (_simulationOwner.set(newSimOwner)) { - _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; // recompute weOwnSimulation for later weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); @@ -994,7 +994,7 @@ SharedSoundPointer EntityItem::getCollisionSound() { } void EntityItem::simulate(const quint64& now) { - if (0 == getLastSimulated()) { + if (getLastSimulated() == 0) { setLastSimulated(now); } @@ -1042,7 +1042,7 @@ void EntityItem::simulate(const quint64& now) { if (!stepKinematicMotion(timeElapsed)) { // this entity is no longer moving // flag it to transition from KINEMATIC to STATIC - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + markDirtyFlags(Simulation::DIRTY_MOTION_TYPE); setAcceleration(Vectors::ZERO); } setLastSimulated(now); @@ -1294,7 +1294,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c } void EntityItem::pokeSimulationOwnership() { - _dirtyFlags |= Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE; + markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE); auto nodeList = DependencyManager::get(); if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) { // we already own it @@ -1306,7 +1306,7 @@ void EntityItem::pokeSimulationOwnership() { } void EntityItem::grabSimulationOwnership() { - _dirtyFlags |= Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB; + markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB); auto nodeList = DependencyManager::get(); if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) { // we already own it @@ -1599,18 +1599,18 @@ float EntityItem::getVolumeEstimate() const { void EntityItem::updateRegistrationPoint(const glm::vec3& value) { if (value != _registrationPoint) { setRegistrationPoint(value); - _dirtyFlags |= Simulation::DIRTY_SHAPE; + markDirtyFlags(Simulation::DIRTY_SHAPE); } } void EntityItem::updatePosition(const glm::vec3& value) { if (getLocalPosition() != value) { setLocalPosition(value); - _dirtyFlags |= Simulation::DIRTY_POSITION; + markDirtyFlags(Simulation::DIRTY_POSITION); forEachDescendant([&](SpatiallyNestablePointer object) { if (object->getNestableType() == NestableType::Entity) { EntityItemPointer entity = std::static_pointer_cast(object); - entity->_dirtyFlags |= Simulation::DIRTY_POSITION; + entity->markDirtyFlags(Simulation::DIRTY_POSITION); } }); } @@ -1619,8 +1619,9 @@ void EntityItem::updatePosition(const glm::vec3& value) { void EntityItem::updateParentID(const QUuid& value) { if (getParentID() != value) { setParentID(value); - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; // children are forced to be kinematic - _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar + // children are forced to be kinematic + // may need to not collide with own avatar + markDirtyFlags(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_COLLISION_GROUP); } } @@ -1634,7 +1635,7 @@ void EntityItem::updatePositionFromNetwork(const glm::vec3& value) { void EntityItem::updateDimensions(const glm::vec3& value) { if (getDimensions() != value) { setDimensions(value); - _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); + markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); } } @@ -1645,8 +1646,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) { forEachDescendant([&](SpatiallyNestablePointer object) { if (object->getNestableType() == NestableType::Entity) { EntityItemPointer entity = std::static_pointer_cast(object); - entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; - entity->_dirtyFlags |= Simulation::DIRTY_POSITION; + entity->markDirtyFlags(Simulation::DIRTY_ROTATION | Simulation::DIRTY_POSITION); } }); } @@ -1913,7 +1913,7 @@ void EntityItem::updateSimulationOwner(const SimulationOwner& owner) { } if (_simulationOwner.set(owner)) { - _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); } } @@ -1926,7 +1926,7 @@ void EntityItem::clearSimulationOwnership() { // don't bother setting the DIRTY_SIMULATOR_ID flag because: // (a) when entity-server calls clearSimulationOwnership() the dirty-flags are meaningless (only used by interface) // (b) the interface only calls clearSimulationOwnership() in a context that already knows best about dirty flags - //_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + //markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); } @@ -2776,6 +2776,13 @@ uint32_t EntityItem::getDirtyFlags() const { return result; } + +void EntityItem::markDirtyFlags(uint32_t mask) { + withWriteLock([&] { + _dirtyFlags |= mask; + }); +} + void EntityItem::clearDirtyFlags(uint32_t mask) { withWriteLock([&] { _dirtyFlags &= ~mask; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 929fe8a698..e705fcbe2a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -367,6 +367,7 @@ public: virtual void setShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const; + void markDirtyFlags(uint32_t mask); void clearDirtyFlags(uint32_t mask = 0xffffffff); bool isMoving() const; @@ -509,7 +510,7 @@ protected: // NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class // rather than in all of the derived classes. If we ever collapse these classes to one we could do it a // different way. - float _volumeMultiplier { 1.0f }; + const float _volumeMultiplier { 1.0f }; glm::vec3 _gravity; glm::vec3 _acceleration; float _damping; diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index e09822f028..753ff1d3c8 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -69,38 +69,59 @@ EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredP } void LightEntityItem::setFalloffRadius(float value) { - _falloffRadius = glm::max(value, 0.0f); - _lightPropertiesChanged = true; + value = glm::max(value, 0.0f); + if (value == getFalloffRadius()) { + return; + } + withWriteLock([&] { + _falloffRadius = value; + _lightPropertiesChanged = true; + }); } void LightEntityItem::setIsSpotlight(bool value) { - if (value != _isSpotlight) { - _isSpotlight = value; - - glm::vec3 dimensions = getDimensions(); - if (_isSpotlight) { - const float length = dimensions.z; - const float width = length * glm::sin(glm::radians(_cutoff)); - setDimensions(glm::vec3(width, width, length)); - } else { - float maxDimension = glm::compMax(dimensions); - setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); - } - _lightPropertiesChanged = true; + if (value == getIsSpotlight()) { + return; } + + glm::vec3 dimensions = getDimensions(); + glm::vec3 newDimensions; + if (value) { + const float length = dimensions.z; + const float width = length * glm::sin(glm::radians(getCutoff())); + newDimensions = glm::vec3(width, width, length); + } else { + newDimensions = glm::vec3(glm::compMax(dimensions)); + } + + withWriteLock([&] { + _isSpotlight = value; + _lightPropertiesChanged = true; + }); + setDimensions(newDimensions); } void LightEntityItem::setCutoff(float value) { - _cutoff = glm::clamp(value, 0.0f, 90.0f); + value = glm::clamp(value, 0.0f, 90.0f); + if (value == getCutoff()) { + return; + } - if (_isSpotlight) { + withWriteLock([&] { + _cutoff = value; + }); + + if (getIsSpotlight()) { // If we are a spotlight, adjusting the cutoff will affect the area we encapsulate, // so update the dimensions to reflect this. const float length = getDimensions().z; const float width = length * glm::sin(glm::radians(_cutoff)); setDimensions(glm::vec3(width, width, length)); } - _lightPropertiesChanged = true; + + withWriteLock([&] { + _lightPropertiesChanged = true; + }); } bool LightEntityItem::setProperties(const EntityItemProperties& properties) { @@ -205,5 +226,86 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit void LightEntityItem::somethingChangedNotification() { EntityItem::somethingChangedNotification(); - _lightPropertiesChanged = false; + withWriteLock([&] { + _lightPropertiesChanged = false; + }); } + +const rgbColor& LightEntityItem::getColor() const { + return _color; +} + +xColor LightEntityItem::getXColor() const { + xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; +} + +void LightEntityItem::setColor(const rgbColor& value) { + withWriteLock([&] { + memcpy(_color, value, sizeof(_color)); + _lightPropertiesChanged = true; + }); +} + +void LightEntityItem::setColor(const xColor& value) { + withWriteLock([&] { + _color[RED_INDEX] = value.red; + _color[GREEN_INDEX] = value.green; + _color[BLUE_INDEX] = value.blue; + _lightPropertiesChanged = true; + }); +} + +bool LightEntityItem::getIsSpotlight() const { + bool result; + withReadLock([&] { + result = _isSpotlight; + }); + return result; +} + +float LightEntityItem::getIntensity() const { + float result; + withReadLock([&] { + result = _intensity; + }); + return result; +} + +void LightEntityItem::setIntensity(float value) { + withWriteLock([&] { + _intensity = value; + _lightPropertiesChanged = true; + }); +} + +float LightEntityItem::getFalloffRadius() const { + float result; + withReadLock([&] { + result = _falloffRadius; + }); + return result; +} + +float LightEntityItem::getExponent() const { + float result; + withReadLock([&] { + result = _exponent; + }); + return result; +} + +void LightEntityItem::setExponent(float value) { + withWriteLock([&] { + _exponent = value; + _lightPropertiesChanged = true; + }); +} + +float LightEntityItem::getCutoff() const { + float result; + withReadLock([&] { + result = _cutoff; + }); + return result; +} + diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 3444b11cae..f0ed58f47a 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -97,7 +97,7 @@ public: static bool getLightsArePickable() { return _lightsArePickable; } static void setLightsArePickable(bool value) { _lightsArePickable = value; } -protected: +private: // properties of a light diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 8ace665616..fe2c803f43 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -88,8 +88,10 @@ bool LineEntityItem::appendPoint(const glm::vec3& point) { qCDebug(entities) << "Point is outside entity's bounding box"; return false; } - _points << point; - _pointsChanged = true; + withWriteLock([&] { + _points << point; + _pointsChanged = true; + }); return true; } @@ -105,8 +107,11 @@ bool LineEntityItem::setLinePoints(const QVector& points) { return false; } } - _points = points; - _pointsChanged = true; + + withWriteLock([&] { + _points = points; + _pointsChanged = true; + }); return true; } @@ -159,3 +164,51 @@ void LineEntityItem::debugDump() const { qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } + +const rgbColor& LineEntityItem::getColor() const { + return _color; +} + +xColor LineEntityItem::getXColor() const { + xColor result; + withReadLock([&] { + result = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; + }); + return result; +} + +void LineEntityItem::setColor(const rgbColor& value) { + withWriteLock([&] { + memcpy(_color, value, sizeof(_color)); + }); +} + +void LineEntityItem::setColor(const xColor& value) { + withWriteLock([&] { + _color[RED_INDEX] = value.red; + _color[GREEN_INDEX] = value.green; + _color[BLUE_INDEX] = value.blue; + }); +} + +void LineEntityItem::setLineWidth(float lineWidth) { + withWriteLock([&] { + _lineWidth = lineWidth; + }); +} + +float LineEntityItem::getLineWidth() const { + float result; + withReadLock([&] { + result = _lineWidth; + }); + return result; +} + +QVector LineEntityItem::getLinePoints() const { + QVector result; + withReadLock([&] { + result = _points; + }); + return result; +} diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 8629c94eb4..7a882f6b9d 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -42,23 +42,19 @@ class LineEntityItem : public EntityItem { EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) override; - const rgbColor& getColor() const { return _color; } - xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } + const rgbColor& getColor() const; + xColor getXColor() const; - void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } - void setColor(const xColor& value) { - _color[RED_INDEX] = value.red; - _color[GREEN_INDEX] = value.green; - _color[BLUE_INDEX] = value.blue; - } + void setColor(const rgbColor& value); + void setColor(const xColor& value); - void setLineWidth(float lineWidth){ _lineWidth = lineWidth; } - float getLineWidth() const{ return _lineWidth; } + void setLineWidth(float lineWidth); + float getLineWidth() const; bool setLinePoints(const QVector& points); bool appendPoint(const glm::vec3& point); - const QVector& getLinePoints() const{ return _points; } + QVector getLinePoints() const; virtual ShapeType getShapeType() const override { return SHAPE_TYPE_NONE; } @@ -74,7 +70,7 @@ class LineEntityItem : public EntityItem { static const float DEFAULT_LINE_WIDTH; static const int MAX_POINTS_PER_LINE; - protected: + private: rgbColor _color; float _lineWidth; bool _pointsChanged; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e1cb5cd92c..972bf1e18d 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -130,7 +130,7 @@ private: void setAnimationSettings(const QString& value); // only called for old bitstream format ShapeType computeTrueShapeType() const; -protected: +private: // these are used: // - to bounce joint data from an animation into the model/rig. // - to relay changes from scripts to model/rig. diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 4e49bb8ef0..ee421d567a 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -80,7 +80,7 @@ public: bool getFaceCamera() const; void setFaceCamera(bool value); -protected: +private: QString _text; float _lineHeight; rgbColor _textColor; From d89104f69ca3f68ae44236f81f1ea126a0b5dfe4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 3 Apr 2017 14:22:00 -0700 Subject: [PATCH 03/18] Use getters instead of direct member access --- .../src/RenderableModelEntityItem.cpp | 27 ++++++++++--------- .../src/RenderableTextEntityItem.cpp | 8 +++--- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 487a3e1e56..06b79bb6a2 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -277,10 +277,11 @@ bool RenderableModelEntityItem::getAnimationFrame() { return false; } - if (_animation && _animation->isLoaded()) { + auto animation = getAnimation(); + if (animation && animation->isLoaded()) { - const QVector& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy - auto& fbxJoints = _animation->getGeometry().joints; + const QVector& frames = animation->getFramesReference(); // NOTE: getFrames() is too heavy + auto& fbxJoints = animation->getGeometry().joints; int frameCount = frames.size(); if (frameCount > 0) { @@ -566,7 +567,7 @@ void RenderableModelEntityItem::update(const quint64& now) { } // make a copy of the animation properites - _renderAnimationProperties = _animationProperties; + _renderAnimationProperties = getAnimationProperties(); ModelEntityItem::update(now); } @@ -608,11 +609,11 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori void RenderableModelEntityItem::setShapeType(ShapeType type) { ModelEntityItem::setShapeType(type); - if (_shapeType == SHAPE_TYPE_COMPOUND) { - if (!_compoundShapeResource && !_compoundShapeURL.isEmpty()) { + if (getShapeType() == SHAPE_TYPE_COMPOUND) { + if (!_compoundShapeResource && !getCompoundShapeURL().isEmpty()) { _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL()); } - } else if (_compoundShapeResource && !_compoundShapeURL.isEmpty()) { + } else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) { // the compoundURL has been set but the shapeType does not agree _compoundShapeResource.reset(); } @@ -627,7 +628,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); } - if (_shapeType == SHAPE_TYPE_COMPOUND) { + if (getShapeType() == SHAPE_TYPE_COMPOUND) { _compoundShapeResource = DependencyManager::get()->getGeometryResource(url); } } @@ -637,7 +638,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { ShapeType type = getShapeType(); if (type == SHAPE_TYPE_COMPOUND) { - if (!_model || _compoundShapeURL.isEmpty()) { + if (!_model || getCompoundShapeURL().isEmpty()) { EntityTreePointer tree = getTree(); if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); @@ -659,8 +660,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { doInitialModelSimulation(); } return true; - } else if (!_compoundShapeURL.isEmpty()) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(_compoundShapeURL); + } else if (!getCompoundShapeURL().isEmpty()) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL()); } } @@ -775,7 +776,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + _model->getOffset()) - registrationOffset; } } - shapeInfo.setParams(type, dimensions, _compoundShapeURL); + shapeInfo.setParams(type, dimensions, getCompoundShapeURL()); } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { // should never fall in here when model not fully loaded assert(_model && _model->isLoaded()); @@ -1001,7 +1002,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { } } - shapeInfo.setParams(type, 0.5f * dimensions, _modelURL); + shapeInfo.setParams(type, 0.5f * dimensions, getModelURL()); } else { ModelEntityItem::computeShapeInfo(shapeInfo); shapeInfo.setParams(type, 0.5f * dimensions); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 9c98e699f1..a58ed8bbff 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -77,14 +77,16 @@ void RenderableTextEntityItem::render(RenderArgs* args) { geometryCache->bindSimpleProgram(batch, false, transparent, false, false, true); geometryCache->renderQuad(batch, minCorner, maxCorner, backgroundColor, _geometryID); - float scale = _lineHeight / _textRenderer->getFontSize(); + float lineheight = getLineHeight(); + float scale = lineheight / _textRenderer->getFontSize(); transformToTopLeft.setScale(scale); // Scale to have the correct line height batch.setModelTransform(transformToTopLeft); - float leftMargin = 0.1f * _lineHeight, topMargin = 0.1f * _lineHeight; + float leftMargin = 0.1f * lineheight, topMargin = 0.1f * lineheight; glm::vec2 bounds = glm::vec2(dimensions.x - 2.0f * leftMargin, dimensions.y - 2.0f * topMargin); - _textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, _text, textColor, bounds / scale); + auto text = getText(); + _textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, text, textColor, bounds / scale); } From fe84232ab459765041b141b7f458862b0bfd9dac Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 3 Apr 2017 14:22:37 -0700 Subject: [PATCH 04/18] More work on thread safety --- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/LightEntityItem.h | 37 ++++++++---------------- libraries/entities/src/LineEntityItem.h | 3 +- libraries/entities/src/ModelEntityItem.h | 2 +- 4 files changed, 16 insertions(+), 28 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e705fcbe2a..a751fd88b2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -510,7 +510,7 @@ protected: // NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class // rather than in all of the derived classes. If we ever collapse these classes to one we could do it a // different way. - const float _volumeMultiplier { 1.0f }; + float _volumeMultiplier { 1.0f }; glm::vec3 _gravity; glm::vec3 _acceleration; float _damping; diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index f0ed58f47a..b3cadcf0c7 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -57,41 +57,27 @@ public: EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) override; - const rgbColor& getColor() const { return _color; } - xColor getXColor() const { - xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; - } + const rgbColor& getColor() const; + xColor getXColor() const; - void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } - void setColor(const xColor& value) { - _color[RED_INDEX] = value.red; - _color[GREEN_INDEX] = value.green; - _color[BLUE_INDEX] = value.blue; - _lightPropertiesChanged = true; - } + void setColor(const rgbColor& value); + void setColor(const xColor& value); - bool getIsSpotlight() const { return _isSpotlight; } + bool getIsSpotlight() const; void setIsSpotlight(bool value); void setIgnoredColor(const rgbColor& value) { } void setIgnoredAttenuation(float value) { } - float getIntensity() const { return _intensity; } - void setIntensity(float value) { - _intensity = value; - _lightPropertiesChanged = true; - } - - float getFalloffRadius() const { return _falloffRadius; } + float getIntensity() const; + void setIntensity(float value); + float getFalloffRadius() const; void setFalloffRadius(float value); - float getExponent() const { return _exponent; } - void setExponent(float value) { - _exponent = value; - _lightPropertiesChanged = true; - } + float getExponent() const; + void setExponent(float value); - float getCutoff() const { return _cutoff; } + float getCutoff() const; void setCutoff(float value); static bool getLightsArePickable() { return _lightsArePickable; } @@ -108,6 +94,7 @@ private: float _exponent { DEFAULT_EXPONENT }; float _cutoff { DEFAULT_CUTOFF }; +protected: // Dirty flag turn true when either light properties is changing values. // This gets back to false in the somethingChangedNotification() call // Which is called after a setProperties() or a readEntitySubClassFromBUfferCall on the entity. diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 7a882f6b9d..bb8ae8a21a 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -73,8 +73,9 @@ class LineEntityItem : public EntityItem { private: rgbColor _color; float _lineWidth; - bool _pointsChanged; QVector _points; +protected: + bool _pointsChanged; }; #endif // hifi_LineEntityItem_h diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 972bf1e18d..e1cb5cd92c 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -130,7 +130,7 @@ private: void setAnimationSettings(const QString& value); // only called for old bitstream format ShapeType computeTrueShapeType() const; -private: +protected: // these are used: // - to bounce joint data from an animation into the model/rig. // - to relay changes from scripts to model/rig. From 54200c03a73fee13bbbe07e48ce80170c8aafc26 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 4 Apr 2017 13:53:49 -0700 Subject: [PATCH 05/18] Fixing deadlock --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 891196862a..3f732e26cb 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2133,7 +2133,7 @@ void EntityItem::deserializeActionsInternal() { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(".*action creation failed for.*"); qCDebug(entities) << "EntityItem::deserializeActionsInternal -- action creation failed for" - << getID() << getName(); + << getID() << _name; // getName(); removeActionInternal(actionID, nullptr); } } From cd7c1643a3492c8ed4c2824d98ed2cee8d67207e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 4 Apr 2017 14:03:30 -0700 Subject: [PATCH 06/18] More thread safety --- libraries/entities/src/LineEntityItem.cpp | 4 +- .../entities/src/ParticleEffectEntityItem.cpp | 17 +++ .../entities/src/ParticleEffectEntityItem.h | 9 +- libraries/entities/src/PolyLineEntityItem.cpp | 110 +++++++++++++----- libraries/entities/src/PolyLineEntityItem.h | 15 +-- 5 files changed, 106 insertions(+), 49 deletions(-) diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index fe2c803f43..58cdb1cd7b 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -34,8 +34,8 @@ EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const En LineEntityItem::LineEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _lineWidth(DEFAULT_LINE_WIDTH), - _pointsChanged(true), - _points(QVector(0)) + _points(QVector(0)), + _pointsChanged(true) { _type = EntityTypes::Line; } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 140522b00e..80f7f3b6b8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -733,3 +733,20 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _timeUntilNextEmit = 0.0f; } } + +QString ParticleEffectEntityItem::getTextures() const { + QString result; + withReadLock([&] { + result = _textures; + }); + return result; +} + +void ParticleEffectEntityItem::setTextures(const QString& textures) { + withWriteLock([&] { + if (_textures != textures) { + _textures = textures; + _texturesChangedFlag = true; + } + }); +} diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 6c6596e7a2..4d053e5a45 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -205,13 +205,8 @@ public: void computeAndUpdateDimensions(); static const QString DEFAULT_TEXTURES; - const QString& getTextures() const { return _textures; } - void setTextures(const QString& textures) { - if (_textures != textures) { - _textures = textures; - _texturesChangedFlag = true; - } - } + QString getTextures() const; + void setTextures(const QString& textures); static const bool DEFAULT_EMITTER_SHOULD_TRAIL; bool getEmitterShouldTrail() const { return _emitterShouldTrail; } diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 7abafad627..9fe8ac0c8f 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -104,14 +104,18 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { bool PolyLineEntityItem::setStrokeWidths(const QVector& strokeWidths) { - _strokeWidths = strokeWidths; - _strokeWidthsChanged = true; + withWriteLock([&] { + _strokeWidths = strokeWidths; + _strokeWidthsChanged = true; + }); return true; } bool PolyLineEntityItem::setNormals(const QVector& normals) { - _normals = normals; - _normalsChanged = true; + withWriteLock([&] { + _normals = normals; + _normalsChanged = true; + }); return true; } @@ -119,35 +123,39 @@ bool PolyLineEntityItem::setLinePoints(const QVector& points) { if (points.size() > MAX_POINTS_PER_LINE) { return false; } - if (points.size() != _points.size()) { - _pointsChanged = true; - } - //Check to see if points actually changed. If they haven't, return before doing anything else - else if (points.size() == _points.size()) { - //same number of points, so now compare every point - for (int i = 0; i < points.size(); i++) { - if (points.at(i) != _points.at(i)){ - _pointsChanged = true; - break; + bool result = false; + withWriteLock([&] { + //Check to see if points actually changed. If they haven't, return before doing anything else + if (points.size() != _points.size()) { + _pointsChanged = true; + } else if (points.size() == _points.size()) { + //same number of points, so now compare every point + for (int i = 0; i < points.size(); i++) { + if (points.at(i) != _points.at(i)) { + _pointsChanged = true; + break; + } } } - } - if (!_pointsChanged) { - return false; - } - - for (int i = 0; i < points.size(); i++) { - glm::vec3 point = points.at(i); - glm::vec3 halfBox = getDimensions() * 0.5f; - if ((point.x < -halfBox.x || point.x > halfBox.x) || - (point.y < -halfBox.y || point.y > halfBox.y) || - (point.z < -halfBox.z || point.z > halfBox.z)) { - qCDebug(entities) << "Point is outside entity's bounding box"; - return false; + if (!_pointsChanged) { + return; } - } - _points = points; - return true; + + for (int i = 0; i < points.size(); i++) { + glm::vec3 point = points.at(i); + glm::vec3 halfBox = getDimensions() * 0.5f; + if ((point.x < -halfBox.x || point.x > halfBox.x) || + (point.y < -halfBox.y || point.y > halfBox.y) || + (point.z < -halfBox.z || point.z > halfBox.z)) { + qCDebug(entities) << "Point is outside entity's bounding box"; + return; + } + } + _points = points; + result = true; + }); + + return result; } int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, @@ -210,3 +218,45 @@ void PolyLineEntityItem::debugDump() const { qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } + + +QVector PolyLineEntityItem::getLinePoints() const { + QVector result; + withReadLock([&] { + result = _points; + }); + return result; +} + +QVector PolyLineEntityItem::getNormals() const { + QVector result; + withReadLock([&] { + result = _normals; + }); + return result; +} + +QVector PolyLineEntityItem::getStrokeWidths() const { + QVector result; + withReadLock([&] { + result = _strokeWidths; + }); + return result; +} + +QString PolyLineEntityItem::getTextures() const { + QString result; + withReadLock([&] { + result = _textures; + }); + return result; +} + +void PolyLineEntityItem::setTextures(const QString& textures) { + withWriteLock([&] { + if (_textures != textures) { + _textures = textures; + _texturesChangedFlag = true; + } + }); +} diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 5f9f9124cf..0ee9a638de 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -59,21 +59,16 @@ class PolyLineEntityItem : public EntityItem { bool setLinePoints(const QVector& points); bool appendPoint(const glm::vec3& point); - const QVector& getLinePoints() const{ return _points; } + QVector getLinePoints() const; bool setNormals(const QVector& normals); - const QVector& getNormals() const{ return _normals; } + QVector getNormals() const; bool setStrokeWidths(const QVector& strokeWidths); - const QVector& getStrokeWidths() const{ return _strokeWidths; } + QVector getStrokeWidths() const; - const QString& getTextures() const { return _textures; } - void setTextures(const QString& textures) { - if (_textures != textures) { - _textures = textures; - _texturesChangedFlag = true; - } - } + QString getTextures() const; + void setTextures(const QString& textures); virtual bool needsToCallUpdate() const override { return true; } From 15f7e895aafb0243cdb903eaa637e146985d704e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 4 Apr 2017 15:09:21 -0700 Subject: [PATCH 07/18] More thread safety --- .../src/RenderablePolyVoxEntityItem.cpp | 12 +- .../src/RenderablePolyVoxEntityItem.h | 6 +- libraries/entities/src/PolyVoxEntityItem.cpp | 126 ++++++++++++++++++ libraries/entities/src/PolyVoxEntityItem.h | 48 +++---- libraries/entities/src/WebEntityItem.cpp | 24 ++-- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 33 ++++- libraries/entities/src/ZoneEntityItem.h | 6 +- 8 files changed, 207 insertions(+), 50 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 419f32f897..a8e422be0f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -660,22 +660,22 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { }); } -void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) { - if (xTextureURL != _xTextureURL) { +void RenderablePolyVoxEntityItem::setXTextureURL(const QString& xTextureURL) { + if (xTextureURL != getXTextureURL()) { _xTexture.clear(); PolyVoxEntityItem::setXTextureURL(xTextureURL); } } -void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) { - if (yTextureURL != _yTextureURL) { +void RenderablePolyVoxEntityItem::setYTextureURL(const QString& yTextureURL) { + if (yTextureURL != getYTextureURL()) { _yTexture.clear(); PolyVoxEntityItem::setYTextureURL(yTextureURL); } } -void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) { - if (zTextureURL != _zTextureURL) { +void RenderablePolyVoxEntityItem::setZTextureURL(const QString& zTextureURL) { + if (zTextureURL != getZTextureURL()) { _zTexture.clear(); PolyVoxEntityItem::setZTextureURL(zTextureURL); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index cdfe2e38fe..e416f59858 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -101,9 +101,9 @@ public: virtual bool setAll(uint8_t toValue) override; virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) override; - virtual void setXTextureURL(QString xTextureURL) override; - virtual void setYTextureURL(QString yTextureURL) override; - virtual void setZTextureURL(QString zTextureURL) override; + virtual void setXTextureURL(const QString& xTextureURL) override; + virtual void setYTextureURL(const QString& yTextureURL) override; + virtual void setZTextureURL(const QString& zTextureURL) override; virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 2a374c1d17..711c3b5625 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -242,3 +242,129 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const { }); return voxelDataCopy; } + + +void PolyVoxEntityItem::setXTextureURL(const QString& xTextureURL) { + withWriteLock([&] { + _xTextureURL = xTextureURL; + }); +} + +QString PolyVoxEntityItem::getXTextureURL() const { + QString result; + withReadLock([&] { + result = _xTextureURL; + }); + return result; +} + +void PolyVoxEntityItem::setYTextureURL(const QString& yTextureURL) { + withWriteLock([&] { + _yTextureURL = yTextureURL; + }); +} + +QString PolyVoxEntityItem::getYTextureURL() const { + QString result; + withReadLock([&] { + result = _yTextureURL; + }); + return result; +} + +void PolyVoxEntityItem::setZTextureURL(const QString& zTextureURL) { + withWriteLock([&] { + _zTextureURL = zTextureURL; + }); +} +QString PolyVoxEntityItem::getZTextureURL() const { + QString result; + withReadLock([&] { + result = _zTextureURL; + }); + return result; +} + +void PolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighborID) { + withWriteLock([&] { + _xNNeighborID = xNNeighborID; + }); +} + +EntityItemID PolyVoxEntityItem::getXNNeighborID() const { + EntityItemID result; + withReadLock([&] { + result = _xNNeighborID; + }); + return result; +} + +void PolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighborID) { + withWriteLock([&] { + _yNNeighborID = yNNeighborID; + }); +} + +EntityItemID PolyVoxEntityItem::getYNNeighborID() const { + EntityItemID result; + withReadLock([&] { + result = _yNNeighborID; + }); + return result; +} + +void PolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighborID) { + withWriteLock([&] { + _zNNeighborID = zNNeighborID; + }); +} + +EntityItemID PolyVoxEntityItem::getZNNeighborID() const { + EntityItemID result; + withReadLock([&] { + result = _zNNeighborID; + }); + return result; +} + +void PolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighborID) { + withWriteLock([&] { + _xPNeighborID = xPNeighborID; + }); +} + +EntityItemID PolyVoxEntityItem::getXPNeighborID() const { + EntityItemID result; + withReadLock([&] { + result = _xPNeighborID; + }); + return result; +} + +void PolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighborID) { + withWriteLock([&] { + _yPNeighborID = yPNeighborID; + }); +} + +EntityItemID PolyVoxEntityItem::getYPNeighborID() const { + EntityItemID result; + withReadLock([&] { + result = _yPNeighborID; + }); + return result; +} + +void PolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighborID) { + withWriteLock([&] { + _zPNeighborID = zPNeighborID; + }); +} + +EntityItemID PolyVoxEntityItem::getZPNeighborID() const { + EntityItemID result; + withReadLock([&] { + result = _zPNeighborID; + }); + return result; +} diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index cf7531fc9e..05b5cb33a6 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -99,36 +99,36 @@ class PolyVoxEntityItem : public EntityItem { static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16); static const QString DEFAULT_X_TEXTURE_URL; - virtual void setXTextureURL(QString xTextureURL) { _xTextureURL = xTextureURL; } - virtual const QString& getXTextureURL() const { return _xTextureURL; } + virtual void setXTextureURL(const QString& xTextureURL); + QString getXTextureURL() const; static const QString DEFAULT_Y_TEXTURE_URL; - virtual void setYTextureURL(QString yTextureURL) { _yTextureURL = yTextureURL; } - virtual const QString& getYTextureURL() const { return _yTextureURL; } + virtual void setYTextureURL(const QString& yTextureURL); + QString getYTextureURL() const; static const QString DEFAULT_Z_TEXTURE_URL; - virtual void setZTextureURL(QString zTextureURL) { _zTextureURL = zTextureURL; } - virtual const QString& getZTextureURL() const { return _zTextureURL; } + virtual void setZTextureURL(const QString& zTextureURL); + QString getZTextureURL() const; - virtual void setXNNeighborID(const EntityItemID& xNNeighborID) { _xNNeighborID = xNNeighborID; } - void setXNNeighborID(const QString& xNNeighborID) { setXNNeighborID(QUuid(xNNeighborID)); } - virtual const EntityItemID& getXNNeighborID() const { return _xNNeighborID; } - virtual void setYNNeighborID(const EntityItemID& yNNeighborID) { _yNNeighborID = yNNeighborID; } - void setYNNeighborID(const QString& yNNeighborID) { setYNNeighborID(QUuid(yNNeighborID)); } - virtual const EntityItemID& getYNNeighborID() const { return _yNNeighborID; } - virtual void setZNNeighborID(const EntityItemID& zNNeighborID) { _zNNeighborID = zNNeighborID; } - void setZNNeighborID(const QString& zNNeighborID) { setZNNeighborID(QUuid(zNNeighborID)); } - virtual const EntityItemID& getZNNeighborID() const { return _zNNeighborID; } + virtual void setXNNeighborID(const EntityItemID& xNNeighborID); + void setXNNeighborID(const QString& xNNeighborID); + virtual EntityItemID getXNNeighborID() const; + virtual void setYNNeighborID(const EntityItemID& yNNeighborID); + void setYNNeighborID(const QString& yNNeighborID); + virtual EntityItemID getYNNeighborID() const; + virtual void setZNNeighborID(const EntityItemID& zNNeighborID); + void setZNNeighborID(const QString& zNNeighborID); + virtual EntityItemID getZNNeighborID() const; - virtual void setXPNeighborID(const EntityItemID& xPNeighborID) { _xPNeighborID = xPNeighborID; } - void setXPNeighborID(const QString& xPNeighborID) { setXPNeighborID(QUuid(xPNeighborID)); } - virtual const EntityItemID& getXPNeighborID() const { return _xPNeighborID; } - virtual void setYPNeighborID(const EntityItemID& yPNeighborID) { _yPNeighborID = yPNeighborID; } - void setYPNeighborID(const QString& yPNeighborID) { setYPNeighborID(QUuid(yPNeighborID)); } - virtual const EntityItemID& getYPNeighborID() const { return _yPNeighborID; } - virtual void setZPNeighborID(const EntityItemID& zPNeighborID) { _zPNeighborID = zPNeighborID; } - void setZPNeighborID(const QString& zPNeighborID) { setZPNeighborID(QUuid(zPNeighborID)); } - virtual const EntityItemID& getZPNeighborID() const { return _zPNeighborID; } + virtual void setXPNeighborID(const EntityItemID& xPNeighborID); + void setXPNeighborID(const QString& xPNeighborID); + virtual EntityItemID getXPNeighborID() const; + virtual void setYPNeighborID(const EntityItemID& yPNeighborID); + void setYPNeighborID(const QString& yPNeighborID); + virtual EntityItemID getYPNeighborID() const; + virtual void setZPNeighborID(const EntityItemID& zPNeighborID); + void setZPNeighborID(const QString& zPNeighborID); + virtual EntityItemID getZPNeighborID() const; virtual void rebakeMesh() {}; diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 182d58ba36..5b060cc702 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -124,18 +124,26 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g } void WebEntityItem::setSourceUrl(const QString& value) { - if (_sourceUrl != value) { - auto newURL = QUrl::fromUserInput(value); + withWriteLock([&] { + if (_sourceUrl != value) { + auto newURL = QUrl::fromUserInput(value); - if (newURL.isValid()) { - _sourceUrl = newURL.toDisplayString(); - } else { - qCDebug(entities) << "Clearing web entity source URL since" << value << "cannot be parsed to a valid URL."; + if (newURL.isValid()) { + _sourceUrl = newURL.toDisplayString(); + } else { + qCDebug(entities) << "Clearing web entity source URL since" << value << "cannot be parsed to a valid URL."; + } } - } + }); } -const QString& WebEntityItem::getSourceUrl() const { return _sourceUrl; } +QString WebEntityItem::getSourceUrl() const { + QString result; + withReadLock([&] { + result = _sourceUrl; + }); + return result; +} void WebEntityItem::setDPI(uint16_t value) { _dpi = value; diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 19a7b577fe..5cd081687f 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -52,7 +52,7 @@ public: void** intersectedObject, bool precisionPicking) const override; virtual void setSourceUrl(const QString& value); - const QString& getSourceUrl() const; + QString getSourceUrl() const; virtual bool wantsHandControllerPointerEvents() const override { return true; } diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 37b3be99a3..26d566a795 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -208,10 +208,12 @@ ShapeType ZoneEntityItem::getShapeType() const { } void ZoneEntityItem::setCompoundShapeURL(const QString& url) { - _compoundShapeURL = url; - if (_compoundShapeURL.isEmpty() && _shapeType == SHAPE_TYPE_COMPOUND) { - _shapeType = DEFAULT_SHAPE_TYPE; - } + withWriteLock([&] { + _compoundShapeURL = url; + if (_compoundShapeURL.isEmpty() && _shapeType == SHAPE_TYPE_COMPOUND) { + _shapeType = DEFAULT_SHAPE_TYPE; + } + }); } bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, @@ -223,7 +225,9 @@ bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const } void ZoneEntityItem::setFilterURL(QString url) { - _filterURL = url; + withWriteLock([&] { + _filterURL = url; + }); if (DependencyManager::isSet()) { auto entityEditFilters = DependencyManager::get(); qCDebug(entities) << "adding filter " << url << "for zone" << getEntityItemID(); @@ -231,3 +235,22 @@ void ZoneEntityItem::setFilterURL(QString url) { } } +QString ZoneEntityItem::getFilterURL() const { + QString result; + withReadLock([&] { + result = _filterURL; + }); + return result; +} + +bool ZoneEntityItem::hasCompoundShapeURL() const { + return !getCompoundShapeURL().isEmpty(); +} + +QString ZoneEntityItem::getCompoundShapeURL() const { + QString result; + withReadLock([&] { + result = _compoundShapeURL; + }); + return result; +} diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 2bef95e452..dfc18aff80 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -58,8 +58,8 @@ public: void setShapeType(ShapeType type) override { _shapeType = type; } virtual ShapeType getShapeType() const override; - virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); } - const QString getCompoundShapeURL() const { return _compoundShapeURL; } + virtual bool hasCompoundShapeURL() const; + QString getCompoundShapeURL() const; virtual void setCompoundShapeURL(const QString& url); const KeyLightPropertyGroup& getKeyLightProperties() const { return _keyLightProperties; } @@ -74,7 +74,7 @@ public: void setFlyingAllowed(bool value) { _flyingAllowed = value; } bool getGhostingAllowed() const { return _ghostingAllowed; } void setGhostingAllowed(bool value) { _ghostingAllowed = value; } - QString getFilterURL() const { return _filterURL; } + QString getFilterURL() const; void setFilterURL(const QString url); virtual bool supportsDetailedRayIntersection() const override { return true; } From e9934ac696b7d70466ca962d97b18a2272592719 Mon Sep 17 00:00:00 2001 From: Faye Li Date: Wed, 5 Apr 2017 14:59:19 -0700 Subject: [PATCH 08/18] selfie stick script --- script-archive/selfieStick.js | 104 ++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 script-archive/selfieStick.js diff --git a/script-archive/selfieStick.js b/script-archive/selfieStick.js new file mode 100644 index 0000000000..767cf55144 --- /dev/null +++ b/script-archive/selfieStick.js @@ -0,0 +1,104 @@ +// selfieStick.js +// +// Created by Faye Li on March 23, 2016 +// +// Usage instruction: Spacebar toggles camera control - WASD first person free movement or no movement but allowing others to grab the selfie stick +// and control your camera. +// For best result, turn off avatar collisions(Developer > Avatar > Uncheck Enable Avatar Collisions) +// + +(function() { // BEGIN LOCAL_SCOPE + var MODEL_URL = "https://hifi-content.s3.amazonaws.com/faye/twitch-stream/selfie_stick.json"; + var AVATAR_URL = "https://hifi-content.s3.amazonaws.com/jimi/avatar/camera/fst/camera.fst"; + var originalAvatar = null; + var importedEntityIDs = []; + var selfieStickEntityID = null; + var lensEntityID = null; + var freeMovementMode = true; + + changeAvatar(); + importModel(); + processImportedEntities(); + parentEntityToAvatar(); + setupSpaceBarControl(); + + function changeAvatar() { + originalAvatar = MyAvatar.skeletonModelURL; + MyAvatar.skeletonModelURL = AVATAR_URL; + } + + function importModel() { + var success = Clipboard.importEntities(MODEL_URL); + var spawnLocation = MyAvatar.position; + if (success) { + importedEntityIDs = Clipboard.pasteEntities(spawnLocation); + } + } + + function processImportedEntities() { + importedEntityIDs.forEach(function(id){ + var props = Entities.getEntityProperties(id); + if (props.name === "Selfie Stick") { + selfieStickEntityID = id; + } else if (props.name === "Lens") { + lensEntityID = id; + } + }); + } + + function parentEntityToAvatar() { + var props = { + "parentID" : MyAvatar.sessionUUID + }; + Entities.editEntity(selfieStickEntityID, props); + } + + function unparentEntityFromAvatar() { + var props = { + "parentID" : 0 + }; + Entities.editEntity(selfieStickEntityID, props); + } + + function parentAvatarToEntity() { + MyAvatar.setParentID(selfieStickEntityID); + } + + function unparentAvatarFromEntity() { + MyAvatar.setParentID(0); + } + + function setupSpaceBarControl() { + var mappingName = "Handheld-Cam-Space-Bar"; + var myMapping = Controller.newMapping(mappingName); + myMapping.from(Controller.Hardware.Keyboard.Space).to(function(value){ + if ( value === 0 ) { + return; + } + if (freeMovementMode) { + freeMovementMode = false; + // Camera.mode = "entity"; + // Camera.cameraEntity = lensEntityID; + unparentEntityFromAvatar(); + parentAvatarToEntity(); + } else { + freeMovementMode = true; + // Camera.mode = "first person"; + unparentAvatarFromEntity(); + parentEntityToAvatar(); + } + }); + Controller.enableMapping(mappingName); + } + + // Removes all entities we imported and reset settings we've changed + function cleanup() { + importedEntityIDs.forEach(function(id) { + Entities.deleteEntity(id); + }); + Camera.mode = "first person"; + Controller.disableMapping("Handheld-Cam-Space-Bar"); + MyAvatar.skeletonModelURL = originalAvatar; + } + Script.scriptEnding.connect(cleanup); +}()); // END LOCAL_SCOPE \ No newline at end of file From 97d75e654e22cf732d104334e66357bb99b43054 Mon Sep 17 00:00:00 2001 From: Faye Li Date: Wed, 5 Apr 2017 15:04:21 -0700 Subject: [PATCH 09/18] mannually bind avatar and entity --- script-archive/selfieStick.js | 68 +++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/script-archive/selfieStick.js b/script-archive/selfieStick.js index 767cf55144..c6fb9c5349 100644 --- a/script-archive/selfieStick.js +++ b/script-archive/selfieStick.js @@ -7,6 +7,15 @@ // For best result, turn off avatar collisions(Developer > Avatar > Uncheck Enable Avatar Collisions) // +// selfieStick.js +// +// Created by Faye Li on March 23, 2016 +// +// Usage instruction: Spacebar toggles camera control - WASD first person free movement or no movement but allowing others to grab the selfie stick +// and control your camera. +// For best result, turn off avatar collisions(Developer > Avatar > Uncheck Enable Avatar Collisions) +// + (function() { // BEGIN LOCAL_SCOPE var MODEL_URL = "https://hifi-content.s3.amazonaws.com/faye/twitch-stream/selfie_stick.json"; var AVATAR_URL = "https://hifi-content.s3.amazonaws.com/jimi/avatar/camera/fst/camera.fst"; @@ -19,8 +28,8 @@ changeAvatar(); importModel(); processImportedEntities(); - parentEntityToAvatar(); setupSpaceBarControl(); + Script.update.connect(update); function changeAvatar() { originalAvatar = MyAvatar.skeletonModelURL; @@ -46,28 +55,6 @@ }); } - function parentEntityToAvatar() { - var props = { - "parentID" : MyAvatar.sessionUUID - }; - Entities.editEntity(selfieStickEntityID, props); - } - - function unparentEntityFromAvatar() { - var props = { - "parentID" : 0 - }; - Entities.editEntity(selfieStickEntityID, props); - } - - function parentAvatarToEntity() { - MyAvatar.setParentID(selfieStickEntityID); - } - - function unparentAvatarFromEntity() { - MyAvatar.setParentID(0); - } - function setupSpaceBarControl() { var mappingName = "Handheld-Cam-Space-Bar"; var myMapping = Controller.newMapping(mappingName); @@ -77,20 +64,41 @@ } if (freeMovementMode) { freeMovementMode = false; - // Camera.mode = "entity"; - // Camera.cameraEntity = lensEntityID; - unparentEntityFromAvatar(); - parentAvatarToEntity(); + Camera.mode = "entity"; + Camera.cameraEntity = lensEntityID; } else { freeMovementMode = true; - // Camera.mode = "first person"; - unparentAvatarFromEntity(); - parentEntityToAvatar(); + Camera.mode = "first person"; } }); Controller.enableMapping(mappingName); } + function update(deltaTime) { + if (freeMovementMode) { + var upFactor = 0.1; + var upUnitVec = Vec3.normalize(Quat.getUp(MyAvatar.orientation)); + var upOffset = Vec3.multiply(upUnitVec, upFactor); + var forwardFactor = -0.1; + var forwardUnitVec = Vec3.normalize(Quat.getFront(MyAvatar.orientation)); + var forwardOffset = Vec3.multiply(forwardUnitVec, forwardFactor); + var newPos = Vec3.sum(Vec3.sum(MyAvatar.position, upOffset), forwardOffset); + var newRot = MyAvatar.orientation; + Entities.editEntity(selfieStickEntityID, {position: newPos, rotation: newRot}); + } else { + var props = Entities.getEntityProperties(selfieStickEntityID); + var upFactor = 0.1; + var upUnitVec = Vec3.normalize(Quat.getUp(props.rotation)); + var upOffset = Vec3.multiply(upUnitVec, -upFactor); + var forwardFactor = -0.1; + var forwardUnitVec = Vec3.normalize(Quat.getFront(props.rotation)); + var forwardOffset = Vec3.multiply(forwardUnitVec, -forwardFactor); + var newPos = Vec3.sum(Vec3.sum(props.position, upOffset), forwardOffset); + MyAvatar.position = newPos; + MyAvatar.orientation = props.rotation; + } + } + // Removes all entities we imported and reset settings we've changed function cleanup() { importedEntityIDs.forEach(function(id) { From 90f5d02c990db8f79b25002da949d4947423fbc6 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 6 Apr 2017 00:13:53 +0100 Subject: [PATCH 10/18] goto toggle option --- interface/src/ui/DialogsManager.cpp | 43 +++++++++++++++++-- interface/src/ui/DialogsManager.h | 1 + .../src/TabletScriptingInterface.cpp | 8 ++++ .../src/TabletScriptingInterface.h | 3 ++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 402e27e256..a95ac8d91f 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -31,6 +31,7 @@ #include "TabletScriptingInterface.h" #include "scripting/HMDScriptingInterface.h" +static const QVariant TABLET_ADDRESS_DIALOG = "TabletAddressDialog.qml"; template void DialogsManager::maybeCreateDialog(QPointer& member) { if (!member) { @@ -46,12 +47,48 @@ void DialogsManager::maybeCreateDialog(QPointer& member) { } void DialogsManager::toggleAddressBar() { - AddressBarDialog::toggle(); - emit addressBarToggled(); + auto hmd = DependencyManager::get(); + auto tabletScriptingInterface = DependencyManager::get(); + auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); + if (tablet->getToolbarMode()) { + if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG)) { + tablet->gotoHomeScreen(); + emit addressBarToggled(); + } else { + tablet->loadQMLSource(TABLET_ADDRESS_DIALOG); + emit addressBarToggled(); + } + } else { + if (hmd->getShouldShowTablet()) { + if (tablet->isPathLoaded(TABLET_ADDRESS_DIALOG) && _closeAddressBar) { + tablet->gotoHomeScreen(); + hmd->closeTablet(); + _closeAddressBar = false; + emit addressBarToggled(); + } else { + tablet->loadQMLSource(TABLET_ADDRESS_DIALOG); + _closeAddressBar = true; + emit addressBarToggled(); + } + } else { + tablet->loadQMLSource(TABLET_ADDRESS_DIALOG); + hmd->openTablet(); + _closeAddressBar = true; + emit addressBarToggled(); + } + + } } void DialogsManager::showAddressBar() { - AddressBarDialog::show(); + auto hmd = DependencyManager::get(); + auto tabletScriptingInterface = DependencyManager::get(); + auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); + tablet->loadQMLSource(TABLET_ADDRESS_DIALOG); + + if (!hmd->getShouldShowTablet()) { + hmd->openTablet(); + } } void DialogsManager::showFeed() { diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 608195aca7..24b9078baf 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -79,6 +79,7 @@ private: QPointer _octreeStatsDialog; QPointer _testingDialog; QPointer _domainConnectionDialog; + bool _closeAddressBar { false }; }; #endif // hifi_DialogsManager_h diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index b4d8977b6d..7747e1b6dc 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -275,6 +275,9 @@ void TabletProxy::emitWebEvent(QVariant msg) { emit webEventReceived(msg); } +bool TabletProxy::isPathLoaded(QVariant path) { + return path.toString() == _currentPathLoaded.toString(); +} void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface) { std::lock_guard guard(_mutex); _qmlOffscreenSurface = qmlOffscreenSurface; @@ -322,6 +325,7 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr removeButtonsFromHomeScreen(); _state = State::Uninitialized; emit screenChanged(QVariant("Closed"), QVariant("")); + _currentPathLoaded = ""; } } @@ -345,6 +349,7 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) { QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL))); _state = State::Menu; emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL)); + _currentPathLoaded = VRMENU_SOURCE_URL; QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); } } @@ -364,6 +369,7 @@ void TabletProxy::loadQMLSource(const QVariant& path) { QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path)); _state = State::QML; emit screenChanged(QVariant("QML"), path); + _currentPathLoaded = path; QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); } } else { @@ -426,6 +432,7 @@ void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) { } _state = State::Home; emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL)); + _currentPathLoaded = TABLET_SOURCE_URL; } } @@ -450,6 +457,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS } _state = State::Web; emit screenChanged(QVariant("Web"), QVariant(url)); + _currentPathLoaded = QVariant(url); } QObject* TabletProxy::addButton(const QVariant& properties) { diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index e9ae60fee1..195db02789 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -183,6 +183,8 @@ public: Q_INVOKABLE void setLandscape(bool landscape) { _landscape = landscape; } Q_INVOKABLE bool getLandscape() { return _landscape; } + Q_INVOKABLE bool isPathLoaded(QVariant path); + QQuickItem* getTabletRoot() const { return _qmlTabletRoot; } QObject* getTabletSurface(); @@ -235,6 +237,7 @@ protected: bool _initialScreen { false }; QVariant _initialPath { "" }; + QVariant _currentPathLoaded { "" }; QString _name; std::mutex _mutex; std::vector> _tabletButtonProxies; From 52fd446d4d5bc965acd6d60b11a2d05236206df3 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 6 Apr 2017 22:27:37 +0100 Subject: [PATCH 11/18] toggle goto in tablet --- interface/resources/qml/hifi/Card.qml | 7 +----- .../qml/hifi/tablet/TabletAddressDialog.qml | 25 ++++++++++++++----- interface/src/Application.cpp | 1 + .../src/TabletScriptingInterface.cpp | 2 +- scripts/system/tablet-goto.js | 13 +++++++--- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 217cfec707..b72901fbdf 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -243,12 +243,7 @@ Rectangle { } } } - DropShadow { - anchors.fill: actionIcon - radius: 8.0 - color: "#80000000" - source: actionIcon - } + MouseArea { id: messageArea; width: rectIcon.width; diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index b0b8c68789..fbb78d2694 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -25,22 +25,31 @@ StackView { HifiConstants { id: hifi } HifiStyles.HifiConstants { id: hifiStyleConstants } initialItem: addressBarDialog - width: parent.width - height: parent.height property var eventBridge; property var allStories: []; property int cardWidth: 460; property int cardHeight: 320; property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/"; + property var tablet: null; + property bool isDesktop: false; + Component { id: tabletStoryCard; TabletStoryCard {} } Component.onCompleted: { root.currentItem.focus = true; root.currentItem.forceActiveFocus(); + addressLine.focus = true; + addressLine.forceActiveFocus(); fillDestinations(); updateLocationText(false); root.parentChanged.connect(center); center(); + isDesktop = (typeof desktop !== "undefined"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + if (desktop) { + root.title = "GOTO"; + } } Component.onDestruction: { root.parentChanged.disconnect(center); @@ -107,7 +116,6 @@ StackView { imageURL: "../../../images/home.svg" onClicked: { addressBarDialog.loadHome(); - root.shown = false; } anchors { left: parent.left @@ -291,9 +299,8 @@ StackView { left: parent.left right: parent.right leftMargin: 10 - verticalCenter: parent.verticalCenter; - horizontalCenter: parent.horizontalCenter; } + model: suggestions orientation: ListView.Vertical @@ -547,7 +554,13 @@ StackView { if (addressLine.text !== "") { addressBarDialog.loadAddress(addressLine.text, fromSuggestions) } - root.shown = false; + + if (root.desktop) { + tablet.gotoHomeScreen(); + } else { + HMD.closeTablet(); + } + } Keys.onPressed: { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e19eea0a2e..feba5a74a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2010,6 +2010,7 @@ void Application::initializeUi() { rootContext->setContextProperty("SoundCache", DependencyManager::get().data()); rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); + rootContext->setContextProperty("Tablet", DependencyManager::get().data()); rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); rootContext->setContextProperty("FaceTracker", DependencyManager::get().data()); diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 7747e1b6dc..3aa0cc99e7 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -83,7 +83,7 @@ QQuickWindow* TabletScriptingInterface::getTabletWindow() { QObject* qmlSurface = tablet->getTabletSurface(); OffscreenQmlSurface* surface = dynamic_cast(qmlSurface); - if (!surface) { + if (!surface) { return nullptr; } QQuickWindow* window = surface->getWindow(); diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index eb95d9d8a3..84f7357b1a 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -29,10 +29,15 @@ } function onScreenChanged(type, url) { - // for toolbar mode: change button to active when window is first openend, false otherwise. - button.editProperties({isActive: shouldActivateButton}); - shouldActivateButton = false; - onGotoScreen = false; + if (url === gotoQmlSource) { + onGotoScreen = true; + shouldActivateButton = true; + button.editProperties({isActive: shouldActivateButton}); + } else { + shouldActivateButton = false; + onGotoScreen = false; + button.editProperties({isActive: shouldActivateButton}); + } } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); From 22521526ece9f2b4af843169906c87500911323c Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 6 Apr 2017 23:41:30 +0100 Subject: [PATCH 12/18] removed stray space --- libraries/script-engine/src/TabletScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 3aa0cc99e7..7747e1b6dc 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -83,7 +83,7 @@ QQuickWindow* TabletScriptingInterface::getTabletWindow() { QObject* qmlSurface = tablet->getTabletSurface(); OffscreenQmlSurface* surface = dynamic_cast(qmlSurface); - if (!surface) { + if (!surface) { return nullptr; } QQuickWindow* window = surface->getWindow(); From f88ba7bc5756d24775ec8960d891d015e40ff20a Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Fri, 7 Apr 2017 15:45:33 +0200 Subject: [PATCH 13/18] Yahoo, Reddit etc now works correctly --- interface/resources/qml/TabletBrowser.qml | 7 +------ interface/resources/qml/controls/TabletWebView.qml | 14 +++++++++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index 2650102b27..74318a165e 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -104,6 +104,7 @@ Item { // Required to support clicking on "hifi://" links if (WebEngineView.LoadStartedStatus == loadRequest.status) { + urlAppend(loadRequest.url.toString()) var url = loadRequest.url.toString(); if (urlHandler.canHandleUrl(url)) { if (urlHandler.handleUrl(url)) { @@ -113,12 +114,6 @@ Item { } } - onNavigationRequested: { - if (request.navigationType == WebEngineNavigationRequest.LinkClickedNavigation) { - pagesModel.append({webUrl: request.url.toString()}) - } - } - onNewViewRequested: { request.openIn(webView); } diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 50d6e1c504..e5b891777f 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -117,7 +117,7 @@ Item { } function gotoPage(url) { - pagesModel.append({webUrl: url}) + urlAppend(url) } function reloadPage() { @@ -126,9 +126,20 @@ Item { view.setEnabled(true); } + function urlAppend(url) { + var _url = decodeURIComponent(url) + if (_url[_url.length - 1] !== "/") + _url = _url + "/" + if (currentPage === -1 || pagesModel.get(currentPage).webUrl !== _url) { + pagesModel.append({webUrl: _url}) + } + } + onCurrentPageChanged: { if (currentPage >= 0 && currentPage < pagesModel.count && loader.item !== null) { loader.item.url = pagesModel.get(currentPage).webUrl + web.url = loader.item.url + web.address = loader.item.url } } @@ -160,6 +171,7 @@ Item { if (currentPage >= 0) { //we got something to load already item.url = pagesModel.get(currentPage).webUrl + web.address = loader.item.url } } } From 3caea886413f63e6835ece7c3f3858d4f05c3f0e Mon Sep 17 00:00:00 2001 From: Faye Li Date: Fri, 7 Apr 2017 10:02:30 -0700 Subject: [PATCH 14/18] use JS method to enable/disable avatar collisions --- script-archive/selfieStick.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/script-archive/selfieStick.js b/script-archive/selfieStick.js index c6fb9c5349..fd3bb82145 100644 --- a/script-archive/selfieStick.js +++ b/script-archive/selfieStick.js @@ -13,7 +13,6 @@ // // Usage instruction: Spacebar toggles camera control - WASD first person free movement or no movement but allowing others to grab the selfie stick // and control your camera. -// For best result, turn off avatar collisions(Developer > Avatar > Uncheck Enable Avatar Collisions) // (function() { // BEGIN LOCAL_SCOPE @@ -25,12 +24,21 @@ var lensEntityID = null; var freeMovementMode = true; + turnOffAvatarCollisions(); changeAvatar(); importModel(); processImportedEntities(); setupSpaceBarControl(); Script.update.connect(update); + function turnOffAvatarCollisions() { + Menu.setIsOptionChecked("Enable avatar collisions", 0); + } + + function turnOnAvatarCollisions() { + Menu.setIsOptionChecked("Enable avatar collisions", 1); + } + function changeAvatar() { originalAvatar = MyAvatar.skeletonModelURL; MyAvatar.skeletonModelURL = AVATAR_URL; @@ -107,6 +115,7 @@ Camera.mode = "first person"; Controller.disableMapping("Handheld-Cam-Space-Bar"); MyAvatar.skeletonModelURL = originalAvatar; + turnOnAvatarCollisions(); } Script.scriptEnding.connect(cleanup); }()); // END LOCAL_SCOPE \ No newline at end of file From 9a563ba02fc76e06ce100c278c444190ebd95aad Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Fri, 7 Apr 2017 19:17:09 +0200 Subject: [PATCH 15/18] Check if offset outside image, set to last image --- interface/resources/qml/hifi/toolbars/StateImage.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/toolbars/StateImage.qml b/interface/resources/qml/hifi/toolbars/StateImage.qml index e0389c5e02..ebf1544f2b 100644 --- a/interface/resources/qml/hifi/toolbars/StateImage.qml +++ b/interface/resources/qml/hifi/toolbars/StateImage.qml @@ -12,7 +12,10 @@ Item { property bool pinned: false clip: true - function updateYOffset() { yOffset = size * buttonState; } + function updateYOffset() { + //make sure offset not set outside image + yOffset = (size * buttonState >= image.height) ? image.height - size : size * buttonState + } onButtonStateChanged: updateYOffset(); Component.onCompleted: { From a1892b351ff2680ed9786f4ed29b7550eb62e0fc Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Fri, 7 Apr 2017 19:40:46 +0200 Subject: [PATCH 16/18] Cant use underscores outside class internals --- interface/resources/qml/controls/TabletWebView.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index e5b891777f..ee26a32a85 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -127,11 +127,11 @@ Item { } function urlAppend(url) { - var _url = decodeURIComponent(url) - if (_url[_url.length - 1] !== "/") - _url = _url + "/" - if (currentPage === -1 || pagesModel.get(currentPage).webUrl !== _url) { - pagesModel.append({webUrl: _url}) + var lurl = decodeURIComponent(url) + if (lurl[lurl.length - 1] !== "/") + lurl = lurl + "/" + if (currentPage === -1 || pagesModel.get(currentPage).webUrl !== lurl) { + pagesModel.append({webUrl: lurl}) } } From 909fda98a48ec9bd6ab57b5fa77f5870e74c66e6 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 7 Apr 2017 21:01:53 +0100 Subject: [PATCH 17/18] git goto button toggle hightlight --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 396f03a1c9..e4f6aa3407 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -560,7 +560,7 @@ StackView { addressBarDialog.loadAddress(addressLine.text, fromSuggestions) } - if (root.desktop) { + if (isDesktop) { tablet.gotoHomeScreen(); } else { HMD.closeTablet(); From cde9310f3e1c56ae6afb8b74012acd3f5ba2b7ba Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 7 Apr 2017 21:35:28 +0100 Subject: [PATCH 18/18] goto home button fix --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index e4f6aa3407..39892f27a4 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -119,6 +119,8 @@ StackView { onClicked: { addressBarDialog.loadHome(); tabletRoot.shown = false; + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet.gotoHomeScreen(); } anchors { left: parent.left