//// Created by Sam Gondelman 10/20/2017// Copyright 2017 High Fidelity, Inc.// Copyright 2023 Overte e.V.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// SPDX-License-Identifier: Apache-2.0//#ifndef hifi_PointerScriptingInterface_h#define hifi_PointerScriptingInterface_h #include <QtCore/QObject> #include "DependencyManager.h"#include "RegisteredMetaTypes.h"#include <EntityItemProperties.h>#include <PointerManager.h>#include <Pick.h> class ScriptValue; /*@jsdoc * The <code>Pointers</code> API lets you create, manage, and visually represent objects for repeatedly calculating * intersections with avatars, entities, and overlays. Pointers can also be configured to generate events on entities and * overlays intersected. * * @namespace Pointers * * @hifi-interface * @hifi-client-entity * @hifi-avatar */ class PointerProperties {public: QVariantMap properties; QList<EntityItemProperties> entityProperties;}; class RayPointerProperties : public PointerProperties {}; class ParabolaPointerProperties : public PointerProperties {}; class StylusPointerProperties : public PointerProperties {}; Q_DECLARE_METATYPE(RayPointerProperties);Q_DECLARE_METATYPE(StylusPointerProperties);Q_DECLARE_METATYPE(ParabolaPointerProperties);Q_DECLARE_METATYPE(PointerProperties); class PointerScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: // The purpose of registering different classes is to let the script engine know what data structure it has to // expect in JS object that will be converted to PointerProperties /*@jsdoc * Specifies that a {@link Controller} action or function should trigger events on the entity or overlay currently * intersected by a {@link Pointers.RayPointerProperties|Ray} or {@link Pointers.ParabolaPointerProperties|Parabola} * pointer. * @typedef {object} Pointers.Trigger * @property {Controller.Standard|Controller.Actions|function} action - The controller output or function that triggers the * events on the entity or overlay. If a function, it must return a number <code>>= 1.0</code> to start the action * and <code>< 1.0</code> to terminate the action. * @property {string} button - Which button to trigger: * <ul> * <li><code>"Primary"</code>, <code>"Secondary"</code>, and <code>"Tertiary"</code> cause {@link Entities} and * {@link Overlays} mouse pointer events. Other button names also cause mouse events but the <code>button</code> * property in the event will be <code>"None"</code>.</li> * <li><code>"Focus"</code> will try to give focus to the entity or overlay which the pointer is intersecting.</li> * </ul> */ /*@jsdoc * Creates a new ray, parabola, or stylus pointer. The pointer can have a wide range of behaviors depending on the * properties specified. For example, a ray pointer may be a static ray pointer, a mouse ray pointer, or joint ray * pointer. * <p><strong>Warning:</strong> Pointers created using this method currently always intersect at least visible and * collidable things but this may not always be the case.</p> * @function Pointers.createPointer * @param {PickType} type - The type of pointer to create. Cannot be {@link PickType|PickType.Collision}. * @param {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|Pointers.StylusPointerProperties} properties - * The properties of the pointer, per the pointer <code>type</code>, including the properties of the underlying pick * that the pointer uses to do its picking. * @returns {number} The ID of the pointer if successfully created, otherwise <code>0</code>. * * @example <caption>Create a ray pointer on the left hand that changes color when it's intersecting and that triggers * events.<br /> * Note: Stop controllerScripts.js from running to disable similar behavior from it.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * type: "PolyLine", * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * type: "PolyLine", * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [{ name: "example", path: intersectedPath, end: intersectEnd }]; * var defaultRenderStates = [{ name: "example", distance: 20.0, path: searchPath, end: searchEnd }]; * * // Create the pointer. * var rayPointer = Pointers.createPointer(PickType.Ray, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates, * hover: true, // Generate hover events. * triggers: [ * { action: Controller.Standard.LTClick, button: "Primary" }, // Generate mouse events. * { action: Controller.Standard.LTClick, button: "Focus" } // Focus on web entities. * ], * enabled: true * }); * Pointers.setRenderState(rayPointer, "example"); * * // Hover events. * Entities.hoverEnterEntity.connect(function (entityID, event) { * print("hoverEnterEntity() : " + entityID); * }); * Entities.hoverLeaveEntity.connect(function (entityID, event) { * print("hoverLeaveEntity() : " + entityID); * }); * * // Mouse events. * Entities.mousePressOnEntity.connect(function (entityID, event) { * print("mousePressOnEntity() : " + entityID + " , " + event.button); * }); * Entities.mouseReleaseOnEntity.connect(function (entityID, event) { * print("mouseReleaseOnEntity() : " + entityID + " , " + event.button); * }); * * // Tidy up. * Script.scriptEnding.connect(function () { * Pointers.removePointer(rayPointer); * }); */ // TODO: expand Pointers to be able to be fully configurable with PickFilters // V8TODO: add documentation Q_INVOKABLE unsigned int createRayPointer(RayPointerProperties properties); Q_INVOKABLE unsigned int createStylusPointer(StylusPointerProperties properties); Q_INVOKABLE unsigned int createParabolaPointer(ParabolaPointerProperties properties); /*@jsdoc * Enables and shows a pointer. Enabled pointers update their pick results and generate events. * @function Pointers.enablePointer * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void enablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); } /*@jsdoc * Disables and hides a pointer. Disabled pointers do not update their pick results or generate events. * @function Pointers.disablePointer * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void disablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); } /*@jsdoc * Gets the enabled status of a pointer. Enabled pointers update their pick results and generate events. * @function Pointers.isPointerEnabled * @param {number} id - The ID of the pointer. * @returns {boolean} enabled - Whether or not the pointer is enabled. */ Q_INVOKABLE bool isPointerEnabled(unsigned int uid) const; /*@jsdoc * Removes (deletes) a pointer. * @function Pointers.removePointer * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void removePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->removePointer(uid); } /*@jsdoc * Gets the parameters that were passed in to {@link Pointers.createPointer} to create the pointer when the pointer was * created through a script. * <p><strong>Note:</strong> 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|Pointers.ParabolaPointerProperties|Pointers.StylusPointerProperties} * Script-provided properties, per the pointer <code>type</code>. */ Q_INVOKABLE QVariantMap getPointerScriptParameters(unsigned int uid) const; /*@jsdoc * Gets all pointers which currently exist, including disabled pointers. * @function Pointers.getPointers * @returns {number[]} pointers - The IDs of the pointers. */ Q_INVOKABLE QVector<unsigned int> getPointers() const; /*@jsdoc * Edits a render state of a {@link Pointers.RayPointerProperties|ray} or * {@link Pointers.ParabolaPointerProperties|parabola} pointer, to change its visual appearance for the state when the * pointer is intersecting something. * <p><strong>Note:</strong> You can only edit the properties of the existing parts of the pointer; you cannot change the * type of any part.</p> * <p><strong>Note:</strong> You cannot use this method to change the appearance of a default render state.</p> * <p><strong>Note:</strong> Not able to be used with stylus pointers.</p> * @function Pointers.editRenderState * @param {number} id - The ID of the pointer. * @param {string} renderState - The name of the render state to edit. * @param {Pointers.RayPointerRenderState|Pointers.ParabolaPointerRenderState} properties - The new properties for the * render state. Only the properties to change need be specified. * @example <caption>Change the dimensions of a ray pointer's intersecting end entity.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * type: "PolyLine", * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * type: "PolyLine", * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [ { name: "example", path: intersectedPath, end: intersectEnd } ]; * var defaultRenderStates = [ { name: "example", distance: 20.0, path: searchPath, end: searchEnd } ]; * * // Create the pointer. * var rayPointer = Pointers.createPointer(PickType.Ray, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates, * enabled: true * }); * Pointers.setRenderState(rayPointer, "example"); * * // Edit the intersecting render state. * Script.setTimeout(function () { * print("Edit render state"); * Pointers.editRenderState(rayPointer, "example", { * end: { dimensions: { x: 0.5, y: 0.5, z: 0.5 } } * }); * }, 10000); * * Script.setTimeout(function () { * print("Edit render state"); * Pointers.editRenderState(rayPointer, "example", { * end: { dimensions: { x: 0.2, y: 0.2, z: 0.2 } } * }); * }, 15000); * * // Tidy up. * Script.scriptEnding.connect(function () { * Pointers.removePointer(rayPointer); * }); */ Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const; /*@jsdoc * Sets the render state of a pointer, to change its visual appearance and possibly disable or enable it. * @function Pointers.setRenderState * @param {number} id - The ID of the pointer. * @param {string} renderState - <p>The name of the render state to set the pointer to.</p> * <p>For {@link Pointers.RayPointerProperties|ray} and {@link Pointers.ParabolaPointerProperties|parabola} pointers, * this may be:</p> * <ul> * <li>The name of one of the render states set in the pointer's properties.</li> * <li><code>""</code>, to hide the pointer and disable emitting of events.</li> * </ul> * <p>For {@link Pointers.StylusPointerProperties|stylus} pointers, the values may be:</p> * <ul> * <li><code>"events on"</code>, to render and emit events (the default).</li> * <li><code>"events off"</code>, to render but don't emit events.</li> * <li><code>"disabled"</code>, to not render and not emit events.</li> * </ul> * @example <caption>Switch a ray pointer between having a path and not having a path.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * type: "PolyLine", * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * type: "PolyLine", * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [ * { name: "examplePath", path: intersectedPath, end: intersectEnd }, * { name: "exampleNoPath", end: intersectEnd } * ]; * var defaultRenderStates = [ * { name: "examplePath", distance: 20.0, path: searchPath, end: searchEnd }, * { name: "exampleNoPath", distance: 20.0, end: searchEnd } * ]; * * // Create the pointer. * var rayPointer = Pointers.createPointer(PickType.Ray, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates, * enabled: true * }); * Pointers.setRenderState(rayPointer, "examplePath"); * * // Change states. * Script.setTimeout(function () { * print("Without path"); * Pointers.setRenderState(rayPointer, "exampleNoPath"); * }, 10000); * * Script.setTimeout(function () { * print("With path"); * Pointers.setRenderState(rayPointer, "examplePath"); * }, 15000); * * // Tidy up. * Script.scriptEnding.connect(function () { * Pointers.removePointer(rayPointer); * }); */ Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get<PointerManager>()->setRenderState(uid, renderState.toStdString()); } /*@jsdoc * Gets the most recent intersection of a pointer. A pointer continues to be updated ready to return a result, as long as * it is enabled, regardless of the render state. * @function Pointers.getPrevPickResult * @param {number} id - The ID of the pointer. * @returns {RayPickResult|ParabolaPickResult|StylusPickResult} The most recent intersection of the pointer. */ Q_INVOKABLE QVariantMap getPrevPickResult(unsigned int uid) const; /*@jsdoc * Sets whether or not a pointer should use precision picking, i.e., whether it should pick against precise meshes or * coarse meshes. This has the same effect as using the <code>PICK_PRECISE</code> or <code>PICK_COARSE</code> filter flags. * @function Pointers.setPrecisionPicking * @param {number} id - The ID of the pointer. * @param {boolean} precisionPicking - <code>true</code> to use precision picking, <code>false</code> to use coarse picking. */ Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get<PointerManager>()->setPrecisionPicking(uid, precisionPicking); } /*@jsdoc * Sets the length of a pointer. * <p><strong>Note:</strong> Not used by stylus pointers.</p> * @function Pointers.setLength * @param {number} id - The ID of the pointer. * @param {number} length - The desired length of the pointer. */ Q_INVOKABLE void setLength(unsigned int uid, float length) const { DependencyManager::get<PointerManager>()->setLength(uid, length); } /*@jsdoc * Sets a list of entity and avatar IDs that a pointer should ignore during intersection. * <p><strong>Note:</strong> Not used by stylus pointers.</p> * @function Pointers.setIgnoreItems * @param {number} id - The ID of the pointer. * @param {Uuid[]} ignoreItems - A list of IDs to ignore. */ Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValue& ignoreEntities) const; /*@jsdoc * Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with * everything. * <p><strong>Note:</strong> Stylus pointers only intersect with items in their include list.</p> * @function Pointers.setIncludeItems * @param {number} id - The ID of the pointer. * @param {Uuid[]} includeItems - A list of IDs to include. */ Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValue& includeEntities) const; /*@jsdoc * Locks a pointer onto a specific entity or avatar. * <p><strong>Note:</strong> Not used by stylus pointers.</p> * @function Pointers.setLockEndUUID * @param {number} id - The ID of the pointer. * @param {Uuid} targetID - The ID of the entity or avatar to lock the pointer on to. * @param {boolean} isAvatar - <code>true</code> if the target is an avatar, <code>false</code> if it is an entity. * @param {Mat4} [offset] - The offset of the target point from the center of the target item. If not specified, the * pointer locks on to the center of the target item. */ Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); } /*@jsdoc * Sets the delay of a Ray pointer. * <p><strong>Note:</strong> Not used by stylus or parabola pointers.</p> * @function Pointers.setDelay * @param {number} id - The ID of the pointer. * @param {number} delay - The desired delay in seconds. */ Q_INVOKABLE void setDelay(unsigned int uid, float delay) const { DependencyManager::get<PointerManager>()->setDelay(uid, delay); } /*@jsdoc * Checks if a pointer is associated with the left hand: a ray or parabola pointer with <code>joint</code> property set to * <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pointer with * <code>hand</code> property set to <code>0</code>. * @function Pointers.isLeftHand * @param {number} id - The ID of the pointer. * @returns {boolean} <code>true</code> if the pointer is associated with the left hand, <code>false</code> if it isn't. */ Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isLeftHand(uid); } /*@jsdoc * Checks if a pointer is associated with the right hand: a ray or parabola pointer with <code>joint</code> property set to * <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pointer with * <code>hand</code> property set to <code>1</code>. * @function Pointers.isRightHand * @param {number} id - The ID of the pointer. * @returns {boolean} <code>true</code> if the pointer is associated with the right hand, <code>false</code> if it isn't. */ Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isRightHand(uid); } /*@jsdoc * Checks if a pointer is associated with the system mouse: a ray or parabola pointer with <code>joint</code> property set * to <code>"Mouse"</code>. * @function Pointers.isMouse * @param {number} id - The ID of the pointer. * @returns {boolean} <code>true</code> if the pointer is associated with the system mouse, <code>false</code> if it isn't. */ Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get<PointerManager>()->isMouse(uid); } /*@jsdoc * Gets information about a pointer. * @function Pointers.getPointerProperties * @param {number} id - The ID of the pointer. * @returns {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|object} The <code>renderStates</code> and * <code>defaultRenderStates</code> for ray and parabola pointers, <code>{}</code> for stylus pointers. * @example <caption>Report the properties of a parabola pointer.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [{ name: "example", path: intersectedPath, end: intersectEnd }]; * var defaultRenderStates = [{ name: "example", distance: 20.0, path: searchPath, end: searchEnd }]; * * // Create the pointer. * var parabolaPointer = Pointers.createPointer(PickType.Parabola, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates,Lines 1–500 of 534. Load more
// // Created by Sam Gondelman 10/20/2017 // Copyright 2017 High Fidelity, Inc. // Copyright 2023 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // SPDX-License-Identifier: Apache-2.0 // #ifndef hifi_PointerScriptingInterface_h #define hifi_PointerScriptingInterface_h #include <QtCore/QObject> #include "DependencyManager.h" #include "RegisteredMetaTypes.h" #include <EntityItemProperties.h> #include <PointerManager.h> #include <Pick.h> class ScriptValue; /*@jsdoc * The <code>Pointers</code> API lets you create, manage, and visually represent objects for repeatedly calculating * intersections with avatars, entities, and overlays. Pointers can also be configured to generate events on entities and * overlays intersected. * * @namespace Pointers * * @hifi-interface * @hifi-client-entity * @hifi-avatar */ class PointerProperties { public: QVariantMap properties; QList<EntityItemProperties> entityProperties; }; class RayPointerProperties : public PointerProperties { }; class ParabolaPointerProperties : public PointerProperties { }; class StylusPointerProperties : public PointerProperties { }; Q_DECLARE_METATYPE(RayPointerProperties); Q_DECLARE_METATYPE(StylusPointerProperties); Q_DECLARE_METATYPE(ParabolaPointerProperties); Q_DECLARE_METATYPE(PointerProperties); class PointerScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: // The purpose of registering different classes is to let the script engine know what data structure it has to // expect in JS object that will be converted to PointerProperties /*@jsdoc * Specifies that a {@link Controller} action or function should trigger events on the entity or overlay currently * intersected by a {@link Pointers.RayPointerProperties|Ray} or {@link Pointers.ParabolaPointerProperties|Parabola} * pointer. * @typedef {object} Pointers.Trigger * @property {Controller.Standard|Controller.Actions|function} action - The controller output or function that triggers the * events on the entity or overlay. If a function, it must return a number <code>>= 1.0</code> to start the action * and <code>< 1.0</code> to terminate the action. * @property {string} button - Which button to trigger: * <ul> * <li><code>"Primary"</code>, <code>"Secondary"</code>, and <code>"Tertiary"</code> cause {@link Entities} and * {@link Overlays} mouse pointer events. Other button names also cause mouse events but the <code>button</code> * property in the event will be <code>"None"</code>.</li> * <li><code>"Focus"</code> will try to give focus to the entity or overlay which the pointer is intersecting.</li> * </ul> */ /*@jsdoc * Creates a new ray, parabola, or stylus pointer. The pointer can have a wide range of behaviors depending on the * properties specified. For example, a ray pointer may be a static ray pointer, a mouse ray pointer, or joint ray * pointer. * <p><strong>Warning:</strong> Pointers created using this method currently always intersect at least visible and * collidable things but this may not always be the case.</p> * @function Pointers.createPointer * @param {PickType} type - The type of pointer to create. Cannot be {@link PickType|PickType.Collision}. * @param {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|Pointers.StylusPointerProperties} properties - * The properties of the pointer, per the pointer <code>type</code>, including the properties of the underlying pick * that the pointer uses to do its picking. * @returns {number} The ID of the pointer if successfully created, otherwise <code>0</code>. * * @example <caption>Create a ray pointer on the left hand that changes color when it's intersecting and that triggers * events.<br /> * Note: Stop controllerScripts.js from running to disable similar behavior from it.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * type: "PolyLine", * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * type: "PolyLine", * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [{ name: "example", path: intersectedPath, end: intersectEnd }]; * var defaultRenderStates = [{ name: "example", distance: 20.0, path: searchPath, end: searchEnd }]; * * // Create the pointer. * var rayPointer = Pointers.createPointer(PickType.Ray, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates, * hover: true, // Generate hover events. * triggers: [ * { action: Controller.Standard.LTClick, button: "Primary" }, // Generate mouse events. * { action: Controller.Standard.LTClick, button: "Focus" } // Focus on web entities. * ], * enabled: true * }); * Pointers.setRenderState(rayPointer, "example"); * * // Hover events. * Entities.hoverEnterEntity.connect(function (entityID, event) { * print("hoverEnterEntity() : " + entityID); * }); * Entities.hoverLeaveEntity.connect(function (entityID, event) { * print("hoverLeaveEntity() : " + entityID); * }); * * // Mouse events. * Entities.mousePressOnEntity.connect(function (entityID, event) { * print("mousePressOnEntity() : " + entityID + " , " + event.button); * }); * Entities.mouseReleaseOnEntity.connect(function (entityID, event) { * print("mouseReleaseOnEntity() : " + entityID + " , " + event.button); * }); * * // Tidy up. * Script.scriptEnding.connect(function () { * Pointers.removePointer(rayPointer); * }); */ // TODO: expand Pointers to be able to be fully configurable with PickFilters // V8TODO: add documentation Q_INVOKABLE unsigned int createRayPointer(RayPointerProperties properties); Q_INVOKABLE unsigned int createStylusPointer(StylusPointerProperties properties); Q_INVOKABLE unsigned int createParabolaPointer(ParabolaPointerProperties properties); /*@jsdoc * Enables and shows a pointer. Enabled pointers update their pick results and generate events. * @function Pointers.enablePointer * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void enablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); } /*@jsdoc * Disables and hides a pointer. Disabled pointers do not update their pick results or generate events. * @function Pointers.disablePointer * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void disablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); } /*@jsdoc * Gets the enabled status of a pointer. Enabled pointers update their pick results and generate events. * @function Pointers.isPointerEnabled * @param {number} id - The ID of the pointer. * @returns {boolean} enabled - Whether or not the pointer is enabled. */ Q_INVOKABLE bool isPointerEnabled(unsigned int uid) const; /*@jsdoc * Removes (deletes) a pointer. * @function Pointers.removePointer * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void removePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->removePointer(uid); } /*@jsdoc * Gets the parameters that were passed in to {@link Pointers.createPointer} to create the pointer when the pointer was * created through a script. * <p><strong>Note:</strong> 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|Pointers.ParabolaPointerProperties|Pointers.StylusPointerProperties} * Script-provided properties, per the pointer <code>type</code>. */ Q_INVOKABLE QVariantMap getPointerScriptParameters(unsigned int uid) const; /*@jsdoc * Gets all pointers which currently exist, including disabled pointers. * @function Pointers.getPointers * @returns {number[]} pointers - The IDs of the pointers. */ Q_INVOKABLE QVector<unsigned int> getPointers() const; /*@jsdoc * Edits a render state of a {@link Pointers.RayPointerProperties|ray} or * {@link Pointers.ParabolaPointerProperties|parabola} pointer, to change its visual appearance for the state when the * pointer is intersecting something. * <p><strong>Note:</strong> You can only edit the properties of the existing parts of the pointer; you cannot change the * type of any part.</p> * <p><strong>Note:</strong> You cannot use this method to change the appearance of a default render state.</p> * <p><strong>Note:</strong> Not able to be used with stylus pointers.</p> * @function Pointers.editRenderState * @param {number} id - The ID of the pointer. * @param {string} renderState - The name of the render state to edit. * @param {Pointers.RayPointerRenderState|Pointers.ParabolaPointerRenderState} properties - The new properties for the * render state. Only the properties to change need be specified. * @example <caption>Change the dimensions of a ray pointer's intersecting end entity.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * type: "PolyLine", * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * type: "PolyLine", * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [ { name: "example", path: intersectedPath, end: intersectEnd } ]; * var defaultRenderStates = [ { name: "example", distance: 20.0, path: searchPath, end: searchEnd } ]; * * // Create the pointer. * var rayPointer = Pointers.createPointer(PickType.Ray, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates, * enabled: true * }); * Pointers.setRenderState(rayPointer, "example"); * * // Edit the intersecting render state. * Script.setTimeout(function () { * print("Edit render state"); * Pointers.editRenderState(rayPointer, "example", { * end: { dimensions: { x: 0.5, y: 0.5, z: 0.5 } } * }); * }, 10000); * * Script.setTimeout(function () { * print("Edit render state"); * Pointers.editRenderState(rayPointer, "example", { * end: { dimensions: { x: 0.2, y: 0.2, z: 0.2 } } * }); * }, 15000); * * // Tidy up. * Script.scriptEnding.connect(function () { * Pointers.removePointer(rayPointer); * }); */ Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const; /*@jsdoc * Sets the render state of a pointer, to change its visual appearance and possibly disable or enable it. * @function Pointers.setRenderState * @param {number} id - The ID of the pointer. * @param {string} renderState - <p>The name of the render state to set the pointer to.</p> * <p>For {@link Pointers.RayPointerProperties|ray} and {@link Pointers.ParabolaPointerProperties|parabola} pointers, * this may be:</p> * <ul> * <li>The name of one of the render states set in the pointer's properties.</li> * <li><code>""</code>, to hide the pointer and disable emitting of events.</li> * </ul> * <p>For {@link Pointers.StylusPointerProperties|stylus} pointers, the values may be:</p> * <ul> * <li><code>"events on"</code>, to render and emit events (the default).</li> * <li><code>"events off"</code>, to render but don't emit events.</li> * <li><code>"disabled"</code>, to not render and not emit events.</li> * </ul> * @example <caption>Switch a ray pointer between having a path and not having a path.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * type: "PolyLine", * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * type: "PolyLine", * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [ * { name: "examplePath", path: intersectedPath, end: intersectEnd }, * { name: "exampleNoPath", end: intersectEnd } * ]; * var defaultRenderStates = [ * { name: "examplePath", distance: 20.0, path: searchPath, end: searchEnd }, * { name: "exampleNoPath", distance: 20.0, end: searchEnd } * ]; * * // Create the pointer. * var rayPointer = Pointers.createPointer(PickType.Ray, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates, * enabled: true * }); * Pointers.setRenderState(rayPointer, "examplePath"); * * // Change states. * Script.setTimeout(function () { * print("Without path"); * Pointers.setRenderState(rayPointer, "exampleNoPath"); * }, 10000); * * Script.setTimeout(function () { * print("With path"); * Pointers.setRenderState(rayPointer, "examplePath"); * }, 15000); * * // Tidy up. * Script.scriptEnding.connect(function () { * Pointers.removePointer(rayPointer); * }); */ Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get<PointerManager>()->setRenderState(uid, renderState.toStdString()); } /*@jsdoc * Gets the most recent intersection of a pointer. A pointer continues to be updated ready to return a result, as long as * it is enabled, regardless of the render state. * @function Pointers.getPrevPickResult * @param {number} id - The ID of the pointer. * @returns {RayPickResult|ParabolaPickResult|StylusPickResult} The most recent intersection of the pointer. */ Q_INVOKABLE QVariantMap getPrevPickResult(unsigned int uid) const; /*@jsdoc * Sets whether or not a pointer should use precision picking, i.e., whether it should pick against precise meshes or * coarse meshes. This has the same effect as using the <code>PICK_PRECISE</code> or <code>PICK_COARSE</code> filter flags. * @function Pointers.setPrecisionPicking * @param {number} id - The ID of the pointer. * @param {boolean} precisionPicking - <code>true</code> to use precision picking, <code>false</code> to use coarse picking. */ Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get<PointerManager>()->setPrecisionPicking(uid, precisionPicking); } /*@jsdoc * Sets the length of a pointer. * <p><strong>Note:</strong> Not used by stylus pointers.</p> * @function Pointers.setLength * @param {number} id - The ID of the pointer. * @param {number} length - The desired length of the pointer. */ Q_INVOKABLE void setLength(unsigned int uid, float length) const { DependencyManager::get<PointerManager>()->setLength(uid, length); } /*@jsdoc * Sets a list of entity and avatar IDs that a pointer should ignore during intersection. * <p><strong>Note:</strong> Not used by stylus pointers.</p> * @function Pointers.setIgnoreItems * @param {number} id - The ID of the pointer. * @param {Uuid[]} ignoreItems - A list of IDs to ignore. */ Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValue& ignoreEntities) const; /*@jsdoc * Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with * everything. * <p><strong>Note:</strong> Stylus pointers only intersect with items in their include list.</p> * @function Pointers.setIncludeItems * @param {number} id - The ID of the pointer. * @param {Uuid[]} includeItems - A list of IDs to include. */ Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValue& includeEntities) const; /*@jsdoc * Locks a pointer onto a specific entity or avatar. * <p><strong>Note:</strong> Not used by stylus pointers.</p> * @function Pointers.setLockEndUUID * @param {number} id - The ID of the pointer. * @param {Uuid} targetID - The ID of the entity or avatar to lock the pointer on to. * @param {boolean} isAvatar - <code>true</code> if the target is an avatar, <code>false</code> if it is an entity. * @param {Mat4} [offset] - The offset of the target point from the center of the target item. If not specified, the * pointer locks on to the center of the target item. */ Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); } /*@jsdoc * Sets the delay of a Ray pointer. * <p><strong>Note:</strong> Not used by stylus or parabola pointers.</p> * @function Pointers.setDelay * @param {number} id - The ID of the pointer. * @param {number} delay - The desired delay in seconds. */ Q_INVOKABLE void setDelay(unsigned int uid, float delay) const { DependencyManager::get<PointerManager>()->setDelay(uid, delay); } /*@jsdoc * Checks if a pointer is associated with the left hand: a ray or parabola pointer with <code>joint</code> property set to * <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pointer with * <code>hand</code> property set to <code>0</code>. * @function Pointers.isLeftHand * @param {number} id - The ID of the pointer. * @returns {boolean} <code>true</code> if the pointer is associated with the left hand, <code>false</code> if it isn't. */ Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isLeftHand(uid); } /*@jsdoc * Checks if a pointer is associated with the right hand: a ray or parabola pointer with <code>joint</code> property set to * <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pointer with * <code>hand</code> property set to <code>1</code>. * @function Pointers.isRightHand * @param {number} id - The ID of the pointer. * @returns {boolean} <code>true</code> if the pointer is associated with the right hand, <code>false</code> if it isn't. */ Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isRightHand(uid); } /*@jsdoc * Checks if a pointer is associated with the system mouse: a ray or parabola pointer with <code>joint</code> property set * to <code>"Mouse"</code>. * @function Pointers.isMouse * @param {number} id - The ID of the pointer. * @returns {boolean} <code>true</code> if the pointer is associated with the system mouse, <code>false</code> if it isn't. */ Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get<PointerManager>()->isMouse(uid); } /*@jsdoc * Gets information about a pointer. * @function Pointers.getPointerProperties * @param {number} id - The ID of the pointer. * @returns {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|object} The <code>renderStates</code> and * <code>defaultRenderStates</code> for ray and parabola pointers, <code>{}</code> for stylus pointers. * @example <caption>Report the properties of a parabola pointer.</caption> * var intersectEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 0, green: 255, blue: 0 }, * ignorePickIntersection: true * }; * var intersectedPath = { * color: { red: 0, green: 255, blue: 0 }, * }; * var searchEnd = { * type: "sphere", * dimensions: { x: 0.2, y: 0.2, z: 0.2 }, * solid: true, * color: { red: 255, green: 0, blue: 0 }, * ignorePickIntersection: true * }; * var searchPath = { * color: { red: 255, green: 0, blue: 0 }, * }; * * var renderStates = [{ name: "example", path: intersectedPath, end: intersectEnd }]; * var defaultRenderStates = [{ name: "example", distance: 20.0, path: searchPath, end: searchEnd }]; * * // Create the pointer. * var parabolaPointer = Pointers.createPointer(PickType.Parabola, { * joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, * renderStates: renderStates, * defaultRenderStates: defaultRenderStates,