Logical keys that drive your avatar and camera.
* 2 | Auto | Interface detects when the user is standing or seated in the real world.
* Avatar leaning is disabled when the user is sitting (i.e., avatar always recenters), and avatar leaning is enabled
@@ -607,7 +654,7 @@ public:
* Note: When using pre-built animation data, it's critical that the joint orientation of the source animation and target
* rig are equivalent, since the animation data applies absolute values onto the joints. If the orientations are different,
* the avatar will move in unpredictable ways. For more information about avatar joint orientation standards, see
- * Avatar Standards.
+ * Avatar Standards.
* @function MyAvatar.overrideAnimation
* @param {string} url - The URL to the animation file. Animation files may be in glTF or FBX format, but only need to
* contain the avatar skeleton and animation data. glTF models may be in JSON or binary format (".gltf" or ".glb" URLs
@@ -618,7 +665,7 @@ public:
* @param {number} firstFrame - The frame to start the animation at.
* @param {number} lastFrame - The frame to end the animation at.
* @example Play a clapping animation on your avatar for three seconds.
- * var ANIM_URL = "https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx";
+ * var ANIM_URL = "https://apidocs.vircadia.dev/models/ClapHands_Standing.fbx";
* MyAvatar.overrideAnimation(ANIM_URL, 30, true, 0, 53);
* Script.setTimeout(function () {
* MyAvatar.restoreAnimation();
@@ -641,7 +688,7 @@ public:
* @param {number} firstFrame - The frame to start the animation at.
* @param {number} lastFrame - The frame to end the animation at.
* @example Override left hand animation for three seconds.
- * var ANIM_URL = "https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx";
+ * var ANIM_URL = "https://apidocs.vircadia.dev/models/ClapHands_Standing.fbx";
* MyAvatar.overrideHandAnimation(isLeft, ANIM_URL, 30, true, 0, 53);
* Script.setTimeout(function () {
* MyAvatar.restoreHandAnimation();
@@ -658,7 +705,7 @@ public:
* animation, this function has no effect.
* @function MyAvatar.restoreAnimation
* @example Play a clapping animation on your avatar for three seconds.
- * var ANIM_URL = "https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx";
+ * var ANIM_URL = "https://apidocs.vircadia.dev/models/ClapHands_Standing.fbx";
* MyAvatar.overrideAnimation(ANIM_URL, 30, true, 0, 53);
* Script.setTimeout(function () {
* MyAvatar.restoreAnimation();
@@ -675,7 +722,7 @@ public:
* @function MyAvatar.restoreHandAnimation
* @param isLeft {boolean} Set to true if using the left hand
* @example Override left hand animation for three seconds.
- * var ANIM_URL = "https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx";
+ * var ANIM_URL = "https://apidocs.projectathena.dev/models/ClapHands_Standing.fbx";
* MyAvatar.overrideHandAnimation(isLeft, ANIM_URL, 30, true, 0, 53);
* Script.setTimeout(function () {
* MyAvatar.restoreHandAnimation();
@@ -733,7 +780,7 @@ public:
* hanging at its sides when it is not moving, the avatar will stand and clap its hands. Note that just as it did before, as soon as the avatar
* starts to move, the animation will smoothly blend into the walk animation used by the "walkFwd" animation role.
* // An animation of the avatar clapping its hands while standing. Restore default after 30s.
- * var ANIM_URL = "https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx";
+ * var ANIM_URL = "https://apidocs.projectathena.dev/models/ClapHands_Standing.fbx";
* MyAvatar.overrideRoleAnimation("idleStand", ANIM_URL, 30, true, 0, 53);
* Script.setTimeout(function () {
* MyAvatar.restoreRoleAnimation();
@@ -1003,7 +1050,7 @@ public:
/**jsdoc
* Gets the value of a drive key, regardless of whether it is disabled.
* @function MyAvatar.getRawDriveKey
- * @param {MyAvatar.DriveKeys} key - The drive key.
+ * @param {DriveKey} key - The drive key.
* @returns {number} The value of the drive key.
*/
Q_INVOKABLE float getRawDriveKey(DriveKeys key) const;
@@ -1013,11 +1060,10 @@ public:
/**jsdoc
* Disables the action associated with a drive key.
* @function MyAvatar.disableDriveKey
- * @param {MyAvatar.DriveKeys} key - The drive key to disable.
+ * @param {DriveKey} key - The drive key to disable.
* @example Disable rotating your avatar using the keyboard for a couple of seconds.
- * var YAW = 3;
* print("Disable");
- * MyAvatar.disableDriveKey(YAW);
+ * MyAvatar.disableDriveKey(DriveKeys.YAW);
* Script.setTimeout(function () {
* print("Enable");
* MyAvatar.enableDriveKey(YAW);
@@ -1029,14 +1075,14 @@ public:
* Enables the action associated with a drive key. The action may have been disabled with
* {@link MyAvatar.disableDriveKey|disableDriveKey}.
* @function MyAvatar.enableDriveKey
- * @param {MyAvatar.DriveKeys} key - The drive key to enable.
+ * @param {DriveKey} key - The drive key to enable.
*/
Q_INVOKABLE void enableDriveKey(DriveKeys key);
/**jsdoc
* Checks whether a drive key is disabled.
* @function MyAvatar.isDriveKeyDisabled
- * @param {DriveKeys} key - The drive key to check.
+ * @param {DriveKey} key - The drive key to check.
* @returns {boolean} true if the drive key is disabled, false if it isn't.
*/
Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const;
@@ -1137,7 +1183,7 @@ public:
/**jsdoc
* Gets information on the avatar your avatar is currently looking at.
* @function MyAvatar.getTargetAvatar
- * @returns {AvatarData} Information on the avatar being looked at.
+ * @returns {ScriptAvatar} Information on the avatar being looked at, null if no avatar is being looked at.
*/
// FIXME: The return type doesn't have a conversion to a script value so the function always returns undefined in
// JavaScript. Note: When fixed, JSDoc is needed for the return type.
@@ -1746,57 +1792,57 @@ public:
void prepareAvatarEntityDataForReload();
/**jsdoc
- * Turn the avatar's head until it faces the target point within the 90/-90 degree range.
- * Once this method is called, API calls will have full control of the head for a limited time.
- * If this method is not called for two seconds, the engine will regain control of the head.
- * @function MyAvatar.setHeadLookAt
- * @param {Vec3} lookAtTarget - The target point in world coordinates.
- */
+ * Turns the avatar's head until it faces the target point within a +90/-90 degree range.
+ * Once this method is called, API calls have full control of the head for a limited time.
+ * If this method is not called for 2 seconds, the engine regains control of the head.
+ * @function MyAvatar.setHeadLookAt
+ * @param {Vec3} lookAtTarget - The target point in world coordinates.
+ */
Q_INVOKABLE void setHeadLookAt(const glm::vec3& lookAtTarget);
/**jsdoc
- * Returns the current head look at target point in world coordinates.
- * @function MyAvatar.getHeadLookAt
- * @returns {Vec3} The head's look at target in world coordinates.
- */
+ * Gets the current target point of the head's look direction in world coordinates.
+ * @function MyAvatar.getHeadLookAt
+ * @returns {Vec3} The head's look-at target in world coordinates.
+ */
Q_INVOKABLE glm::vec3 getHeadLookAt() { return _lookAtCameraTarget; }
/**jsdoc
- * When this function is called the engine regains control of the head immediately.
- * @function MyAvatar.releaseHeadLookAtControl
- */
+ * Returns control of the avatar's head to the engine, and releases control from API calls.
+ * @function MyAvatar.releaseHeadLookAtControl
+ */
Q_INVOKABLE void releaseHeadLookAtControl();
/**jsdoc
- * Force the avatar's eyes to look to the specified location.
- * Once this method is called, API calls will have full control of the eyes for a limited time.
- * If this method is not called for two seconds, the engine will regain control of the eyes.
- * @function MyAvatar.setEyesLookAt
- * @param {Vec3} lookAtTarget - The target point in world coordinates.
- */
+ * Forces the avatar's eyes to look at a specified location. Once this method is called, API calls
+ * full control of the eyes for a limited time. If this method is not called for 2 seconds,
+ * the engine regains control of the eyes.
+ * @function MyAvatar.setEyesLookAt
+ * @param {Vec3} lookAtTarget - The target point in world coordinates.
+ */
Q_INVOKABLE void setEyesLookAt(const glm::vec3& lookAtTarget);
/**jsdoc
- * Returns the current eyes look at target point in world coordinates.
- * @function MyAvatar.getEyesLookAt
- * @returns {Vec3} The eyes's look at target in world coordinates.
- */
+ * Gets the current target point of the eyes look direction in world coordinates.
+ * @function MyAvatar.getEyesLookAt
+ * @returns {Vec3} The eyes' look-at target in world coordinates.
+ */
Q_INVOKABLE glm::vec3 getEyesLookAt() { return _eyesLookAtTarget.get(); }
/**jsdoc
- * When this function is called the engine regains control of the eyes immediately.
- * @function MyAvatar.releaseEyesLookAtControl
- */
+ * Returns control of the avatar's eyes to the engine, and releases control from API calls.
+ * @function MyAvatar.releaseEyesLookAtControl
+ */
Q_INVOKABLE void releaseEyesLookAtControl();
/**jsdoc
- * Aims the pointing directional blending towards the provided target point.
- * The "point" reaction should be triggered before using this method.
- * MyAvatar.beginReaction("point")
- * Returns true if the target point lays in front of the avatar.
- * @function MyAvatar.setPointAt
- * @param {Vec3} pointAtTarget - The target point in world coordinates.
- */
+ * Sets the point-at target for the "point" reaction that may be started with {@link MyAvatar.beginReaction}.
+ * The point-at target is set only if it is in front of the avatar.
+ * Note: The "point" reaction should be started before calling this method.
+ * @function MyAvatar.setPointAt
+ * @param {Vec3} pointAtTarget - The target to point at, in world coordinates.
+ * @returns {boolean} true if the target point was set, false if it wasn't.
+ */
Q_INVOKABLE bool setPointAt(const glm::vec3& pointAtTarget);
glm::quat getLookAtRotation() { return _lookAtYaw * _lookAtPitch; }
@@ -1840,14 +1886,17 @@ public:
/**jsdoc
* Gets details of all avatar entities.
+ * Warning: Potentially an expensive call. Do not use if possible.
* @function MyAvatar.getAvatarEntityData
- * @returns {AvatarEntityMap} Details of the avatar entities.
+ * @returns {AvatarEntityMap} Details of all avatar entities.
* @example Report the current avatar entities.
* var avatarEntityData = MyAvatar.getAvatarEntityData();
* print("Avatar entities: " + JSON.stringify(avatarEntityData));
*/
AvatarEntityMap getAvatarEntityData() const override;
+ AvatarEntityMap getAvatarEntityDataNonDefault() const override;
+
/**jsdoc
* Sets all avatar entities from an object.
* @function MyAvatar.setAvatarEntityData
@@ -1877,7 +1926,7 @@ public:
* @param {boolean} isActive - true if flow simulation is enabled on the joint, false if it isn't.
* @param {boolean} isCollidable - true to enable collisions in the flow simulation, false to
* disable.
- * @param {Object} [physicsConfig>] - Physics configurations for particular entity
+ * @param {Object} [physicsConfig] - Physics configurations for particular entity
* and avatar joints.
* @param {Object} [collisionsConfig] - Collision configurations for particular
* entity and avatar joints.
@@ -1899,26 +1948,25 @@ public:
Q_INVOKABLE QVariantList getCollidingFlowJoints();
/**jsdoc
- * Starts a sitting action for the avatar
+ * Starts a sitting action for the avatar.
* @function MyAvatar.beginSit
- * @param {Vec3} position - The point in space where the avatar will sit.
- * @param {Quat} rotation - Initial absolute orientation of the avatar once is seated.
+ * @param {Vec3} position - The position where the avatar should sit.
+ * @param {Quat} rotation - The initial orientation of the seated avatar.
*/
Q_INVOKABLE void beginSit(const glm::vec3& position, const glm::quat& rotation);
/**jsdoc
- * Ends a sitting action for the avatar
+ * Ends a sitting action for the avatar.
* @function MyAvatar.endSit
* @param {Vec3} position - The position of the avatar when standing up.
- * @param {Quat} rotation - The absolute rotation of the avatar once the sitting action ends.
+ * @param {Quat} rotation - The orientation of the avatar when standing up.
*/
Q_INVOKABLE void endSit(const glm::vec3& position, const glm::quat& rotation);
/**jsdoc
- * Gets whether the avatar is in a seated pose. The seated pose is set by calling the
- * MyAvatar::beginSit method.
+ * Gets whether the avatar is in a seated pose. The seated pose is set by calling {@link MyAvatar.beginSit}.
* @function MyAvatar.isSeated
- * @returns {boolean} true if the avatar is in a seated pose.
+ * @returns {boolean} true if the avatar is in a seated pose, false if it isn't.
*/
Q_INVOKABLE bool isSeated() { return _characterController.getSeated(); }
@@ -2003,7 +2051,8 @@ public slots:
float getGravity();
/**jsdoc
- * Moves the avatar to a new position and/or orientation in the domain, while taking into account Avatar leg-length.
+ * Moves the avatar to a new position and/or orientation in the domain, with safe landing, while taking into account avatar
+ * leg length.
* @function MyAvatar.goToFeetLocation
* @param {Vec3} position - The new position for the avatar, in world coordinates.
* @param {boolean} [hasOrientation=false] - Set to true to set the orientation of the avatar.
@@ -2021,21 +2070,21 @@ public slots:
* @param {boolean} [hasOrientation=false] - Set to true to set the orientation of the avatar.
* @param {Quat} [orientation=Quat.IDENTITY] - The new orientation for the avatar.
* @param {boolean} [shouldFaceLocation=false] - Set to true to position the avatar a short distance away from
- * @param {boolean} [withSafeLanding=true] - Set to false MyAvatar::safeLanding will not be called (used when teleporting).
* the new position and orientate the avatar to face the position.
+ * @param {boolean} [withSafeLanding=true] - Set to false to disable safe landing when teleporting.
*/
void goToLocation(const glm::vec3& newPosition,
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
bool shouldFaceLocation = false, bool withSafeLanding = true);
/**jsdoc
- * Moves the avatar to a new position and (optional) orientation in the domain.
+ * Moves the avatar to a new position and (optional) orientation in the domain, with safe landing.
* @function MyAvatar.goToLocation
* @param {MyAvatar.GoToProperties} target - The goto target.
*/
void goToLocation(const QVariant& properties);
/**jsdoc
- * Moves the avatar to a new position and then enables collisions.
+ * Moves the avatar to a new position, with safe landing, and enables collisions.
* @function MyAvatar.goToLocationAndEnableCollisions
* @param {Vec3} position - The new position for the avatar, in world coordinates.
*/
@@ -2297,43 +2346,52 @@ public slots:
virtual void setModelScale(float scale) override;
/**jsdoc
- * MyAvatar.getTriggerReactions
- * Returns a list of reactions names that can be triggered using MyAvatar.triggerReaction().
- * @returns {string[]} Array of reaction names.
+ * Gets the list of reactions names that can be triggered using {@link MyAvatar.triggerReaction}.
+ * See also: {@link MyAvatar.getBeginEndReactions}.
+ * @function MyAvatar.getTriggerReactions
+ * @returns {string[]} List of reaction names that can be triggered using {@link MyAvatar.triggerReaction}.
+ * @example List the available trigger reactions.
+ * print("Trigger reactions:", JSON.stringify(MyAvatar.getTriggerReactions()));
*/
QStringList getTriggerReactions() const;
/**jsdoc
- * MyAvatar.getBeginReactions
- * Returns a list of reactions names that can be enabled using MyAvatar.beginReaction() and MyAvatar.endReaction().
- * @returns {string[]} Array of reaction names.
+ * Gets the list of reactions names that can be enabled using {@link MyAvatar.beginReaction} and
+ * {@link MyAvatar.endReaction}.
+ * See also: {@link MyAvatar.getTriggerReactions}.
+ * @function MyAvatar.getBeginEndReactions
+ * @returns {string[]} List of reaction names that can be enabled using {@link MyAvatar.beginReaction} and
+ * {@link MyAvatar.endReaction}.
+ * @example List the available begin-end reactions.
+ * print("Begin-end reactions:", JSON.stringify(MyAvatar.getBeginEndReactions()));
*/
QStringList getBeginEndReactions() const;
/**jsdoc
- * MyAvatar.triggerReaction
- * Plays the given reaction on the avatar, once the reaction is complete it will automatically complete. Only reaction names returned from MyAvatar.getTriggerReactions() are available.
- * @param {string} reactionName - reaction name
- * @returns {bool} false if the given reaction is not supported.
+ * Plays a reaction on the avatar. Once the reaction is complete it will stop playing.
+ * Only reaction names returned by {@link MyAvatar.getTriggerReactions} are available.
+ * @function MyAvatar.triggerReaction
+ * @param {string} reactionName - The reaction to trigger.
+ * @returns {boolean} true if the reaction was played, false if the reaction is not supported.
*/
bool triggerReaction(QString reactionName);
/**jsdoc
- * MyAvatar.beginReaction
- * Plays the given reaction on the avatar. The avatar will continue to play the reaction until stopped via the MyAvatar.endReaction() call or superseeded by another reaction.
- * Only reaction names returned from MyAvatar.getBeginEndReactions() are available.
- * NOTE: the caller is responsible for calling the corresponding MyAvatar.endReaction(), otherwise the avatar might become stuck in the reaction forever.
- * @param {string} reactionName - reaction name
- * @returns {bool} false if the given reaction is not supported.
+ * Starts playing a reaction on the avatar. The reaction will continue to play until stopped using
+ * {@link MyAvatar.endReaction} or superseded by another reaction.
+ * Only reactions returned by {@link MyAvatar.getBeginEndReactions} are available.
+ * @function MyAvatar.beginReaction
+ * @param {string} reactionName - The reaction to start playing.
+ * @returns {boolean} true if the reaction was started, false if the reaction is not supported.
*/
bool beginReaction(QString reactionName);
/**jsdoc
- * MyAvatar.endReaction
- * Used to stop a given reaction that was started via MyAvatar.beginReaction().
- * @param {string} reactionName - reaction name
- * @returns {bool} false if the given reaction is not supported.
+ * Stops playing a reaction that was started using {@link MyAvatar.beginReaction}.
+ * @function MyAvatar.endReaction
+ * @param {string} reactionName - The reaction to stop playing.
+ * @returns {boolean} true if the reaction was stopped, false if the reaction is not supported.
*/
bool endReaction(QString reactionName);
@@ -2970,19 +3028,19 @@ private:
// correctly stored in _cachedAvatarEntityBlobs. These come from loadAvatarEntityDataFromSettings() and
// setAvatarEntityData(). These changes need to be extracted from _cachedAvatarEntityBlobs and applied to
// real EntityItems.
- std::vector _entitiesToDelete;
- std::vector _entitiesToAdd;
- std::vector _entitiesToUpdate;
+ std::vector _entitiesToDelete;
+ std::vector _entitiesToAdd;
+ std::vector _entitiesToUpdate;
//
// The _cachedAvatarEntityBlobsToDelete/Add/Update lists are for changes whose "authoritative sources" are
// already reflected in real EntityItems. These changes need to be propagated to _cachedAvatarEntityBlobs
// and eventually to settings.
- std::vector _cachedAvatarEntityBlobsToDelete;
- std::vector _cachedAvatarEntityBlobsToAddOrUpdate;
- std::vector _cachedAvatarEntityBlobUpdatesToSkip;
+ std::vector _cachedAvatarEntityBlobsToDelete;
+ std::vector _cachedAvatarEntityBlobsToAddOrUpdate;
+ std::vector _cachedAvatarEntityBlobUpdatesToSkip;
//
// Also these lists for tracking delayed changes to blobs and Settings
- mutable std::set _staleCachedAvatarEntityBlobs;
+ mutable std::set _staleCachedAvatarEntityBlobs;
//
// keep a ScriptEngine around so we don't have to instantiate on the fly (these are very slow to create/delete)
mutable std::mutex _scriptEngineLock;
diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp
index 1b88a518c8..4b6f85de1c 100644
--- a/interface/src/avatar/MyHead.cpp
+++ b/interface/src/avatar/MyHead.cpp
@@ -134,11 +134,11 @@ void MyHead::simulate(float deltaTime) {
userInputMapper->getActionStateValid(controller::Action::MOUTHSMILE_L) ||
userInputMapper->getActionStateValid(controller::Action::MOUTHSMILE_R);
- bool eyesTracked =
- userInputMapper->getPoseState(controller::Action::LEFT_EYE).valid &&
- userInputMapper->getPoseState(controller::Action::RIGHT_EYE).valid;
-
MyAvatar* myAvatar = static_cast(_owningAvatar);
+ bool eyesTracked =
+ myAvatar->getControllerPoseInSensorFrame(controller::Action::LEFT_EYE).valid &&
+ myAvatar->getControllerPoseInSensorFrame(controller::Action::RIGHT_EYE).valid;
+
int leftEyeJointIndex = myAvatar->getJointIndex("LeftEye");
int rightEyeJointIndex = myAvatar->getJointIndex("RightEye");
bool eyeJointsOverridden = myAvatar->getIsJointOverridden(leftEyeJointIndex) || myAvatar->getIsJointOverridden(rightEyeJointIndex);
diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp
index 50f6369dbe..aa6c074d08 100755
--- a/interface/src/avatar/OtherAvatar.cpp
+++ b/interface/src/avatar/OtherAvatar.cpp
@@ -561,9 +561,18 @@ void OtherAvatar::handleChangedAvatarEntityData() {
_avatarEntitiesLock.withReadLock([&] {
packedAvatarEntityData = _packedAvatarEntityData;
});
- foreach (auto entityID, recentlyRemovedAvatarEntities) {
- if (!packedAvatarEntityData.contains(entityID)) {
- entityTree->deleteEntity(entityID, true, true);
+ if (!recentlyRemovedAvatarEntities.empty()) {
+ std::vector idsToDelete;
+ idsToDelete.reserve(recentlyRemovedAvatarEntities.size());
+ foreach (auto entityID, recentlyRemovedAvatarEntities) {
+ if (!packedAvatarEntityData.contains(entityID)) {
+ idsToDelete.push_back(entityID);
+ }
+ }
+ if (!idsToDelete.empty()) {
+ bool force = true;
+ bool ignoreWarnings = true;
+ entityTree->deleteEntitiesByID(idsToDelete, force, ignoreWarnings);
}
}
diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp
index 2602bdb0a0..756c8fab7f 100644
--- a/interface/src/raypick/CollisionPick.cpp
+++ b/interface/src/raypick/CollisionPick.cpp
@@ -121,8 +121,9 @@ bool CollisionPick::isLoaded() const {
bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) {
if (_mathPick.shouldComputeShapeInfo()) {
if (_cachedResource && _cachedResource->isLoaded()) {
- computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource);
- _mathPick.loaded = true;
+ // TODO: Model CollisionPick support
+ //computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource);
+ //_mathPick.loaded = true;
} else {
_mathPick.loaded = false;
}
@@ -134,7 +135,7 @@ bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) {
return _mathPick.loaded;
}
-void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) {
+void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) {
ShapeType type = shapeInfo.getType();
glm::vec3 dimensions = pick.transform.getScale();
QString modelURL = (resource ? resource->getURL().toString() : "");
@@ -147,241 +148,12 @@ void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick,
}
}
-void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) {
- // This code was copied and modified from RenderableModelEntityItem::computeShapeInfo
- // TODO: Move to some shared code area (in entities-renderer? model-networking?)
- // after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo
- // to consolidate the code.
- // We may also want to make computeShapeInfo always abstract away from the gpu model mesh, like it does here.
- const uint32_t TRIANGLE_STRIDE = 3;
- const uint32_t QUAD_STRIDE = 4;
-
- ShapeType type = shapeInfo.getType();
- glm::vec3 dimensions = pick.transform.getScale();
- if (type == SHAPE_TYPE_COMPOUND) {
- // should never fall in here when collision model not fully loaded
- // TODO: assert that all geometries exist and are loaded
- //assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded());
- const HFMModel& collisionModel = resource->getHFMModel();
-
- ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
- pointCollection.clear();
- uint32_t i = 0;
-
- // the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect
- // to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case.
- foreach (const HFMMesh& mesh, collisionModel.meshes) {
- // each meshPart is a convex hull
- foreach (const HFMMeshPart &meshPart, mesh.parts) {
- pointCollection.push_back(QVector());
- ShapeInfo::PointList& pointsInPart = pointCollection[i];
-
- // run through all the triangles and (uniquely) add each point to the hull
- uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size();
- // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
- //assert(numIndices % TRIANGLE_STRIDE == 0);
- numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
-
- for (uint32_t j = 0; j < numIndices; j += TRIANGLE_STRIDE) {
- glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]];
- glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[j + 1]];
- glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[j + 2]];
- if (!pointsInPart.contains(p0)) {
- pointsInPart << p0;
- }
- if (!pointsInPart.contains(p1)) {
- pointsInPart << p1;
- }
- if (!pointsInPart.contains(p2)) {
- pointsInPart << p2;
- }
- }
-
- // run through all the quads and (uniquely) add each point to the hull
- numIndices = (uint32_t)meshPart.quadIndices.size();
- // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
- //assert(numIndices % QUAD_STRIDE == 0);
- numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
-
- for (uint32_t j = 0; j < numIndices; j += QUAD_STRIDE) {
- glm::vec3 p0 = mesh.vertices[meshPart.quadIndices[j]];
- glm::vec3 p1 = mesh.vertices[meshPart.quadIndices[j + 1]];
- glm::vec3 p2 = mesh.vertices[meshPart.quadIndices[j + 2]];
- glm::vec3 p3 = mesh.vertices[meshPart.quadIndices[j + 3]];
- if (!pointsInPart.contains(p0)) {
- pointsInPart << p0;
- }
- if (!pointsInPart.contains(p1)) {
- pointsInPart << p1;
- }
- if (!pointsInPart.contains(p2)) {
- pointsInPart << p2;
- }
- if (!pointsInPart.contains(p3)) {
- pointsInPart << p3;
- }
- }
-
- if (pointsInPart.size() == 0) {
- qCDebug(scriptengine) << "Warning -- meshPart has no faces";
- pointCollection.pop_back();
- continue;
- }
- ++i;
- }
- }
-
- // We expect that the collision model will have the same units and will be displaced
- // from its origin in the same way the visual model is. The visual model has
- // been centered and probably scaled. We take the scaling and offset which were applied
- // to the visual model and apply them to the collision model (without regard for the
- // collision model's extents).
-
- glm::vec3 scaleToFit = dimensions / resource->getHFMModel().getUnscaledMeshExtents().size();
- // multiply each point by scale
- for (int32_t i = 0; i < pointCollection.size(); i++) {
- for (int32_t j = 0; j < pointCollection[i].size(); j++) {
- // back compensate for registration so we can apply that offset to the shapeInfo later
- pointCollection[i][j] = scaleToFit * pointCollection[i][j];
- }
- }
- shapeInfo.setParams(type, dimensions, resource->getURL().toString());
- } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
- const HFMModel& hfmModel = resource->getHFMModel();
- int numHFMMeshes = hfmModel.meshes.size();
- int totalNumVertices = 0;
- for (int i = 0; i < numHFMMeshes; i++) {
- const HFMMesh& mesh = hfmModel.meshes.at(i);
- totalNumVertices += mesh.vertices.size();
- }
- const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6;
- if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) {
- qWarning() << "model" << "has too many vertices" << totalNumVertices << "and will collide as a box.";
- shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
- return;
- }
-
- auto& meshes = resource->getHFMModel().meshes;
- int32_t numMeshes = (int32_t)(meshes.size());
-
- const int MAX_ALLOWED_MESH_COUNT = 1000;
- if (numMeshes > MAX_ALLOWED_MESH_COUNT) {
- // too many will cause the deadlock timer to throw...
- shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
- return;
- }
-
- ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
- pointCollection.clear();
- if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
- pointCollection.resize(numMeshes);
- } else {
- pointCollection.resize(1);
- }
-
- ShapeInfo::TriangleIndices& triangleIndices = shapeInfo.getTriangleIndices();
- triangleIndices.clear();
-
- Extents extents;
- int32_t meshCount = 0;
- int32_t pointListIndex = 0;
- for (auto& mesh : meshes) {
- if (!mesh.vertices.size()) {
- continue;
- }
- QVector vertices = mesh.vertices;
-
- ShapeInfo::PointList& points = pointCollection[pointListIndex];
-
- // reserve room
- int32_t sizeToReserve = (int32_t)(vertices.count());
- if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
- // a list of points for each mesh
- pointListIndex++;
- } else {
- // only one list of points
- sizeToReserve += (int32_t)points.size();
- }
- points.reserve(sizeToReserve);
-
- // copy points
- const glm::vec3* vertexItr = vertices.cbegin();
- while (vertexItr != vertices.cend()) {
- glm::vec3 point = *vertexItr;
- points.push_back(point);
- extents.addPoint(point);
- ++vertexItr;
- }
-
- if (type == SHAPE_TYPE_STATIC_MESH) {
- // copy into triangleIndices
- size_t triangleIndicesCount = 0;
- for (const HFMMeshPart& meshPart : mesh.parts) {
- triangleIndicesCount += meshPart.triangleIndices.count();
- }
- triangleIndices.reserve((int)triangleIndicesCount);
-
- for (const HFMMeshPart& meshPart : mesh.parts) {
- const int* indexItr = meshPart.triangleIndices.cbegin();
- while (indexItr != meshPart.triangleIndices.cend()) {
- triangleIndices.push_back(*indexItr);
- ++indexItr;
- }
- }
- } else if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
- // for each mesh copy unique part indices, separated by special bogus (flag) index values
- for (const HFMMeshPart& meshPart : mesh.parts) {
- // collect unique list of indices for this part
- std::set uniqueIndices;
- auto numIndices = meshPart.triangleIndices.count();
- // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
- //assert(numIndices% TRIANGLE_STRIDE == 0);
- numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
-
- auto indexItr = meshPart.triangleIndices.cbegin();
- while (indexItr != meshPart.triangleIndices.cend()) {
- uniqueIndices.insert(*indexItr);
- ++indexItr;
- }
-
- // store uniqueIndices in triangleIndices
- triangleIndices.reserve(triangleIndices.size() + (int32_t)uniqueIndices.size());
- for (auto index : uniqueIndices) {
- triangleIndices.push_back(index);
- }
- // flag end of part
- triangleIndices.push_back(END_OF_MESH_PART);
- }
- // flag end of mesh
- triangleIndices.push_back(END_OF_MESH);
- }
- ++meshCount;
- }
-
- // scale and shift
- glm::vec3 extentsSize = extents.size();
- glm::vec3 scaleToFit = dimensions / extentsSize;
- for (int32_t i = 0; i < 3; ++i) {
- if (extentsSize[i] < 1.0e-6f) {
- scaleToFit[i] = 1.0f;
- }
- }
- for (auto points : pointCollection) {
- for (int32_t i = 0; i < points.size(); ++i) {
- points[i] = (points[i] * scaleToFit);
- }
- }
-
- shapeInfo.setParams(type, 0.5f * dimensions, resource->getURL().toString());
- }
-}
-
CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, bool scaleWithParent, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine) :
Pick(collisionRegion, filter, maxDistance, enabled),
_scaleWithParent(scaleWithParent),
_physicsEngine(physicsEngine) {
if (collisionRegion.shouldComputeShapeInfo()) {
- _cachedResource = DependencyManager::get()->getCollisionGeometryResource(collisionRegion.modelURL);
+ _cachedResource = DependencyManager::get()->getCollisionModelResource(collisionRegion.modelURL);
}
_mathPick.loaded = isLoaded();
}
diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h
index 24317bf19a..617c7b1f00 100644
--- a/interface/src/raypick/CollisionPick.h
+++ b/interface/src/raypick/CollisionPick.h
@@ -63,14 +63,13 @@ protected:
bool isLoaded() const;
// Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use.
bool getShapeInfoReady(const CollisionRegion& pick);
- void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource);
- void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource);
+ void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource);
void filterIntersections(std::vector& intersections) const;
bool _scaleWithParent;
PhysicsEnginePointer _physicsEngine;
- QSharedPointer _cachedResource;
+ QSharedPointer _cachedResource;
// Options for what information to get from collision results
bool _includeNormals;
diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp
index 3a7b67a8e9..1f940f761d 100644
--- a/interface/src/raypick/PickScriptingInterface.cpp
+++ b/interface/src/raypick/PickScriptingInterface.cpp
@@ -99,9 +99,11 @@ PickFilter getPickFilter(unsigned int filter) {
* @property {Vec3} [dirOffset] - Synonym for direction .
* @property {Quat} [orientation] - Alternative property for specifying direction . The value is applied to the
* default direction value.
- * @property {PickType} pickType - The type of pick when getting these properties from {@link Picks.getPickProperties} or {@link Picks.getPickScriptParameters}. A ray pick's type is {@link PickType.Ray}.
- * @property {Vec3} baseScale - Returned from {@link Picks.getPickProperties} when the pick has a parent with varying scale (usually an avatar or an entity).
- * Its value is the original scale of the parent at the moment the pick was created, and is used to scale the pointer which owns this pick, if any.
+ * @property {PickType} pickType - The type of pick when getting these properties from {@link Picks.getPickProperties} or
+ * {@link Picks.getPickScriptParameters}. A ray pick's type is {@link PickType.Ray}.
+ * @property {Vec3} baseScale - Returned from {@link Picks.getPickProperties} when the pick has a parent with varying scale
+ * (usually an avatar or an entity). Its value is the original scale of the parent at the moment the pick was created, and
+ * is used to scale the pointer which owns this pick, if any.
*/
std::shared_ptr PickScriptingInterface::buildRayPick(const QVariantMap& propMap) {
#if defined (Q_OS_ANDROID)
@@ -170,7 +172,8 @@ std::shared_ptr PickScriptingInterface::buildRayPick(const QVariantMa
* means no maximum.
* @property {Vec3} [tipOffset=0,0.095,0] - The position of the stylus tip relative to the hand position at default avatar
* scale.
- * @property {PickType} pickType - The type of pick when getting these properties from {@link Picks.getPickProperties} or {@link Picks.getPickScriptParameters}. A stylus pick's type is {@link PickType.Stylus}.
+ * @property {PickType} pickType - The type of pick when getting these properties from {@link Picks.getPickProperties} or
+ * {@link Picks.getPickScriptParameters}. A stylus pick's type is {@link PickType.Stylus}.
*/
std::shared_ptr PickScriptingInterface::buildStylusPick(const QVariantMap& propMap) {
bilateral::Side side = bilateral::Side::Invalid;
@@ -204,7 +207,8 @@ std::shared_ptr PickScriptingInterface::buildStylusPick(const QVarian
return std::make_shared(side, filter, maxDistance, enabled, tipOffset);
}
-// NOTE: Laser pointer still uses scaleWithAvatar. Until scaleWithAvatar is also deprecated for pointers, scaleWithAvatar should not be removed from the pick API.
+// NOTE: Laser pointer still uses scaleWithAvatar. Until scaleWithAvatar is also deprecated for pointers, scaleWithAvatar
+// should not be removed from the pick API.
/**jsdoc
* The properties of a parabola pick.
*
@@ -245,9 +249,11 @@ std::shared_ptr PickScriptingInterface::buildStylusPick(const QVarian
* with the avatar or other parent.
* @property {boolean} [scaleWithAvatar=true] - Synonym for scalewithParent .
* Deprecated: This property is deprecated and will be removed.
- * @property {PickType} pickType - The type of pick when getting these properties from {@link Picks.getPickProperties} or {@link Picks.getPickScriptParameters}. A parabola pick's type is {@link PickType.Parabola}.
- * @property {Vec3} baseScale - Returned from {@link Picks.getPickProperties} when the pick has a parent with varying scale (usually an avatar or an entity).
- * Its value is the original scale of the parent at the moment the pick was created, and is used to rescale the pick, and/or the pointer which owns this pick, if any.
+ * @property {PickType} pickType - The type of pick when getting these properties from {@link Picks.getPickProperties} or
+ * {@link Picks.getPickScriptParameters}. A parabola pick's type is {@link PickType.Parabola}.
+ * @property {Vec3} baseScale - Returned from {@link Picks.getPickProperties} when the pick has a parent with varying scale
+ * (usually an avatar or an entity). Its value is the original scale of the parent at the moment the pick was created, and
+ * is used to rescale the pick and the pointer which owns this pick, if any.
*/
std::shared_ptr PickScriptingInterface::buildParabolaPick(const QVariantMap& propMap) {
bool enabled = false;
diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h
index e26b91b9a2..58ed3326ec 100644
--- a/interface/src/raypick/PickScriptingInterface.h
+++ b/interface/src/raypick/PickScriptingInterface.h
@@ -52,6 +52,10 @@
* Read-only.
* Warning: Not yet implemented.
*
+ * @property {FilterFlags} PICK_BYPASS_IGNORE - Allows pick to intersect entities even when their
+ * ignorePickIntersection property value is true . For debug purposes.
+ * Read-only.
+ *
* @property {IntersectionType} INTERSECTED_NONE - Intersected nothing. Read-only.
* @property {IntersectionType} INTERSECTED_ENTITY - Intersected an entity. Read-only.
* @property {IntersectionType} INTERSECTED_LOCAL_ENTITY - Intersected a local entity. Read-only.
@@ -87,6 +91,8 @@ class PickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
+ Q_PROPERTY(unsigned int PICK_BYPASS_IGNORE READ PICK_BYPASS_IGNORE CONSTANT)
+
Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_LOCAL_ENTITY READ INTERSECTED_LOCAL_ENTITY CONSTANT)
@@ -147,19 +153,20 @@ public:
* Gets the current properties of the pick.
* @function Picks.getPickProperties
* @param {number} id - The ID of the pick.
- * @returns {Picks.RayPickProperties|Picks.ParabolaPickProperties|Picks.StylusPickProperties|Picks.CollisionPickProperties} Properties of the pick, per the pick type .
+ * @returns {Picks.RayPickProperties|Picks.ParabolaPickProperties|Picks.StylusPickProperties|Picks.CollisionPickProperties}
+ * Properties of the pick, per the pick type .
*/
Q_INVOKABLE QVariantMap getPickProperties(unsigned int uid) const;
/**jsdoc
- * Gets the parameters that were passed in to {@link Picks.createPick} to create the pick,
- * if the pick was created through a script.
- * Note that these properties do not reflect the current state of the pick.
- * See {@link Picks.getPickProperties}.
- * @function Picks.getPickScriptParameters
- * @param {number} id - The ID of the pick.
- * @returns {Picks.RayPickProperties|Picks.ParabolaPickProperties|Picks.StylusPickProperties|Picks.CollisionPickProperties} User-provided properties, per the pick type .
- */
+ * Gets the parameters that were passed in to {@link Picks.createPick} to create the pick, if the pick was created through
+ * a script. Note that these properties do not reflect the current state of the pick.
+ * See {@link Picks.getPickProperties}.
+ * @function Picks.getPickScriptParameters
+ * @param {number} id - The ID of the pick.
+ * @returns {Picks.RayPickProperties|Picks.ParabolaPickProperties|Picks.StylusPickProperties|Picks.CollisionPickProperties}
+ * Script-provided properties, per the pick type .
+ */
Q_INVOKABLE QVariantMap getPickScriptParameters(unsigned int uid) const;
/**jsdoc
@@ -282,6 +289,8 @@ public:
unsigned int getPerFrameTimeBudget() const;
void setPerFrameTimeBudget(unsigned int numUsecs);
+ static constexpr unsigned int PICK_BYPASS_IGNORE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_BYPASS_IGNORE); }
+
public slots:
/**jsdoc
diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp
index 3520aacbd0..a3aeb314e5 100644
--- a/interface/src/raypick/PointerScriptingInterface.cpp
+++ b/interface/src/raypick/PointerScriptingInterface.cpp
@@ -89,10 +89,13 @@ QVariantMap PointerScriptingInterface::getPointerScriptParameters(unsigned int u
* @property {Pointers.StylusPointerModel} [model] - Override some or all of the default stylus model properties.
* @property {boolean} [hover=false] - true if the pointer generates {@link Entities} hover events,
* false if it doesn't.
- * @property {PickType} pointerType - The type of pointer when getting these properties from {@link Pointers.getPointerProperties} or {@link Pointers.getPointerScriptParameters}. A stylus pointer's type is {@link PickType.Stylus}.
- * @property {number} [pickID] - Returned from {@link Pointers.getPointerProperties}. The ID of the pick created alongside this pointer.
+ * @property {PickType} pointerType - The type of the stylus pointer returned from {@link Pointers.getPointerProperties}
+ * or {@link Pointers.getPointerScriptParameters}. A stylus pointer's type is {@link PickType(0)|PickType.Stylus}.
+ * @property {number} [pickID] - The ID of the pick created alongside this pointer, returned from
+ * {@link Pointers.getPointerProperties}.
* @see {@link Picks.StylusPickProperties} for additional properties from the underlying stylus pick.
*/
+
/**jsdoc
* The properties of a stylus pointer model.
* @typedef {object} Pointers.StylusPointerModel
@@ -208,8 +211,10 @@ std::shared_ptr PointerScriptingInterface::buildStylus(const QVariant&
* false if it doesn't.
* @property {Pointers.Trigger[]} [triggers=[]] - A list of ways that a {@link Controller} action or function should trigger
* events on the entity or overlay currently intersected.
- * @property {PickType} pointerType - The type of pointer when getting these properties from {@link Pointers.getPointerProperties} or {@link Pointers.getPointerScriptParameters}. A laser pointer's type is {@link PickType.Ray}.
- * @property {number} [pickID] - Returned from {@link Pointers.getPointerProperties}. The ID of the pick created alongside this pointer.
+ * @property {PickType} pointerType - The type of pointer returned from {@link Pointers.getPointerProperties} or
+ * {@link Pointers.getPointerScriptParameters}. A laser pointer's type is {@link PickType(0)|PickType.Ray}.
+ * @property {number} [pickID] - The ID of the pick created alongside this pointer, returned from
+ * {@link Pointers.getPointerProperties}.
* @see {@link Picks.RayPickProperties} for additional properties from the underlying ray pick.
*/
std::shared_ptr PointerScriptingInterface::buildLaserPointer(const QVariant& properties) {
@@ -401,8 +406,10 @@ std::shared_ptr PointerScriptingInterface::buildLaserPointer(const QVar
* false if it doesn't.
* @property {Pointers.Trigger[]} [triggers=[]] - A list of ways that a {@link Controller} action or function should trigger
* events on the entity or overlay currently intersected.
- * @property {PickType} pointerType - The type of pointer when getting these properties from {@link Pointers.getPointerProperties} or {@link Pointers.getPointerScriptParameters}. A parabola pointer's type is {@link PickType.Parabola}.
- * @property {number} [pickID] - Returned from {@link Pointers.getPointerProperties}. The ID of the pick created alongside this pointer.
+ * @property {PickType} pointerType - The type of pointer returned from {@link Pointers.getPointerProperties} or
+ * {@link Pointers.getPointerScriptParameters}. A parabola pointer's type is {@link PickType(0)|PickType.Parabola}.
+ * @property {number} [pickID] - The ID of the pick created alongside this pointer, returned from
+ * {@link Pointers.getPointerProperties}.
* @see {@link Picks.ParabolaPickProperties} for additional properties from the underlying parabola pick.
*/
std::shared_ptr PointerScriptingInterface::buildParabolaPointer(const QVariant& properties) {
diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h
index 2d2f3f6dae..555136e7a7 100644
--- a/interface/src/raypick/PointerScriptingInterface.h
+++ b/interface/src/raypick/PointerScriptingInterface.h
@@ -161,13 +161,14 @@ public:
Q_INVOKABLE void removePointer(unsigned int uid) const { DependencyManager::get()->removePointer(uid); }
/**jsdoc
- * Gets the parameters that were passed in to {@link Pointers.createPointer} to create the pointer,
- * if the pointer was created through a script.
- * Note that these properties do not reflect the current state of the pointer.
- * See {@link Pointers.getPointerProperties}.
+ * Gets the parameters that were passed in to {@link Pointers.createPointer} to create the pointer when the pointer was
+ * created through a script.
+ * Note: These properties do not reflect the current state of the pointer. To get the current state
+ * of the pointer, see {@link Pointers.getPointerProperties}.
* @function Pointers.getPointerScriptParameters
* @param {number} id - The ID of the pointer.
- * @returns {Pointers.RayPointerProperties|Picks.ParabolaPointerProperties|Picks.StylusPointerProperties} User-provided properties, per the pointer type .
+ * @returns {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|Pointers.StylusPointerProperties}
+ * Script-provided properties, per the pointer type .
*/
Q_INVOKABLE QVariantMap getPointerScriptParameters(unsigned int uid) const;
diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h
index 3ad637d0e6..288137e166 100644
--- a/interface/src/scripting/AccountServicesScriptingInterface.h
+++ b/interface/src/scripting/AccountServicesScriptingInterface.h
@@ -46,6 +46,7 @@ class AccountServicesScriptingInterface : public QObject {
* @hifi-avatar
*
* @namespace AccountServices
+ *
* @property {string} username - The user name of the user logged in. If there is no user logged in, it is
* "Unknown user" . Read-only.
* @property {boolean} loggedIn - true if the user is logged in, otherwise false .
@@ -61,6 +62,86 @@ class AccountServicesScriptingInterface : public QObject {
* — typically "https://metaverse.highfidelity.com" . Read-only.
*/
+ /**jsdoc
+ * The Account API provides functions that give information on user connectivity, visibility, and asset
+ * download progress.
+ *
+ * @deprecated This API is the same as the {@link AccountServices} API and will be removed.
+ *
+ * @hifi-interface
+ * @hifi-client-entity
+ * @hifi-avatar
+ *
+ * @namespace Account
+ *
+ * @property {string} username - The user name of the user logged in. If there is no user logged in, it is
+ * "Unknown user" . Read-only.
+ * @property {boolean} loggedIn - true if the user is logged in, otherwise false .
+ * Read-only.
+ * @property {string} findableBy - The user's visibility to other users:
+ *
+ * "none" — user appears offline.
+ * "friends" — user is visible only to friends.
+ * "connections" — user is visible to friends and connections.
+ * "all" — user is visible to everyone.
+ *
+ * @property {string} metaverseServerURL - The metaverse server that the user is authenticated against when logged in
+ * — typically "https://metaverse.highfidelity.com" . Read-only.
+ *
+ * @borrows AccountServices.getDownloadInfo as getDownloadInfo
+ * @borrows AccountServices.updateDownloadInfo as updateDownloadInfo
+ * @borrows AccountServices.isLoggedIn as isLoggedIn
+ * @borrows AccountServices.checkAndSignalForAccessToken as checkAndSignalForAccessToken
+ * @borrows AccountServices.logOut as logOut
+ *
+ * @borrows AccountServices.connected as connected
+ * @borrows AccountServices.disconnected as disconnected
+ * @borrows AccountServices.myUsernameChanged as myUsernameChanged
+ * @borrows AccountServices.downloadInfoChanged as downloadInfoChanged
+ * @borrows AccountServices.findableByChanged as findableByChanged
+ * @borrows AccountServices.loggedInChanged as loggedInChanged
+ */
+
+ /**jsdoc
+ * The GlobalServices API provides functions that give information on user connectivity, visibility, and asset
+ * download progress.
+ *
+ * @deprecated This API is the same as the {@link AccountServices} API and will be removed.
+ *
+ * @hifi-interface
+ * @hifi-client-entity
+ * @hifi-avatar
+ *
+ * @namespace GlobalServices
+ *
+ * @property {string} username - The user name of the user logged in. If there is no user logged in, it is
+ * "Unknown user" . Read-only.
+ * @property {boolean} loggedIn - true if the user is logged in, otherwise false .
+ * Read-only.
+ * @property {string} findableBy - The user's visibility to other users:
+ *
+ * "none" — user appears offline.
+ * "friends" — user is visible only to friends.
+ * "connections" — user is visible to friends and connections.
+ * "all" — user is visible to everyone.
+ *
+ * @property {string} metaverseServerURL - The metaverse server that the user is authenticated against when logged in
+ * — typically "https://metaverse.highfidelity.com" . Read-only.
+ *
+ * @borrows AccountServices.getDownloadInfo as getDownloadInfo
+ * @borrows AccountServices.updateDownloadInfo as updateDownloadInfo
+ * @borrows AccountServices.isLoggedIn as isLoggedIn
+ * @borrows AccountServices.checkAndSignalForAccessToken as checkAndSignalForAccessToken
+ * @borrows AccountServices.logOut as logOut
+ *
+ * @borrows AccountServices.connected as connected
+ * @borrows AccountServices.disconnected as disconnected
+ * @borrows AccountServices.myUsernameChanged as myUsernameChanged
+ * @borrows AccountServices.downloadInfoChanged as downloadInfoChanged
+ * @borrows AccountServices.findableByChanged as findableByChanged
+ * @borrows AccountServices.loggedInChanged as loggedInChanged
+ */
+
Q_PROPERTY(QString username READ getUsername NOTIFY myUsernameChanged)
Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged)
Q_PROPERTY(QString findableBy READ getFindableBy WRITE setFindableBy NOTIFY findableByChanged)
diff --git a/interface/src/scripting/DesktopScriptingInterface.cpp b/interface/src/scripting/DesktopScriptingInterface.cpp
index ae4af48cd6..f78f7853ca 100644
--- a/interface/src/scripting/DesktopScriptingInterface.cpp
+++ b/interface/src/scripting/DesktopScriptingInterface.cpp
@@ -30,21 +30,6 @@
* @property {InteractiveWindow.DockArea} LEFT - Dock to the left edge of the Interface window.
* @property {InteractiveWindow.DockArea} RIGHT - Dock to the right edge of the Interface window.
*/
-/**jsdoc
- * A docking location of an InteractiveWindow .
- *
- *
- * Value | Name | Description |
- *
- *
- * 0 | TOP | Dock to the top edge of the Interface window. |
- * 1 | BOTTOM | Dock to the bottom edge of the Interface window. |
- * 2 | LEFT | Dock to the left edge of the Interface window. |
- * 3 | RIGHT | Dock to the right edge of the Interface window. |
- *
- *
- * @typedef {number} InteractiveWindow.DockArea
- */
static const QVariantMap DOCK_AREA {
{ "TOP", DockArea::TOP },
{ "BOTTOM", DockArea::BOTTOM },
@@ -53,13 +38,17 @@ static const QVariantMap DOCK_AREA {
};
/**jsdoc
- * The possible "relative position anchors" of an InteractiveWindow . Used when defining the `relativePosition` property of an `InteractiveWindow`.
+ * The possible relative position anchors of an InteractiveWindow relative to the Interface window.
* @typedef {object} InteractiveWindow.RelativePositionAnchors
- * @property {InteractiveWindow.RelativePositionAnchor} NO_ANCHOR - Specifies that the position of the `InteractiveWindow` will not be relative to any part of the Interface window.
- * @property {InteractiveWindow.RelativePositionAnchor} TOP_LEFT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the top left of the Interface window.
- * @property {InteractiveWindow.RelativePositionAnchor} TOP_RIGHT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the top right of the Interface window.
- * @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_RIGHT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the bottom right of the Interface window.
- * @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_LEFT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the bottom left of the Interface window.
+ * @property {InteractiveWindow.RelativePositionAnchor} NO_ANCHOR - Position is not relative to any part of the Interface
+ * window.
+ * @property {InteractiveWindow.RelativePositionAnchor} TOP_LEFT - Position is offset from the top left of the Interface window.
+ * @property {InteractiveWindow.RelativePositionAnchor} TOP_RIGHT - Position is offset from the top right of the Interface
+ * window.
+ * @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_RIGHT - Position offset from the bottom right of the Interface
+ * window.
+ * @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_LEFT - Position is offset from the bottom left of the Interface
+ * window.
*/
static const QVariantMap RELATIVE_POSITION_ANCHOR {
{ "NO_ANCHOR", RelativePositionAnchor::NO_ANCHOR },
@@ -89,21 +78,6 @@ int DesktopScriptingInterface::getHeight() {
* @property {InteractiveWindow.PresentationMode} NATIVE - The window is displayed separately from the Interface window, as its
* own separate window.
*/
-/**jsdoc
- * A display mode for an InteractiveWindow .
- *
- *
- * Value | Name | Description |
- *
- *
- * 0 | VIRTUAL | The window is displayed inside Interface: in the desktop window in
- * desktop mode or on the HUD surface in HMD mode. |
- * 1 | NATIVE | The window is displayed separately from the Interface window, as its
- * own separate window. |
- *
- *
- * @typedef {number} InteractiveWindow.PresentationMode
- */
QVariantMap DesktopScriptingInterface::getPresentationMode() {
static QVariantMap presentationModes {
{ "VIRTUAL", Virtual },
diff --git a/interface/src/scripting/DesktopScriptingInterface.h b/interface/src/scripting/DesktopScriptingInterface.h
index c25f382891..e57d7a6805 100644
--- a/interface/src/scripting/DesktopScriptingInterface.h
+++ b/interface/src/scripting/DesktopScriptingInterface.h
@@ -22,7 +22,7 @@
/**jsdoc
* The Desktop API provides the dimensions of the computer screen, sets the opacity of the HUD surface, and
* enables QML and HTML windows to be shown inside or outside of Interface.
- *
+ *
* @namespace Desktop
*
* @hifi-interface
@@ -42,8 +42,8 @@
* @property {InteractiveWindow.DockAreas} DockArea - The possible docking locations of an {@link InteractiveWindow}: top,
* bottom, left, or right of the Interface window.
* Read-only.
- * @property {InteractiveWindow.RelativePositionAnchors} RelativePositionAnchor - The possible "relative position anchors" for an {@link InteractiveWindow}: top left,
- * top right, bottom right, or bottom left of the Interface window.
+ * @property {InteractiveWindow.RelativePositionAnchors} RelativePositionAnchor - The possible relative position anchors for an
+ * {@link InteractiveWindow}: none, top left, top right, bottom right, or bottom left of the Interface window.
* Read-only.
*/
class DesktopScriptingInterface : public QObject, public Dependency {
@@ -84,7 +84,7 @@ public:
* @param {string} url - The QML file that specifies the window content. The QML file can use a WebView
* control (defined by "WebView.qml" included in the Interface install) to embed an HTML web page (complete with
* EventBridge object).
- * @param {InteractiveWindow.Properties} [properties] - Initial window properties.
+ * @param {InteractiveWindow.WindowProperties} [properties] - Initial window properties.
* @returns {InteractiveWindow} A new window object.
* @example Open a dialog in its own window separate from Interface.
* var nativeWindow = Desktop.createWindow(Script.resourcesPath() + 'qml/OverlayWindowTest.qml', {
diff --git a/interface/src/scripting/DialogsManagerScriptingInterface.h b/interface/src/scripting/DialogsManagerScriptingInterface.h
index b223799cfe..ee1baeecf5 100644
--- a/interface/src/scripting/DialogsManagerScriptingInterface.h
+++ b/interface/src/scripting/DialogsManagerScriptingInterface.h
@@ -14,19 +14,56 @@
#include
+/**jsdoc
+ * The DialogsMamnager API provides facilities to work with some key dialogs.
+ *
+ * @namespace DialogsManager
+ *
+ * @hifi-interface
+ * @hifi-client-entity
+ * @hifi-avatar
+ */
+
class DialogsManagerScriptingInterface : public QObject {
Q_OBJECT
public:
DialogsManagerScriptingInterface();
static DialogsManagerScriptingInterface* getInstance();
+
+ /**jsdoc
+ * Currently performs no action.
+ * @function DialogsManager.showFeed
+ */
Q_INVOKABLE void showFeed();
public slots:
+ /**jsdoc
+ * Shows the "Goto" dialog.
+ * @function DialogsManager.showAddressBar
+ */
void showAddressBar();
+
+ /**jsdoc
+ * Hides the "Goto" dialog.
+ * @function DialogsManager.hideAddressBar
+ */
void hideAddressBar();
+
+ /**jsdoc
+ * Shows the login dialog.
+ * @function DialogsManager.showLoginDialog
+ */
void showLoginDialog();
signals:
+ /**jsdoc
+ * Triggered when the "Goto" dialog is opened or closed.
+ * Warning: Currently isn't always triggered.
+ * @function DialogsManager.addressBarShown
+ * @param {boolean} visible - true if the Goto dialog has been opened, false if it has been
+ * closed.
+ * @returns {Signal}
+ */
void addressBarShown(bool visible);
};
diff --git a/interface/src/scripting/PerformanceScriptingInterface.h b/interface/src/scripting/PerformanceScriptingInterface.h
index 92d4273dfb..8a7e403e5d 100644
--- a/interface/src/scripting/PerformanceScriptingInterface.h
+++ b/interface/src/scripting/PerformanceScriptingInterface.h
@@ -18,6 +18,18 @@
#include "../RefreshRateManager.h"
+/**jsdoc
+ * The Performance API provides control and information on graphics performance settings.
+ *
+ * @namespace Performance
+ *
+ * @hifi-interface
+ * @hifi-client-entity
+ * @hifi-avatar
+ *
+ * @property {Performance.PerformancePreset} performancePreset - The current graphics performance preset.
+ * @property {Performance.RefreshRateProfile} refreshRateProfile - The current refresh rate profile.
+ */
class PerformanceScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(PerformancePreset performancePreset READ getPerformancePreset WRITE setPerformancePreset NOTIFY settingsChanged)
@@ -25,6 +37,23 @@ class PerformanceScriptingInterface : public QObject {
public:
+ /**jsdoc
+ * Graphics performance presets.
+ *
+ *
+ * Value | Name | Description |
+ *
+ *
+ * 0 | UNKNOWN | Custom settings of world detail, rendering effects, and refresh
+ * rate. |
+ * 1 | LOW | Low world detail, no rendering effects, lo refresh rate. |
+ * 2 | MID | Medium world detail, some rendering effects, medium refresh
+ * rate. |
+ * 3 | HIGH | Maximum world detail, all rendering effects, high refresh rate. |
+ *
+ *
+ * @typedef {number} Performance.PerformancePreset
+ */
// PerformanceManager PerformancePreset tri state level enums
enum PerformancePreset {
UNKNOWN = PerformanceManager::PerformancePreset::UNKNOWN,
@@ -34,6 +63,23 @@ public:
};
Q_ENUM(PerformancePreset)
+ /**jsdoc
+ * Refresh rate profile.
+ *
+ *
+ * Value | Name | Description |
+ *
+ *
+ * 0 | ECO | Low refresh rate, which is reduced when Interface doesn't have focus or
+ * is minimized. |
+ * 1 | INTERACTIVE | Medium refresh rate, which is reduced when Interface doesn't have
+ * focus or is minimized. |
+ * 2 | REALTIME | High refresh rate, even when Interface doesn't have focus or is
+ * minimized. |
+ *
+ *
+ * @typedef {number} Performance.RefreshRateProfile
+ */
// Must match RefreshRateManager enums
enum RefreshRateProfile {
ECO = RefreshRateManager::RefreshRateProfile::ECO,
@@ -47,19 +93,81 @@ public:
public slots:
+ /**jsdoc
+ * Sets graphics performance to a preset.
+ * @function Performance.setPerformancePreset
+ * @param {Performance.PerformancePreset} performancePreset - The graphics performance preset to to use.
+ */
void setPerformancePreset(PerformancePreset performancePreset);
+
+ /**jsdoc
+ * Gets the current graphics performance preset in use.
+ * @function Performance.getPerformancePreset
+ * @returns {Performance.PerformancePreset} The current graphics performance preset in use.
+ */
PerformancePreset getPerformancePreset() const;
+
+ /**jsdoc
+ * Gets the names of the graphics performance presets.
+ * @function Performance.getPerformancePresetNames
+ * @returns {string[]} The names of the graphics performance presets. The array index values correspond to
+ * {@link Performance.PerformancePreset} values.
+ */
QStringList getPerformancePresetNames() const;
+
+ /**jsdoc
+ * Sets the curfrent refresh rate profile.
+ * @function Performance.setRefreshRateProfile
+ * @param {Performance.RefreshRateProfile} refreshRateProfile - The refresh rate profile.
+ */
void setRefreshRateProfile(RefreshRateProfile refreshRateProfile);
+
+ /**jsdoc
+ * Gets the current refresh rate profile in use.
+ * @function Performance.getRefreshRateProfile
+ * @returns {Performance.RefreshRateProfile} The refresh rate profile.
+ */
RefreshRateProfile getRefreshRateProfile() const;
+
+ /**jsdoc
+ * Gets the names of the refresh rate profiles.
+ * @function Performance.getRefreshRateProfileNames
+ * @returns {string[]} The names of the refresh rate profiles. The array index values correspond to
+ * {@link Performance.RefreshRateProfile} values.
+ */
QStringList getRefreshRateProfileNames() const;
+
+ /**jsdoc
+ * Gets the current target refresh rate, in Hz, per the current refresh rate profile and refresh rate regime if in desktop
+ * mode; a higher rate if in VR mode.
+ * @function Performance.getActiveRefreshRate
+ * @returns {number} The current target refresh rate, in Hz.
+ */
int getActiveRefreshRate() const;
+
+ /**jsdoc
+ * Gets the current user experience mode.
+ * @function Performance.getUXMode
+ * @returns {UXMode} The current user experience mode.
+ */
RefreshRateManager::UXMode getUXMode() const;
+
+ /**jsdoc
+ * Gets the current refresh rate regime that's in effect.
+ * @function Performance.getRefreshRateRegime
+ * @returns {RefreshRateRegime} The current refresh rate regime.
+ */
RefreshRateManager::RefreshRateRegime getRefreshRateRegime() const;
signals:
+
+ /**jsdoc
+ * Triggered when the performance preset or refresh rate profile is changed.
+ * @function Performance.settingsChanged
+ * @returns {Signal}
+ */
void settingsChanged();
private:
diff --git a/interface/src/scripting/RatesScriptingInterface.h b/interface/src/scripting/RatesScriptingInterface.h
index 5658ed99a0..6feef94d17 100644
--- a/interface/src/scripting/RatesScriptingInterface.h
+++ b/interface/src/scripting/RatesScriptingInterface.h
@@ -14,6 +14,41 @@
#include
+/**jsdoc
+ * The Rates API provides some information on current rendering performance.
+ *
+ * @namespace Rates
+ *
+ * @hifi-interface
+ * @hifi-client-entity
+ * @hifi-avatar
+ *
+ * @property {number} render - The rate at which new GPU frames are being created, in Hz.
+ * Read-only.
+ * @property {number} present - The rate at which the display plugin is presenting to the display device, in Hz.
+ * Read-only.
+ * @property {number} newFrame - The rate at which the display plugin is presenting new GPU frames, in Hz.
+ * Read-only.
+ * @property {number} dropped - The rate at which the display plugin is dropping GPU frames, in Hz.
+ * Read-only.
+ * @property {number} simulation - The rate at which the game loop is running, in Hz.
+ * Read-only.
+ *
+ * @example Report current rendering rates.
+ * // The rates to report.
+ * var rates = [
+ * "render",
+ * "present",
+ * "newFrame",
+ * "dropped",
+ * "simulation"
+ * ];
+ *
+ * // Report the rates.
+ * for (var i = 0; i < rates.length; i++) {
+ * print("Rates." + rates[i], "=", Rates[rates[i]]);
+ * }
+ */
class RatesScriptingInterface : public QObject {
Q_OBJECT
diff --git a/interface/src/scripting/ScreenshareScriptingInterface.cpp b/interface/src/scripting/ScreenshareScriptingInterface.cpp
new file mode 100644
index 0000000000..3bf8336fe4
--- /dev/null
+++ b/interface/src/scripting/ScreenshareScriptingInterface.cpp
@@ -0,0 +1,348 @@
+//
+// ScreenshareScriptingInterface.cpp
+// interface/src/scripting/
+//
+// Created by Milad Nazeri and Zach Fox on 2019-10-23.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "EntityScriptingInterface.h"
+#include "ScreenshareScriptingInterface.h"
+
+static const int SCREENSHARE_INFO_REQUEST_RETRY_TIMEOUT_MS = 300;
+ScreenshareScriptingInterface::ScreenshareScriptingInterface() {
+ auto esi = DependencyManager::get();
+ if (!esi) {
+ return;
+ }
+
+ // This signal/slot connection is used when the screen share local web entity sends an event bridge message.
+ QObject::connect(esi.data(), &EntityScriptingInterface::webEventReceived, this, &ScreenshareScriptingInterface::onWebEventReceived);
+
+ _requestScreenshareInfoRetryTimer = new QTimer;
+ _requestScreenshareInfoRetryTimer->setSingleShot(true);
+ _requestScreenshareInfoRetryTimer->setInterval(SCREENSHARE_INFO_REQUEST_RETRY_TIMEOUT_MS);
+ connect(_requestScreenshareInfoRetryTimer, &QTimer::timeout, this, &ScreenshareScriptingInterface::requestScreenshareInfo);
+
+ // This packet listener handles the packet containing information about the latest zone ID in which we are allowed to share.
+ auto nodeList = DependencyManager::get();
+ PacketReceiver& packetReceiver = nodeList->getPacketReceiver();
+ packetReceiver.registerListener(PacketType::AvatarZonePresence, this, "processAvatarZonePresencePacketOnClient");
+};
+
+ScreenshareScriptingInterface::~ScreenshareScriptingInterface() {
+ stopScreenshare();
+}
+
+void ScreenshareScriptingInterface::processAvatarZonePresencePacketOnClient(QSharedPointer message) {
+ QUuid zone = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
+
+ if (zone.isNull()) {
+ qWarning() << "Ignoring avatar zone presence packet that doesn't specify a zone.";
+ return;
+ }
+
+ // Set the last known authorized screenshare zone ID to the zone that the Domain Server just told us about.
+ _lastAuthorizedZoneID = zone;
+
+ // If we had previously started the screenshare process but knew that we weren't going to be authorized to screenshare,
+ // let's continue the screenshare process here.
+ if (_waitingForAuthorization) {
+ requestScreenshareInfo();
+ }
+}
+
+static const int MAX_NUM_SCREENSHARE_INFO_REQUEST_RETRIES = 5;
+void ScreenshareScriptingInterface::requestScreenshareInfo() {
+ // If the screenshare zone that we're currently in (i.e. `startScreenshare()` was called) is different from
+ // the zone in which we are authorized to screenshare...
+ // ...return early here and wait for the DS to send us a packet containing this zone's ID.
+ if (_screenshareZoneID != _lastAuthorizedZoneID) {
+ qDebug() << "Client not yet authorized to screenshare. Waiting for authorization message from domain server...";
+ _waitingForAuthorization = true;
+ return;
+ }
+
+ _waitingForAuthorization = false;
+
+ _requestScreenshareInfoRetries++;
+
+ if (_requestScreenshareInfoRetries >= MAX_NUM_SCREENSHARE_INFO_REQUEST_RETRIES) {
+ qDebug() << "Maximum number of retries for screenshare info exceeded. Screenshare will not function.";
+ return;
+ }
+
+ // Don't continue with any more of this logic if we can't get the `AccountManager` or `AddressManager`.
+ auto accountManager = DependencyManager::get();
+ if (!accountManager) {
+ return;
+ }
+ auto addressManager = DependencyManager::get();
+ if (!addressManager) {
+ return;
+ }
+
+ // Construct and send a request to the Metaverse to obtain the information
+ // necessary to start the screen sharing process.
+ // This request requires:
+ // 1. The domain ID of the domain in which the user's avatar is present
+ // 2. User authentication information that is automatically included when `sendRequest()` is passed
+ // with the `AccountManagerAuth::Required` argument.
+ // Note that this request will only return successfully if the Domain Server has already registered
+ // the user paired with the current domain with the Metaverse.
+ // See `DomainServer::screensharePresence()` for more info about that.
+
+ QString currentDomainID = uuidStringWithoutCurlyBraces(addressManager->getDomainID());
+ QString requestURLPath = "api/v1/domains/%1/screenshare";
+ JSONCallbackParameters callbackParams;
+ callbackParams.callbackReceiver = this;
+ callbackParams.jsonCallbackMethod = "handleSuccessfulScreenshareInfoGet";
+ callbackParams.errorCallbackMethod = "handleFailedScreenshareInfoGet";
+ accountManager->sendRequest(
+ requestURLPath.arg(currentDomainID),
+ AccountManagerAuth::Required,
+ QNetworkAccessManager::GetOperation,
+ callbackParams
+ );
+}
+
+static const EntityTypes::EntityType LOCAL_SCREENSHARE_WEB_ENTITY_TYPE = EntityTypes::Web;
+static const uint8_t LOCAL_SCREENSHARE_WEB_ENTITY_FPS = 30;
+// This is going to be a good amount of work to make this work dynamically for any screensize.
+// V1 will have only hardcoded values.
+// The `z` value here is dynamic.
+static const glm::vec3 LOCAL_SCREENSHARE_WEB_ENTITY_LOCAL_POSITION(0.0128f, -0.0918f, 0.0f);
+static const glm::vec3 LOCAL_SCREENSHARE_WEB_ENTITY_DIMENSIONS(3.6790f, 2.0990f, 0.0100f);
+static const QString LOCAL_SCREENSHARE_WEB_ENTITY_URL =
+ "https://content.highfidelity.com/Experiences/Releases/usefulUtilities/smartBoard/screenshareViewer/screenshareClient.html";
+static const QString LOCAL_SCREENSHARE_WEB_ENTITY_HOST_TYPE = "local";
+void ScreenshareScriptingInterface::startScreenshare(const QUuid& screenshareZoneID,
+ const QUuid& smartboardEntityID,
+ const bool& isPresenter) {
+ // We must start a new QProcess from the main thread.
+ if (QThread::currentThread() != thread()) {
+ QMetaObject::invokeMethod(this, "startScreenshare", Q_ARG(const QUuid&, screenshareZoneID),
+ Q_ARG(const QUuid&, smartboardEntityID), Q_ARG(const bool&, isPresenter));
+ return;
+ }
+
+ // These three private member variables are set now so that they may be used later during asynchronous
+ // callbacks.
+ _screenshareZoneID = screenshareZoneID;
+ _smartboardEntityID = smartboardEntityID;
+ _isPresenter = isPresenter;
+
+ // If we are presenting, and the screenshare process is already running, don't do anything else here.
+ if (_isPresenter && _screenshareProcess && _screenshareProcess->state() != QProcess::NotRunning) {
+ return;
+ }
+
+ // If we're presenting...
+ if (_isPresenter) {
+ // ...make sure we first reset this `std::unique_ptr`.
+ _screenshareProcess.reset(new QProcess(this));
+
+ // Ensure that the screenshare executable exists where we expect it to.
+ // Error out and reset the screen share state machine if the executable doesn't exist.
+ QFileInfo screenshareExecutable(SCREENSHARE_EXE_PATH);
+ if (!screenshareExecutable.exists() || !(screenshareExecutable.isFile() || screenshareExecutable.isBundle())) {
+ qDebug() << "Screenshare executable doesn't exist at" << SCREENSHARE_EXE_PATH;
+ stopScreenshare();
+ emit screenshareError();
+ return;
+ }
+ }
+
+ if (_requestScreenshareInfoRetryTimer && _requestScreenshareInfoRetryTimer->isActive()) {
+ _requestScreenshareInfoRetryTimer->stop();
+ }
+
+ _requestScreenshareInfoRetries = 0;
+ requestScreenshareInfo();
+}
+
+void ScreenshareScriptingInterface::stopScreenshare() {
+ // We can only deal with our Screen Share `QProcess` on the main thread.
+ if (QThread::currentThread() != thread()) {
+ QMetaObject::invokeMethod(this, "stopScreenshare");
+ return;
+ }
+
+ // If the retry timer is active, stop it.
+ if (_requestScreenshareInfoRetryTimer && _requestScreenshareInfoRetryTimer->isActive()) {
+ _requestScreenshareInfoRetryTimer->stop();
+ }
+
+ // If the Screen Share process is running...
+ if (_screenshareProcess && _screenshareProcess->state() != QProcess::NotRunning) {
+ //...terminate it and make sure that scripts know we terminated it by emitting
+ // `screenshareProcessTerminated()`.
+ _screenshareProcess->terminate();
+ }
+
+ // Delete the local web entity if we know about it here.
+ if (!_screenshareViewerLocalWebEntityUUID.isNull()) {
+ auto esi = DependencyManager::get();
+ if (esi) {
+ esi->deleteEntity(_screenshareViewerLocalWebEntityUUID);
+ }
+ }
+
+ // Reset all private member variables related to screen share here.
+ _screenshareViewerLocalWebEntityUUID = "{00000000-0000-0000-0000-000000000000}";
+ _token = "";
+ _projectAPIKey = "";
+ _sessionID = "";
+ _isPresenter = false;
+ _waitingForAuthorization = false;
+}
+
+// Called when the Metaverse returns the information necessary to start/view a screen share.
+void ScreenshareScriptingInterface::handleSuccessfulScreenshareInfoGet(QNetworkReply* reply) {
+ // Read the reply and get it into a format we understand.
+ QString answer = reply->readAll();
+ QByteArray answerByteArray = answer.toUtf8();
+ QJsonDocument answerJSONObject = QJsonDocument::fromJson(answerByteArray);
+
+ // This Metaverse endpoint will always return a status key/value pair of "success" if things went well.
+ QString status = answerJSONObject["status"].toString();
+ if (status != "success") {
+ qDebug() << "Error when retrieving screenshare info via HTTP. Error:" << reply->errorString();
+ stopScreenshare();
+ emit screenshareError();
+ return;
+ }
+
+ // Store the information necessary to start/view a screen share in these private member variables.
+ _token = answerJSONObject["token"].toString();
+ _projectAPIKey = answerJSONObject["projectApiKey"].toString();
+ _sessionID = answerJSONObject["sessionID"].toString();
+
+ // Make sure we have all of the info that we need.
+ if (_token.isEmpty() || _projectAPIKey.isEmpty() || _sessionID.isEmpty()) {
+ qDebug() << "Not all Screen Share information was retrieved from the backend. Stopping...";
+ stopScreenshare();
+ emit screenshareError();
+ return;
+ }
+
+ // If we're presenting:
+ // 1. Build a list of arguments that we're going to pass to the screen share Electron app.
+ // 2. Make sure we connect a signal/slot to know when the user quits the Electron app.
+ // 3. Start the screen share Electron app with the list of args from (1).
+ if (_isPresenter) {
+ QStringList arguments;
+ arguments << " ";
+ arguments << "--token=" + _token << " ";
+ arguments << "--projectAPIKey=" + _projectAPIKey << " ";
+ arguments << "--sessionID=" + _sessionID << " ";
+
+ connect(_screenshareProcess.get(), QOverload::of(&QProcess::finished),
+ [=](int exitCode, QProcess::ExitStatus exitStatus) {
+ stopScreenshare();
+ emit screenshareProcessTerminated();
+ });
+
+ _screenshareProcess->start(SCREENSHARE_EXE_PATH, arguments);
+ }
+
+ // Make sure we can grab the entity scripting interface. Error out if we can't.
+ auto esi = DependencyManager::get();
+ if (!esi) {
+ stopScreenshare();
+ emit screenshareError();
+ return;
+ }
+
+ // If, for some reason, we already have a record of a screen share local Web entity, delete it.
+ if (!_screenshareViewerLocalWebEntityUUID.isNull()) {
+ esi->deleteEntity(_screenshareViewerLocalWebEntityUUID);
+ }
+
+ // Set up the entity properties associated with the screen share local Web entity.
+ EntityItemProperties localScreenshareWebEntityProps;
+ localScreenshareWebEntityProps.setType(LOCAL_SCREENSHARE_WEB_ENTITY_TYPE);
+ localScreenshareWebEntityProps.setMaxFPS(LOCAL_SCREENSHARE_WEB_ENTITY_FPS);
+ glm::vec3 localPosition(LOCAL_SCREENSHARE_WEB_ENTITY_LOCAL_POSITION);
+ localPosition.z = _localWebEntityZOffset;
+ localScreenshareWebEntityProps.setLocalPosition(localPosition);
+ localScreenshareWebEntityProps.setSourceUrl(LOCAL_SCREENSHARE_WEB_ENTITY_URL);
+ localScreenshareWebEntityProps.setParentID(_smartboardEntityID);
+ localScreenshareWebEntityProps.setDimensions(LOCAL_SCREENSHARE_WEB_ENTITY_DIMENSIONS);
+
+ // The lines below will be used when writing the feature to support scaling the Smartboard entity to any arbitrary size.
+ //EntityPropertyFlags desiredSmartboardProperties;
+ //desiredSmartboardProperties += PROP_POSITION;
+ //desiredSmartboardProperties += PROP_DIMENSIONS;
+ //EntityItemProperties smartboardProps = esi->getEntityProperties(_smartboardEntityID, desiredSmartboardProperties);
+
+ // Add the screen share local Web entity to Interface's entity tree.
+ // When the Web entity loads the page specified by `LOCAL_SCREENSHARE_WEB_ENTITY_URL`, it will broadcast an Event Bridge
+ // message, which we will consume inside `ScreenshareScriptingInterface::onWebEventReceived()`.
+ _screenshareViewerLocalWebEntityUUID = esi->addEntity(localScreenshareWebEntityProps, LOCAL_SCREENSHARE_WEB_ENTITY_HOST_TYPE);
+}
+
+void ScreenshareScriptingInterface::handleFailedScreenshareInfoGet(QNetworkReply* reply) {
+ if (_requestScreenshareInfoRetries >= MAX_NUM_SCREENSHARE_INFO_REQUEST_RETRIES) {
+ qDebug() << "Failed to get screenshare info via HTTP after" << MAX_NUM_SCREENSHARE_INFO_REQUEST_RETRIES << "retries. Error:" << reply->errorString();
+ stopScreenshare();
+ emit screenshareError();
+ return;
+ }
+
+ _requestScreenshareInfoRetryTimer->start();
+}
+
+// This function will handle _all_ web events received via `EntityScriptingInterface::webEventReceived()`, including
+// those not related to screen sharing.
+void ScreenshareScriptingInterface::onWebEventReceived(const QUuid& entityID, const QVariant& message) {
+ // Bail early if the entity that sent the Web event isn't the one we care about.
+ if (entityID == _screenshareViewerLocalWebEntityUUID) {
+ // Bail early if we can't grab the Entity Scripting Interface.
+ auto esi = DependencyManager::get();
+ if (!esi) {
+ return;
+ }
+
+ // Web events received from the screen share Web JS will always be in stringified JSON format.
+ QByteArray jsonByteArray = QVariant(message).toString().toUtf8();
+ QJsonDocument jsonObject = QJsonDocument::fromJson(jsonByteArray);
+
+ // It should never happen where the screen share Web JS sends a message without the `app` key's value
+ // set to "screenshare".
+ if (jsonObject["app"] != "screenshare") {
+ return;
+ }
+
+ // The screen share Web JS only sends a message with one method: "eventBridgeReady". Handle it here.
+ if (jsonObject["method"] == "eventBridgeReady") {
+ // Stuff a JSON object full of information necessary for the screen share local Web entity
+ // to connect to the screen share session associated with the room in which the user's avatar is standing.
+ QJsonObject responseObject;
+ responseObject.insert("app", "screenshare");
+ responseObject.insert("method", "receiveConnectionInfo");
+ QJsonObject responseObjectData;
+ responseObjectData.insert("token", _token);
+ responseObjectData.insert("projectAPIKey", _projectAPIKey);
+ responseObjectData.insert("sessionID", _sessionID);
+ responseObject.insert("data", responseObjectData);
+
+ esi->emitScriptEvent(_screenshareViewerLocalWebEntityUUID, responseObject.toVariantMap());
+ }
+ }
+}
diff --git a/interface/src/scripting/ScreenshareScriptingInterface.h b/interface/src/scripting/ScreenshareScriptingInterface.h
new file mode 100644
index 0000000000..ec8f3cd619
--- /dev/null
+++ b/interface/src/scripting/ScreenshareScriptingInterface.h
@@ -0,0 +1,92 @@
+//
+// ScreenshareScriptingInterface.h
+// interface/src/scripting/
+//
+// Created by Milad Nazeri and Zach Fox on 2019-10-23.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_ScreenshareScriptingInterface_h
+#define hifi_ScreenshareScriptingInterface_h
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+class ScreenshareScriptingInterface : public QObject, public Dependency {
+ Q_OBJECT
+ Q_PROPERTY(float localWebEntityZOffset MEMBER _localWebEntityZOffset NOTIFY localWebEntityZOffsetChanged)
+public:
+ ScreenshareScriptingInterface();
+ ~ScreenshareScriptingInterface();
+
+ Q_INVOKABLE void startScreenshare(const QUuid& screenshareZoneID, const QUuid& smartboardEntityID, const bool& isPresenter = false);
+ Q_INVOKABLE void stopScreenshare();
+
+signals:
+ void screenshareError();
+ void screenshareProcessTerminated();
+ void startScreenshareViewer();
+ void localWebEntityZOffsetChanged(const float& newZOffset);
+
+private slots:
+ void processAvatarZonePresencePacketOnClient(QSharedPointer message);
+ void onWebEventReceived(const QUuid& entityID, const QVariant& message);
+ void handleSuccessfulScreenshareInfoGet(QNetworkReply* reply);
+ void handleFailedScreenshareInfoGet(QNetworkReply* reply);
+
+private:
+#if DEV_BUILD
+#ifdef Q_OS_WIN
+ const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/screenshare/hifi-screenshare-win32-x64/hifi-screenshare.exe" };
+#elif defined(Q_OS_MAC)
+ const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/../Resources/hifi-screenshare.app" };
+#else
+ // This path won't exist on other platforms, so the Screenshare Scripting Interface will exit early when invoked.
+ const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/screenshare/hifi-screenshare-other-os/hifi-screenshare" };
+#endif
+#else
+#ifdef Q_OS_WIN
+ const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare.exe" };
+#elif defined(Q_OS_MAC)
+ const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/../Resources/hifi-screenshare.app" };
+#else
+ // This path won't exist on other platforms, so the Screenshare Scripting Interface will exit early when invoked.
+ const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare" };
+#endif
+#endif
+
+ QTimer* _requestScreenshareInfoRetryTimer{ nullptr };
+ int _requestScreenshareInfoRetries{ 0 };
+ void requestScreenshareInfo();
+
+ // Empirically determined. The default value here can be changed in Screenshare scripts, which enables faster iteration when we discover
+ // positional issues with various Smartboard entities.
+ // The following four values are closely linked:
+ // 1. The z-offset of whiteboard polylines (`STROKE_FORWARD_OFFSET_M` in `drawSphereClient.js`).
+ // 2. The z-offset of the screenshare local web entity (`LOCAL_WEB_ENTITY_Z_OFFSET` in `smartboardZoneClient.js`).
+ // 3. The z-offset of the screenshare "glass bezel" (`DEFAULT_SMARTBOARD_SCREENSHARE_GLASS_PROPS` in `smartboardZoneClient.js`).
+ // 4. The z-offset of the screenshare "status icon" (handled in the screenshare JSON file).
+ float _localWebEntityZOffset{ 0.0375f };
+
+ std::unique_ptr _screenshareProcess{ nullptr };
+ QUuid _screenshareViewerLocalWebEntityUUID;
+ QString _token{ "" };
+ QString _projectAPIKey{ "" };
+ QString _sessionID{ "" };
+ QUuid _screenshareZoneID;
+ QUuid _smartboardEntityID;
+ bool _isPresenter{ false };
+
+ QUuid _lastAuthorizedZoneID;
+ bool _waitingForAuthorization{ false };
+};
+
+#endif // hifi_ScreenshareScriptingInterface_h
diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp
index d2147ac5cc..32f837668d 100644
--- a/interface/src/scripting/SelectionScriptingInterface.cpp
+++ b/interface/src/scripting/SelectionScriptingInterface.cpp
@@ -17,7 +17,7 @@ GameplayObjects::GameplayObjects() {
}
bool GameplayObjects::addToGameplayObjects(const QUuid& avatarID) {
- containsData = true;
+ _containsData = true;
if (std::find(_avatarIDs.begin(), _avatarIDs.end(), avatarID) == _avatarIDs.end()) {
_avatarIDs.push_back(avatarID);
}
@@ -29,7 +29,7 @@ bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) {
}
bool GameplayObjects::addToGameplayObjects(const EntityItemID& entityID) {
- containsData = true;
+ _containsData = true;
if (std::find(_entityIDs.begin(), _entityIDs.end(), entityID) == _entityIDs.end()) {
_entityIDs.push_back(entityID);
}
diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h
index 4386ee5ee6..f477a25b42 100644
--- a/interface/src/scripting/SelectionScriptingInterface.h
+++ b/interface/src/scripting/SelectionScriptingInterface.h
@@ -26,7 +26,7 @@ class GameplayObjects {
public:
GameplayObjects();
- bool getContainsData() const { return containsData; }
+ bool getContainsData() const { return _containsData; }
std::vector getAvatarIDs() const { return _avatarIDs; }
bool addToGameplayObjects(const QUuid& avatarID);
@@ -37,7 +37,7 @@ public:
bool removeFromGameplayObjects(const EntityItemID& entityID);
private:
- bool containsData { false };
+ bool _containsData { false };
std::vector _avatarIDs;
std::vector _entityIDs;
};
diff --git a/interface/src/scripting/WalletScriptingInterface.h b/interface/src/scripting/WalletScriptingInterface.h
index e9535ceb4e..849caa8427 100644
--- a/interface/src/scripting/WalletScriptingInterface.h
+++ b/interface/src/scripting/WalletScriptingInterface.h
@@ -145,7 +145,8 @@ signals:
/**jsdoc
* Triggered when a certified avatar entity's ownership check requested via
- * {@link WalletScriptingInterface.proveAvatarEntityOwnershipVerification|proveAvatarEntityOwnershipVerification} succeeds.
+ * {@link WalletScriptingInterface.proveAvatarEntityOwnershipVerification|proveAvatarEntityOwnershipVerification} or
+ * {@link ContextOverlay.requestOwnershipVerification} succeeds.
* @function WalletScriptingInterface.ownershipVerificationSuccess
* @param {Uuid} entityID - The ID of the avatar entity checked.
* @returns {Signal}
@@ -154,7 +155,8 @@ signals:
/**jsdoc
* Triggered when a certified avatar entity's ownership check requested via
- * {@link WalletScriptingInterface.proveAvatarEntityOwnershipVerification|proveAvatarEntityOwnershipVerification} fails.
+ * {@link WalletScriptingInterface.proveAvatarEntityOwnershipVerification|proveAvatarEntityOwnershipVerification} or
+ * {@link ContextOverlay.requestOwnershipVerification} fails.
* @function WalletScriptingInterface.ownershipVerificationFailed
* @param {Uuid} entityID - The ID of the avatar entity checked.
* @returns {Signal}
diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index 341b012c2d..0c2fdd1614 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -206,7 +206,7 @@ public slots:
void browseAsync(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
/**jsdoc
- * Prompts the user to specify the path and name of a file to save to. Displays a model dialog that navigates the directory
+ * Prompts the user to specify the path and name of a file to save to. Displays a modal dialog that navigates the directory
* tree and allows the user to type in a file name.
* @function Window.save
* @param {string} [title=""] - The title to display at the top of the dialog.
@@ -222,7 +222,7 @@ public slots:
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
/**jsdoc
- * Prompts the user to specify the path and name of a file to save to. Displays a non-model dialog that navigates the
+ * Prompts the user to specify the path and name of a file to save to. Displays a non-modal dialog that navigates the
* directory tree and allows the user to type in a file name. A {@link Window.saveFileChanged|saveFileChanged} signal is
* emitted when a file is specified; no signal is emitted if the user cancels the dialog.
* @function Window.saveAsync
@@ -325,7 +325,7 @@ public slots:
* @param {number} [aspectRatio=0] - The width/height ratio of the snapshot required. If the value is 0 , the
* full resolution is used (window dimensions in desktop mode; HMD display dimensions in HMD mode), otherwise one of the
* dimensions is adjusted in order to match the aspect ratio.
- * @param {string} [filename=""] - If a filename is not provided, the image is saved as "hifi-snap-by-<user
+ * @param {string} [filename=""] - If a filename is not provided, the image is saved as "vircadia-snap-by-<user
* name>-on-YYYY-MM-DD_HH-MM-SS".
* Still images are saved in JPEG or PNG format according to the extension provided — ".jpg" ,
* ".jpeg" , or ".png" — or if not provided then in JPEG format with an extension of
@@ -364,7 +364,7 @@ public slots:
* @function Window.takeSecondaryCameraSnapshot
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
* signal.
- * @param {string} [filename=""] - If a filename is not provided, the image is saved as "hifi-snap-by-<user
+ * @param {string} [filename=""] - If a filename is not provided, the image is saved as "vircadia-snap-by-<user
* name>-on-YYYY-MM-DD_HH-MM-SS".
* Images are saved in JPEG or PNG format according to the extension provided — ".jpg" ,
* ".jpeg" , or ".png" — or if not provided then in JPEG format with an extension of
@@ -383,7 +383,7 @@ public slots:
* otherwise it is saved as an equirectangular image.
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
* signal.
- * @param {string} [filename=""] - If a filename is not provided, the image is saved as "hifi-snap-by-<user
+ * @param {string} [filename=""] - If a filename is not provided, the image is saved as "vircadia-snap-by-<user
* name>-on-YYYY-MM-DD_HH-MM-SS".
* Images are saved in JPEG or PNG format according to the extension provided — ".jpg" ,
* ".jpeg" , or ".png" — or if not provided then in JPEG format with an extension of
@@ -818,8 +818,12 @@ signals:
/**jsdoc
* Triggered when "minimized" state of the Interface window changes.
* @function Window.minimizedChanged
- * @param {bool} isMinimized - true if the Interface window is now minimized; false otherwise.
+ * @param {boolean} isMinimized - true if the Interface window is minimized, false if it isn't.
* @returns {Signal}
+ * @example Report the "minimized" state of the Interface window when it changes.
+ * function onWindowMinimizedChanged(minimized) {
+ * print("Window minimized: " + minimized);
+ * }
*
* Window.minimizedChanged.connect(onWindowMinimizedChanged);
*/
diff --git a/interface/src/ui/AvatarCertifyBanner.cpp b/interface/src/ui/AvatarCertifyBanner.cpp
index 5101188885..3fe2ed2027 100644
--- a/interface/src/ui/AvatarCertifyBanner.cpp
+++ b/interface/src/ui/AvatarCertifyBanner.cpp
@@ -62,16 +62,7 @@ void AvatarCertifyBanner::show(const QUuid& avatarID) {
void AvatarCertifyBanner::clear() {
if (_active) {
- auto entityTreeRenderer = DependencyManager::get();
- EntityTreePointer entityTree = entityTreeRenderer->getTree();
- if (!entityTree) {
- return;
- }
-
- entityTree->withWriteLock([&] {
- entityTree->deleteEntity(_bannerID);
- });
-
+ DependencyManager::get()->deleteEntity(_bannerID);
_active = false;
}
}
diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index 6cc26e2409..0ac1f05737 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -129,8 +129,8 @@ void InteractiveWindow::emitMainWindowResizeEvent() {
}
/**jsdoc
- * A set of properties used when creating an InteractiveWindow .
- * @typedef {object} InteractiveWindow.Properties
+ * Property values used when creating an InteractiveWindow .
+ * @typedef {object} InteractiveWindow.WindowProperties
* @property {string} [title="InteractiveWindow] - The title of the window.
* @property {Vec2} [position] - The initial position of the window, in pixels.
* @property {Vec2} [size] - The initial size of the window, in pixels
@@ -142,13 +142,36 @@ void InteractiveWindow::emitMainWindowResizeEvent() {
* @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a NATIVE window is
* displayed. If used, the window is docked to the specified edge of the Interface window, otherwise the window is
* displayed as its own separate window.
- * @property {InteractiveWindow.AdditionalFlags} [additionalFlags=0] - Window behavior flags in addition to "native window flags" (minimize/maximize/close),
- * set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}.
- * Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum.
- * @property {InteractiveWindow.OverrideFlags} [overrideFlags=0] - Window behavior flags instead of the default window flags.
- * Set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}.
- * Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum.
+ * @property {InteractiveWindow.Flags} [additionalFlags=0] - Customizes window behavior.
+ * @property {InteractiveWindow.OverrideFlags} [overrideFlags=0] - Customizes window controls.
+
+ * @property {InteractiveWindow.RelativePositionAnchor} [relativePositionAnchor] - The anchor for the
+ * relativePosition , if used.
+ * @property {Vec2} [relativePosition] - The position of the window, relative to the relativePositionAnchor , in
+ * pixels. Excludes the window frame.
+ * @property {boolean} [isFullScreenWindow] - true to make the window full screen.
*/
+/**jsdoc
+ * A set of flags customizing InteractiveWindow controls. The value is constructed by using the |
+ * (bitwise OR) operator on the individual flag values..
+ *
+ *
+ * Value | Name | Description |
+ *
+ *
+ * 0x00000001 | Window | Displays the window as a window rather than a dialog. |
+ * 0x00001000 | WindowTitleHint | Adds a title bar. |
+ * | 0x00002000 | WindowSystemMenuHint | Adds a window system menu. |
+ * | 0x00004000 | WindowMinimizeButtonHint | Adds a minimize button. |
+ * | 0x00008000 | WindowMaximizeButtonHint | Adds a maximize button. |
+ * | 0x00040000 | WindowStaysOnTopHint | The window stays on top of other windows.
+ * Not used on Windows.
+ * | 0x08000000 | WindowCloseButtonHint | Adds a close button. |
+ * |
+ *
+ * @typedef {number} InteractiveWindow.OverrideFlags
+ */
+// OverrideFlags is per InteractiveWindow.qml.
InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties, bool restricted) {
InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native;
diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h
index fb10aac444..7c8897059f 100644
--- a/interface/src/ui/InteractiveWindow.h
+++ b/interface/src/ui/InteractiveWindow.h
@@ -76,12 +76,42 @@ namespace InteractiveWindowEnums {
};
Q_ENUM_NS(InteractiveWindowFlags);
+ /**jsdoc
+ * A display mode for an InteractiveWindow .
+ *
+ *
+ * Value | Name | Description |
+ *
+ *
+ * 0 | VIRTUAL | The window is displayed inside Interface: in the desktop window in
+ * desktop mode or on the HUD surface in HMD mode. |
+ * 1 | NATIVE | The window is displayed separately from the Interface window, as its
+ * own separate window. |
+ *
+ *
+ * @typedef {number} InteractiveWindow.PresentationMode
+ */
enum InteractiveWindowPresentationMode {
Virtual,
Native
};
Q_ENUM_NS(InteractiveWindowPresentationMode);
+ /**jsdoc
+ * A docking location of an InteractiveWindow .
+ *
+ *
+ * Value | Name | Description |
+ *
+ *
+ * 0 | TOP | Dock to the top edge of the Interface window. |
+ * 1 | BOTTOM | Dock to the bottom edge of the Interface window. |
+ * 2 | LEFT | Dock to the left edge of the Interface window. |
+ * 3 | RIGHT | Dock to the right edge of the Interface window. |
+ *
+ *
+ * @typedef {number} InteractiveWindow.DockArea
+ */
enum DockArea {
TOP,
BOTTOM,
@@ -90,6 +120,24 @@ namespace InteractiveWindowEnums {
};
Q_ENUM_NS(DockArea);
+ /**jsdoc
+ * The anchor for a relative position of an InteractiveWindow .
+ *
+ *
+ * Value | Name | Description |
+ *
+ *
+ * 0 | NO_ANCHOR | Position is not relative to any part of the Interface window. |
+ * 1 | TOP_LEFT | Position is offset from the top left of the Interface window. |
+ * 2 | TOP_RIGHT | Position is offset from the top right of the Interface window. |
+ * 3 | BOTTOM_RIGHT | Position offset from the bottom right of the Interface
+ * window. |
+ * 4 | BOTTOM_LEFFT | Position is offset from the bottom left of the Interface
+ * window. |
+ *
+ *
+ * @typedef {number} InteractiveWindow.RelativePositionAnchor
+ */
enum RelativePositionAnchor {
NO_ANCHOR,
TOP_LEFT,
@@ -110,13 +158,18 @@ using namespace InteractiveWindowEnums;
* Create using {@link Desktop.createWindow}.
*
* @class InteractiveWindow
+ * @hideconstructor
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {string} title - The title of the window.
- * @property {Vec2} position - The position of the window, in pixels.
+ * @property {Vec2} position - The absolute position of the window, in pixels.
+ * @property {InteractiveWindow.RelativePositionAnchor} relativePositionAnchor - The anchor for the
+ * relativePosition , if used.
+ * @property {Vec2} relativePosition - The position of the window, relative to the relativePositionAnchor , in
+ * pixels. Excludes the window frame.
* @property {Vec2} size - The size of the window, in pixels.
* @property {boolean} visible - true if the window is visible, false if it isn't.
* @property {InteractiveWindow.PresentationMode} presentationMode - The presentation mode of the window:
@@ -186,24 +239,24 @@ public slots:
* @example Send and receive messages with a QML window.
* // JavaScript file.
*
- * var qmlWindow = Desktop.createWindow(Script.resolvePath("QMLWindow.qml"), {
- * title: "QML Window",
+ * var interactiveWindow = Desktop.createWindow(Script.resolvePath("InteractiveWindow.qml"), {
+ * title: "Interactive Window",
* size: { x: 400, y: 300 }
* });
*
- * qmlWindow.fromQml.connect(function (message) {
+ * interactiveWindow.fromQml.connect(function (message) {
* print("Message received: " + message);
* });
*
* Script.setTimeout(function () {
- * qmlWindow.sendToQml("Hello world!");
+ * interactiveWindow.sendToQml("Hello world!");
* }, 2000);
*
* Script.scriptEnding.connect(function () {
- * qmlWindow.close();
+ * interactiveWindow.close();
* });
* @example
- * // QML file, "QMLWindow.qml".
+ * // QML file, "InteractiveWindow.qml".
*
* import QtQuick 2.5
* import QtQuick.Controls 1.4
@@ -227,7 +280,7 @@ public slots:
/**jsdoc
* Sends a message to an embedded HTML web page. To receive the message, the HTML page's script must connect to the
- * EventBridge that is automatically provided to the script:
+ * EventBridge that is automatically provided for the script:
* EventBridge.scriptEventReceived.connect(function(message) {
* ...
* });
@@ -239,8 +292,8 @@ public slots:
/**jsdoc
* @function InteractiveWindow.emitWebEvent
- * @param {object|string} message - The message.
- * @deprecated This function is deprecated and will be removed from the API.
+ * @param {object|string} message - Message.
+ * @deprecated This function is deprecated and will be removed.
*/
void emitWebEvent(const QVariant& webMessage);
@@ -318,9 +371,9 @@ signals:
/**jsdoc
* @function InteractiveWindow.scriptEventReceived
- * @param {object} message - The message.
+ * @param {object} message - Message.
* @returns {Signal}
- * @deprecated This signal is deprecated and will be removed from the API.
+ * @deprecated This signal is deprecated and will be removed.
*/
// InteractiveWindow content may include WebView requiring EventBridge.
void scriptEventReceived(const QVariant& message);
@@ -337,9 +390,8 @@ signals:
protected slots:
/**jsdoc
* @function InteractiveWindow.qmlToScript
- * @param {object} message
- * @returns {Signal}
- * @deprecated This signal is deprecated and will be removed from the API.
+ * @param {object} message - Message.
+ * @deprecated This method is deprecated and will be removed.
*/
void qmlToScript(const QVariant& message);
diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp
index bb9971e582..4882d6e5da 100644
--- a/interface/src/ui/Snapshot.cpp
+++ b/interface/src/ui/Snapshot.cpp
@@ -42,9 +42,9 @@
#include "Snapshot.h"
#include "SnapshotUploader.h"
-// filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg
+// filename format: vircadia-snap-by-%username%-on-%date%_%time%_@-%location%.jpg
// %1 <= username, %2 <= date and time, %3 <= current location
-const QString FILENAME_PATH_FORMAT = "hifi-snap-by-%1-on-%2.jpg";
+const QString FILENAME_PATH_FORMAT = "vircadia-snap-by-%1-on-%2.jpg";
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss";
const QString SNAPSHOTS_DIRECTORY = "Snapshots";
const QString URL = "highfidelity_url";
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index a9e2e4d8e3..b013bbff0d 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -251,7 +251,7 @@ void Stats::updateStats(bool force) {
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
auto audioClient = DependencyManager::get().data();
- if (audioMixerNode || force) {
+ if (audioMixerNode) {
STAT_UPDATE(audioMixerKbps, (int)roundf(audioMixerNode->getInboundKbps() +
audioMixerNode->getOutboundKbps()));
STAT_UPDATE(audioMixerPps, audioMixerNode->getInboundPPS() +
@@ -261,6 +261,7 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(audioMixerInPps, audioMixerNode->getInboundPPS());
STAT_UPDATE(audioMixerOutKbps, (int)roundf(audioMixerNode->getOutboundKbps()));
STAT_UPDATE(audioMixerOutPps, audioMixerNode->getOutboundPPS());
+ STAT_UPDATE(audioInboundPPS, (int)audioClient->getAudioInboundPPS());
STAT_UPDATE(audioAudioInboundPPS, (int)audioClient->getAudioInboundPPS());
STAT_UPDATE(audioSilentInboundPPS, (int)audioClient->getSilentInboundPPS());
STAT_UPDATE(audioOutboundPPS, (int)audioClient->getAudioOutboundPPS());
@@ -274,6 +275,7 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(audioMixerOutPps, -1);
STAT_UPDATE(audioOutboundPPS, -1);
STAT_UPDATE(audioSilentOutboundPPS, -1);
+ STAT_UPDATE(audioInboundPPS, -1);
STAT_UPDATE(audioAudioInboundPPS, -1);
STAT_UPDATE(audioSilentInboundPPS, -1);
}
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index 96f0ea725a..d4dc4d3307 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -24,6 +24,10 @@ private: \
type _##name{ initialValue };
/**jsdoc
+ * The Stats API provides statistics on Interface and domain operation, per the statistics overlay.
+ *
+ * Note: This API is primarily an internal diagnostics tool and is provided "as is".
+ *
* @namespace Stats
*
* @hifi-interface
@@ -32,159 +36,422 @@ private: \
* @hifi-server-entity
* @hifi-assignment-client
*
- * @property {boolean} expanded
- * @property {boolean} timingExpanded - Read-only.
- * @property {string} monospaceFont - Read-only.
+ * @property {boolean} expanded - true if the statistics overlay should be in expanded form when the overlay is
+ * displayed, false if it shouldn't be expanded.
+ * @property {boolean} timingExpanded - true if timing details should be displayed when the statistics overlay is
+ * displayed in expanded form, false if timing details should not be displayed. Set by the menu item,
+ * Developer > Timing > Performance Timer > Display Timing Details.
+ * Read-only.
+ * @property {string} monospaceFont - The name of the monospace font used in the statistics overlay.
+ * Read-only.
*
- * @property {number} serverCount - Read-only.
- * @property {number} renderrate - How often the app is creating new gpu::Frames. Read-only.
- * @property {number} presentrate - How often the display plugin is presenting to the device. Read-only.
- * @property {number} stutterrate - How often the display device is reprojecting old frames. Read-only.
+ * @property {number} serverCount - The number of servers that Interface is connected to.
+ * Read-only.
+ * @property {number} renderrate - The rate at which new GPU frames are being created, in Hz.
+ * Read-only.
+ * @property {number} presentrate - The rate at which the display plugin is presenting to the display device, in Hz.
+ * Read-only.
+ * @property {number} stutterrate - The rate at which the display plugin is reprojecting old GPU frames, in Hz.
+ * Read-only.
*
- * @property {number} appdropped - Read-only.
- * @property {number} longsubmits - Read-only.
- * @property {number} longrenders - Read-only.
- * @property {number} longframes - Read-only.
+ * @property {number} appdropped - The number of times a frame has not been provided to the display device in time.
+ * Read-only.
+ * @property {number} longsubmits - The number of times the display device has taken longer than 11ms to return after being
+ * given a frame.
+ * Read-only.
+ * @property {number} longrenders - The number of times it has taken longer than 11ms to submit a new frame to the display
+ * device.
+ * Read-only.
+ * @property {number} longframes - The number of times longsubmits + longrenders has taken longer than 15ms.
+ * Read-only.
*
- * @property {number} presentnewrate - Read-only.
- * @property {number} presentdroprate - Read-only.
- * @property {number} gameLoopRate - Read-only.
- * @property {number} avatarCount - Read-only.
- * @property {number} heroAvatarCount - Read-only.
- * @property {number} physicsObjectCount - Read-only.
- * @property {number} updatedAvatarCount - Read-only.
- * @property {number} updatedHeroAvatarCount - Read-only.
- * @property {number} notUpdatedAvatarCount - Read-only.
- * @property {number} packetInCount - Read-only.
- * @property {number} packetOutCount - Read-only.
- * @property {number} mbpsIn - Read-only.
- * @property {number} mbpsOut - Read-only.
- * @property {number} assetMbpsIn - Read-only.
- * @property {number} assetMbpsOut - Read-only.
- * @property {number} audioPing - Read-only.
- * @property {number} avatarPing - Read-only.
- * @property {number} entitiesPing - Read-only.
- * @property {number} assetPing - Read-only.
- * @property {number} messagePing - Read-only.
- * @property {Vec3} position - Read-only.
- * @property {number} speed - Read-only.
- * @property {number} yaw - Read-only.
- * @property {number} avatarMixerInKbps - Read-only.
- * @property {number} avatarMixerInPps - Read-only.
- * @property {number} avatarMixerOutKbps - Read-only.
- * @property {number} avatarMixerOutPps - Read-only.
- * @property {number} myAvatarSendRate - Read-only.
- *
- * @property {number} audioMixerInKbps - Read-only.
- * @property {number} audioMixerInPps - Read-only.
- * @property {number} audioMixerOutKbps - Read-only.
- * @property {number} audioMixerOutPps - Read-only.
- * @property {number} audioMixerKbps - Read-only.
- * @property {number} audioMixerPps - Read-only.
- * @property {number} audioOutboundPPS - Read-only.
- * @property {number} audioSilentOutboundPPS - Read-only.
- * @property {number} audioAudioInboundPPS - Read-only.
- * @property {number} audioSilentInboundPPS - Read-only.
- * @property {number} audioPacketLoss - Read-only.
- * @property {string} audioCodec - Read-only.
- * @property {string} audioNoiseGate - Read-only.
- * @property {Vec2} audioInjectors - Read-only.
- * @property {number} entityPacketsInKbps - Read-only.
- *
- * @property {number} downloads - Read-only.
- * @property {number} downloadLimit - Read-only.
- * @property {number} downloadsPending - Read-only.
- * @property {string[]} downloadUrls - Read-only.
- * @property {number} processing - Read-only.
- * @property {number} processingPending - Read-only.
- * @property {number} triangles - Read-only.
- * @property {number} materialSwitches - Read-only.
- * @property {number} itemConsidered - Read-only.
- * @property {number} itemOutOfView - Read-only.
- * @property {number} itemTooSmall - Read-only.
- * @property {number} itemRendered - Read-only.
- * @property {number} shadowConsidered - Read-only.
- * @property {number} shadowOutOfView - Read-only.
- * @property {number} shadowTooSmall - Read-only.
- * @property {number} shadowRendered - Read-only.
- * @property {string} sendingMode - Read-only.
- * @property {string} packetStats - Read-only.
- * @property {number} lodAngle - Read-only.
- * @property {number} lodTargetFramerate - Read-only.
- * @property {string} lodStatus - Read-only.
- * @property {string} numEntityUpdates - Read-only.
- * @property {string} numNeededEntityUpdates - Read-only.
- * @property {string} timingStats - Read-only.
- * @property {string} gameUpdateStats - Read-only.
- * @property {number} serverElements - Read-only.
- * @property {number} serverInternal - Read-only.
- * @property {number} serverLeaves - Read-only.
- * @property {number} localElements - Read-only.
- * @property {number} localInternal - Read-only.
- * @property {number} localLeaves - Read-only.
- * @property {number} rectifiedTextureCount - Read-only.
- * @property {number} decimatedTextureCount - Read-only.
- * @property {number} gpuBuffers - Read-only.
- * @property {number} gpuBufferMemory - Read-only.
- * @property {number} gpuTextures - Read-only.
- * @property {number} glContextSwapchainMemory - Read-only.
- * @property {number} qmlTextureMemory - Read-only.
- * @property {number} texturePendingTransfers - Read-only.
- * @property {number} gpuTextureMemory - Read-only.
- * @property {number} gpuTextureResidentMemory - Read-only.
- * @property {number} gpuTextureFramebufferMemory - Read-only.
- * @property {number} gpuTextureResourceMemory - Read-only.
- * @property {number} gpuTextureResourceIdealMemory - Read-only.
- * @property {number} gpuTextureResourcePopulatedMemory - Read-only.
- * @property {number} gpuTextureExternalMemory - Read-only.
- * @property {string} gpuTextureMemoryPressureState - Read-only.
- * @property {number} gpuFreeMemory - Read-only.
- * @property {number} gpuFrameTime - Read-only.
- * @property {number} batchFrameTime - Read-only.
- * @property {number} engineFrameTime - Read-only.
- * @property {number} avatarSimulationTime - Read-only.
- *
- *
- * @property {number} x
- * @property {number} y
- * @property {number} z
- * @property {number} width
- * @property {number} height
- *
- * @property {number} opacity
- * @property {boolean} enabled
- * @property {boolean} visible
- *
- * @property {string} state
- * @property {object} anchors - Read-only.
- * @property {number} baselineOffset
- *
- * @property {boolean} clip
- *
- * @property {boolean} focus
- * @property {boolean} activeFocus - Read-only.
- * @property {boolean} activeFocusOnTab
- *
- * @property {number} rotation
- * @property {number} scale
- * @property {number} transformOrigin
- *
- * @property {boolean} smooth
- * @property {boolean} antialiasing
- * @property {number} implicitWidth
- * @property {number} implicitHeight
- *
- * @property {object} layer - Read-only.
+ * @property {number} presentnewrate - The rate at which the display plugin is presenting new GPU frames, in Hz.
+ * Read-only.
+ * @property {number} presentdroprate - The rate at which the display plugin is dropping GPU frames, in Hz.
+ * Read-only.
- * @property {number} stylusPicksCount - Read-only.
- * @property {number} rayPicksCount - Read-only.
- * @property {number} parabolaPicksCount - Read-only.
- * @property {number} collisionPicksCount - Read-only.
- * @property {Vec3} stylusPicksUpdated - Read-only.
- * @property {Vec3} rayPicksUpdated - Read-only.
- * @property {Vec3} parabolaPicksUpdated - Read-only.
- * @property {Vec3} collisionPicksUpdated - Read-only.
- * @property {bool} eventQueueDebuggingOn - Read-only.
+ * @property {number} gameLoopRate - The rate at which the game loop is running, in Hz.
+ * Read-only.
+ * @property {number} refreshRateTarget - The current target refresh rate, in Hz, per the current refreshRateMode
+ * and refreshRateRegime if in desktop mode; a higher rate if in VR mode.
+ * Read-only.
+ * @property {RefreshRateProfileName} refreshRateMode - The current refresh rate profile.
+ * Read-only.
+ * @property {RefreshRateRegimeName} refreshRateRegime - The current refresh rate regime.
+ * Read-only.
+ * @property {UXModeName} uxMode - The user experience (UX) mode that Interface is running in.
+ * Read-only.
+ * @property {number} avatarCount - The number of avatars in the domain other than the client's.
+ * Read-only.
+ * @property {number} heroAvatarCount - The number avatars in a "hero" zone in the domain, other than the client's.
+ * Read-only.
+ * @property {number} physicsObjectCount - The number of objects that have collisions enabled.
+ * Read-only.
+ * @property {number} updatedAvatarCount - The number of avatars in the domain, other than the client's, that were updated in
+ * the most recent game loop.
+ * Read-only.
+ * @property {number} updatedHeroAvatarCount - The number of avatars in a "hero" zone in the domain, other than the client's,
+ * that were updated in the most recent game loop.
+ * Read-only.
+ * @property {number} notUpdatedAvatarCount - The number of avatars in the domain, other than the client's, that weren't able
+ * to be updated in the most recent game loop because there wasn't enough time to.
+ * Read-only.
+ * @property {number} packetInCount - The number of packets being received from the domain server, in packets per second.
+ * Read-only.
+ * @property {number} packetOutCount - The number of packets being sent to the domain server, in packets per second.
+ * Read-only.
+ * @property {number} mbpsIn - The amount of data being received from the domain server, in megabits per second.
+ * Read-only.
+ * @property {number} mbpsOut - The amount of data being sent to the domain server, in megabits per second.
+ * Read-only.
+ @property {number} assetMbpsIn - The amount of data being received from the asset server, in megabits per second.
+ * 0.0 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} assetMbpsOut - The amount of data being sent to the asset server, in megabits per second.
+ * 0.0 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} audioPing - The ping time to the audio mixer, in ms.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} avatarPing - The ping time to the avatar mixer, in ms.
+ * -1 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} entitiesPing - The average ping time to the entity servers, in ms.
+ * -1 if not connected to an entity server.
+ * Read-only.
+ * @property {number} assetPing - The ping time to the asset server, in ms.
+ * -1 if not connected to an asset server.
+ * Read-only.
+ * @property {number} messagePing - The ping time to the message mixer, in ms.
+ * -1 if not connected to a message mixer.
+ * Read-only.
+ * @property {Vec3} position - The position of the user's avatar.
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {number} speed - The speed of the user's avatar, in m/s.
+ * Read-only.
+ * @property {number} yaw - The yaw of the user's avatar body, in degrees.
+ * Read-only.
+ * @property {number} avatarMixerInKbps - The amount of data being received from the avatar mixer, in kilobits per second.
+ * -1 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} avatarMixerInPps - The number of packets being received from the avatar mixer, in packets per second.
+ * -1 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} avatarMixerOutKbps - The amount of data being sent to the avatar mixer, in kilobits per second.
+ * -1 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} avatarMixerOutPps - The number of packets being sent to the avatar mixer, in packets per second.
+ * -1 if not connected to an avatar mixer.
+ * Read-only.
+ * @property {number} myAvatarSendRate - The number of avatar packets being sent by the user's avatar, in packets per second.
+ * Read-only.
+ *
+ * @property {number} audioMixerInKbps - The amount of data being received from the audio mixer, in kilobits per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioMixerInPps - The number of packets being received from the audio mixer, in packets per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioMixerOutKbps - The amount of data being sent to the audio mixer, in kilobits per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioMixerOutPps - The number of packets being sent to the audio mixer, in packets per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioMixerKbps - The total amount of data being sent to and received from the audio mixer, in kilobits
+ * per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioMixerPps - The total number of packets being sent to and received from the audio mixer, in packets
+ * per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioOutboundPPS - The number of non-silent audio packets being sent by the user, in packets per second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioSilentOutboundPPS - The number of silent audio packets being sent by the user, in packets per
+ * second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioInboundPPS - The number of non-silent audio packets being received by the user, in packets per
+ * second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioAudioInboundPPS - The number of non-silent audio packets being received by the user, in packets per
+ * second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * Deprecated: This property is deprecated and will be removed. Use audioInboundPPS
+ * instead.
+ * @property {number} audioSilentInboundPPS - The number of silent audio packets being received by the user, in packets per
+ * second.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {number} audioPacketLoss - The number of audio packets being lost, sent to or received from the audio mixer, in %.
+ * -1 if not connected to an audio mixer.
+ * Read-only.
+ * @property {string} audioCodec - The name of the audio codec.
+ * Read-only.
+ * @property {string} audioNoiseGate - The status of the audio noise gate: "Open" or "Closed" .
+ * Read-only.
+ * @property {Vec2} audioInjectors - The number of audio injectors, local and non-local.
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {number} entityPacketsInKbps - The average amount of data being received from entity servers, in kilobits per
+ * second. (Multiply by the number of entity servers to get the total amount of data being received.)
+ * -1 if not connected to an entity server.
+ * Read-only.
+ *
+ * @property {number} downloads - The number of downloads in progress.
+ * Read-only.
+ * @property {number} downloadLimit - The maximum number of concurrent downloads.
+ * Read-only.
+ * @property {number} downloadsPending - The number of downloads pending.
+ * Read-only.
+ * @property {string[]} downloadUrls - The download URLs.
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {number} processing - The number of completed downloads being processed.
+ * Read-only.
+ * @property {number} processingPending - The number of completed downloads waiting to be processed.
+ * Read-only.
+ * @property {number} triangles - The number of triangles in the rendered scene.
+ * Read-only.
+ * @property {number} drawcalls - The number of draw calls made for the rendered scene.
+ * Read-only.
+ * @property {number} materialSwitches - The number of material switches performed for the rendered scene.
+ * Read-only.
+ * @property {number} itemConsidered - The number of item considerations made for rendering.
+ * Read-only.
+ * @property {number} itemOutOfView - The number of items out of view.
+ * Read-only.
+ * @property {number} itemTooSmall - The number of items too small to render.
+ * Read-only.
+ * @property {number} itemRendered - The number of items rendered.
+ * Read-only.
+ * @property {number} shadowConsidered - The number of shadow considerations made for rendering.
+ * Read-only.
+ * @property {number} shadowOutOfView - The number of shadows out of view.
+ * Read-only.
+ * @property {number} shadowTooSmall - The number of shadows too small to render.
+ * Read-only.
+ * @property {number} shadowRendered - The number of shadows rendered.
+ * Read-only.
+ * @property {string} sendingMode - Description of the octree sending mode.
+ * Read-only.
+ * @property {string} packetStats - Description of the octree packet processing state.
+ * Read-only.
+ * @property {number} lodAngle - The target LOD angle, in degrees.
+ * Read-only.
+ * @property {number} lodTargetFramerate - The target LOD frame rate, in Hz.
+ * Read-only.
+ * @property {string} lodStatus - Description of the current LOD.
+ * Read-only.
+ * @property {string} numEntityUpdates - The number of entity updates that happened last frame.
+ * Read-only.
+ * @property {string} numNeededEntityUpdates - The total number of entity updates scheduled for last frame.
+ * Read-only.
+ * @property {string} timingStats - Details of the average time (ms) spent in and number of calls made to different parts of
+ * the code. Provided only if timingExpanded is true . Only the top 10 items are provided if
+ * Developer > Timing > Performance Timer > Only Display Top 10 is enabled.
+ * Read-only.
+ * @property {string} gameUpdateStats - Details of the average time (ms) spent in different parts of the game loop.
+ * Read-only.
+ * @property {number} serverElements - The total number of elements in the server octree.
+ * Read-only.
+ * @property {number} serverInternal - The number of internal elements in the server octree.
+ * Read-only.
+ * @property {number} serverLeaves - The number of leaf elements in the server octree.
+ * Read-only.
+ * @property {number} localElements - The total number of elements in the client octree.
+ * Read-only.
+ * @property {number} localInternal - The number of internal elements in the client octree.
+ * Read-only.
+ * @property {number} localLeaves - The number of leaf elements in the client octree.
+ * Read-only.
+ * @property {number} rectifiedTextureCount - The number of textures that have been resized so that their dimensions is a power
+ * of 2 if smaller than 128 pixels, or a multiple of 128 if greater than 128 pixels.
+ * Read-only.
+ * @property {number} decimatedTextureCount - The number of textures that have been reduced in size because they were over the
+ * maximum allowed dimensions of 4096 pixels on desktop or 2048 pixels on mobile.
+ * Read-only.
+ * @property {number} gpuBuffers - The number of OpenGL buffer objects managed by the GPU back-end.
+ * Read-only.
+ * @property {number} gpuBufferMemory - The total memory size of the gpuBuffers , in MB.
+ * Read-only.
+ * @property {number} gpuTextures - The number of OpenGL textures managed by the GPU back-end. This is the sum of the number of
+ * textures managed for gpuTextureResidentMemory , gpuTextureResourceMemory , and
+ * gpuTextureFramebufferMemory .
+ * Read-only.
+ * @property {number} gpuTextureMemory - The total memory size of the gpuTextures , in MB. This is the sum of
+ * gpuTextureResidentMemory , gpuTextureResourceMemory , and
+ * gpuTextureFramebufferMemory .
+ * Read-only.
+ * @property {number} glContextSwapchainMemory - The estimated memory used by the default OpenGL frame buffer, in MB.
+ * Read-only.
+ * @property {number} qmlTextureMemory - The memory size of textures managed by the offscreen QML surface, in MB.
+ * Read-only.
+ * @property {number} texturePendingTransfers - The memory size of textures pending transfer to the GPU, in MB.
+ * Read-only.
+ * @property {number} gpuTextureResidentMemory - The memory size of the "strict" textures that always have their full
+ * resolution in GPU memory, in MB.
+ * Read-only.
+ * @property {number} gpuTextureFramebufferMemory - The memory size of the frame buffer on the GPU, in MB.
+ * Read-only.
+ * @property {number} gpuTextureResourceMemory - The amount of GPU memory that has been allocated for "variable" textures that
+ * don't necessarily always have their full resolution in GPU memory, in MB.
+ * Read-only.
+ * @property {number} gpuTextureResourceIdealMemory - The amount of memory that "variable" textures would take up if they were
+ * all completely loaded, in MB.
+ * Read-only.
+ * @property {number} gpuTextureResourcePopulatedMemory - How much of the GPU memory allocated has actually been populated, in
+* MB.
+ * Read-only.
+ * @property {string} gpuTextureMemoryPressureState - The stats of the texture transfer engine.
+ *
+ * "Undersubscribed" : There is texture data that can fit in memory but that isn't on the GPU, so more
+ * GPU texture memory should be allocated if possible.
+ * "Transfer" : More GPU texture memory has been allocated and texture data is being transferred.
+ * "Idle" : Either all texture data has been transferred to the GPU or there is nor more space
+ * available.
+ *
+ * Read-only.
+ * @property {number} gpuFreeMemory - The amount of GPU memory available after all allocations, in MB.
+ * Read-only.
+ * Note: This is not a reliable number because OpenGL doesn't have an official method of getting this
+ * information.
+ * @property {number} gpuTextureExternalMemory - The estimated amount of memory consumed by textures being used but that are
+ * not managed by the GPU library, in MB.
+ * Read-only.
+ * @property {Vec2} gpuFrameSize - The dimensions of the frames being rendered, in pixels.
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {number} gpuFrameTime - The time the GPU is spending on a frame, in ms.
+ * Read-only.
+ * @property {number} gpuFrameTimePerPixel - The time the GPU is spending on a pixel, in ns.
+ * Read-only.
+ * @property {number} batchFrameTime - The time being spent batch processing each frame, in ms.
+ * Read-only.
+ * @property {number} engineFrameTime - The time being spent in the render engine each frame, in ms.
+ * Read-only.
+ * @property {number} avatarSimulationTime - The time being spent simulating avatars each frame, in ms.
+ * Read-only.
+ *
+ * @property {number} stylusPicksCount - The number of stylus picks currently in effect.
+ * Read-only.
+ * @property {number} rayPicksCount - The number of ray picks currently in effect.
+ * Read-only.
+ * @property {number} parabolaPicksCount - The number of parabola picks currently in effect.
+ * Read-only.
+ * @property {number} collisionPicksCount - The number of collision picks currently in effect.
+ * Read-only.
+ * @property {Vec3} stylusPicksUpdated - The number of stylus pick intersection that were found in the most recent game loop:
+ *
+ * x = entity intersections.
+ * y = avatar intersections.
+ * z = HUD intersections.
+ *
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {Vec3} rayPicksUpdated - The number of ray pick intersections that were found in the most recent game loop:
+ *
+ * x = entity intersections.
+ * y = avatar intersections.
+ * z = HUD intersections.
+ *
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {Vec3} parabolaPicksUpdated - The number of parabola pick intersections that were found in the most recent game
+ * loop:
+ *
+ * x = entity intersections.
+ * y = avatar intersections.
+ * z = HUD intersections.
+ *
+ * Read-only.
+ * Note: Property not available in the API.
+ * @property {Vec3} collisionPicksUpdated - The number of collision pick intersections that were found in the most recent game
+ * loop:
+ *
+ * x = entity intersections.
+ * y = avatar intersections.
+ * z = HUD intersections.
+ *
+ * Read-only.
+ * Note: Property not available in the API.
+ *
+ * @property {boolean} eventQueueDebuggingOn - true if event queue statistics are provided, false if
+ * they're not.
+ * Read-only.
+ * @property {number} mainThreadQueueDepth - The number of events in the main thread's event queue.
+ * Only provided if eventQueueDebuggingOn is true .
+ * Read-only.
+ * @property {number} nodeListThreadQueueDepth - The number of events in the node list thread's event queue.
+ * Only provided if eventQueueDebuggingOn is true .
+ * Read-only.
+ *
+ * @comment The following property is from Stats.qml. It shouldn't be in the API.
+ * @property {string} bgColor
+ * Read-only.
+ * Deprecated: This property is deprecated and will be removed.
+ *
+ * @comment The following properties are from QQuickItem. They shouldn't be in the API.
+ * @property {boolean} activeFocus
+ * Read-only.
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} activeFocusOnTab
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {object} anchors
+ * Read-only.
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} antialiasing
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} baselineOffset
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {object[]} children
+ * Read-only.
+ * Note: Property not available in the API.
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} clip
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {object} containmentMask
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} enabled
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} focus
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} height
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} implicitHeight
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} implicitWidth
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {object} layer
+ * Read-only.
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} opacity
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} rotation
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} scale
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} smooth
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {string} state
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} transformOrigin
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} visible
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} width
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} x
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} y
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {number} z
+ * Deprecated: This property is deprecated and will be removed.
*/
// Properties from x onwards are QQuickItem properties.
@@ -249,6 +516,7 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, audioMixerPps, 0)
STATS_PROPERTY(int, audioOutboundPPS, 0)
STATS_PROPERTY(int, audioSilentOutboundPPS, 0)
+ STATS_PROPERTY(int, audioInboundPPS, 0)
STATS_PROPERTY(int, audioAudioInboundPPS, 0)
STATS_PROPERTY(int, audioSilentInboundPPS, 0)
STATS_PROPERTY(int, audioPacketLoss, 0)
@@ -291,6 +559,7 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, localLeaves, 0)
STATS_PROPERTY(int, rectifiedTextureCount, 0)
STATS_PROPERTY(int, decimatedTextureCount, 0)
+
STATS_PROPERTY(int, gpuBuffers, 0)
STATS_PROPERTY(int, gpuBufferMemory, 0)
STATS_PROPERTY(int, gpuTextures, 0)
@@ -356,37 +625,35 @@ public:
QStringList downloadUrls () { return _downloadUrls; }
public slots:
+
+ /**jsdoc
+ * Updates statistics to make current values available to scripts even though the statistics overlay may not be displayed.
+ * (Many statistics values are normally updated only if the statistics overlay is displayed.)
+ * Note: Not all statistics values are updated when the statistics overlay isn't displayed or
+ * expanded.
+ * @function Stats.forceUpdateStats
+ * @example Report avatar mixer data and packet rates.
+ * // The statistics to report.
+ * var stats = [
+ * "avatarMixerInKbps",
+ * "avatarMixerInPps",
+ * "avatarMixerOutKbps",
+ * "avatarMixerOutPps"
+ * ];
+ *
+ * // Update the statistics for the script.
+ * Stats.forceUpdateStats();
+ *
+ * // Report the statistics.
+ * for (var i = 0; i < stats.length; i++) {
+ * print(stats[i], "=", Stats[stats[i]]);
+ * }
+ */
void forceUpdateStats() { updateStats(true); }
signals:
- /**jsdoc
- * Triggered when the value of the longsubmits property changes.
- * @function Stats.longsubmitsChanged
- * @returns {Signal}
- */
- void longsubmitsChanged();
-
- /**jsdoc
- * Triggered when the value of the longrenders property changes.
- * @function Stats.longrendersChanged
- * @returns {Signal}
- */
- void longrendersChanged();
-
- /**jsdoc
- * Triggered when the value of the longframes property changes.
- * @function Stats.longframesChanged
- * @returns {Signal}
- */
- void longframesChanged();
-
- /**jsdoc
- * Triggered when the value of the appdropped property changes.
- * @function Stats.appdroppedChanged
- * @returns {Signal}
- */
- void appdroppedChanged();
+ // Signals for properties...
/**jsdoc
* Triggered when the value of the expanded property changes.
@@ -423,6 +690,41 @@ signals:
*/
void presentrateChanged();
+ /**jsdoc
+ * Triggered when the value of the stutterrate property changes.
+ * @function Stats.stutterrateChanged
+ * @returns {Signal}
+ */
+ void stutterrateChanged();
+
+ /**jsdoc
+ * Triggered when the value of the appdropped property changes.
+ * @function Stats.appdroppedChanged
+ * @returns {Signal}
+ */
+ void appdroppedChanged();
+
+ /**jsdoc
+ * Triggered when the value of the longsubmits property changes.
+ * @function Stats.longsubmitsChanged
+ * @returns {Signal}
+ */
+ void longsubmitsChanged();
+
+ /**jsdoc
+ * Triggered when the value of the longrenders property changes.
+ * @function Stats.longrendersChanged
+ * @returns {Signal}
+ */
+ void longrendersChanged();
+
+ /**jsdoc
+ * Triggered when the value of the longframes property changes.
+ * @function Stats.longframesChanged
+ * @returns {Signal}
+ */
+ void longframesChanged();
+
/**jsdoc
* Triggered when the value of the presentnewrate property changes.
* @function Stats.presentnewrateChanged
@@ -437,13 +739,6 @@ signals:
*/
void presentdroprateChanged();
- /**jsdoc
- * Triggered when the value of the stutterrate property changes.
- * @function Stats.stutterrateChanged
- * @returns {Signal}
- */
- void stutterrateChanged();
-
/**jsdoc
* Triggered when the value of the gameLoopRate property changes.
* @function Stats.gameLoopRateChanged
@@ -451,13 +746,6 @@ signals:
*/
void gameLoopRateChanged();
- /**jsdoc
- * Trigered when
- * @function Stats.numPhysicsBodiesChanged
- * @returns {Signal}
- */
- void physicsObjectCountChanged();
-
/**jsdoc
* Triggered when the value of the avatarCount property changes.
* @function Stats.avatarCountChanged
@@ -465,6 +753,34 @@ signals:
*/
void avatarCountChanged();
+ /**jsdoc
+ * Triggered when the value of the refreshRateTarget property changes.
+ * @function Stats.refreshRateTargetChanged
+ * @returns {Signal}
+ */
+ void refreshRateTargetChanged();
+
+ /**jsdoc
+ * Triggered when the value of the refreshRateMode property changes.
+ * @function Stats.refreshRateModeChanged
+ * @returns {Signal}
+ */
+ void refreshRateModeChanged();
+
+ /**jsdoc
+ * Triggered when the value of the refreshRateRegime property changes.
+ * @function Stats.refreshRateRegimeChanged
+ * @returns {Signal}
+ */
+ void refreshRateRegimeChanged();
+
+ /**jsdoc
+ * Triggered when the value of the uxMode property changes.
+ * @function Stats.uxModeChanged
+ * @returns {Signal}
+ */
+ void uxModeChanged();
+
/**jsdoc
* Triggered when the value of the heroAvatarCount property changes.
* @function Stats.heroAvatarCountChanged
@@ -472,6 +788,13 @@ signals:
*/
void heroAvatarCountChanged();
+ /**jsdoc
+ * Triggered when the value of the physicsObjectCount property changes.
+ * @function Stats.physicsObjectCountChanged
+ * @returns {Signal}
+ */
+ void physicsObjectCountChanged();
+
/**jsdoc
* Triggered when the value of the updatedAvatarCount property changes.
* @function Stats.updatedAvatarCountChanged
@@ -682,10 +1005,19 @@ signals:
*/
void audioSilentOutboundPPSChanged();
+ /**jsdoc
+ * Triggered when the value of the audioInboundPPS property changes.
+ * @function Stats.audioInboundPPSChanged
+ * @returns {Signal}
+ */
+ void audioInboundPPSChanged();
+
/**jsdoc
* Triggered when the value of the audioAudioInboundPPS property changes.
* @function Stats.audioAudioInboundPPSChanged
* @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed. Use
+ * {@link Stats.audioInboundPPSChanged|audioInboundPPSChanged} instead.
*/
void audioAudioInboundPPSChanged();
@@ -731,7 +1063,6 @@ signals:
*/
void entityPacketsInKbpsChanged();
-
/**jsdoc
* Triggered when the value of the downloads property changes.
* @function Stats.downloadsChanged
@@ -782,11 +1113,10 @@ signals:
void trianglesChanged();
/**jsdoc
- * Triggered when the value of the drawcalls property changes.
- * This
- * @function Stats.drawcallsChanged
- * @returns {Signal}
- */
+ * Triggered when the value of the drawcalls property changes.
+ * @function Stats.drawcallsChanged
+ * @returns {Signal}
+ */
void drawcallsChanged();
/**jsdoc
@@ -901,6 +1231,20 @@ signals:
*/
void numNeededEntityUpdatesChanged();
+ /**jsdoc
+ * Triggered when the value of the timingStats property changes.
+ * @function Stats.timingStatsChanged
+ * @returns {Signal}
+ */
+ void timingStatsChanged();
+
+ /**jsdoc
+ * Triggered when the value of the gameUpdateStats property changes.
+ * @function Stats.gameUpdateStatsChanged
+ * @returns {Signal}
+ */
+ void gameUpdateStatsChanged();
+
/**jsdoc
* Triggered when the value of the serverElements property changes.
* @function Stats.serverElementsChanged
@@ -944,39 +1288,18 @@ signals:
void localLeavesChanged();
/**jsdoc
- * Triggered when the value of the timingStats property changes.
- * @function Stats.timingStatsChanged
+ * Triggered when the value of the rectifiedTextureCount property changes.
+ * @function Stats.rectifiedTextureCountChanged
* @returns {Signal}
*/
- void timingStatsChanged();
+ void rectifiedTextureCountChanged();
/**jsdoc
- * Triggered when the value of the gameUpdateStats property changes.
- * @function Stats.gameUpdateStatsChanged
+ * Triggered when the value of the decimatedTextureCount property changes.
+ * @function Stats.decimatedTextureCountChanged
* @returns {Signal}
*/
- void gameUpdateStatsChanged();
-
- /**jsdoc
- * Triggered when the value of the glContextSwapchainMemory property changes.
- * @function Stats.glContextSwapchainMemoryChanged
- * @returns {Signal}
- */
- void glContextSwapchainMemoryChanged();
-
- /**jsdoc
- * Triggered when the value of the qmlTextureMemory property changes.
- * @function Stats.qmlTextureMemoryChanged
- * @returns {Signal}
- */
- void qmlTextureMemoryChanged();
-
- /**jsdoc
- * Triggered when the value of the texturePendingTransfers property changes.
- * @function Stats.texturePendingTransfersChanged
- * @returns {Signal}
- */
- void texturePendingTransfersChanged();
+ void decimatedTextureCountChanged();
/**jsdoc
* Triggered when the value of the gpuBuffers property changes.
@@ -999,6 +1322,27 @@ signals:
*/
void gpuTexturesChanged();
+ /**jsdoc
+ * Triggered when the value of the glContextSwapchainMemory property changes.
+ * @function Stats.glContextSwapchainMemoryChanged
+ * @returns {Signal}
+ */
+ void glContextSwapchainMemoryChanged();
+
+ /**jsdoc
+ * Triggered when the value of the qmlTextureMemory property changes.
+ * @function Stats.qmlTextureMemoryChanged
+ * @returns {Signal}
+ */
+ void qmlTextureMemoryChanged();
+
+ /**jsdoc
+ * Triggered when the value of the texturePendingTransfers property changes.
+ * @function Stats.texturePendingTransfersChanged
+ * @returns {Signal}
+ */
+ void texturePendingTransfersChanged();
+
/**jsdoc
* Triggered when the value of the gpuTextureMemory property changes.
* @function Stats.gpuTextureMemoryChanged
@@ -1063,15 +1407,8 @@ signals:
void gpuFreeMemoryChanged();
/**jsdoc
- * Triggered when the value of the gpuFrameTime property changes.
- * @function Stats.gpuFrameTimeChanged
- * @returns {Signal}
- */
- void gpuFrameTimeChanged();
-
- /**jsdoc
- * Triggered when the value of the gpuFrameTime property changes.
- * @function Stats.gpuFrameTimeChanged
+ * Triggered when the value of the gpuFrameSize property changes.
+ * @function Stats.gpuFrameSizeChanged
* @returns {Signal}
*/
void gpuFrameSizeChanged();
@@ -1081,6 +1418,13 @@ signals:
* @function Stats.gpuFrameTimeChanged
* @returns {Signal}
*/
+ void gpuFrameTimeChanged();
+
+ /**jsdoc
+ * Triggered when the value of the gpuFrameTimePerPixel property changes.
+ * @function Stats.gpuFrameTimePerPixelChanged
+ * @returns {Signal}
+ */
void gpuFrameTimePerPixelChanged();
/**jsdoc
@@ -1104,250 +1448,6 @@ signals:
*/
void avatarSimulationTimeChanged();
- /**jsdoc
- * Triggered when the value of the rectifiedTextureCount property changes.
- * @function Stats.rectifiedTextureCountChanged
- * @returns {Signal}
- */
- void rectifiedTextureCountChanged();
-
- /**jsdoc
- * Triggered when the value of the decimatedTextureCount property changes.
- * @function Stats.decimatedTextureCountChanged
- * @returns {Signal}
- */
- void decimatedTextureCountChanged();
-
-
- void refreshRateTargetChanged();
-
- void refreshRateModeChanged();
-
- void refreshRateRegimeChanged();
-
- void uxModeChanged();
-
- // QQuickItem signals.
-
- /**jsdoc
- * Triggered when the parent item changes.
- * @function Stats.parentChanged
- * @param {object} parent
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the x property changes.
- * @function Stats.xChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the y property changes.
- * @function Stats.yChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the z property changes.
- * @function Stats.zChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the width property changes.
- * @function Stats.widthChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the height property changes.
- * @function Stats.heightChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the opacity property changes.
- * @function Stats.opacityChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the enabled property changes.
- * @function Stats.enabledChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the visibleChanged property changes.
- * @function Stats.visibleChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the list of visible children changes.
- * @function Stats.visibleChildrenChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the state property changes.
- * @function Stats.stateChanged
- * @paramm {string} state
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the position and size of the rectangle containing the children changes.
- * @function Stats.childrenRectChanged
- * @param {Rect} childrenRect
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the baselineOffset property changes.
- * @function Stats.baselineOffsetChanged
- * @param {number} baselineOffset
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the clip property changes.
- * @function Stats.clipChanged
- * @param {boolean} clip
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the focus property changes.
- * @function Stats.focusChanged
- * @param {boolean} focus
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the activeFocus property changes.
- * @function Stats.activeFocusChanged
- * @param {boolean} activeFocus
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the activeFocusOnTab property changes.
- * @function Stats.activeFocusOnTabChanged
- * @param {boolean} activeFocusOnTab
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the rotation property changes.
- * @function Stats.rotationChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the scaleChanged property changes.
- * @function Stats.scaleChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the transformOrigin property changes.
- * @function Stats.transformOriginChanged
- * @param {number} transformOrigin
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the smooth property changes.
- * @function Stats.smoothChanged
- * @param {boolean} smooth
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the antialiasing property changes.
- * @function Stats.antialiasingChanged
- * @param {boolean} antialiasing
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the implicitWidth property changes.
- * @function Stats.implicitWidthChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * Triggered when the value of the implicitHeight property changes.
- * @function Stats.implicitHeightChanged
- * @returns {Signal}
- */
-
- /**jsdoc
- * @function Stats.windowChanged
- * @param {object} window
- * @returns {Signal}
- */
-
-
- // QQuickItem functions.
-
- /**jsdoc
- * @function Stats.grabToImage
- * @param {object} callback
- * @param {Size} [targetSize=0,0]
- * @returns {boolean}
- */
-
- /**jsdoc
- * @function Stats.contains
- * @param {Vec2} point
- * @returns {boolean}
- */
-
- /**jsdoc
- * @function Stats.mapFromItem
- * @param {object} item
- */
-
- /**jsdoc
- * @function Stats.mapToItem
- * @param {object} item
- */
-
- /**jsdoc
- * @function Stats.mapFromGlobal
- * @param {object} global
- */
-
- /**jsdoc
- * @function Stats.mapToGlobal
- * @param {object} global
- */
-
- /**jsdoc
- * @function Stats.forceActiveFocus
- * @param {number} [reason=7]
- */
-
- /**jsdoc
- * @function Stats.nextItemInFocusChain
- * @param {boolean} [forward=true]
- * @returns {object}
- */
-
- /**jsdoc
- * @function Stats.childAt
- * @param {number} x
- * @param {number} y
- * @returns {object}
- */
-
- /**jsdoc
- * @function Stats.update
- */
-
/**jsdoc
* Triggered when the value of the stylusPicksCount property changes.
* @function Stats.stylusPicksCountChanged
@@ -1405,11 +1505,11 @@ signals:
void collisionPicksUpdatedChanged();
/**jsdoc
- * Triggered when the value of the eventQueueDebuggingOn property changes.
- * @function Stats.eventQueueDebuggingOn
+ * Triggered when the value of the mainThreadQueueDepth property changes.
+ * @function Stats.mainThreadQueueDepthChanged
* @returns {Signal}
*/
- void eventQueueDebuggingOnChanged();
+ void mainThreadQueueDepthChanged();
/**jsdoc
* Triggered when the value of the nodeListThreadQueueDepth property changes.
@@ -1419,11 +1519,294 @@ signals:
void nodeListThreadQueueDepthChanged();
/**jsdoc
- * Triggered when the value of the nodeListThreadQueueDepth property changes.
- * @function Stats.nodeListThreadQueueDepth
+ * Triggered when the value of the eventQueueDebuggingOn property changes.
+ * @function Stats.eventQueueDebuggingOnChanged
* @returns {Signal}
*/
- void mainThreadQueueDepthChanged();
+ void eventQueueDebuggingOnChanged();
+
+
+ // Stats.qml signals: shouldn't be in the API.
+
+ /**jsdoc
+ * Triggered when the value of the bgColor property changes.
+ * @function Stats.bgColorChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+
+ // QQuickItem signals: shouldn't be in the API.
+
+ /**jsdoc
+ * Triggered when the value of the activeFocus property changes.
+ * @function Stats.activeFocusChanged
+ * @param {boolean} activeFocus - Active focus.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the activeFocusOnTab property changes.
+ * @function Stats.activeFocusOnTabChanged
+ * @param {boolean} activeFocusOnTab - Active focus on tab.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the antialiasing property changes.
+ * @function Stats.antialiasingChanged
+ * @param {boolean} antialiasing - Antialiasing.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the baselineOffset property changes.
+ * @function Stats.baselineOffsetChanged
+ * @param {number} baselineOffset - Baseline offset.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the children property changes.
+ * @function Stats.childrenChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the position and size of the rectangle containing the children changes.
+ * @function Stats.childrenRectChanged
+ * @param {Rect} childrenRect - Children rect.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+
+ /**jsdoc
+ * Triggered when the value of the clip property changes.
+ * @function Stats.clipChanged
+ * @param {boolean} clip - Clip.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the containmentMask property changes.
+ * @function Stats.containmentMaskChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the enabled property changes.
+ * @function Stats.enabledChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the focus property changes.
+ * @function Stats.focusChanged
+ * @param {boolean} focus - Focus.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the height property changes.
+ * @function Stats.heightChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the implicitHeight property changes.
+ * @function Stats.implicitHeightChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the implicitWidth property changes.
+ * @function Stats.implicitWidthChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the opacity property changes.
+ * @function Stats.opacityChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the parent item changes.
+ * @function Stats.parentChanged
+ * @param {object} parent - Parent.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the rotation property changes.
+ * @function Stats.rotationChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the scale property changes.
+ * @function Stats.scaleChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the smooth property changes.
+ * @function Stats.smoothChanged
+ * @param {boolean} smooth - Smooth.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the state property changes.
+ * @function Stats.stateChanged
+ * @paramm {string} state - State.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the transformOrigin property changes.
+ * @function Stats.transformOriginChanged
+ * @param {number} transformOrigin - Transformm origin.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the visibleChanged property changes.
+ * @function Stats.visibleChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the list of visible children changes.
+ * @function Stats.visibleChildrenChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the width property changes.
+ * @function Stats.widthChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the stats window changes.
+ * @function Stats.windowChanged
+ * @param {object} window - Window.
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the x property changes.
+ * @function Stats.xChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the y property changes.
+ * @function Stats.yChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * Triggered when the value of the z property changes.
+ * @function Stats.zChanged
+ * @returns {Signal}
+ * @deprecated This signal is deprecated and will be removed.
+ */
+
+
+ // QQuickItem methods: shouldn't be in the API.
+
+ /**jsdoc
+ * @function Stats.childAt
+ * @param {number} x - X.
+ * @param {number} y - Y.
+ * @returns {object}
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.contains
+ * @param {Vec2} point - Point
+ * @returns {boolean}
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.forceActiveFocus
+ * @param {number} [reason=7] - Reason
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.grabToImage
+ * @param {object} callback - Callback.
+ * @param {Size} [targetSize=0,0] - Target size.
+ * @returns {boolean}
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.mapFromGlobal
+ * @param {object} global - Global.
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.mapFromItem
+ * @param {object} item - Item.
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.mapToGlobal
+ * @param {object} global - Global.
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.mapToItem
+ * @param {object} item - Item
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.nextItemInFocusChain
+ * @param {boolean} [forward=true] - Forward.
+ * @returns {object}
+ * @deprecated This method is deprecated and will be removed.
+ */
+
+ /**jsdoc
+ * @function Stats.update
+ * @deprecated This method is deprecated and will be removed.
+ */
private:
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h
index e688d1c115..5d11b254fc 100644
--- a/interface/src/ui/overlays/ContextOverlayInterface.h
+++ b/interface/src/ui/overlays/ContextOverlayInterface.h
@@ -29,6 +29,22 @@
#include "EntityTree.h"
#include "ContextOverlayLogging.h"
+/**jsdoc
+ * The ContextOverlay API manages the "i" proof-of-provenance context overlay that appears on Marketplace items
+ * when a user right-clicks them.
+ *
+ * @namespace ContextOverlay
+ *
+ * @hifi-interface
+ * @hifi-client-entity
+ * @hifi-avatar
+ *
+ * @property {boolean} enabled - true if the context overlay is enabled to be displayed, false if it
+ * is disabled and will never be displayed.
+ * @property {Uuid} entityWithContextOverlay - The ID of the entity that the context overlay is currently displayed for,
+ * null if the context overlay is not currently displayed.
+ * @property {boolean} isInMarketplaceInspectionMode - Currently not used.
+ */
class ContextOverlayInterface : public QObject, public Dependency {
Q_OBJECT
@@ -44,30 +60,140 @@ class ContextOverlayInterface : public QObject, public Dependency {
QUuid _contextOverlayID { UNKNOWN_ENTITY_ID };
public:
ContextOverlayInterface();
+
+ /**jsdoc
+ * Gets the ID of the entity that the context overlay is currently displayed for.
+ * @function ContextOverlay.getCurrentEntityWithContextOverlay
+ * @returns {Uuid} - The ID of the entity that the context overlay is currently displayed for, null if the
+ * context overlay is not currently displayed.
+ */
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
+
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); }
void setEnabled(bool enabled);
bool getEnabled() { return _enabled; }
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
+
+ /**jsdoc
+ * Initiates a check on an avatar entity belongs to the user wearing it. The result is returned via
+ * {@link WalletScriptingInterface.ownershipVerificationSuccess} or
+ * {@link WalletScriptingInterface.ownershipVerificationFailed}.
+ * Warning: Neither of these signals are triggered if the entity is not an avatar entity or is not
+ * certified.
+ * @function ContextOverlay.requestOwnershipVerification
+ * @param {Uuid} entityID - The ID of the entity to check.
+ */
Q_INVOKABLE void requestOwnershipVerification(const QUuid& entityID);
+
EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; }
signals:
+ /**jsdoc
+ * Triggered when the user clicks on the context overlay.
+ * @function ContextOverlay.contextOverlayClicked
+ * @param {Uuid} id - The ID of the entity that the context overlay is for.
+ * @returns {Signal}
+ * @example Report when a context overlay is clicked.
+ * ContextOverlay.contextOverlayClicked.connect(function (id) {
+ * print("Context overlay clicked for:", id);
+ * });
+ */
void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay);
public slots:
+
+ /**jsdoc
+ * @function ContextOverlay.clickDownOnEntity
+ * @param {Uuid} id - Entity ID.
+ * @param {PointerEvent} event - Pointer event.
+ * @deprecated This method is deprecated and will be removed.
+ */
+ // FIXME: Method shouldn't be in the API.
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
+
+ /**jsdoc
+ * @function ContextOverlay.mouseReleaseOnEntity
+ * @param {Uuid} id - Entity ID.
+ * @param {PointerEvent} event - Pointer event.
+ * @deprecated This method is deprecated and will be removed.
+ */
+ // FIXME: Method shouldn't be in the API.
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
+ /**jsdoc
+ * Displays or deletes the context overlay as appropriate for the target entity and a pointer event: the context overlay
+ * must be enabled and the pointer event must be a right-click; if so, then any current context overlay is deleted, and if
+ * the target entity should have a context overlay then it is displayed.
+ * @function ContextOverlay.createOrDestroyContextOverlay
+ * @param {Uuid} entityID - The target entity.
+ * @param {PointerEvent} pointerEvent - The pointer event.
+ * @returns {boolean} - true if the context overlay was deleted or displayed on the specified entity,
+ * false if no action was taken.
+ */
bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
+
+ /**jsdoc
+ * Deletes the context overlay and removes the entity highlight, if shown.
+ * @function ContextOverlay.destroyContextOverlay
+ * @param {Uuid} entityID - The ID of the entity.
+ * @param {PointerEvent} [event] - Not used.
+ * @returns {boolean} - true if the context overlay was deleted, false if it wasn't (e.g., it
+ * wasn't displayed).
+ */
bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
bool destroyContextOverlay(const EntityItemID& entityItemID);
+
+ /**jsdoc
+ * @function ContextOverlay.contextOverlays_hoverEnterOverlay
+ * @param {Uuid} id - Overlay ID.
+ * @param {PointerEvent} event - Pointer event.
+ * @deprecated This method is deprecated and will be removed.
+ */
+ // FIXME: Method shouldn't be in the API.
void contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event);
+
+ /**jsdoc
+ * @function ContextOverlay.contextOverlays_hoverLeaveOverlay
+ * @param {Uuid} id - Overlay ID.
+ * @param {PointerEvent} event - Pointer event.
+ * @deprecated This method is deprecated and will be removed.
+ */
+ // FIXME: Method shouldn't be in the API.
void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
+
+ /**jsdoc
+ * @function ContextOverlay.contextOverlays_hoverEnterEntity
+ * @param {Uuid} id - Entity ID.
+ * @param {PointerEvent} event - Pointer event.
+ * @deprecated This method is deprecated and will be removed.
+ */
+ // FIXME: Method shouldn't be in the API.
void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event);
+
+ /**jsdoc
+ * @function ContextOverlay.contextOverlays_hoverLeaveEntity
+ * @param {Uuid} id - Entity ID.
+ * @param {PointerEvent} event - Pointer event.
+ * @deprecated This method is deprecated and will be removed.
+ */
+ // FIXME: Method shouldn't be in the API.
void contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event);
+
+ /**jsdoc
+ * Checks with a context overlay should be displayed for an entity — in particular, whether the item has a non-empty
+ * certificate ID.
+ * @function ContextOverlay.contextOverlayFilterPassed
+ * @param {Uuid} entityID - The ID of the entity to check.
+ * @returns {boolean} - true if the context overlay should be shown for the entity, false if it
+ * shouldn't.
+ * @example Report whether the context overlay should be displayed for entities clicked.
+ * Entities.clickDownOnEntity.connect(function (id, event) {
+ * print("Item clicked:", id);
+ * print("Should display context overlay:", ContextOverlay.contextOverlayFilterPassed(id));
+ * });
+ */
bool contextOverlayFilterPassed(const EntityItemID& entityItemID);
private slots:
diff --git a/interface/src/workload/GameWorkload.cpp b/interface/src/workload/GameWorkload.cpp
index afbd166c89..d9cda7f16a 100644
--- a/interface/src/workload/GameWorkload.cpp
+++ b/interface/src/workload/GameWorkload.cpp
@@ -9,6 +9,7 @@
//
#include "GameWorkload.h"
#include "GameWorkloadRenderer.h"
+#include "SelectedWorkloadRenderer.h"
#include
#include
#include
@@ -35,6 +36,7 @@ public:
model.addJob("PhysicsBoundary", regionTrackerOut);
model.addJob("SpaceToRender");
+ model.addJob("SelectedWorkloadRender");
out = regionTrackerOut;
}
diff --git a/interface/src/workload/GameWorkloadRenderer.cpp b/interface/src/workload/GameWorkloadRenderer.cpp
index 2bb73999f1..f65bf88754 100644
--- a/interface/src/workload/GameWorkloadRenderer.cpp
+++ b/interface/src/workload/GameWorkloadRenderer.cpp
@@ -16,6 +16,7 @@
#include
#include
+#include "SelectedWorkloadRenderer.h"
void GameSpaceToRender::configure(const Config& config) {
_freezeViews = config.freezeViews;
diff --git a/interface/src/workload/SelectedWorkloadRenderer.cpp b/interface/src/workload/SelectedWorkloadRenderer.cpp
new file mode 100644
index 0000000000..29cdc46f35
--- /dev/null
+++ b/interface/src/workload/SelectedWorkloadRenderer.cpp
@@ -0,0 +1,88 @@
+//
+// SelectedWorkloadRenderer.cpp
+//
+// Created by Andrew Meadows 2019.11.08
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#include "SelectedWorkloadRenderer.h"
+
+#include
+#include
+
+#include
+
+#include "Application.h"
+#include "GameWorkloadRenderer.h"
+#include "scripting/SelectionScriptingInterface.h"
+
+void SelectedWorkloadRenderer::run(const workload::WorkloadContextPointer& runContext, Outputs& outputs) {
+ auto gameWorkloadContext = std::dynamic_pointer_cast(runContext);
+ if (!gameWorkloadContext) {
+ return;
+ }
+ auto space = gameWorkloadContext->_space;
+ if (!space) {
+ return;
+ }
+
+ render::Transaction transaction;
+ auto scene = gameWorkloadContext->_scene;
+
+ auto selection = DependencyManager::get();
+ // Note: the "DebugWorkloadSelection" name is a secret hard-coded C++ debug feature.
+ // If you create such a named list using JS and the "Selection" API then it will be picked up here
+ // and the workload proxies for corresponding entities will be rendered.
+ GameplayObjects selectedObjects = selection->getList("DebugWorkloadSelection");
+
+ if (!selectedObjects.getContainsData()) {
+ // nothing to render
+ // clear item if it exists and bail
+ if (render::Item::isValidID(_spaceRenderItemID)) {
+ transaction.updateItem(_spaceRenderItemID, [](GameWorkloadRenderItem& item) {
+ item.setVisible(false);
+ });
+ scene->enqueueTransaction(transaction);
+ }
+ return;
+ }
+
+ std::vector entityIDs = selectedObjects.getEntityIDs();
+ workload::indexed_container::Indices indices;
+ indices.reserve(entityIDs.size());
+
+ auto entityTreeRenderer = qApp->getEntities();
+ auto entityTree = entityTreeRenderer->getTree();
+ for (auto id : entityIDs) {
+ EntityItemPointer entity = entityTree->findEntityByID(id);
+ if (entity) {
+ indices.push_back(entity->getSpaceIndex());
+ }
+ }
+
+ workload::Proxy::Vector proxies;
+ proxies.reserve(indices.size());
+ space->copySelectedProxyValues(proxies, indices);
+
+ if (!render::Item::isValidID(_spaceRenderItemID)) {
+ _spaceRenderItemID = scene->allocateID();
+ auto renderItem = std::make_shared();
+ renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f);
+ transaction.resetItem(_spaceRenderItemID, std::make_shared(renderItem));
+ }
+
+ bool showProxies = true;
+ bool showViews = false;
+ bool visible = true;
+ workload::Views views(0);
+ transaction.updateItem(_spaceRenderItemID, [visible, showProxies, proxies, showViews, views](GameWorkloadRenderItem& item) {
+ item.setVisible(visible);
+ item.showProxies(showProxies);
+ item.setAllProxies(proxies);
+ item.showViews(showViews);
+ item.setAllViews(views);
+ });
+ scene->enqueueTransaction(transaction);
+}
diff --git a/interface/src/workload/SelectedWorkloadRenderer.h b/interface/src/workload/SelectedWorkloadRenderer.h
new file mode 100644
index 0000000000..9b3ac1005e
--- /dev/null
+++ b/interface/src/workload/SelectedWorkloadRenderer.h
@@ -0,0 +1,32 @@
+//
+// GameWorkloadRender.h
+//
+// Created by Sam Gateau on 2/20/2018.
+// Copyright 2018 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#ifndef hifi_SelectedWorkloadRenderer_h
+#define hifi_SelectedWorkloadRenderer_h
+
+#include "GameWorkload.h"
+
+#include "GameWorkloadRenderer.h"
+
+class SelectedWorkloadRenderer {
+public:
+ using Config = GameSpaceToRenderConfig;
+ using Outputs = render::Transaction;
+ using JobModel = workload::Job::ModelO;
+
+ SelectedWorkloadRenderer() {}
+
+ void configure(const Config& config) {}
+ void run(const workload::WorkloadContextPointer& renderContext, Outputs& outputs);
+
+protected:
+ render::ItemID _spaceRenderItemID{ render::Item::INVALID_ITEM_ID };
+};
+
+#endif
diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt
index 48ae0485b5..a25aec37a7 100644
--- a/launchers/darwin/CMakeLists.txt
+++ b/launchers/darwin/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.0)
-set(ENV{MACOSX_DEPLOYMENT_TARGET} 10.9)
+set(ENV{MACOSX_DEPLOYMENT_TARGET} 10.11)
project(HQLauncher)
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
include("cmake/macros/SetPackagingParameters.cmake")
diff --git a/launchers/qt/BUILD.md b/launchers/qt/BUILD.md
new file mode 100644
index 0000000000..d08aa6bfa0
--- /dev/null
+++ b/launchers/qt/BUILD.md
@@ -0,0 +1,13 @@
+# Dependencies
+- [cmake](https://cmake.org/download/): 3.9
+
+# Windows
+* Download `Visual Studio 2019`
+`cmake -G "Visual Studio 16 2019" ..`
+
+# MacOS
+* Install `Xcode`
+`cmake -G Xcode ..`
+
+
+If you wish to not use the compiled qml files, pass the `-DLAUNCHER_SOURCE_TREE_RESOURCES=On` argument to cmake.
\ No newline at end of file
diff --git a/launchers/qt/readme.md b/launchers/qt/readme.md
new file mode 100644
index 0000000000..ce4e846172
--- /dev/null
+++ b/launchers/qt/readme.md
@@ -0,0 +1,34 @@
+# HQ Launcher
+Behavior of the HQ Launcher is as follows:
+* Update the HQ Launcher to the latest version
+* Sign up or sign in if is the user is not already signed in
+* Download the latest Interface client
+* Launch the user in the current HQ domain
+
+# directory structure
+
+## src/ - contains the c++ and objective-c.
+* `BuildsRequest` - getting / parsing the build info from thunder api
+* `CommandlineOptions` - parses and stores commandline arguments
+* `Helper` - helper functions
+* `Helper_darwin` - objective-c implemention of helper funcions
+* `Helper_windows` - helper function that depend on windows api
+* `Launcher` - initialized the Launcher Application and resources
+* `LauncherInstaller_windows` - logic of how to install/uninstall HQ Launcher on windows
+* `LauncherState` - hold majority of the logic of the launcher (signin, config file, updating, running launcher)
+ * config files hold the following saved data
+ * logged in
+ * home location
+* `LauncherWindows` - wrapper for `QQuickWindow` that implements drag feature
+* `LoginRequest` - checks the login credentials the user typed in.
+* `NSTask+NSTaskExecveAdditions` - Extension of NSTask for replacing Launcher process with interface client process
+* `PathUtils` - Helper class for getting relative paths for HQ Launcher
+* `SignupRequest` - Determines if the users request to signup for a new account succeeded based on the entered credentials
+* `Unzipper` - helper class for extracting zip files
+* `UserSettingsRequest` - getting the users setting (home location) from metaverse
+
+## resources/
+* `images/`- Holds the images and icon that are used by the launcher
+* `qml/`
+ * UI elements
+ * `QML_FILE_FOR_UI_STATE` variable in `LauncherState` defines what QML files are used by the Launcher.
\ No newline at end of file
diff --git a/libraries/animation/src/AnimBlendDirectional.cpp b/libraries/animation/src/AnimBlendDirectional.cpp
index 4e7c67f276..4cc67683da 100644
--- a/libraries/animation/src/AnimBlendDirectional.cpp
+++ b/libraries/animation/src/AnimBlendDirectional.cpp
@@ -96,7 +96,9 @@ const AnimPoseVec& AnimBlendDirectional::evaluate(const AnimVariantMap& animVars
}
}
_poses.resize(minSize);
- blend4(minSize, &poseVecs[0][0], &poseVecs[1][0], &poseVecs[2][0], &poseVecs[3][0], &alphas[0], &_poses[0]);
+ if (minSize > 0) {
+ blend4(minSize, &poseVecs[0][0], &poseVecs[1][0], &poseVecs[2][0], &poseVecs[3][0], &alphas[0], &_poses[0]);
+ }
// animation stack debug stats
for (int i = 0; i < 9; i++) {
diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp
index b26d00d8d0..e5f05ab45f 100644
--- a/libraries/animation/src/AnimSkeleton.cpp
+++ b/libraries/animation/src/AnimSkeleton.cpp
@@ -20,24 +20,17 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
_geometryOffset = hfmModel.offset;
- // convert to std::vector of joints
- std::vector joints;
- joints.reserve(hfmModel.joints.size());
- for (auto& joint : hfmModel.joints) {
- joints.push_back(joint);
- }
- buildSkeletonFromJoints(joints, hfmModel.jointRotationOffsets);
+ buildSkeletonFromJoints(hfmModel.joints, hfmModel.jointRotationOffsets);
// we make a copy of the inverseBindMatrices in order to prevent mutating the model bind pose
// when we are dealing with a joint offset in the model
- for (int i = 0; i < (int)hfmModel.meshes.size(); i++) {
- const HFMMesh& mesh = hfmModel.meshes.at(i);
+ for (uint32_t i = 0; i < (uint32_t)hfmModel.skinDeformers.size(); i++) {
+ const auto& deformer = hfmModel.skinDeformers[i];
std::vector dummyClustersList;
- for (int j = 0; j < mesh.clusters.size(); j++) {
- std::vector bindMatrices;
+ for (uint32_t j = 0; j < (uint32_t)deformer.clusters.size(); j++) {
// cast into a non-const reference, so we can mutate the FBXCluster
- HFMCluster& cluster = const_cast(mesh.clusters.at(j));
+ HFMCluster& cluster = const_cast(deformer.clusters.at(j));
HFMCluster localCluster;
localCluster.jointIndex = cluster.jointIndex;
diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h
index efc1c1599f..a6470ac609 100644
--- a/libraries/animation/src/AnimSkeleton.h
+++ b/libraries/animation/src/AnimSkeleton.h
@@ -68,7 +68,7 @@ public:
void dump(const AnimPoseVec& poses) const;
std::vector lookUpJointIndices(const std::vector& jointNames) const;
- const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; }
+ const HFMCluster getClusterBindMatricesOriginalValues(int skinDeformerIndex, int clusterIndex) const { return _clusterBindMatrixOriginalValues[skinDeformerIndex][clusterIndex]; }
protected:
void buildSkeletonFromJoints(const std::vector& joints, const QMap jointOffsets);
diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.h b/libraries/animation/src/AnimationCacheScriptingInterface.h
index 0ceb302913..fc31ecaa2b 100644
--- a/libraries/animation/src/AnimationCacheScriptingInterface.h
+++ b/libraries/animation/src/AnimationCacheScriptingInterface.h
@@ -38,6 +38,10 @@ class AnimationCacheScriptingInterface : public ScriptableResourceCache, public
* @property {number} numCached - Total number of cached resource. Read-only.
* @property {number} sizeTotal - Size in bytes of all resources. Read-only.
* @property {number} sizeCached - Size in bytes of all cached resources. Read-only.
+ * @property {number} numGlobalQueriesPending - Total number of global queries pending (across all resource cache managers).
+ * Read-only.
+ * @property {number} numGlobalQueriesLoading - Total number of global queries loading (across all resource cache managers).
+ * Read-only.
*
* @borrows ResourceCache.getResourceList as getResourceList
* @borrows ResourceCache.updateTotalSize as updateTotalSize
diff --git a/libraries/animation/src/AnimationObject.h b/libraries/animation/src/AnimationObject.h
index 303d0e0d9e..40fd534a71 100644
--- a/libraries/animation/src/AnimationObject.h
+++ b/libraries/animation/src/AnimationObject.h
@@ -23,6 +23,7 @@ class QScriptEngine;
* Information about an animation resource, created by {@link AnimationCache.getAnimation}.
*
* @class AnimationObject
+ * @hideconstructor
*
* @hifi-interface
* @hifi-client-entity
@@ -57,9 +58,10 @@ public:
};
/**jsdoc
- * Joint rotations in one frame of an animation.
+ * Joint rotations in one frame of an {@link AnimationObject}.
*
* @class AnimationFrameObject
+ * @hideconstructor
*
* @hifi-interface
* @hifi-client-entity
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 85b9ecdc42..06fe558964 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1093,6 +1093,12 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
const float TURN_ENTER_SPEED_THRESHOLD = 0.5f; // rad/sec
const float TURN_EXIT_SPEED_THRESHOLD = 0.2f; // rad/sec
+ //stategraph vars based on input
+ const float INPUT_DEADZONE_THRESHOLD = 0.05f;
+ const float SLOW_SPEED_THRESHOLD = 1.5f;
+ const float HAS_MOMENTUM_THRESHOLD = 2.2f;
+ const float RESET_MOMENTUM_THRESHOLD = 0.05f;
+
if (ccState == CharacterControllerState::Hover) {
if (_desiredState != RigRole::Hover) {
_desiredStateAge = 0.0f;
@@ -1171,6 +1177,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_desiredStateAge += deltaTime;
+
if (_state == RigRole::Move) {
glm::vec3 horizontalVel = localVel - glm::vec3(0.0f, localVel.y, 0.0f);
if (glm::length(horizontalVel) > MOVE_ENTER_SPEED_THRESHOLD) {
@@ -1244,6 +1251,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
_animVars.set("isNotSeated", true);
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
} else if (_state == RigRole::Turn) {
if (turningSpeed > 0.0f) {
@@ -1274,6 +1284,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
_animVars.set("isNotSeated", true);
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
} else if (_state == RigRole::Idle) {
// default anim vars to notMoving and notTurning
@@ -1297,6 +1310,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
_animVars.set("isNotSeated", true);
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
} else if (_state == RigRole::Hover) {
// flying.
@@ -1320,6 +1336,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotInAir", true);
_animVars.set("isSeated", false);
_animVars.set("isNotSeated", true);
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
} else if (_state == RigRole::Takeoff) {
// jumping in-air
@@ -1351,6 +1370,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotInAir", false);
_animVars.set("isSeated", false);
_animVars.set("isNotSeated", true);
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
} else if (_state == RigRole::InAir) {
// jumping in-air
@@ -1371,6 +1393,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotTakeoff", true);
_animVars.set("isSeated", false);
_animVars.set("isNotSeated", true);
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
bool inAirRun = forwardSpeed > 0.1f;
if (inAirRun) {
@@ -1393,6 +1418,23 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("inAirAlpha", alpha);
} else if (_state == RigRole::Seated) {
+ if (fabsf(_previousControllerParameters.inputX) <= INPUT_DEADZONE_THRESHOLD) {
+ // seated not turning
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", true);
+ } else if (_previousControllerParameters.inputX > 0.0f) {
+ // seated turning right
+ _animVars.set("isSeatedTurningRight", true);
+ _animVars.set("isSeatedTurningLeft", false);
+ _animVars.set("isSeatedNotTurning", false);
+ } else {
+ // seated turning left
+ _animVars.set("isSeatedTurningRight", false);
+ _animVars.set("isSeatedTurningLeft", true);
+ _animVars.set("isSeatedNotTurning", false);
+ }
+
_animVars.set("isMovingForward", false);
_animVars.set("isMovingBackward", false);
_animVars.set("isMovingRight", false);
@@ -1434,20 +1476,36 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_lastEnableInverseKinematics = _enableInverseKinematics;
- //stategraph vars based on input
- const float INPUT_DEADZONE_THRESHOLD = 0.05f;
- const float SLOW_SPEED_THRESHOLD = 1.5f;
+
if (fabsf(_previousControllerParameters.inputX) <= INPUT_DEADZONE_THRESHOLD &&
fabsf(_previousControllerParameters.inputZ) <= INPUT_DEADZONE_THRESHOLD) {
// no WASD input
if (fabsf(forwardSpeed) <= SLOW_SPEED_THRESHOLD && fabsf(lateralSpeed) <= SLOW_SPEED_THRESHOLD) {
+
+ //reset this when stopped
+ if (fabsf(forwardSpeed) <= RESET_MOMENTUM_THRESHOLD &&
+ fabsf(lateralSpeed) <= RESET_MOMENTUM_THRESHOLD) {
+ _isMovingWithMomentum = false;
+ }
+
+
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
- _animVars.set("isNotInput", true);
- _animVars.set("isNotInputSlow", true);
+
+ // directly reflects input
+ _animVars.set("isNotInput", true);
+
+ // no input + speed drops to SLOW_SPEED_THRESHOLD
+ // (don't transition run->idle - slow to walk first)
+ _animVars.set("isNotInputSlow", _isMovingWithMomentum);
+
+ // no input + speed didn't get above HAS_MOMENTUM_THRESHOLD since last idle
+ // (brief inputs and movement adjustments)
+ _animVars.set("isNotInputNoMomentum", !_isMovingWithMomentum);
+
} else {
_animVars.set("isInputForward", false);
@@ -1456,8 +1514,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", true);
_animVars.set("isNotInputSlow", false);
+ _animVars.set("isNotInputNoMomentum", false);
}
} else if (fabsf(_previousControllerParameters.inputZ) >= fabsf(_previousControllerParameters.inputX)) {
+ if (fabsf(forwardSpeed) > HAS_MOMENTUM_THRESHOLD) {
+ _isMovingWithMomentum = true;
+ }
+
if (_previousControllerParameters.inputZ > 0.0f) {
// forward
_animVars.set("isInputForward", true);
@@ -1466,6 +1529,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
+ _animVars.set("isNotInputNoMomentum", false);
} else {
// backward
_animVars.set("isInputForward", false);
@@ -1474,8 +1538,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
+ _animVars.set("isNotInputNoMomentum", false);
}
} else {
+ if (fabsf(lateralSpeed) > HAS_MOMENTUM_THRESHOLD) {
+ _isMovingWithMomentum = true;
+ }
+
if (_previousControllerParameters.inputX > 0.0f) {
// right
if (!_headEnabled) {
@@ -1489,6 +1558,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInputBackward", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
+ _animVars.set("isNotInputNoMomentum", false);
} else {
// left
if (!_headEnabled) {
@@ -1502,6 +1572,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isInputRight", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
+ _animVars.set("isNotInputNoMomentum", false);
}
}
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index b2b9ecd5b4..60a2602316 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -330,6 +330,7 @@ protected:
glm::vec3 _lastForward;
glm::vec3 _lastPosition;
glm::vec3 _lastVelocity;
+ bool _isMovingWithMomentum{ false };
QUrl _animGraphURL;
std::shared_ptr _animNode;
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 7494081c55..d9ad82fb51 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -111,11 +111,17 @@ QList getAvailableDevices(QAudio::Mode mode, const QString&
}
if (defaultDesktopDevice.getDevice().isNull()) {
- qCDebug(audioclient) << __FUNCTION__ << "Default device not found in list:" << defDeviceName
- << "Setting Default to: " << devices.first().deviceName();
- defaultDesktopDevice = HifiAudioDeviceInfo(devices.first(), true, mode, HifiAudioDeviceInfo::desktop);
+ if (devices.size() > 0) {
+ qCDebug(audioclient) << __FUNCTION__ << "Default device not found in list:" << defDeviceName
+ << "Setting Default to: " << devices.first().deviceName();
+ newDevices.push_front(HifiAudioDeviceInfo(devices.first(), true, mode, HifiAudioDeviceInfo::desktop));
+ } else {
+ //current audio list is empty for some reason.
+ qCDebug(audioclient) << __FUNCTION__ << "Default device not found in list no alternative selection available";
+ }
+ } else {
+ newDevices.push_front(defaultDesktopDevice);
}
- newDevices.push_front(defaultDesktopDevice);
if (!hmdName.isNull()) {
HifiAudioDeviceInfo hmdDevice;
@@ -153,16 +159,20 @@ void AudioClient::checkDevices() {
auto inputDevices = getAvailableDevices(QAudio::AudioInput, hmdInputName);
auto outputDevices = getAvailableDevices(QAudio::AudioOutput, hmdOutputName);
- Lock lock(_deviceMutex);
- if (inputDevices != _inputDevices) {
- _inputDevices.swap(inputDevices);
- emit devicesChanged(QAudio::AudioInput, _inputDevices);
- }
+ static const QMetaMethod devicesChangedSig= QMetaMethod::fromSignal(&AudioClient::devicesChanged);
+ //only emit once the scripting interface has connected to the signal
+ if (isSignalConnected(devicesChangedSig)) {
+ Lock lock(_deviceMutex);
+ if (inputDevices != _inputDevices) {
+ _inputDevices.swap(inputDevices);
+ emit devicesChanged(QAudio::AudioInput, _inputDevices);
+ }
- if (outputDevices != _outputDevices) {
- _outputDevices.swap(outputDevices);
- emit devicesChanged(QAudio::AudioOutput, _outputDevices);
- }
+ if (outputDevices != _outputDevices) {
+ _outputDevices.swap(outputDevices);
+ emit devicesChanged(QAudio::AudioOutput, _outputDevices);
+ }
+ }
}
HifiAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudio::Mode mode) const {
@@ -325,9 +335,9 @@ AudioClient::AudioClient() {
connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat);
// initialize wasapi; if getAvailableDevices is called from the CheckDevicesThread before this, it will crash
- getAvailableDevices(QAudio::AudioInput, QString());
- getAvailableDevices(QAudio::AudioOutput, QString());
-
+ defaultAudioDeviceName(QAudio::AudioInput);
+ defaultAudioDeviceName(QAudio::AudioOutput);
+
// start a thread to detect any device changes
_checkDevicesTimer = new QTimer(this);
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
@@ -777,8 +787,11 @@ void AudioClient::start() {
inputName = _hmdInputName;
outputName = _hmdOutputName;
}
+
+ //initialize input to the dummy device to prevent starves
+ switchInputToAudioDevice(HifiAudioDeviceInfo());
+ switchOutputToAudioDevice(defaultAudioDeviceForMode(QAudio::AudioOutput, QString()));
-
#if defined(Q_OS_ANDROID)
connect(&_checkInputTimer, &QTimer::timeout, this, &AudioClient::checkInputTimeout);
_checkInputTimer.start(CHECK_INPUT_READS_MSECS);
@@ -1829,6 +1842,8 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice
_audioInput->deleteLater();
_audioInput = NULL;
_numInputCallbackBytes = 0;
+
+ _inputDeviceInfo.setDevice(QAudioDeviceInfo());
}
if (_dummyAudioInput) {
@@ -2052,6 +2067,11 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi
Lock localAudioLock(_localAudioMutex);
_localSamplesAvailable.exchange(0, std::memory_order_release);
+ //wait on local injectors prep to finish running
+ if ( !_localPrepInjectorFuture.isFinished()) {
+ _localPrepInjectorFuture.waitForFinished();
+ }
+
// cleanup any previously initialized device
if (_audioOutput) {
_audioOutputIODevice.close();
@@ -2075,6 +2095,8 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi
delete[] _localOutputMixBuffer;
_localOutputMixBuffer = NULL;
+
+ _outputDeviceInfo.setDevice(QAudioDeviceInfo());
}
// cleanup any resamplers
@@ -2328,9 +2350,9 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
qCDebug(audiostream, "Read %d samples from injectors (%d available, %d requested)", injectorSamplesPopped, _localInjectorsStream.samplesAvailable(), samplesRequested);
}
}
-
+
// prepare injectors for the next callback
- QtConcurrent::run(QThreadPool::globalInstance(), [this] {
+ _audio->_localPrepInjectorFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
_audio->prepareLocalAudioInjectors();
});
diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h
index e31b4789ce..09abb2c356 100644
--- a/libraries/audio-client/src/AudioClient.h
+++ b/libraries/audio-client/src/AudioClient.h
@@ -18,6 +18,7 @@
#include |