more overlay wip

This commit is contained in:
SamGondelman 2019-01-25 11:10:11 -08:00
parent ca8d64bc05
commit 5ce8f566cc
62 changed files with 611 additions and 855 deletions

View file

@ -1,5 +1,5 @@
//
// Web3DOverlay.qml
// Web3DSurface.qml
//
// Created by Gabriel Calero & Cristian Duarte on Jun 22, 2018
// Copyright 2016 High Fidelity, Inc.

View file

@ -1,5 +1,5 @@
//
// Web3DOverlay.qml
// Web3DSurface.qml
//
// Created by David Rowe on 16 Dec 2016.
// Copyright 2016 High Fidelity, Inc.

View file

@ -203,7 +203,6 @@
#include "ui/Stats.h"
#include "ui/AnimStats.h"
#include "ui/UpdateDialog.h"
#include "ui/overlays/Overlays.h"
#include "ui/DomainConnectionModel.h"
#include "ui/Keyboard.h"
#include "Util.h"
@ -4900,7 +4899,7 @@ void Application::idle() {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusLocalEntity(UNKNOWN_ENTITY_ID);
} else {
// update position of highlight overlay
// update position of highlight object
if (!_keyboardFocusedEntity.get().isInvalidID()) {
auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
if (entity && !_keyboardFocusHighlightID.isNull()) {

View file

@ -50,15 +50,6 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& s
return avatarManager->getMyAvatar();
}
// search overlays
auto& overlays = qApp->getOverlays();
auto overlay = overlays.getOverlay(parentID);
parent = std::dynamic_pointer_cast<SpatiallyNestable>(overlay); // this will return nullptr for non-3d overlays
if (!parent.expired()) {
success = true;
return parent;
}
success = false;
return parent;
}

View file

@ -170,7 +170,7 @@ void LoginStateManager::setUp() {
const unsigned int leftHand = 0;
QVariantMap leftPointerProperties {
{ "joint", "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND" },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "triggers", leftPointerTriggerProperties },
{ "posOffset", vec3toVariant(grabPointSphereOffsetLeft + malletOffset) },
{ "hover", true },
@ -197,7 +197,7 @@ void LoginStateManager::setUp() {
rightPointerTriggerProperties = QList<QVariant>({rtClick1, rtClick2});
QVariantMap rightPointerProperties{
{ "joint", "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "triggers", rightPointerTriggerProperties },
{ "posOffset", vec3toVariant(grabPointSphereOffsetRight + malletOffset) },
{ "hover", true },
@ -212,7 +212,7 @@ void LoginStateManager::setUp() {
pointers->enablePointer(_rightLoginPointerID);
}
void LoginStateManager::update(const QString dominantHand, const QUuid loginOverlayID) {
void LoginStateManager::update(const QString& dominantHand, const QUuid& loginEntityID) {
if (!isSetUp()) {
return;
}
@ -224,8 +224,8 @@ void LoginStateManager::update(const QString dominantHand, const QUuid loginOver
if (pointers && raypicks) {
const auto rightObjectID = raypicks->getPrevRayPickResult(_rightLoginPointerID)["objectID"].toUuid();
const auto leftObjectID = raypicks->getPrevRayPickResult(_leftLoginPointerID)["objectID"].toUuid();
const QString leftMode = (leftObjectID.isNull() || leftObjectID != loginOverlayID) ? "" : "full";
const QString rightMode = (rightObjectID.isNull() || rightObjectID != loginOverlayID) ? "" : "full";
const QString leftMode = (leftObjectID.isNull() || leftObjectID != loginEntityID) ? "" : "full";
const QString rightMode = (rightObjectID.isNull() || rightObjectID != loginEntityID) ? "" : "full";
pointers->setRenderState(_leftLoginPointerID, leftMode);
pointers->setRenderState(_rightLoginPointerID, rightMode);
if (_dominantHand == "left" && !leftObjectID.isNull()) {

View file

@ -26,7 +26,7 @@ public:
void setUp();
void tearDown();
void update(const QString dominantHand, const QUuid loginOverlayID);
void update(const QString& dominantHand, const QUuid& loginObjectID);
bool isSetUp() const { return (_leftLoginPointerID > PointerEvent::INVALID_POINTER_ID) && (_rightLoginPointerID > PointerEvent::INVALID_POINTER_ID); }

View file

@ -16,7 +16,6 @@
#include <workload/Space.h>
#include "InterfaceLogging.h"
#include "ui/overlays/Overlays.h"
class AvatarManager;
class AvatarMotionState;

View file

@ -247,6 +247,7 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const P
glm::vec3 LaserPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::intersectRayWithEntityXYPlane(pickedObject.objectID, origin, direction);
default:
return glm::vec3(NAN);

View file

@ -67,7 +67,15 @@ PickResultPointer ParabolaPick::getEntityIntersection(const PickParabola& pick)
DependencyManager::get<EntityScriptingInterface>()->evalParabolaIntersectionVector(pick, searchFilter,
getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (entityRes.intersects) {
return std::make_shared<ParabolaPickResult>(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.parabolicDistance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityRes.entityID, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
return std::make_shared<ParabolaPickResult>(type, entityRes.entityID, entityRes.distance, entityRes.parabolicDistance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
}
}
return std::make_shared<ParabolaPickResult>(pick.toVariantMap());

View file

@ -322,6 +322,7 @@ glm::vec3 ParabolaPointer::findIntersection(const PickedObject& pickedObject, co
// TODO: implement
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
//return ParabolaPick::intersectParabolaWithEntityXYPlane(pickedObject.objectID, origin, velocity, acceleration);
default:
return glm::vec3(NAN);

View file

@ -199,6 +199,7 @@ void PathPointer::editRenderState(const std::string& state, const QVariant& star
}
void PathPointer::updateRenderState(const QUuid& id, const QVariant& props) {
// FIXME: we have to keep using the Overlays interface here, because existing scripts use overlay properties to define pointers
if (!id.isNull() && props.isValid()) {
QVariantMap propMap = props.toMap();
propMap.remove("visible");
@ -243,65 +244,79 @@ Pointer::Buttons PathPointer::getPressedButtons(const PickResultPointer& pickRes
return toReturn;
}
StartEndRenderState::StartEndRenderState(const OverlayID& startID, const OverlayID& endID) :
StartEndRenderState::StartEndRenderState(const QUuid& startID, const QUuid& endID) :
_startID(startID), _endID(endID) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!_startID.isNull()) {
_startDim = vec3FromVariant(qApp->getOverlays().getProperty(_startID, "dimensions").value);
_startIgnoreRays = qApp->getOverlays().getProperty(_startID, "ignorePickIntersection").value.toBool();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
auto properties = entityScriptingInterface->getEntityProperties(_startID, desiredProperties);
_startDim = properties.getDimensions();
_startIgnorePicks = properties.getIgnorePickIntersection();
}
if (!_endID.isNull()) {
_endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value);
_endRot = quatFromVariant(qApp->getOverlays().getProperty(_endID, "rotation").value);
_endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignorePickIntersection").value.toBool();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_ROTATION;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
auto properties = entityScriptingInterface->getEntityProperties(_endID, desiredProperties);
_endDim = properties.getDimensions();
_endRot = properties.getRotation();
_endIgnorePicks = properties.getIgnorePickIntersection();
}
}
void StartEndRenderState::cleanup() {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!_startID.isNull()) {
qApp->getOverlays().deleteOverlay(_startID);
entityScriptingInterface->deleteEntity(_startID);
}
if (!_endID.isNull()) {
qApp->getOverlays().deleteOverlay(_endID);
entityScriptingInterface->deleteEntity(_endID);
}
}
void StartEndRenderState::disable() {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!getStartID().isNull()) {
QVariantMap startProps;
startProps.insert("visible", false);
startProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getStartID(), startProps);
EntityItemProperties properties;
properties.setVisible(false);
properties.setIgnorePickIntersection(true);
entityScriptingInterface->editEntity(getStartID(), properties);
}
if (!getEndID().isNull()) {
QVariantMap endProps;
endProps.insert("visible", false);
endProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getEndID(), endProps);
EntityItemProperties properties;
properties.setVisible(false);
properties.setIgnorePickIntersection(true);
entityScriptingInterface->editEntity(getEndID(), properties);
}
_enabled = false;
}
void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end, const glm::vec3& surfaceNormal, float parentScale, bool distanceScaleEnd, bool centerEndY,
bool faceAvatar, bool followNormal, float followNormalStrength, float distance, const PickResultPointer& pickResult) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (!getStartID().isNull()) {
QVariantMap startProps;
startProps.insert("position", vec3toVariant(origin));
startProps.insert("visible", true);
startProps.insert("dimensions", vec3toVariant(getStartDim() * parentScale));
startProps.insert("ignorePickIntersection", doesStartIgnoreRays());
qApp->getOverlays().editOverlay(getStartID(), startProps);
EntityItemProperties properties;
properties.setPosition(origin);
properties.setVisible(true);
properties.setDimensions(getStartDim() * parentScale);
properties.setIgnorePickIntersection(doesStartIgnorePicks());
entityScriptingInterface->editEntity(getStartID(), properties);
}
if (!getEndID().isNull()) {
QVariantMap endProps;
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(getEndID(), "dimensions").value);
EntityItemProperties properties;
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
glm::vec3 dim = entityScriptingInterface->getEntityProperties(getEndID(), desiredProperties).getDimensions();
if (distanceScaleEnd) {
dim = getEndDim() * glm::distance(origin, end);
endProps.insert("dimensions", vec3toVariant(dim));
} else {
dim = getEndDim() * parentScale;
endProps.insert("dimensions", vec3toVariant(dim));
}
properties.setDimensions(dim);
glm::quat normalQuat = Quat().lookAtSimple(Vectors::ZERO, surfaceNormal);
normalQuat = normalQuat * glm::quat(glm::vec3(-M_PI_2, 0, 0));
@ -337,11 +352,11 @@ void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end,
_avgEndRot = rotation;
}
}
endProps.insert("position", vec3toVariant(position));
endProps.insert("rotation", quatToVariant(rotation));
endProps.insert("visible", true);
endProps.insert("ignorePickIntersection", doesEndIgnoreRays());
qApp->getOverlays().editOverlay(getEndID(), endProps);
properties.setPosition(position);
properties.setRotation(rotation);
properties.setVisible(true);
properties.setIgnorePickIntersection(doesEndIgnorePicks());
entityScriptingInterface->editEntity(getEndID(), properties);
}
_enabled = true;
}
@ -349,9 +364,8 @@ void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end,
glm::vec2 PathPointer::findPos2D(const PickedObject& pickedObject, const glm::vec3& origin) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::projectOntoEntityXYPlane(pickedObject.objectID, origin);
case OVERLAY:
return RayPick::projectOntoOverlayXYPlane(pickedObject.objectID, origin);
case HUD:
return DependencyManager::get<PickManager>()->calculatePos2DFromHUD(origin);
default:

View file

@ -12,8 +12,6 @@
#include <QString>
#include <glm/glm.hpp>
#include "ui/overlays/Overlay.h"
#include <Pointer.h>
#include <Pick.h>
@ -78,7 +76,7 @@ public:
virtual ~PathPointer();
void setRenderState(const std::string& state) override;
// You cannot use editRenderState to change the type of any part of the pointer. You can only edit the properties of the existing overlays.
// You cannot use editRenderState to change the type of any part of the pointer. You can only edit the properties of the existing parts.
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override;
void setLength(float length) override;
@ -119,7 +117,7 @@ protected:
bool shouldHover(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
bool shouldTrigger(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
void updateRenderState(const QUuid& id, const QVariant& props);
virtual void editRenderStatePath(const std::string& state, const QVariant& pathProps) = 0;
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;

View file

@ -26,7 +26,6 @@
#include "avatar/AvatarManager.h"
#include "NestableTransformNode.h"
#include "avatars-renderer/AvatarTransformNode.h"
#include "ui/overlays/OverlayTransformNode.h"
#include "EntityTransformNode.h"
#include <ScriptEngine.h>
@ -61,7 +60,7 @@ PickFilter getPickFilter(unsigned int filter) {
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
* @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
* @property {Vec3} [posOffset=Vec3.ZERO] Only for Joint Ray Picks. A local joint position offset, in meters. x = upward, y = forward, z = lateral
@ -161,7 +160,7 @@ unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
* @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
* @property {Vec3} [posOffset=Vec3.ZERO] Only for Joint Parabola Picks. A local joint position offset, in meters. x = upward, y = forward, z = lateral
@ -264,7 +263,7 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti
* The depth is measured in world space, but will scale with the parent if defined.
* @property {CollisionMask} [collisionGroup=8] - The type of object this collision pick collides as. Objects whose collision masks overlap with the pick's collision group
* will be considered colliding with the pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
* @property {boolean} [scaleWithParent=true] If true, the collision pick's dimensions and threshold will adjust according to the scale of the parent.
@ -415,8 +414,6 @@ void PickScriptingInterface::setParentTransform(std::shared_ptr<PickQuery> pick,
NestableType nestableType = sharedNestablePointer->getNestableType();
if (nestableType == NestableType::Avatar) {
pick->parentTransform = std::make_shared<AvatarTransformNode>(std::static_pointer_cast<Avatar>(sharedNestablePointer), parentJointIndex);
} else if (nestableType == NestableType::Overlay) {
pick->parentTransform = std::make_shared<OverlayTransformNode>(std::static_pointer_cast<Base3DOverlay>(sharedNestablePointer), parentJointIndex);
} else if (nestableType == NestableType::Entity) {
pick->parentTransform = std::make_shared<EntityTransformNode>(std::static_pointer_cast<EntityItem>(sharedNestablePointer), parentJointIndex);
} else {

View file

@ -46,7 +46,8 @@
*
* @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags. <em>Read-only.</em>
* @property {number} INTERSECTED_ENTITY An intersection type. Intersected an entity. <em>Read-only.</em>
* @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an overlay. <em>Read-only.</em>
* @property {number} INTERSECTED_LOCAL_ENTITY An intersection type. Intersected a local entity.</em>
* @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an entity (3D Overlays no longer exist). <em>Read-only.</em>
* @property {number} INTERSECTED_AVATAR An intersection type. Intersected an avatar. <em>Read-only.</em>
* @property {number} INTERSECTED_HUD An intersection type. Intersected the HUD sphere. <em>Read-only.</em>
* @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results.
@ -76,6 +77,7 @@ class PickScriptingInterface : public QObject, public Dependency {
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)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
@ -211,7 +213,7 @@ public:
Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking);
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to ignore during intersection. Not used by Stylus Picks.
* Sets a list of Entity IDs and/or Avatar IDs to ignore during intersection. Not used by Stylus Picks.
* @function Picks.setIgnoreItems
* @param {number} uid The ID of the Pick, as returned by {@link Picks.createPick}.
* @param {Uuid[]} ignoreItems A list of IDs to ignore.
@ -219,7 +221,7 @@ public:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems);
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Sets a list of Entity IDs and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Picks <b>only</b> intersect with objects in their include list.
* @function Picks.setIncludeItems
* @param {number} uid The ID of the Pick, as returned by {@link Picks.createPick}.
@ -348,7 +350,13 @@ public slots:
* @function Picks.INTERSECTED_OVERLAY
* @returns {number}
*/
static constexpr unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; }
static constexpr unsigned int INTERSECTED_LOCAL_ENTITY() { return IntersectionType::LOCAL_ENTITY; }
/**jsdoc
* @function Picks.INTERSECTED_OVERLAY
* @returns {number}
*/
static constexpr unsigned int INTERSECTED_OVERLAY() { return INTERSECTED_LOCAL_ENTITY(); }
/**jsdoc
* @function Picks.INTERSECTED_AVATAR

View file

@ -99,7 +99,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
}
}
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<StylusPointer>(properties, StylusPointer::buildStylusOverlay(propertyMap), hover, enabled, modelPositionOffset,
return DependencyManager::get<PointerManager>()->addPointer(std::make_shared<StylusPointer>(properties, StylusPointer::buildStylus(propertyMap), hover, enabled, modelPositionOffset,
modelRotationOffset, modelDimensions));
}
@ -116,15 +116,15 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
*
* @typedef {object} Pointers.RayPointerRenderState
* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Ray Pointer,
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined object to represent the beginning of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [path] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the path of the Ray Pointer,
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [path] When using {@link Pointers.createPointer}, an optionally defined object to represent the path of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field), which <b>must</b> be <code>"line3d"</code>.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the end of the Ray Pointer,
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined object to represent the end of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
@ -271,14 +271,14 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
*
* @typedef {object} Pointers.ParabolaPointerRenderState
* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the beginning of the Parabola Pointer,
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined object to represent the beginning of the Parabola Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Pointers.ParabolaProperties} [path] When using {@link Pointers.createPointer}, the optionally defined rendering properties of the parabolic path defined by the Parabola Pointer.
* Not defined in {@link Pointers.getPointerProperties}.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined overlay to represent the end of the Parabola Pointer,
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined object to represent the end of the Parabola Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created overlay if it exists, or a null ID otherwise.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.

View file

@ -16,7 +16,7 @@
/**jsdoc
* The Pointers API lets you create and manage objects for repeatedly calculating intersections in different ways, as well as the visual representation of those objects.
* Pointers can also be configured to automatically generate {@link PointerEvent}s on {@link Entities} and {@link Overlays}.
* Pointers can also be configured to automatically generate {@link PointerEvent}s on {@link Entities}.
*
* @namespace Pointers
*
@ -39,7 +39,7 @@ public:
* @typedef {object} Pointers.Trigger
* @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger <code>button</code>.
* @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered,
* it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
* it will try to set the entity focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
*/
/**jsdoc
@ -153,7 +153,7 @@ public:
Q_INVOKABLE void setLength(unsigned int uid, float length) const { DependencyManager::get<PointerManager>()->setLength(uid, length); }
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to ignore during intersection. Not used by Stylus Pointers.
* Sets a list of Entity IDs and/or Avatar IDs to ignore during intersection. Not used by Stylus Pointers.
* @function Pointers.setIgnoreItems
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid[]} ignoreItems A list of IDs to ignore.
@ -161,7 +161,7 @@ public:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const;
/**jsdoc
* Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Sets a list of Entity IDs and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Pointers <b>only</b> intersect with objects in their include list.
* @function Pointers.setIncludeItems
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
@ -171,15 +171,15 @@ public:
/**jsdoc
* Lock a Pointer onto a specific object (overlay, entity, or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object.
* Lock a Pointer onto a specific object (entity or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object.
* Not used by Stylus Pointers.
* @function Pointers.setLockEndUUID
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid} objectID The ID of the object to which to lock on.
* @param {boolean} isOverlay False for entities or avatars, true for overlays
* @param {boolean} isAvatar False for entities, true for avatars
* @param {Mat4} [offsetMat] The offset matrix to use if you do not want to lock on to the center of the object.
*/
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay, offsetMat); }
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
@ -211,7 +211,7 @@ public:
* @function Pointers.getPointerProperties
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {Pointers.LaserPointerProperties|Pointers.StylusPointerProperties|Pointers.ParabolaPointerProperties} The information about the Pointer.
* Currently only includes renderStates and defaultRenderStates with associated overlay IDs.
* Currently only includes renderStates and defaultRenderStates with associated entity IDs.
*/
Q_INVOKABLE QVariantMap getPointerProperties(unsigned int uid) const;
};

View file

@ -9,7 +9,6 @@
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
@ -37,19 +36,15 @@ PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) {
DependencyManager::get<EntityScriptingInterface>()->evalRayIntersectionVector(pick, searchFilter,
getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (entityRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
}
PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
bool precisionPicking = !(getFilter().isCoarse() || DependencyManager::get<PickManager>()->getForceCoarsePicking());
RayToOverlayIntersectionResult overlayRes =
qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking,
getIncludeItemsAs<OverlayID>(), getIgnoreItemsAs<OverlayID>(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
if (overlayRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, pick, overlayRes.surfaceNormal, overlayRes.extraInfo);
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityRes.entityID, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
return std::make_shared<RayPickResult>(type, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}
@ -88,12 +83,6 @@ glm::vec3 RayPick::intersectRayWithXYPlane(const glm::vec3& origin, const glm::v
return origin + t * direction;
}
glm::vec3 RayPick::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) {
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
return intersectRayWithXYPlane(origin, direction, position, rotation, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT);
}
glm::vec3 RayPick::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint());
@ -112,14 +101,6 @@ glm::vec2 RayPick::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3
return pos2D;
}
glm::vec2 RayPick::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized) {
glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value);
glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value);
glm::vec3 dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f);
return projectOntoXYPlane(worldPos, position, rotation, dimensions, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT, unNormalized);
}
glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) {
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized);

View file

@ -12,7 +12,6 @@
#include <Pick.h>
class EntityItemID;
class OverlayID;
class RayPickResult : public PickResult {
public:
@ -78,16 +77,13 @@ public:
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { return std::make_shared<RayPickResult>(pickVariant); }
PickResultPointer getEntityIntersection(const PickRay& pick) override;
PickResultPointer getOverlayIntersection(const PickRay& pick) override;
PickResultPointer getAvatarIntersection(const PickRay& pick) override;
PickResultPointer getHUDIntersection(const PickRay& pick) override;
Transform getResultTransform() const override;
// These are helper functions for projecting and intersecting rays
static glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction);
static glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction);
static glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized = true);
static glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized = true);
private:
static glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration);

View file

@ -53,6 +53,7 @@ class RayPickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS 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)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
@ -202,7 +203,13 @@ public slots:
* @function RayPick.INTERSECTED_OVERLAY
* @returns {number}
*/
static unsigned int INTERSECTED_OVERLAY() { return PickScriptingInterface::INTERSECTED_OVERLAY(); }
static unsigned int INTERSECTED_LOCAL_ENTITY() { return PickScriptingInterface::INTERSECTED_LOCAL_ENTITY(); }
/**jsdoc
* @function RayPick.INTERSECTED_OVERLAY
* @returns {number}
*/
static unsigned int INTERSECTED_OVERLAY() { return PickScriptingInterface::INTERSECTED_LOCAL_ENTITY(); }
/**jsdoc
* @function RayPick.INTERSECTED_AVATAR

View file

@ -11,8 +11,6 @@
#include <glm/glm.hpp>
#include "ui/overlays/Base3DOverlay.h"
#include "Application.h"
#include <DependencyManager.h>
#include "avatar/AvatarManager.h"
@ -148,7 +146,13 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
continue;
}
if (!entity->getVisible() && !getFilter().doesPickInvisible()) {
bool visible = entity->getVisible();
bool collisionless = entity->getCollisionless();
if ((!visible && !getFilter().doesPickInvisible()) || (visible && !getFilter().doesPickVisible()) ||
(!collisionless && !getFilter().doesPickCollidable()) || (collisionless && !getFilter().doesPickNonCollidable()) ||
(entity->isLocalEntity() && !getFilter().doesPickLocalEntities()) ||
(entity->isAvatarEntity() && !getFilter().doesPickAvatarEntities()) ||
(entity->isDomainEntity() && !getFilter().doesPickDomainEntities())) {
continue;
}
@ -161,47 +165,15 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false);
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
results.push_back(StylusPickResult(IntersectionType::ENTITY, target, distance, intersection, pick, normal));
}
}
StylusPickResult nearestTarget(pick.toVariantMap());
for (const auto& result : results) {
if (result.distance < nearestTarget.distance) {
nearestTarget = result;
}
}
return std::make_shared<StylusPickResult>(nearestTarget);
}
PickResultPointer StylusPick::getOverlayIntersection(const StylusTip& pick) {
std::vector<StylusPickResult> results;
for (const auto& target : getIncludeItems()) {
if (target.isNull()) {
continue;
}
auto overlay = qApp->getOverlays().getOverlay(target);
// Don't interact with non-3D or invalid overlays
if (!overlay || !overlay->is3D()) {
continue;
}
if (!overlay->getVisible() && !getFilter().doesPickInvisible()) {
continue;
}
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
const auto overlayRotation = overlay3D->getWorldOrientation();
const auto overlayPosition = overlay3D->getWorldPosition();
glm::vec3 normal = overlayRotation * Vectors::UNIT_Z;
float distance = glm::dot(pick.position - overlayPosition, normal);
glm::vec3 intersection = pick.position - (normal * distance);
glm::vec2 pos2D = RayPick::projectOntoOverlayXYPlane(target, intersection, false);
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
results.push_back(StylusPickResult(IntersectionType::OVERLAY, target, distance, intersection, pick, normal));
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(target, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
results.push_back(StylusPickResult(type, target, distance, intersection, pick, normal));
}
}

View file

@ -63,7 +63,6 @@ public:
StylusTip getMathematicalPick() const override;
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override;
PickResultPointer getEntityIntersection(const StylusTip& pick) override;
PickResultPointer getOverlayIntersection(const StylusTip& pick) override;
PickResultPointer getAvatarIntersection(const StylusTip& pick) override;
PickResultPointer getHUDIntersection(const StylusTip& pick) override;
Transform getResultTransform() const override;

View file

@ -27,10 +27,10 @@ static const float TOUCH_HYSTERESIS = 0.001f;
static const QString DEFAULT_STYLUS_MODEL_URL = PathUtils::resourcesUrl() + "/meshes/tablet-stylus-fat.fbx";
StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled,
StylusPointer::StylusPointer(const QVariant& props, const QUuid& stylus, bool hover, bool enabled,
const glm::vec3& modelPositionOffset, const glm::quat& modelRotationOffset, const glm::vec3& modelDimensions) :
Pointer(DependencyManager::get<PickScriptingInterface>()->createStylusPick(props), enabled, hover),
_stylusOverlay(stylusOverlay),
_stylus(stylus),
_modelPositionOffset(modelPositionOffset),
_modelDimensions(modelDimensions),
_modelRotationOffset(modelRotationOffset)
@ -38,13 +38,14 @@ StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverl
}
StylusPointer::~StylusPointer() {
if (!_stylusOverlay.isNull()) {
qApp->getOverlays().deleteOverlay(_stylusOverlay);
if (!_stylus.isNull()) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_stylus);
}
}
OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) {
QVariantMap overlayProperties;
QUuid StylusPointer::buildStylus(const QVariantMap& properties) {
// FIXME: we have to keep using the Overlays interface here, because existing scripts use overlay properties to define pointers
QVariantMap propertiesMap;
QString modelUrl = DEFAULT_STYLUS_MODEL_URL;
@ -56,15 +57,15 @@ OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) {
}
}
// TODO: make these configurable per pointer
overlayProperties["name"] = "stylus";
overlayProperties["url"] = modelUrl;
overlayProperties["loadPriority"] = 10.0f;
overlayProperties["solid"] = true;
overlayProperties["visible"] = false;
overlayProperties["ignorePickIntersection"] = true;
overlayProperties["drawInFront"] = false;
propertiesMap["name"] = "stylus";
propertiesMap["url"] = modelUrl;
propertiesMap["loadPriority"] = 10.0f;
propertiesMap["solid"] = true;
propertiesMap["visible"] = false;
propertiesMap["ignorePickIntersection"] = true;
propertiesMap["drawInFront"] = false;
return qApp->getOverlays().addOverlay("model", overlayProperties);
return qApp->getOverlays().addOverlay("model", propertiesMap);
}
void StylusPointer::updateVisuals(const PickResultPointer& pickResult) {
@ -83,25 +84,25 @@ void StylusPointer::updateVisuals(const PickResultPointer& pickResult) {
}
void StylusPointer::show(const StylusTip& tip) {
if (!_stylusOverlay.isNull()) {
QVariantMap props;
if (!_stylus.isNull()) {
auto modelOrientation = tip.orientation * _modelRotationOffset;
auto sensorToWorldScale = DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
auto modelPositionOffset = modelOrientation * (_modelPositionOffset * sensorToWorldScale);
props["position"] = vec3toVariant(tip.position + modelPositionOffset);
props["rotation"] = quatToVariant(modelOrientation);
props["dimensions"] = vec3toVariant(sensorToWorldScale * _modelDimensions);
props["visible"] = true;
qApp->getOverlays().editOverlay(_stylusOverlay, props);
EntityItemProperties properties;
properties.setPosition(tip.position + modelPositionOffset);
properties.setRotation(modelOrientation);
properties.setDimensions(sensorToWorldScale * _modelDimensions);
properties.setVisible(true);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_stylus, properties);
}
_showing = true;
}
void StylusPointer::hide() {
if (!_stylusOverlay.isNull()) {
QVariantMap props;
props.insert("visible", false);
qApp->getOverlays().editOverlay(_stylusOverlay, props);
if (!_stylus.isNull()) {
EntityItemProperties properties;
properties.setVisible(false);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_stylus, properties);
}
_showing = false;
}
@ -234,9 +235,8 @@ QVariantMap StylusPointer::toVariantMap() const {
glm::vec3 StylusPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::intersectRayWithEntityXYPlane(pickedObject.objectID, origin, direction);
case OVERLAY:
return RayPick::intersectRayWithOverlayXYPlane(pickedObject.objectID, origin, direction);
default:
return glm::vec3(NAN);
}
@ -245,9 +245,8 @@ glm::vec3 StylusPointer::findIntersection(const PickedObject& pickedObject, cons
glm::vec2 StylusPointer::findPos2D(const PickedObject& pickedObject, const glm::vec3& origin) {
switch (pickedObject.type) {
case ENTITY:
case LOCAL_ENTITY:
return RayPick::projectOntoEntityXYPlane(pickedObject.objectID, origin);
case OVERLAY:
return RayPick::projectOntoOverlayXYPlane(pickedObject.objectID, origin);
case HUD:
return DependencyManager::get<PickManager>()->calculatePos2DFromHUD(origin);
default:

View file

@ -12,8 +12,6 @@
#include <shared/Bilateral.h>
#include <RegisteredMetaTypes.h>
#include "ui/overlays/Overlay.h"
#include "StylusPick.h"
class StylusPointer : public Pointer {
@ -21,7 +19,7 @@ class StylusPointer : public Pointer {
using Ptr = std::shared_ptr<StylusPointer>;
public:
StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled,
StylusPointer(const QVariant& props, const QUuid& stylus, bool hover, bool enabled,
const glm::vec3& modelPositionOffset, const glm::quat& modelRotationOffset, const glm::vec3& modelDimensions);
~StylusPointer();
@ -36,7 +34,7 @@ public:
QVariantMap toVariantMap() const override;
static OverlayID buildStylusOverlay(const QVariantMap& properties);
static QUuid buildStylus(const QVariantMap& properties);
protected:
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;
@ -74,7 +72,7 @@ private:
RenderState _renderState { EVENTS_ON };
const OverlayID _stylusOverlay;
QUuid _stylus;
static bool isWithinBounds(float distance, float min, float max, float hysteresis);
static glm::vec3 findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction);

View file

@ -53,12 +53,12 @@ class QScriptEngine;
* @property {boolean} tabletContextualMode - <code>true</code> if the tablet has been opened in contextual mode, otherwise
* <code>false</code>. In contextual mode, the tablet has been opened at a specific world position and orientation rather
* than at a position and orientation relative to the user. <em>Read-only.</em>
* @property {Uuid} tabletID - The UUID of the tablet body model overlay.
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen overlay.
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button overlay.
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight overlay.
* @property {Uuid} miniTabletID - The UUID of the mini tablet's body model overlay. <code>null</code> if not in HMD mode.
* @property {Uuid} miniTabletScreenID - The UUID of the mini tablet's screen overlay. <code>null</code> if not in HMD mode.
* @property {Uuid} tabletID - The UUID of the tablet body model entity.
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen entity.
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button entity.
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight entity.
* @property {Uuid} miniTabletID - The UUID of the mini tablet's body model entity. <code>null</code> if not in HMD mode.
* @property {Uuid} miniTabletScreenID - The UUID of the mini tablet's screen entity. <code>null</code> if not in HMD mode.
* @property {number} miniTabletHand - The hand that the mini tablet is displayed on: <code>0</code> for left hand,
* <code>1</code> for right hand, <code>-1</code> if not in HMD mode.
* @property {bool} miniTabletEnabled=true - <code>true</code> if the mini tablet is enabled to be displayed, otherwise

View file

@ -64,6 +64,6 @@ bool KeyboardScriptingInterface::getPreferMalletsOverLasers() const {
return DependencyManager::get<Keyboard>()->getPreferMalletsOverLasers();
}
bool KeyboardScriptingInterface::containsID(OverlayID overlayID) const {
return DependencyManager::get<Keyboard>()->containsID(overlayID);
bool KeyboardScriptingInterface::containsID(const QUuid& id) const {
return DependencyManager::get<Keyboard>()->containsID(id);
}

View file

@ -16,7 +16,6 @@
#include <QtCore/QUuid>
#include "DependencyManager.h"
#include "ui/overlays/Overlay.h"
/**jsdoc
* The Keyboard API provides facilities to use 3D Physical keyboard.
@ -46,7 +45,7 @@ public:
Q_INVOKABLE void disableRightMallet();
Q_INVOKABLE void setLeftHandLaser(unsigned int leftHandLaser);
Q_INVOKABLE void setRightHandLaser(unsigned int rightHandLaser);
Q_INVOKABLE bool containsID(OverlayID overlayID) const;
Q_INVOKABLE bool containsID(const QUuid& overlayID) const;
private:
bool getPreferMalletsOverLasers() const;
bool isRaised() const;

View file

@ -40,19 +40,6 @@ bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) {
return true;
}
bool GameplayObjects::addToGameplayObjects(const OverlayID& overlayID) {
containsData = true;
if (std::find(_overlayIDs.begin(), _overlayIDs.end(), overlayID) == _overlayIDs.end()) {
_overlayIDs.push_back(overlayID);
}
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const OverlayID& overlayID) {
_overlayIDs.erase(std::remove(_overlayIDs.begin(), _overlayIDs.end(), overlayID), _overlayIDs.end());
return true;
}
SelectionScriptingInterface::SelectionScriptingInterface() {
}
@ -64,7 +51,6 @@ SelectionScriptingInterface::SelectionScriptingInterface() {
* <tbody>
* <tr><td><code>"avatar"</code></td><td></td></tr>
* <tr><td><code>"entity"</code></td><td></td></tr>
* <tr><td><code>"overlay"</code></td><td></td></tr>
* </tbody>
* </table>
* @typedef {string} Selection.ItemType
@ -72,20 +58,16 @@ SelectionScriptingInterface::SelectionScriptingInterface() {
bool SelectionScriptingInterface::addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) {
if (itemType == "avatar") {
return addToGameplayObjects(listName, (QUuid)id);
} else if (itemType == "entity") {
} else if (itemType == "entity" || itemType == "overlay") {
return addToGameplayObjects(listName, (EntityItemID)id);
} else if (itemType == "overlay") {
return addToGameplayObjects(listName, (OverlayID)id);
}
return false;
}
bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) {
if (itemType == "avatar") {
return removeFromGameplayObjects(listName, (QUuid)id);
} else if (itemType == "entity") {
} else if (itemType == "entity" || itemType == "overlay") {
return removeFromGameplayObjects(listName, (EntityItemID)id);
} else if (itemType == "overlay") {
return removeFromGameplayObjects(listName, (OverlayID)id);
}
return false;
}
@ -253,12 +235,6 @@ void SelectionScriptingInterface::printList(const QString& listName) {
qDebug() << j << ';';
}
qDebug() << "";
qDebug() << "Overlay IDs:";
for (auto k : (*currentList).getOverlayIDs()) {
qDebug() << k << ';';
}
qDebug() << "";
}
else {
qDebug() << "List named " << listName << " empty";
@ -272,7 +248,6 @@ void SelectionScriptingInterface::printList(const QString& listName) {
* @typedef {object} Selection.SelectedItemsList
* @property {Uuid[]} avatars - The IDs of the avatars in the selection.
* @property {Uuid[]} entities - The IDs of the entities in the selection.
* @property {Uuid[]} overlays - The IDs of the overlays in the selection.
*/
QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& listName) const {
QReadLocker lock(&_selectionListsLock);
@ -281,7 +256,6 @@ QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& lis
if (currentList != _selectedItemsListMap.end()) {
QList<QVariant> avatarIDs;
QList<QVariant> entityIDs;
QList<QVariant> overlayIDs;
if ((*currentList).getContainsData()) {
if (!(*currentList).getAvatarIDs().empty()) {
@ -294,15 +268,9 @@ QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& lis
entityIDs.push_back((QUuid)j );
}
}
if (!(*currentList).getOverlayIDs().empty()) {
for (auto j : (*currentList).getOverlayIDs()) {
overlayIDs.push_back((QUuid)j);
}
}
}
list["avatars"] = (avatarIDs);
list["entities"] = (entityIDs);
list["overlays"] = (overlayIDs);
return list;
}
@ -379,7 +347,6 @@ void SelectionToSceneHandler::updateSceneFromSelectedList() {
render::ItemIDs finalList;
render::ItemID currentID;
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
auto& overlays = qApp->getOverlays();
for (QUuid& currentAvatarID : thisList.getAvatarIDs()) {
auto avatar = std::static_pointer_cast<Avatar>(DependencyManager::get<AvatarManager>()->getAvatarBySessionID(currentAvatarID));
@ -398,16 +365,6 @@ void SelectionToSceneHandler::updateSceneFromSelectedList() {
}
}
for (OverlayID& currentOverlayID : thisList.getOverlayIDs()) {
auto overlay = overlays.getOverlay(currentOverlayID);
if (overlay != NULL) {
currentID = overlay->getRenderItemID();
if (currentID != render::Item::INVALID_ITEM_ID) {
finalList.push_back(currentID);
}
}
}
render::Selection selection(_listName.toStdString(), finalList);
transaction.resetSelection(selection);

View file

@ -19,7 +19,6 @@
#include <AbstractViewStateInterface.h>
#include "RenderableEntityItem.h"
#include "ui/overlays/Overlay.h"
#include <avatar/AvatarManager.h>
#include <render/HighlightStyle.h>
@ -37,15 +36,10 @@ public:
bool addToGameplayObjects(const EntityItemID& entityID);
bool removeFromGameplayObjects(const EntityItemID& entityID);
std::vector<OverlayID> getOverlayIDs() const { return _overlayIDs; }
bool addToGameplayObjects(const OverlayID& overlayID);
bool removeFromGameplayObjects(const OverlayID& overlayID);
private:
bool containsData { false };
std::vector<QUuid> _avatarIDs;
std::vector<EntityItemID> _entityIDs;
std::vector<OverlayID> _overlayIDs;
};
@ -83,7 +77,7 @@ protected:
};
/**jsdoc
* The <code>Selection</code> API provides a means of grouping together avatars, entities, and overlays in named lists.
* The <code>Selection</code> API provides a means of grouping together avatars and entities in named lists.
* @namespace Selection
*
* @hifi-interface
@ -174,14 +168,14 @@ public:
Q_INVOKABLE bool clearSelectedItemsList(const QString& listName);
/**jsdoc
* Print out the list of avatars, entities, and overlays in a selection to the <em>debug log</em> (not the script log).
* Print out the list of avatars and entities in a selection to the <em>debug log</em> (not the script log).
* @function Selection.printList
* @param {string} listName - The name of the selection list.
*/
Q_INVOKABLE void printList(const QString& listName);
/**jsdoc
* Get the list of avatars, entities, and overlays stored in a selection list.
* Get the list of avatars and entities stored in a selection list.
* @function Selection.getSelectedItemsList
* @param {string} listName - The name of the selection list.
* @returns {Selection.SelectedItemsList} The content of a selection list. If the list name doesn't exist, the function

View file

@ -134,9 +134,7 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
batch.resetViewTransform();
// Render all of the Script based "HUD" aka 2D overlays.
// note: we call them HUD, as opposed to 2D, only because there are some cases of 3D HUD overlays, like the
// cameral controls for the edit.js
qApp->getOverlays().renderHUD(renderArgs);
qApp->getOverlays().render(renderArgs);
}
void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {

View file

@ -33,11 +33,6 @@
#include <RegisteredMetaTypes.h>
#include <ui/TabletScriptingInterface.h>
#include "ui/overlays/Overlays.h"
#include "ui/overlays/Overlay.h"
#include "ui/overlays/ModelOverlay.h"
#include "ui/overlays/Cube3DOverlay.h"
#include "ui/overlays/Text3DOverlay.h"
#include "avatar/AvatarManager.h"
#include "avatar/MyAvatar.h"
#include "avatar/AvatarManager.h"
@ -120,21 +115,21 @@ std::pair<glm::vec3, glm::quat> calculateKeyboardPositionAndOrientation() {
float sensorToWorldScale = myAvatar->getSensorToWorldScale();
QUuid tabletID = hmd->getCurrentTabletFrameID();
if (!tabletID.isNull() && hmd->getShouldShowTablet()) {
Overlays& overlays = qApp->getOverlays();
auto tabletOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(tabletID));
if (tabletOverlay) {
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
bool landscapeMode = tablet->getLandscape();
glm::vec3 keyboardOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_OFFSET : KEYBOARD_TABLET_OFFSET;
glm::vec3 keyboardDegreesOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_DEGREES_OFFSET : KEYBOARD_TABLET_DEGREES_OFFSET;
glm::vec3 tabletWorldPosition = tabletOverlay->getWorldPosition();
glm::quat tabletWorldOrientation = tabletOverlay->getWorldOrientation();
glm::vec3 scaledKeyboardTabletOffset = keyboardOffset * sensorToWorldScale;
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(tabletID, desiredProperties);
keyboardLocation.first = tabletWorldPosition + (tabletWorldOrientation * scaledKeyboardTabletOffset);
keyboardLocation.second = tabletWorldOrientation * glm::quat(glm::radians(keyboardDegreesOffset));
}
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
bool landscapeMode = tablet->getLandscape();
glm::vec3 keyboardOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_OFFSET : KEYBOARD_TABLET_OFFSET;
glm::vec3 keyboardDegreesOffset = landscapeMode ? KEYBOARD_TABLET_LANDSCAPE_DEGREES_OFFSET : KEYBOARD_TABLET_DEGREES_OFFSET;
glm::vec3 tabletWorldPosition = properties.getPosition();
glm::quat tabletWorldOrientation = properties.getRotation();
glm::vec3 scaledKeyboardTabletOffset = keyboardOffset * sensorToWorldScale;
keyboardLocation.first = tabletWorldPosition + (tabletWorldOrientation * scaledKeyboardTabletOffset);
keyboardLocation.second = tabletWorldOrientation * glm::quat(glm::radians(keyboardDegreesOffset));
} else {
glm::vec3 avatarWorldPosition = myAvatar->getWorldPosition();
glm::quat avatarWorldOrientation = myAvatar->getWorldOrientation();
@ -148,32 +143,25 @@ std::pair<glm::vec3, glm::quat> calculateKeyboardPositionAndOrientation() {
}
void Key::saveDimensionsAndLocalPosition() {
Overlays& overlays = qApp->getOverlays();
auto model3DOverlay = std::dynamic_pointer_cast<ModelOverlay>(overlays.getOverlay(_keyID));
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_DIMENSIONS;
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(_keyID, desiredProperties);
if (model3DOverlay) {
_originalLocalPosition = model3DOverlay->getLocalPosition();
_originalDimensions = model3DOverlay->getDimensions();
_currentLocalPosition = _originalLocalPosition;
}
_originalLocalPosition = properties.getLocalPosition();
_originalDimensions = properties.getDimensions();
_currentLocalPosition = _originalLocalPosition;
}
void Key::scaleKey(float sensorToWorldScale) {
Overlays& overlays = qApp->getOverlays();
auto model3DOverlay = std::dynamic_pointer_cast<ModelOverlay>(overlays.getOverlay(_keyID));
glm::vec3 scaledLocalPosition = _originalLocalPosition * sensorToWorldScale;
glm::vec3 scaledDimensions = _originalDimensions * sensorToWorldScale;
_currentLocalPosition = scaledLocalPosition;
if (model3DOverlay) {
glm::vec3 scaledLocalPosition = _originalLocalPosition * sensorToWorldScale;
glm::vec3 scaledDimensions = _originalDimensions * sensorToWorldScale;
_currentLocalPosition = scaledLocalPosition;
QVariantMap properties {
{ "dimensions", vec3toVariant(scaledDimensions) },
{ "localPosition", vec3toVariant(scaledLocalPosition) }
};
overlays.editOverlay(_keyID, properties);
}
EntityItemProperties properties;
properties.setDimensions(scaledDimensions);
properties.setLocalPosition(scaledLocalPosition);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_keyID, properties);
}
void Key::startTimer(int time) {
@ -262,21 +250,21 @@ void Keyboard::createKeyboard() {
QVariantMap leftStylusProperties {
{ "hand", LEFT_HAND_CONTROLLER_INDEX },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "model", modelProperties },
{ "tipOffset", vec3toVariant(MALLET_TIP_OFFSET) }
};
QVariantMap rightStylusProperties {
{ "hand", RIGHT_HAND_CONTROLLER_INDEX },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "filter", PickScriptingInterface::PICK_LOCAL_ENTITIES() },
{ "model", modelProperties },
{ "tipOffset", vec3toVariant(MALLET_TIP_OFFSET) }
};
_leftHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(leftStylusProperties, StylusPointer::buildStylusOverlay(leftStylusProperties), true, true,
_leftHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(leftStylusProperties, StylusPointer::buildStylus(leftStylusProperties), true, true,
MALLET_POSITION_OFFSET, MALLET_ROTATION_OFFSET, MALLET_MODEL_DIMENSIONS));
_rightHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(rightStylusProperties, StylusPointer::buildStylusOverlay(rightStylusProperties), true, true,
_rightHandStylus = pointerManager->addPointer(std::make_shared<StylusPointer>(rightStylusProperties, StylusPointer::buildStylus(rightStylusProperties), true, true,
MALLET_POSITION_OFFSET, MALLET_ROTATION_OFFSET, MALLET_MODEL_DIMENSIONS));
pointerManager->disablePointer(_rightHandStylus);
@ -312,93 +300,70 @@ void Keyboard::setRaised(bool raised) {
}
void Keyboard::updateTextDisplay() {
Overlays& overlays = qApp->getOverlays();
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
float sensorToWorldScale = myAvatar->getSensorToWorldScale();
float textWidth = (float) overlays.textSize(_textDisplay.overlayID, _typedCharacters).width();
float textWidth = (float)entityScriptingInterface->textSize(_textDisplay.entityID, _typedCharacters).width();
glm::vec3 scaledDimensions = _textDisplay.dimensions;
scaledDimensions *= sensorToWorldScale;
float leftMargin = (scaledDimensions.x / 2);
scaledDimensions.x += textWidth;
QVariantMap textDisplayProperties {
{ "dimensions", vec3toVariant(scaledDimensions) },
{ "leftMargin", leftMargin },
{ "text", _typedCharacters },
{ "lineHeight", (_textDisplay.lineHeight * sensorToWorldScale) }
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
EntityItemProperties properties;
properties.setDimensions(scaledDimensions);
properties.setLeftMargin(leftMargin);
properties.setText(_typedCharacters);
properties.setLineHeight(_textDisplay.lineHeight * sensorToWorldScale);
entityScriptingInterface->editEntity(_textDisplay.entityID, properties);
}
void Keyboard::raiseKeyboardAnchor(bool raise) const {
Overlays& overlays = qApp->getOverlays();
OverlayID anchorOverlayID = _anchor.overlayID;
auto anchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(anchorOverlayID));
if (anchorOverlay) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityItemProperties properties;
properties.setVisible(raise);
entityScriptingInterface->editEntity(_textDisplay.entityID, properties);
entityScriptingInterface->editEntity(_backPlate.entityID, properties);
if (_resetKeyboardPositionOnRaise) {
std::pair<glm::vec3, glm::quat> keyboardLocation = calculateKeyboardPositionAndOrientation();
if (_resetKeyboardPositionOnRaise) {
anchorOverlay->setWorldPosition(keyboardLocation.first);
anchorOverlay->setWorldOrientation(keyboardLocation.second);
}
anchorOverlay->setVisible(raise);
QVariantMap textDisplayProperties {
{ "visible", raise }
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
auto backPlateOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(_backPlate.overlayID));
if (backPlateOverlay) {
backPlateOverlay->setVisible(raise);
}
properties.setPosition(keyboardLocation.first);
properties.setRotation(keyboardLocation.second);
}
entityScriptingInterface->editEntity(_anchor.entityID, properties);
}
void Keyboard::scaleKeyboard(float sensorToWorldScale) {
Overlays& overlays = qApp->getOverlays();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
glm::vec3 scaledDimensions = _anchor.originalDimensions * sensorToWorldScale;
auto volume3DOverlay = std::dynamic_pointer_cast<Volume3DOverlay>(overlays.getOverlay(_anchor.overlayID));
if (volume3DOverlay) {
volume3DOverlay->setDimensions(scaledDimensions);
{
EntityItemProperties properties;
properties.setDimensions(_anchor.originalDimensions * sensorToWorldScale);
entityScriptingInterface->editEntity(_anchor.entityID, properties);
}
for (auto& keyboardLayer: _keyboardLayers) {
for (auto& keyboardLayer : _keyboardLayers) {
for (auto iter = keyboardLayer.begin(); iter != keyboardLayer.end(); iter++) {
iter.value().scaleKey(sensorToWorldScale);
}
}
{
EntityItemProperties properties;
properties.setLocalPosition(_textDisplay.localPosition * sensorToWorldScale);
properties.setDimensions(_textDisplay.dimensions * sensorToWorldScale);
properties.setLineHeight(_textDisplay.lineHeight * sensorToWorldScale);
entityScriptingInterface->editEntity(_textDisplay.entityID, properties);
}
glm::vec3 scaledLocalPosition = _textDisplay.localPosition * sensorToWorldScale;
glm::vec3 textDisplayScaledDimensions = _textDisplay.dimensions * sensorToWorldScale;
QVariantMap textDisplayProperties {
{ "localPosition", vec3toVariant(scaledLocalPosition) },
{ "dimensions", vec3toVariant(textDisplayScaledDimensions) },
{ "lineHeight", (_textDisplay.lineHeight * sensorToWorldScale) }
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
glm::vec3 backPlateScaledDimensions = _backPlate.dimensions * sensorToWorldScale;
glm::vec3 backPlateScaledLocalPosition = _backPlate.localPosition * sensorToWorldScale;
QVariantMap backPlateProperties {
{ "localPosition", vec3toVariant(backPlateScaledLocalPosition) },
{ "dimensions", vec3toVariant(backPlateScaledDimensions) }
};
overlays.editOverlay(_backPlate.overlayID, backPlateProperties);
{
EntityItemProperties properties;
properties.setLocalPosition(_backPlate.localPosition * sensorToWorldScale);
properties.setDimensions(_backPlate.dimensions * sensorToWorldScale);
entityScriptingInterface->editEntity(_backPlate.entityID, properties);
}
}
void Keyboard::startLayerSwitchTimer() {
@ -419,13 +384,12 @@ void Keyboard::raiseKeyboard(bool raise) const {
if (_keyboardLayers.empty()) {
return;
}
Overlays& overlays = qApp->getOverlays();
const auto& keyboardLayer = _keyboardLayers[_layerIndex];
EntityItemProperties properties;
properties.setVisible(raise);
for (auto iter = keyboardLayer.begin(); iter != keyboardLayer.end(); iter++) {
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(iter.key()));
if (base3DOverlay) {
base3DOverlay->setVisible(raise);
}
DependencyManager::get<EntityScriptingInterface>()->editEntity(iter.key(), properties);
}
}
@ -465,19 +429,15 @@ bool Keyboard::getPreferMalletsOverLasers() const {
}
void Keyboard::switchToLayer(int layerIndex) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (layerIndex >= 0 && layerIndex < (int)_keyboardLayers.size()) {
Overlays& overlays = qApp->getOverlays();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
auto oldProperties = entityScriptingInterface->getEntityProperties(_anchor.entityID, desiredProperties);
OverlayID currentAnchorOverlayID = _anchor.overlayID;
glm::vec3 currentOverlayPosition;
glm::quat currentOverlayOrientation;
auto currentAnchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(currentAnchorOverlayID));
if (currentAnchorOverlay) {
currentOverlayPosition = currentAnchorOverlay->getWorldPosition();
currentOverlayOrientation = currentAnchorOverlay->getWorldOrientation();
}
glm::vec3 currentPosition = oldProperties.getPosition();
glm::quat currentOrientation = oldProperties.getRotation();
raiseKeyboardAnchor(false);
raiseKeyboard(false);
@ -487,19 +447,17 @@ void Keyboard::switchToLayer(int layerIndex) {
raiseKeyboardAnchor(true);
raiseKeyboard(true);
OverlayID newAnchorOverlayID = _anchor.overlayID;
auto newAnchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(newAnchorOverlayID));
if (newAnchorOverlay) {
newAnchorOverlay->setWorldPosition(currentOverlayPosition);
newAnchorOverlay->setWorldOrientation(currentOverlayOrientation);
}
EntityItemProperties properties;
properties.setPosition(currentPosition);
properties.setRotation(currentOrientation);
entityScriptingInterface->editEntity(_anchor.entityID, properties);
startLayerSwitchTimer();
}
}
bool Keyboard::shouldProcessOverlayAndPointerEvent(const PointerEvent& event, const OverlayID& overlayID) const {
return (shouldProcessPointerEvent(event) && shouldProcessOverlay(overlayID));
bool Keyboard::shouldProcessEntityAndPointerEvent(const PointerEvent& event, const QUuid& id) const {
return (shouldProcessPointerEvent(event) && shouldProcessEntity(id));
}
bool Keyboard::shouldProcessPointerEvent(const PointerEvent& event) const {
@ -510,14 +468,14 @@ bool Keyboard::shouldProcessPointerEvent(const PointerEvent& event) const {
return ((isStylusEvent && preferMalletsOverLasers) || (isLaserEvent && !preferMalletsOverLasers));
}
void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event) {
void Keyboard::handleTriggerBegin(const QUuid& id, const PointerEvent& event) {
auto buttonType = event.getButton();
if (!shouldProcessOverlayAndPointerEvent(event, overlayID) || buttonType != PointerEvent::PrimaryButton) {
if (!shouldProcessEntityAndPointerEvent(event, id) || buttonType != PointerEvent::PrimaryButton) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
@ -533,13 +491,9 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->triggerHapticPulse(PULSE_STRENGTH, PULSE_DURATION, handIndex);
Overlays& overlays = qApp->getOverlays();
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
glm::vec3 keyWorldPosition;
if (base3DOverlay) {
keyWorldPosition = base3DOverlay->getWorldPosition();
}
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
glm::vec3 keyWorldPosition = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id, desiredProperties).getPosition();
AudioInjectorOptions audioOptions;
audioOptions.localOnly = true;
@ -601,7 +555,7 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent
key.startTimer(KEY_PRESS_TIMEOUT_MS);
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->addToSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "overlay", overlayID);
selection->addToSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "entity", id);
}
}
@ -617,25 +571,23 @@ void Keyboard::setRightHandLaser(unsigned int rightHandLaser) {
});
}
void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleTriggerEnd(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event, id)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
Key& key = search.value();;
Overlays& overlays = qApp->getOverlays();
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
Key& key = search.value();
if (base3DOverlay) {
base3DOverlay->setLocalPosition(key.getCurrentLocalPosition());
}
EntityItemProperties properties;
properties.setLocalPosition(key.getCurrentLocalPosition());
DependencyManager::get<EntityScriptingInterface>()->editEntity(id, properties);
key.setIsPressed(false);
if (key.timerFinished() && getPreferMalletsOverLasers()) {
@ -643,78 +595,79 @@ void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent&
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->removeFromSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "overlay", overlayID);
selection->removeFromSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "entity", id);
}
void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleTriggerContinue(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event, id)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
Key& key = search.value();
Overlays& overlays = qApp->getOverlays();
if (!key.isPressed() && getPreferMalletsOverLasers()) {
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
unsigned int pointerID = event.getID();
auto pointerManager = DependencyManager::get<PointerManager>();
auto pickResult = pointerManager->getPrevPickResult(pointerID);
auto stylusPickResult = std::dynamic_pointer_cast<StylusPickResult>(pickResult);
float distance = stylusPickResult->distance;
if (base3DOverlay) {
unsigned int pointerID = event.getID();
auto pointerManager = DependencyManager::get<PointerManager>();
auto pickResult = pointerManager->getPrevPickResult(pointerID);
auto stylusPickResult = std::dynamic_pointer_cast<StylusPickResult>(pickResult);
float distance = stylusPickResult->distance;
static const float PENATRATION_THRESHOLD = 0.025f;
if (distance < PENATRATION_THRESHOLD) {
static const float Z_OFFSET = 0.002f;
static const float PENATRATION_THRESHOLD = 0.025f;
if (distance < PENATRATION_THRESHOLD) {
static const float Z_OFFSET = 0.002f;
glm::quat overlayOrientation = base3DOverlay->getWorldOrientation();
glm::vec3 overlayYAxis = overlayOrientation * Z_AXIS;
glm::vec3 overlayYOffset = overlayYAxis * Z_OFFSET;
glm::vec3 localPosition = key.getCurrentLocalPosition() - overlayYOffset;
base3DOverlay->setLocalPosition(localPosition);
key.setIsPressed(true);
}
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ROTATION;
glm::quat orientation = entityScriptingInterface->getEntityProperties(id, desiredProperties).getRotation();
glm::vec3 yAxis = orientation * Z_AXIS;
glm::vec3 yOffset = yAxis * Z_OFFSET;
glm::vec3 localPosition = key.getCurrentLocalPosition() - yOffset;
EntityItemProperties properties;
properties.setLocalPosition(localPosition);
entityScriptingInterface->editEntity(id, properties);
key.setIsPressed(true);
}
}
}
void Keyboard::handleHoverBegin(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleHoverBegin(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event, id)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->addToSelectedItemsList(KEY_HOVER_HIGHLIGHT, "overlay", overlayID);
selection->addToSelectedItemsList(KEY_HOVER_HIGHLIGHT, "entity", id);
}
void Keyboard::handleHoverEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
void Keyboard::handleHoverEnd(const QUuid& id, const PointerEvent& event) {
if (!shouldProcessEntityAndPointerEvent(event, id)) {
return;
}
auto& keyboardLayer = _keyboardLayers[_layerIndex];
auto search = keyboardLayer.find(overlayID);
auto search = keyboardLayer.find(id);
if (search == keyboardLayer.end()) {
return;
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->removeFromSelectedItemsList(KEY_HOVER_HIGHLIGHT, "overlay", overlayID);
selection->removeFromSelectedItemsList(KEY_HOVER_HIGHLIGHT, "entity", id);
}
void Keyboard::disableStylus() {
@ -752,7 +705,6 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
}
clearKeyboardKeys();
Overlays& overlays = qApp->getOverlays();
auto requestData = request->getData();
QVector<QUuid> includeItems;
@ -776,54 +728,58 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
return;
}
QVariantMap anchorProperties {
{ "name", "KeyboardAnchor"},
{ "isSolid", true },
{ "visible", false },
{ "grabbable", true },
{ "ignorePickIntersection", false },
{ "dimensions", anchorObject["dimensions"].toVariant() },
{ "position", anchorObject["position"].toVariant() },
{ "orientation", anchorObject["rotation"].toVariant() }
};
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
{
glm::vec3 dimensions = vec3FromVariant(anchorObject["dimensions"].toVariant());
glm::vec3 dimensions = vec3FromVariant(anchorObject["dimensions"].toVariant());
EntityItemProperties properties;
properties.setType(EntityTypes::Box);
properties.setName("KeyboardAnchor");
properties.setVisible(false);
properties.getGrab().setGrabbable(true);
properties.setIgnorePickIntersection(false);
properties.setDimensions(dimensions);
properties.setPosition(vec3FromVariant(anchorObject["position"].toVariant()));
properties.setRotation(quatFromVariant(anchorObject["rotation"].toVariant()));
Anchor anchor;
anchor.overlayID = overlays.addOverlay("cube", anchorProperties);
anchor.originalDimensions = dimensions;
_anchor = anchor;
Anchor anchor;
anchor.entityID = entityScriptingInterface->addEntity(properties, "local");
anchor.originalDimensions = dimensions;
_anchor = anchor;
}
QJsonObject backPlateObject = jsonObject["backPlate"].toObject();
{
QJsonObject backPlateObject = jsonObject["backPlate"].toObject();
glm::vec3 dimensions = vec3FromVariant(backPlateObject["dimensions"].toVariant());
QVariantMap backPlateProperties {
{ "name", "backPlate"},
{ "isSolid", true },
{ "visible", true },
{ "grabbable", false },
{ "alpha", 0.0 },
{ "ignoreRayIntersection", false},
{ "dimensions", backPlateObject["dimensions"].toVariant() },
{ "position", backPlateObject["position"].toVariant() },
{ "orientation", backPlateObject["rotation"].toVariant() },
{ "parentID", _anchor.overlayID }
};
EntityItemProperties properties;
properties.setType(EntityTypes::Box);
properties.setName("BackPlate");
properties.setVisible(true);
properties.getGrab().setGrabbable(false);
properties.setAlpha(0.0f);
properties.setIgnorePickIntersection(false);
properties.setDimensions(dimensions);
properties.setPosition(vec3FromVariant(backPlateObject["position"].toVariant()));
properties.setRotation(quatFromVariant(backPlateObject["rotation"].toVariant()));
properties.setParentID(_anchor.entityID);
BackPlate backPlate;
backPlate.overlayID = overlays.addOverlay("cube", backPlateProperties);
backPlate.dimensions = vec3FromVariant(backPlateObject["dimensions"].toVariant());
backPlate.localPosition = vec3FromVariant(overlays.getProperty(backPlate.overlayID, "localPosition").value);
_backPlate = backPlate;
BackPlate backPlate;
backPlate.entityID = entityScriptingInterface->addEntity(properties, "local");
backPlate.dimensions = dimensions;
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_LOCAL_POSITION;
backPlate.localPosition = entityScriptingInterface->getEntityProperties(backPlate.entityID, desiredProperties).getLocalPosition();
_backPlate = backPlate;
}
const QJsonArray& keyboardLayers = jsonObject["layers"].toArray();
int keyboardLayerCount = keyboardLayers.size();
_keyboardLayers.reserve(keyboardLayerCount);
for (int keyboardLayerIndex = 0; keyboardLayerIndex < keyboardLayerCount; keyboardLayerIndex++) {
const QJsonValue& keyboardLayer = keyboardLayers[keyboardLayerIndex].toArray();
QHash<OverlayID, Key> keyboardLayerKeys;
QHash<QUuid, Key> keyboardLayerKeys;
foreach (const QJsonValue& keyboardKeyValue, keyboardLayer.toArray()) {
QVariantMap textureMap;
@ -841,21 +797,6 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
QString modelUrl = keyboardKeyValue["modelURL"].toString();
QString url = (useResourcePath ? (resourcePath + modelUrl) : modelUrl);
QVariantMap properties {
{ "dimensions", keyboardKeyValue["dimensions"].toVariant() },
{ "position", keyboardKeyValue["position"].toVariant() },
{ "visible", false },
{ "isSolid", true },
{ "emissive", true },
{ "parentID", _anchor.overlayID },
{ "url", url },
{ "textures", textureMap },
{ "grabbable", false },
{ "localOrientation", keyboardKeyValue["localOrientation"].toVariant() }
};
OverlayID overlayID = overlays.addOverlay("model", properties);
QString keyType = keyboardKeyValue["type"].toString();
QString keyString = keyboardKeyValue["key"].toString();
@ -869,48 +810,65 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
key.setSwitchToLayerIndex(switchToLayer);
}
}
key.setID(overlayID);
EntityItemProperties properties;
properties.setType(EntityTypes::Model);
properties.setDimensions(vec3FromVariant(keyboardKeyValue["dimensions"].toVariant()));
properties.setPosition(vec3FromVariant(keyboardKeyValue["position"].toVariant()));
properties.setVisible(false);
properties.setEmissive(true);
properties.setParentID(_anchor.entityID);
properties.setModelURL(url);
properties.setTextures(QVariant(textureMap).toString());
properties.getGrab().setGrabbable(false);
properties.setLocalRotation(quatFromVariant(keyboardKeyValue["localOrientation"].toVariant()));
QUuid id = entityScriptingInterface->addEntity(properties, "local");
key.setID(id);
key.setKeyString(keyString);
key.saveDimensionsAndLocalPosition();
includeItems.append(key.getID());
_itemsToIgnore.append(key.getID());
keyboardLayerKeys.insert(overlayID, key);
keyboardLayerKeys.insert(id, key);
}
_keyboardLayers.push_back(keyboardLayerKeys);
}
TextDisplay textDisplay;
QJsonObject displayTextObject = jsonObject["textDisplay"].toObject();
{
QJsonObject displayTextObject = jsonObject["textDisplay"].toObject();
glm::vec3 dimensions = vec3FromVariant(displayTextObject["dimensions"].toVariant());
glm::vec3 localPosition = vec3FromVariant(displayTextObject["localPosition"].toVariant());
float lineHeight = (float)displayTextObject["lineHeight"].toDouble();
QVariantMap displayTextProperties {
{ "dimensions", displayTextObject["dimensions"].toVariant() },
{ "localPosition", displayTextObject["localPosition"].toVariant() },
{ "localOrientation", displayTextObject["localOrientation"].toVariant() },
{ "leftMargin", displayTextObject["leftMargin"].toVariant() },
{ "rightMargin", displayTextObject["rightMargin"].toVariant() },
{ "topMargin", displayTextObject["topMargin"].toVariant() },
{ "bottomMargin", displayTextObject["bottomMargin"].toVariant() },
{ "lineHeight", displayTextObject["lineHeight"].toVariant() },
{ "visible", false },
{ "emissive", true },
{ "grabbable", false },
{ "text", ""},
{ "parentID", _anchor.overlayID }
};
EntityItemProperties properties;
properties.setType(EntityTypes::Text);
properties.setDimensions(dimensions);
properties.setLocalPosition(localPosition);
properties.setLocalRotation(quatFromVariant(displayTextObject["localOrientation"].toVariant()));
properties.setLeftMargin((float)displayTextObject["leftMargin"].toDouble());
properties.setRightMargin((float)displayTextObject["rightMargin"].toDouble());
properties.setTopMargin((float)displayTextObject["topMargin"].toDouble());
properties.setBottomMargin((float)displayTextObject["bottomMargin"].toDouble());
properties.setLineHeight((float)displayTextObject["lineHeight"].toDouble());
properties.setVisible(false);
properties.setEmissive(true);
properties.getGrab().setGrabbable(false);
properties.setText("");
properties.setParentID(_anchor.entityID);
textDisplay.overlayID = overlays.addOverlay("text3d", displayTextProperties);
textDisplay.localPosition = vec3FromVariant(displayTextObject["localPosition"].toVariant());
textDisplay.dimensions = vec3FromVariant(displayTextObject["dimensions"].toVariant());
textDisplay.lineHeight = (float) displayTextObject["lineHeight"].toDouble();
_textDisplay = textDisplay;
TextDisplay textDisplay;
textDisplay.entityID = entityScriptingInterface->addEntity(properties, "local");
textDisplay.localPosition = localPosition;
textDisplay.dimensions = dimensions;
textDisplay.lineHeight = lineHeight;
_textDisplay = textDisplay;
}
_ignoreItemsLock.withWriteLock([&] {
_itemsToIgnore.append(_textDisplay.overlayID);
_itemsToIgnore.append(_anchor.overlayID);
_itemsToIgnore.append(_textDisplay.entityID);
_itemsToIgnore.append(_anchor.entityID);
});
_layerIndex = 0;
auto pointerManager = DependencyManager::get<PointerManager>();
@ -922,34 +880,33 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
}
OverlayID Keyboard::getAnchorID() {
return _ignoreItemsLock.resultWithReadLock<OverlayID>([&] {
return _anchor.overlayID;
QUuid Keyboard::getAnchorID() {
return _ignoreItemsLock.resultWithReadLock<QUuid>([&] {
return _anchor.entityID;
});
}
bool Keyboard::shouldProcessOverlay(const OverlayID& overlayID) const {
return (!_keyboardLayers.empty() && isLayerSwitchTimerFinished() && overlayID != _backPlate.overlayID);
bool Keyboard::shouldProcessEntity(const QUuid& id) const {
return (!_keyboardLayers.empty() && isLayerSwitchTimerFinished() && id != _backPlate.entityID);
}
QVector<OverlayID> Keyboard::getKeysID() {
return _ignoreItemsLock.resultWithReadLock<QVector<OverlayID>>([&] {
QVector<QUuid> Keyboard::getKeysID() {
return _ignoreItemsLock.resultWithReadLock<QVector<QUuid>>([&] {
return _itemsToIgnore;
});
}
void Keyboard::clearKeyboardKeys() {
Overlays& overlays = qApp->getOverlays();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
for (const auto& keyboardLayer: _keyboardLayers) {
for (auto iter = keyboardLayer.begin(); iter != keyboardLayer.end(); iter++) {
overlays.deleteOverlay(iter.key());
entityScriptingInterface->deleteEntity(iter.key());
}
}
overlays.deleteOverlay(_anchor.overlayID);
overlays.deleteOverlay(_textDisplay.overlayID);
overlays.deleteOverlay(_backPlate.overlayID);
entityScriptingInterface->deleteEntity(_anchor.entityID);
entityScriptingInterface->deleteEntity(_textDisplay.entityID);
entityScriptingInterface->deleteEntity(_backPlate.entityID);
_keyboardLayers.clear();
@ -989,8 +946,8 @@ void Keyboard::disableRightMallet() {
pointerManager->disablePointer(_rightHandStylus);
}
bool Keyboard::containsID(OverlayID overlayID) const {
bool Keyboard::containsID(const QUuid& id) const {
return resultWithReadLock<bool>([&] {
return _itemsToIgnore.contains(overlayID) || _backPlate.overlayID == overlayID;
return _itemsToIgnore.contains(id) || _backPlate.entityID == id;
});
}

View file

@ -25,8 +25,6 @@
#include <shared/ReadWriteLockable.h>
#include <SettingHandle.h>
#include "ui/overlays/Overlay.h"
class PointerEvent;
@ -47,8 +45,8 @@ public:
static Key::Type getKeyTypeFromString(const QString& keyTypeString);
OverlayID getID() const { return _keyID; }
void setID(OverlayID overlayID) { _keyID = overlayID; }
QUuid getID() const { return _keyID; }
void setID(const QUuid& id) { _keyID = id; }
void startTimer(int time);
bool timerFinished();
@ -77,7 +75,7 @@ private:
int _switchToLayer { 0 };
bool _pressed { false };
OverlayID _keyID;
QUuid _keyID;
QString _keyString;
glm::vec3 _originalLocalPosition;
@ -111,35 +109,35 @@ public:
bool getUse3DKeyboard() const;
void setUse3DKeyboard(bool use);
bool containsID(OverlayID overlayID) const;
bool containsID(const QUuid& id) const;
void loadKeyboardFile(const QString& keyboardFile);
QVector<OverlayID> getKeysID();
OverlayID getAnchorID();
QVector<QUuid> getKeysID();
QUuid getAnchorID();
public slots:
void handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event);
void handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event);
void handleTriggerContinue(const OverlayID& overlayID, const PointerEvent& event);
void handleHoverBegin(const OverlayID& overlayID, const PointerEvent& event);
void handleHoverEnd(const OverlayID& overlayID, const PointerEvent& event);
void handleTriggerBegin(const QUuid& id, const PointerEvent& event);
void handleTriggerEnd(const QUuid& id, const PointerEvent& event);
void handleTriggerContinue(const QUuid& id, const PointerEvent& event);
void handleHoverBegin(const QUuid& id, const PointerEvent& event);
void handleHoverEnd(const QUuid& id, const PointerEvent& event);
void scaleKeyboard(float sensorToWorldScale);
private:
struct Anchor {
OverlayID overlayID;
QUuid entityID;
glm::vec3 originalDimensions;
};
struct BackPlate {
OverlayID overlayID;
QUuid entityID;
glm::vec3 dimensions;
glm::vec3 localPosition;
};
struct TextDisplay {
float lineHeight;
OverlayID overlayID;
QUuid entityID;
glm::vec3 localPosition;
glm::vec3 dimensions;
};
@ -153,9 +151,9 @@ private:
void clearKeyboardKeys();
void switchToLayer(int layerIndex);
void updateTextDisplay();
bool shouldProcessOverlayAndPointerEvent(const PointerEvent& event, const OverlayID& overlayID) const;
bool shouldProcessEntityAndPointerEvent(const PointerEvent& event, const QUuid& id) const;
bool shouldProcessPointerEvent(const PointerEvent& event) const;
bool shouldProcessOverlay(const OverlayID& overlayID) const;
bool shouldProcessEntity(const QUuid& id) const;
void startLayerSwitchTimer();
bool isLayerSwitchTimerFinished() const;
@ -184,8 +182,8 @@ private:
Anchor _anchor;
BackPlate _backPlate;
QVector<OverlayID> _itemsToIgnore;
std::vector<QHash<OverlayID, Key>> _keyboardLayers;
QVector<QUuid> _itemsToIgnore;
std::vector<QHash<QUuid, Key>> _keyboardLayers;
};
#endif

View file

@ -18,7 +18,7 @@
class QNetworkReply;
extern const QUrl OVERLAY_LOGIN_DIALOG;
extern const QUrl LOGIN_DIALOG;
class LoginDialog : public OffscreenQmlDialog {
Q_OBJECT

View file

@ -60,11 +60,12 @@ ContextOverlayInterface::ContextOverlayInterface() {
QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID();
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::quat cameraOrientation = qApp->getCamera().getOrientation();
QVariantMap props;
EntityItemProperties properties;
float sensorToWorldScale = myAvatar->getSensorToWorldScale();
props.insert("position", vec3toVariant(myAvatar->getEyePosition() + glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_OFFSET, 0.0f))) * ((CONTEXT_OVERLAY_TABLET_DISTANCE * sensorToWorldScale) * (cameraOrientation * Vectors::FRONT))));
props.insert("orientation", quatToVariant(cameraOrientation * glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_ORIENTATION, 0.0f)))));
qApp->getOverlays().editOverlay(tabletFrameID, props);
properties.setPosition(myAvatar->getEyePosition() + glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_OFFSET, 0.0f))) * ((CONTEXT_OVERLAY_TABLET_DISTANCE * sensorToWorldScale) * (cameraOrientation * Vectors::FRONT)));
properties.setRotation(cameraOrientation * glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_ORIENTATION, 0.0f))));
DependencyManager::get<EntityScriptingInterface>()->editEntity(tabletFrameID, properties);
_contextOverlayJustClicked = false;
}
});
@ -93,7 +94,6 @@ static const float CONTEXT_OVERLAY_HOVERED_ALPHA = 1.0f;
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMIN = 0.6f;
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMAX = 1.0f;
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD = 1.0f;
static const float CONTEXT_OVERLAY_UNHOVERED_COLORPULSE = 1.0f;
void ContextOverlayInterface::setEnabled(bool enabled) {
_enabled = enabled;
@ -192,22 +192,28 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
}
// Finally, setup and draw the Context Overlay
if (_contextOverlayID == UNKNOWN_OVERLAY_ID || !qApp->getOverlays().isAddedOverlay(_contextOverlayID)) {
_contextOverlay = std::make_shared<Image3DOverlay>();
_contextOverlay->setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA);
_contextOverlay->setPulseMin(CONTEXT_OVERLAY_UNHOVERED_PULSEMIN);
_contextOverlay->setPulseMax(CONTEXT_OVERLAY_UNHOVERED_PULSEMAX);
_contextOverlay->setColorPulse(CONTEXT_OVERLAY_UNHOVERED_COLORPULSE);
_contextOverlay->setIgnorePickIntersection(false);
_contextOverlay->setDrawInFront(true);
_contextOverlay->setURL(PathUtils::resourcesUrl() + "images/inspect-icon.png");
_contextOverlay->setIsFacingAvatar(true);
_contextOverlayID = qApp->getOverlays().addOverlay(_contextOverlay);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (_contextOverlayID == UNKNOWN_ENTITY_ID || !entityScriptingInterface->isAddedEntity(_contextOverlayID)) {
EntityItemProperties properties;
properties.setType(EntityTypes::Image);
properties.setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA);
properties.getPulse().setMin(CONTEXT_OVERLAY_UNHOVERED_PULSEMIN);
properties.getPulse().setMax(CONTEXT_OVERLAY_UNHOVERED_PULSEMAX);
properties.getPulse().setColorMode(PulseMode::IN_PHASE);
properties.setIgnorePickIntersection(false);
properties.setRenderLayer(RenderLayer::FRONT);
properties.setImageURL(PathUtils::resourcesUrl() + "images/inspect-icon.png");
properties.setBillboardMode(BillboardMode::FULL);
_contextOverlayID = entityScriptingInterface->addEntity(properties, "local");
}
_contextOverlay->setWorldPosition(contextOverlayPosition);
_contextOverlay->setDimensions(contextOverlayDimensions);
_contextOverlay->setWorldOrientation(entityProperties.getRotation());
_contextOverlay->setVisible(true);
EntityItemProperties properties;
properties.setPosition(contextOverlayPosition);
properties.setDimensions(glm::vec3(contextOverlayDimensions, 0.01f));
properties.setRotation(entityProperties.getRotation());
properties.setVisible(true);
entityScriptingInterface->editEntity(_contextOverlayID, properties);
return true;
}
@ -227,15 +233,13 @@ bool ContextOverlayInterface::contextOverlayFilterPassed(const EntityItemID& ent
}
bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
if (_contextOverlayID != UNKNOWN_OVERLAY_ID) {
if (_contextOverlayID != UNKNOWN_ENTITY_ID) {
qCDebug(context_overlay) << "Destroying Context Overlay on top of entity with ID: " << entityItemID;
disableEntityHighlight(entityItemID);
setCurrentEntityWithContextOverlay(QUuid());
_entityMarketplaceID.clear();
// Destroy the Context Overlay
qApp->getOverlays().deleteOverlay(_contextOverlayID);
_contextOverlay = NULL;
_contextOverlayID = UNKNOWN_OVERLAY_ID;
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_contextOverlayID);
_contextOverlayID = UNKNOWN_ENTITY_ID;
return true;
}
return false;
@ -254,22 +258,26 @@ void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayI
}
void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event) {
if (_contextOverlayID != UNKNOWN_OVERLAY_ID && _contextOverlay) {
if (_contextOverlayID != UNKNOWN_ENTITY_ID) {
qCDebug(context_overlay) << "Started hovering over Context Overlay. Overlay ID:" << overlayID;
_contextOverlay->setColor(CONTEXT_OVERLAY_COLOR);
_contextOverlay->setColorPulse(0.0f); // pulse off
_contextOverlay->setPulsePeriod(0.0f); // pulse off
_contextOverlay->setAlpha(CONTEXT_OVERLAY_HOVERED_ALPHA);
EntityItemProperties properties;
properties.setColor(CONTEXT_OVERLAY_COLOR);
properties.getPulse().setColorMode(PulseMode::NONE);
properties.getPulse().setPeriod(0.0f);
properties.setAlpha(CONTEXT_OVERLAY_HOVERED_ALPHA);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_contextOverlayID, properties);
}
}
void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) {
if (_contextOverlayID != UNKNOWN_OVERLAY_ID && _contextOverlay) {
if (_contextOverlayID != UNKNOWN_ENTITY_ID) {
qCDebug(context_overlay) << "Stopped hovering over Context Overlay. Overlay ID:" << overlayID;
_contextOverlay->setColor(CONTEXT_OVERLAY_COLOR);
_contextOverlay->setColorPulse(CONTEXT_OVERLAY_UNHOVERED_COLORPULSE);
_contextOverlay->setPulsePeriod(CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD);
_contextOverlay->setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA);
EntityItemProperties properties;
properties.setColor(CONTEXT_OVERLAY_COLOR);
properties.getPulse().setColorMode(PulseMode::IN_PHASE);
properties.getPulse().setPeriod(CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD);
properties.setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_contextOverlayID, properties);
}
}

View file

@ -22,8 +22,6 @@
#include "avatar/AvatarManager.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Image3DOverlay.h"
#include "ui/overlays/Overlays.h"
#include "scripting/HMDScriptingInterface.h"
#include "scripting/SelectionScriptingInterface.h"
#include "scripting/WalletScriptingInterface.h"
@ -43,8 +41,7 @@ class ContextOverlayInterface : public QObject, public Dependency {
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
QSharedPointer<TabletScriptingInterface> _tabletScriptingInterface;
QSharedPointer<SelectionScriptingInterface> _selectionScriptingInterface;
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
QUuid _contextOverlayID { UNKNOWN_ENTITY_ID };
public:
ContextOverlayInterface();
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
@ -83,12 +80,12 @@ private:
enum {
MAX_SELECTION_COUNT = 16
};
bool _verboseLogging{ true };
bool _verboseLogging { true };
bool _enabled { true };
EntityItemID _mouseDownEntity{};
EntityItemID _mouseDownEntity;
quint64 _mouseDownEntityTimestamp;
EntityItemID _currentEntityWithContextOverlay{};
EntityItemID _lastInspectedEntity{};
EntityItemID _currentEntityWithContextOverlay;
EntityItemID _lastInspectedEntity;
QString _entityMarketplaceID;
bool _contextOverlayJustClicked { false };

View file

@ -215,37 +215,6 @@ void Overlay::removeFromScene(Overlay::Pointer overlay, const render::ScenePoint
render::Item::clearID(_renderItemID);
}
QScriptValue OverlayIDtoScriptValue(QScriptEngine* engine, const OverlayID& id) {
return quuidToScriptValue(engine, id);
}
void OverlayIDfromScriptValue(const QScriptValue &object, OverlayID& id) {
quuidFromScriptValue(object, id);
}
QVector<OverlayID> qVectorOverlayIDFromScriptValue(const QScriptValue& array) {
if (!array.isArray()) {
return QVector<OverlayID>();
}
QVector<OverlayID> newVector;
int length = array.property("length").toInteger();
newVector.reserve(length);
for (int i = 0; i < length; i++) {
newVector << OverlayID(array.property(i).toString());
}
return newVector;
}
void Overlay::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[parentMaterialName].push(material);
}
void Overlay::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[parentMaterialName].remove(material);
}
render::ItemKey Overlay::getKey() {
auto builder = render::ItemKey::Builder().withTypeShape().withTypeMeta();

View file

@ -13,13 +13,6 @@
#include <render/Scene.h>
class OverlayID : public QUuid {
public:
OverlayID() : QUuid() {}
OverlayID(QString v) : QUuid(v) {}
OverlayID(QUuid v) : QUuid(v) {}
};
class Overlay : public QObject {
Q_OBJECT
@ -32,8 +25,8 @@ public:
Overlay(const Overlay* overlay);
~Overlay();
virtual OverlayID getOverlayID() const { return _overlayID; }
virtual void setOverlayID(OverlayID overlayID) { _overlayID = overlayID; }
virtual QUuid getID() const { return _id; }
virtual void setID(const QUuid& id) { _id = id; }
virtual void update(float deltatime) {}
virtual void render(RenderArgs* args) = 0;
@ -51,7 +44,6 @@ public:
// getters
virtual QString getType() const = 0;
virtual bool is3D() const = 0;
bool isLoaded() { return _isLoaded; }
bool getVisible() const { return _visible; }
virtual bool isTransparent() { return getAlphaPulse() != 0.0f || getAlpha() != 1.0f; };
@ -92,9 +84,6 @@ public:
unsigned int getStackOrder() const { return _stackOrder; }
void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; }
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
protected:
float updatePulse();
@ -121,11 +110,8 @@ protected:
static const glm::u8vec3 DEFAULT_OVERLAY_COLOR;
static const float DEFAULT_ALPHA;
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;
private:
OverlayID _overlayID; // only used for non-3d overlays
QUuid _id;
};
namespace render {
@ -136,10 +122,4 @@ namespace render {
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
}
Q_DECLARE_METATYPE(OverlayID);
Q_DECLARE_METATYPE(QVector<OverlayID>);
QScriptValue OverlayIDtoScriptValue(QScriptEngine* engine, const OverlayID& id);
void OverlayIDfromScriptValue(const QScriptValue& object, OverlayID& id);
QVector<OverlayID> qVectorOverlayIDFromScriptValue(const QScriptValue& array);
#endif // hifi_Overlay_h

View file

@ -1,13 +0,0 @@
//
// Created by Sabrina Shanman 9/5/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
//
#include "OverlayTransformNode.h"
template<>
glm::vec3 BaseNestableTransformNode<Base3DOverlay>::getActualScale(const std::shared_ptr<Base3DOverlay>& nestablePointer) const {
return nestablePointer->getBounds().getScale();
}

View file

@ -1,21 +0,0 @@
//
// Created by Sabrina Shanman 9/5/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_OverlayTransformNode_h
#define hifi_OverlayTransformNode_h
#include "NestableTransformNode.h"
#include "Base3DOverlay.h"
// For 3D overlays only
class OverlayTransformNode : public BaseNestableTransformNode<Base3DOverlay> {
public:
OverlayTransformNode(std::weak_ptr<Base3DOverlay> spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {};
};
#endif // hifi_OverlayTransformNode_h

View file

@ -37,7 +37,7 @@ class PickRay;
* @typedef {object} Overlays.RayToOverlayIntersectionResult
* @property {boolean} intersects - <code>true</code> if the {@link PickRay} intersected with a 3D overlay, otherwise
* <code>false</code>.
* @property {Uuid} overlayID - The UUID of the overlay that was intersected.
* @property {Uuid} overlayID - The UUID of the local entity that was intersected.
* @property {number} distance - The distance from the {@link PickRay} origin to the intersection point.
* @property {Vec3} surfaceNormal - The normal of the overlay surface at the intersection point.
* @property {Vec3} intersection - The position of the intersection point.
@ -46,7 +46,7 @@ class PickRay;
class RayToOverlayIntersectionResult {
public:
bool intersects { false };
QUuid overlayID { UNKNOWN_OVERLAY_ID };
QUuid overlayID;
float distance { 0.0f };
BoxFace face { UNKNOWN_FACE };
glm::vec3 surfaceNormal;
@ -60,7 +60,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
class ParabolaToOverlayIntersectionResult {
public:
bool intersects { false };
QUuid overlayID { UNKNOWN_OVERLAY_ID };
QUuid overlayID;
float distance { 0.0f };
float parabolicDistance { 0.0f };
BoxFace face { UNKNOWN_FACE };
@ -715,8 +715,8 @@ private:
PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
QMouseEvent* event, PointerEvent::EventType eventType);
QUuid _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
QUuid _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
QUuid _currentClickingOnOverlayID;
QUuid _currentHoverOverOverlayID;
private slots:
void mousePressPointerEvent(const QUuid& id, const PointerEvent& event);

View file

@ -8,27 +8,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <limits>
#include <typeinfo>
#include <avatar/AvatarManager.h>
#include <avatar/MyAvatar.h>
#include <LODManager.h>
#include <render/Scene.h>
#include "Image3DOverlay.h"
#include "Circle3DOverlay.h"
#include "Cube3DOverlay.h"
#include "ImageOverlay.h"
#include "Line3DOverlay.h"
#include "ModelOverlay.h"
#include "Overlays.h"
#include "Rectangle3DOverlay.h"
#include "Sphere3DOverlay.h"
#include "Grid3DOverlay.h"
#include "TextOverlay.h"
#include "Text3DOverlay.h"
#include "Overlay.h"
namespace render {
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {

View file

@ -1038,6 +1038,15 @@ bool EntityScriptingInterface::isLoaded(const QUuid& id) {
return toReturn;
}
bool EntityScriptingInterface::isAddedEntity(const QUuid& id) {
bool toReturn = false;
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(id);
toReturn = (bool)entity;
});
return toReturn;
}
QSizeF EntityScriptingInterface::textSize(const QUuid& id, const QString& text) {
return EntityTree::textSize(id, text);
}

View file

@ -1306,11 +1306,11 @@ public slots:
/**jsdoc
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. Recurse on the IDs returned by the function to get all descendants of an entity, overlay, or avatar.
* Get the IDs of entities and avatars that are directly parented to an entity or avatar model. Recurse on the IDs returned by the function to get all descendants of an entity or avatar.
* @function Entities.getChildrenIDs
* @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of.
* @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the <code>parentID</code>
* entity, overlay, or avatar. Does not include children's children, etc. The array is empty if no children can be found or
* @param {Uuid} parentID - The ID of the entity or avatar to get the children IDs of.
* @returns {Uuid[]} An array of entity and avatar IDs that are parented directly to the <code>parentID</code>
* entity or avatar. Does not include children's children, etc. The array is empty if no children can be found or
* <code>parentID</code> cannot be found.
* @example <caption>Report the children of an entity.</caption>
* function createEntity(description, position, parent) {
@ -1336,12 +1336,12 @@ public slots:
Q_INVOKABLE QVector<QUuid> getChildrenIDs(const QUuid& parentID);
/**jsdoc
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model's joint.
* Get the IDs of entities and avatars that are directly parented to an entity or avatar model's joint.
* @function Entities.getChildrenIDsOfJoint
* @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of.
* @param {Uuid} parentID - The ID of the entity or avatar to get the children IDs of.
* @param {number} jointIndex - Integer number of the model joint to get the children IDs of.
* @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the <code>parentID</code>
* entity, overlay, or avatar at the <code>jointIndex</code> joint. Does not include children's children, etc. The
* @returns {Uuid[]} An array of entity and avatar IDs that are parented directly to the <code>parentID</code>
* entity or avatar at the <code>jointIndex</code> joint. Does not include children's children, etc. The
* array is empty if no children can be found or <code>parentID</code> cannot be found.
* @example <caption>Report the children of your avatar's right hand.</caption>
* function createEntity(description, position, parent) {
@ -1371,11 +1371,11 @@ public slots:
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
/**jsdoc
* Check whether an entity or overlay has an entity as an ancestor (parent, parent's parent, etc.).
* Check whether an entity has an entity as an ancestor (parent, parent's parent, etc.).
* @function Entities.isChildOfParent
* @param {Uuid} childID - The ID of the child entity or overlay to test for being a child, grandchild, etc.
* @param {Uuid} childID - The ID of the child entity to test for being a child, grandchild, etc.
* @param {Uuid} parentID - The ID of the parent entity to test for being a parent, grandparent, etc.
* @returns {boolean} <code>true</code> if the <code>childID</code> entity or overlay has the <code>parentID</code> entity
* @returns {boolean} <code>true</code> if the <code>childID</code> entity has the <code>parentID</code> entity
* as a parent or grandparent etc., otherwise <code>false</code>.
* @example <caption>Check that a grandchild entity is a child of its grandparent.</caption>
* function createEntity(description, position, parent) {
@ -1400,12 +1400,11 @@ public slots:
Q_INVOKABLE bool isChildOfParent(const QUuid& childID, const QUuid& parentID);
/**jsdoc
* Get the type &mdash; entity, overlay, or avatar &mdash; of an in-world item.
* Get the type &mdash; entity or avatar &mdash; of an in-world item.
* @function Entities.getNestableType
* @param {Uuid} entityID - The ID of the item to get the type of.
* @returns {string} The type of the item: <code>"entity"</code> if the item is an entity, <code>"overlay"</code> if the
* the item is an overlay, <code>"avatar"</code> if the item is an avatar; otherwise <code>"unknown"</code> if the item
* cannot be found.
* @returns {string} The type of the item: <code>"entity"</code> if the item is an entity, <code>"avatar"</code>
* if the item is an avatar; otherwise <code>"unknown"</code> if the item cannot be found.
* @example <caption>Print some nestable types.</caption>
* var entity = Entities.addEntity({
* type: "Sphere",

View file

@ -64,9 +64,9 @@ static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) };
* @property {string} equippableIndicatorURL="" - If non-empty, this model will be used to indicate that an
* entity is equippable, rather than the default.
* @property {Vec3} equippableIndicatorScale=1,1,1 - If equippableIndicatorURL is non-empty, this controls the
scale of the displayed overlay.
scale of the displayed indicator.
* @property {Vec3} equippableIndicatorOffset=0,0,0 - If equippableIndicatorURL is non-empty, this controls the
relative offset of the displayed overlay from the equippable entity.
relative offset of the displayed object from the equippable entity.
*/

View file

@ -36,12 +36,12 @@ void GraphicsScriptingInterface::jsThrowError(const QString& error) {
}
}
bool GraphicsScriptingInterface::canUpdateModel(QUuid uuid, int meshIndex, int partNumber) {
bool GraphicsScriptingInterface::canUpdateModel(const QUuid& uuid, int meshIndex, int partNumber) {
auto provider = getModelProvider(uuid);
return provider && provider->canReplaceModelMeshPart(meshIndex, partNumber);
}
bool GraphicsScriptingInterface::updateModel(QUuid uuid, const scriptable::ScriptableModelPointer& model) {
bool GraphicsScriptingInterface::updateModel(const QUuid& uuid, const scriptable::ScriptableModelPointer& model) {
if (!model) {
jsThrowError("null model argument");
}
@ -69,7 +69,7 @@ bool GraphicsScriptingInterface::updateModel(QUuid uuid, const scriptable::Scrip
return provider->replaceScriptableModelMeshPart(base, -1, -1);
}
scriptable::ModelProviderPointer GraphicsScriptingInterface::getModelProvider(QUuid uuid) {
scriptable::ModelProviderPointer GraphicsScriptingInterface::getModelProvider(const QUuid& uuid) {
QString error;
if (auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>()) {
if (auto provider = appProvider->lookupModelProvider(uuid)) {
@ -107,7 +107,7 @@ scriptable::ScriptableModelPointer GraphicsScriptingInterface::newModel(const sc
return modelWrapper;
}
scriptable::ScriptableModelPointer GraphicsScriptingInterface::getModel(QUuid uuid) {
scriptable::ScriptableModelPointer GraphicsScriptingInterface::getModel(const QUuid& uuid) {
QString error;
bool success;
QString providerType = "unknown";

View file

@ -23,6 +23,7 @@
enum IntersectionType {
NONE = 0,
ENTITY,
LOCAL_ENTITY,
AVATAR,
HUD
};
@ -175,7 +176,6 @@ public:
virtual T getMathematicalPick() const = 0;
virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0;
virtual PickResultPointer getEntityIntersection(const T& pick) = 0;
virtual PickResultPointer getOverlayIntersection(const T& pick) = 0;
virtual PickResultPointer getAvatarIntersection(const T& pick) = 0;
virtual PickResultPointer getHUDIntersection(const T& pick) = 0;

View file

@ -37,7 +37,7 @@ template<typename T>
class PickCacheOptimizer {
public:
QVector4D update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks, uint32_t& nextToUpdate, uint64_t expiry, bool shouldPickHUD);
QVector3D update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks, uint32_t& nextToUpdate, uint64_t expiry, bool shouldPickHUD);
protected:
typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
@ -67,9 +67,9 @@ void PickCacheOptimizer<T>::cacheResult(const bool needToCompareResults, const P
}
template<typename T>
QVector4D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks,
QVector3D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks,
uint32_t& nextToUpdate, uint64_t expiry, bool shouldPickHUD) {
QVector4D numIntersectionsComputed;
QVector3D numIntersectionsComputed;
PickCache results;
const uint32_t INVALID_PICK_ID = 0;
auto itr = picks.begin();
@ -88,7 +88,7 @@ QVector4D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared
if (!pick->isEnabled() || pick->getMaxDistance() < 0.0f || !mathematicalPick) {
pick->setPickResult(res);
} else {
if (pick->getFilter().doesPickDomainEntities() || pick->getFilter().doesPickAvatarEntities()) {
if (pick->getFilter().doesPickDomainEntities() || pick->getFilter().doesPickAvatarEntities() || pick->getFilter().doesPickLocalEntities()) {
PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick);
@ -99,22 +99,11 @@ QVector4D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared
}
}
if (pick->getFilter().doesPickLocalEntities()) {
PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) {
PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick);
numIntersectionsComputed[1]++;
if (overlayRes) {
cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick);
}
}
}
if (pick->getFilter().doesPickAvatars()) {
PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) {
PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick);
numIntersectionsComputed[2]++;
numIntersectionsComputed[1]++;
if (avatarRes) {
cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick);
}
@ -126,7 +115,7 @@ QVector4D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared
PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick);
numIntersectionsComputed[3]++;
numIntersectionsComputed[2]++;
if (hudRes) {
cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick);
}

View file

@ -109,14 +109,14 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
if (_enabled && _hover && doHover && !_prevDoHover) {
if (hoveredObject.type == ENTITY) {
emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent);
} else if (hoveredObject.type == OVERLAY) {
} else if (hoveredObject.type == LOCAL_ENTITY) {
emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent);
} else if (hoveredObject.type == HUD) {
emit pointerManager->hoverBeginHUD(hoveredEvent);
}
} else if (_enabled && _hover && doHover) {
if (hoveredObject.type == OVERLAY) {
if (_prevHoveredObject.type == OVERLAY) {
if (hoveredObject.type == LOCAL_ENTITY) {
if (_prevHoveredObject.type == LOCAL_ENTITY) {
if (hoveredObject.objectID == _prevHoveredObject.objectID) {
emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent);
} else {
@ -150,7 +150,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
}
} else {
emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent);
if (_prevHoveredObject.type == OVERLAY) {
if (_prevHoveredObject.type == LOCAL_ENTITY) {
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
} else if (_prevHoveredObject.type == HUD) {
emit pointerManager->hoverEndHUD(hoveredEvent);
@ -166,7 +166,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
emit pointerManager->hoverBeginHUD(hoveredEvent);
if (_prevHoveredObject.type == ENTITY) {
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
} else if (_prevHoveredObject.type == OVERLAY) {
} else if (_prevHoveredObject.type == LOCAL_ENTITY) {
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
}
}
@ -175,7 +175,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
if (hoveredObject.type == NONE) {
if (_prevHoveredObject.type == ENTITY) {
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
} else if (_prevHoveredObject.type == OVERLAY) {
} else if (_prevHoveredObject.type == LOCAL_ENTITY) {
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
} else if (_prevHoveredObject.type == HUD) {
emit pointerManager->hoverEndHUD(hoveredEvent);
@ -191,7 +191,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
hoveredEvent.setShouldFocus(button == SHOULD_FOCUS_BUTTON);
if (hoveredObject.type == ENTITY) {
emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent);
} else if (hoveredObject.type == OVERLAY) {
} else if (hoveredObject.type == LOCAL_ENTITY) {
emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent);
} else if (hoveredObject.type == HUD) {
emit pointerManager->triggerBeginHUD(hoveredEvent);
@ -207,7 +207,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
triggeredEvent.setButton(chooseButton(button));
if (_triggeredObjects[button].type == ENTITY) {
emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent);
} else if (_triggeredObjects[button].type == OVERLAY) {
} else if (_triggeredObjects[button].type == LOCAL_ENTITY) {
emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent);
} else if (_triggeredObjects[button].type == HUD) {
emit pointerManager->triggerContinueHUD(triggeredEvent);
@ -222,7 +222,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
triggeredEvent.setButton(chooseButton(button));
if (_triggeredObjects[button].type == ENTITY) {
emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent);
} else if (_triggeredObjects[button].type == OVERLAY) {
} else if (_triggeredObjects[button].type == LOCAL_ENTITY) {
emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent);
} else if (_triggeredObjects[button].type == HUD) {
emit pointerManager->triggerEndHUD(triggeredEvent);
@ -234,7 +234,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
if (_hover && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) {
if (_prevHoveredObject.type == ENTITY) {
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
} else if (_prevHoveredObject.type == OVERLAY) {
} else if (_prevHoveredObject.type == LOCAL_ENTITY) {
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
} else if (_prevHoveredObject.type == HUD) {
emit pointerManager->hoverEndHUD(hoveredEvent);

View file

@ -62,7 +62,7 @@ public:
// Pointers can choose to implement these
virtual void setLength(float length) {}
virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) {}
virtual void setLockEndUUID(const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) {}
void update(unsigned int pointerID);
virtual void updateVisuals(const PickResultPointer& pickResult) = 0;

View file

@ -124,10 +124,10 @@ void PointerManager::setLength(unsigned int uid, float length) const {
}
}
void PointerManager::setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat) const {
void PointerManager::setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat) const {
auto pointer = find(uid);
if (pointer) {
pointer->setLockEndUUID(objectID, isOverlay, offsetMat);
pointer->setLockEndUUID(objectID, isAvatar, offsetMat);
}
}

View file

@ -37,7 +37,7 @@ public:
void setIncludeItems(unsigned int uid, const QVector<QUuid>& includeEntities) const;
void setLength(unsigned int uid, float length) const;
void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const;
void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const;
void update();

View file

@ -45,13 +45,13 @@ void EndGPURangeTimer::run(const render::RenderContextPointer& renderContext, co
config->setGPUBatchRunTime(timer->getGPUAverage(), timer->getBatchAverage());
}
DrawOverlay3D::DrawOverlay3D(bool opaque) :
DrawLayered3D::DrawLayered3D(bool opaque) :
_shapePlumber(std::make_shared<ShapePlumber>()),
_opaquePass(opaque) {
initForwardPipelines(*_shapePlumber);
}
void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
@ -70,7 +70,7 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
// Needs to be distinct from the other batch because using the clear call
// while stereo is enabled triggers a warning
if (_opaquePass) {
gpu::doInBatch("DrawOverlay3D::run::clear", args->_context, [&](gpu::Batch& batch) {
gpu::doInBatch("DrawLayered3D::run::clear", args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, false);
});
@ -78,7 +78,7 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
if (!inItems.empty()) {
// Render the items
gpu::doInBatch("DrawOverlay3D::main", args->_context, [&](gpu::Batch& batch) {
gpu::doInBatch("DrawLayered3D::main", args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);

View file

@ -40,7 +40,7 @@ public:
protected:
};
class DrawOverlay3DConfig : public render::Job::Config {
class DrawLayered3DConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
@ -58,13 +58,13 @@ protected:
int numDrawn{ 0 };
};
class DrawOverlay3D {
class DrawLayered3D {
public:
using Inputs = render::VaryingSet3<render::ItemBounds, LightingModelPointer, glm::vec2>;
using Config = DrawOverlay3DConfig;
using JobModel = render::Job::ModelI<DrawOverlay3D, Inputs, Config>;
using Config = DrawLayered3DConfig;
using JobModel = render::Job::ModelI<DrawLayered3D, Inputs, Config>;
DrawOverlay3D(bool opaque);
DrawLayered3D(bool opaque);
void configure(const Config& config) { _maxDrawn = config.maxDrawn; }
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);

View file

@ -116,13 +116,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto& items = fetchedItems.get0();
// Extract opaques / transparents / lights / metas / overlays / background
// Extract opaques / transparents / lights / metas / layered / background
const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
const auto& overlaysInFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE];
const auto& overlaysInFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE];
const auto& overlaysHUDOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE];
const auto& overlaysHUDTransparent = items[RenderFetchCullSortTask::LAYER_HUD_TRANSPARENT_SHAPE];
const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE];
const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE];
const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE];
const auto& hudTransparent = items[RenderFetchCullSortTask::LAYER_HUD_TRANSPARENT_SHAPE];
// Lighting model comes next, the big configuration of the view
const auto& lightingModel = inputs[1];
@ -227,12 +227,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<EndGPURangeTimer>("HighlightRangeTimer", outlineRangeTimer);
// Layered Over (in front)
const auto overlayInFrontOpaquesInputs = DrawOverlay3D::Inputs(overlaysInFrontOpaque, lightingModel, jitter).asVarying();
const auto overlayInFrontTransparentsInputs = DrawOverlay3D::Inputs(overlaysInFrontTransparent, lightingModel, jitter).asVarying();
task.addJob<DrawOverlay3D>("DrawOverlayInFrontOpaque", overlayInFrontOpaquesInputs, true);
task.addJob<DrawOverlay3D>("DrawOverlayInFrontTransparent", overlayInFrontTransparentsInputs, false);
const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, jitter).asVarying();
const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, jitter).asVarying();
task.addJob<DrawLayered3D>("DrawInFrontOpaque", inFrontOpaquesInputs, true);
task.addJob<DrawLayered3D>("DrawInFrontTransparent", inFrontTransparentsInputs, false);
const auto toneAndPostRangeTimer = task.addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing");
const auto toneAndPostRangeTimer = task.addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneLayeredAntialiasing");
// AA job before bloom to limit flickering
const auto antialiasingInputs = Antialiasing::Inputs(deferredFrameTransform, lightingFramebuffer, linearDepthTarget, velocityBuffer).asVarying();
@ -257,14 +257,14 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
// Upscale to finale resolution
const auto primaryFramebuffer = task.addJob<render::Upsample>("PrimaryBufferUpscale", scaledPrimaryFramebuffer);
// Composite the HUD and HUD overlays
// Composite the HUD and HUD layered objects
task.addJob<CompositeHUD>("HUD");
const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f));
const auto overlayHUDOpaquesInputs = DrawOverlay3D::Inputs(overlaysHUDOpaque, lightingModel, nullJitter).asVarying();
const auto overlayHUDTransparentsInputs = DrawOverlay3D::Inputs(overlaysHUDTransparent, lightingModel, nullJitter).asVarying();
task.addJob<DrawOverlay3D>("DrawOverlayHUDOpaque", overlayHUDOpaquesInputs, true);
task.addJob<DrawOverlay3D>("DrawOverlayHUDTransparent", overlayHUDTransparentsInputs, false);
const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying();
const auto hudTransparentsInputs = DrawLayered3D::Inputs(hudTransparent, lightingModel, nullJitter).asVarying();
task.addJob<DrawLayered3D>("DrawHUDOpaque", hudOpaquesInputs, true);
task.addJob<DrawLayered3D>("DrawHUDTransparent", hudTransparentsInputs, false);
task.addJob<EndGPURangeTimer>("ToneAndPostRangeTimer", toneAndPostRangeTimer);
@ -283,15 +283,15 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input
const auto& fetchCullSortTaskOut = inputs.get0();
const auto& items = fetchCullSortTaskOut.get0();
// Extract opaques / transparents / lights / metas / overlays InFront and HUD / background
// Extract opaques / transparents / lights / metas / layered / background
const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
const auto& lights = items[RenderFetchCullSortTask::LIGHT];
const auto& metas = items[RenderFetchCullSortTask::META];
const auto& overlaysInFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE];
const auto& overlaysInFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE];
const auto& overlaysHUDOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE];
const auto& overlaysHUDTransparent = items[RenderFetchCullSortTask::LAYER_HUD_TRANSPARENT_SHAPE];
const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE];
const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE];
const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE];
const auto& hudTransparent = items[RenderFetchCullSortTask::LAYER_HUD_TRANSPARENT_SHAPE];
const auto& spatialSelection = fetchCullSortTaskOut[1];
@ -388,14 +388,14 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input
task.addJob<DrawBounds>("DrawSelectionBounds", selectedItems);
}
{ // Debug the bounds of the rendered Overlay items that are marked drawInFront, still look at the zbuffer
task.addJob<DrawBounds>("DrawOverlayInFrontOpaqueBounds", overlaysInFrontOpaque);
task.addJob<DrawBounds>("DrawOverlayInFrontTransparentBounds", overlaysInFrontTransparent);
{ // Debug the bounds of the layered objects, still look at the zbuffer
task.addJob<DrawBounds>("DrawInFrontOpaqueBounds", inFrontOpaque);
task.addJob<DrawBounds>("DrawInFrontTransparentBounds", inFrontTransparent);
}
{ // Debug the bounds of the rendered Overlay items that are marked drawHUDLayer, still look at the zbuffer
task.addJob<DrawBounds>("DrawOverlayHUDOpaqueBounds", overlaysHUDOpaque);
task.addJob<DrawBounds>("DrawOverlayHUDTransparentBounds", overlaysHUDTransparent);
{ // Debug the bounds of the layered objects, still look at the zbuffer
task.addJob<DrawBounds>("DrawHUDOpaqueBounds", hudOpaque);
task.addJob<DrawBounds>("DrawHUDTransparentBounds", hudTransparent);
}
// Debugging stages

View file

@ -65,11 +65,10 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
const auto& metas = items[RenderFetchCullSortTask::META];
const auto& overlaysInFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE];
const auto& overlaysInFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE];
// TODO: Re enable the rendering of the HUD overlayes
// const auto& overlaysHUDOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE];
// const auto& overlaysHUDTransparent = items[RenderFetchCullSortTask::LAYER_HUD_TRANSPARENT_SHAPE];
const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE];
const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE];
const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE];
const auto& hudTransparent = items[RenderFetchCullSortTask::LAYER_HUD_TRANSPARENT_SHAPE];
// Lighting model comes next, the big configuration of the view
const auto& lightingModel = inputs[1];
@ -97,14 +96,12 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
// draw a stencil mask in hidden regions of the framebuffer.
task.addJob<PrepareStencil>("PrepareStencil", framebuffer);
// Layered Overlays
// Layered
const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f));
// Layered Over (in front)
const auto overlayInFrontOpaquesInputs = DrawOverlay3D::Inputs(overlaysInFrontOpaque, lightingModel, nullJitter).asVarying();
const auto overlayInFrontTransparentsInputs = DrawOverlay3D::Inputs(overlaysInFrontTransparent, lightingModel, nullJitter).asVarying();
task.addJob<DrawOverlay3D>("DrawOverlayInFrontOpaque", overlayInFrontOpaquesInputs, true);
task.addJob<DrawOverlay3D>("DrawOverlayInFrontTransparent", overlayInFrontTransparentsInputs, false);
const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, nullJitter).asVarying();
const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, nullJitter).asVarying();
task.addJob<DrawLayered3D>("DrawInFrontOpaque", inFrontOpaquesInputs, true);
task.addJob<DrawLayered3D>("DrawInFrontTransparent", inFrontTransparentsInputs, false);
// Draw opaques forward
const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying();
@ -135,10 +132,14 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
const auto toneMappingInputs = ToneMappingDeferred::Inputs(framebuffer, static_cast<gpu::FramebufferPointer>(nullptr) ).asVarying();
task.addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
// Layered Overlays
// Composite the HUD and HUD overlays
// Composite the HUD and HUD layered objects
task.addJob<CompositeHUD>("HUD");
const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying();
const auto hudTransparentsInputs = DrawLayered3D::Inputs(hudTransparent, lightingModel, nullJitter).asVarying();
task.addJob<DrawLayered3D>("DrawHUDOpaque", hudOpaquesInputs, true);
task.addJob<DrawLayered3D>("DrawHUDTransparent", hudTransparentsInputs, false);
// Disable blit because we do tonemapping and compositing directly to the blit FBO
// Blit!
// task.addJob<Blit>("Blit", framebuffer);

View file

@ -107,7 +107,7 @@ namespace render {
float getOccludedFillOpacity() const { return getStyle()._fillOccluded.alpha; }
void setOccludedFillOpacity(float value);
std::string _selectionName{ "contextOverlayHighlightList" };
std::string _selectionName { "contextOverlayHighlightList" };
mutable SelectionStyles _styles;
const HighlightStyle& getStyle() const;

View file

@ -29,10 +29,10 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
// Overlays are not culled
const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withoutSubMetaCulled().withTagBits(tagBits, tagMask);
const auto nonspatialFilter = render::Varying(overlayfilter);
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection", nonspatialFilter);
// Layered objects are not culled
const ItemFilter layeredFilter = ItemFilter::Builder().withVisible().withoutSubMetaCulled().withTagBits(tagBits, tagMask);
const auto nonspatialFilter = render::Varying(layeredFilter);
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchLayeredSelection", nonspatialFilter);
// Multi filter visible items into different buckets
const int NUM_SPATIAL_FILTERS = 4;
@ -57,26 +57,26 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
task.addJob<MultiFilterItems<NUM_SPATIAL_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters)
.get<MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemBoundsArray>();
const auto filteredNonspatialBuckets =
task.addJob<MultiFilterItems<NUM_NON_SPATIAL_FILTERS>>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters)
task.addJob<MultiFilterItems<NUM_NON_SPATIAL_FILTERS>>("FilterLayeredSelection", nonspatialSelection, nonspatialFilters)
.get<MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemBoundsArray>();
// Extract opaques / transparents / lights / overlays
// Extract opaques / transparents / lights / layered
const auto opaques = task.addJob<DepthSortItems>("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]);
const auto transparents = task.addJob<DepthSortItems>("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
const auto lights = filteredSpatialBuckets[LIGHT_BUCKET];
const auto metas = filteredSpatialBuckets[META_BUCKET];
const auto overlayOpaques = task.addJob<DepthSortItems>("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]);
const auto overlayTransparents = task.addJob<DepthSortItems>("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET];
// split up the overlays into 3D front, hud
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, ItemKey::Layer::LAYER_1);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, ItemKey::Layer::LAYER_1);
// split up the layered objects into 3D front, hud
const auto layeredOpaques = task.addJob<DepthSortItems>("DepthSortLayaredOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]);
const auto layeredTransparents = task.addJob<DepthSortItems>("DepthSortLayeredTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
const auto filteredLayeredOpaque = task.addJob<FilterLayeredItems>("FilterLayeredOpaque", layeredOpaques, ItemKey::Layer::LAYER_1);
const auto filteredLayeredTransparent = task.addJob<FilterLayeredItems>("FilterLayeredTransparent", layeredTransparents, ItemKey::Layer::LAYER_1);
output = Output(BucketList{ opaques, transparents, lights, metas, overlayOpaques, overlayTransparents,
filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0), filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0),
filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(1), filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(1),
output = Output(BucketList{ opaques, transparents, lights, metas,
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(0), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(0),
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(1), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(1),
background }, spatialSelection);
}

View file

@ -23,8 +23,6 @@ public:
TRANSPARENT_SHAPE,
LIGHT,
META,
OVERLAY_OPAQUE_SHAPE,
OVERLAY_TRANSPARENT_SHAPE,
LAYER_FRONT_OPAQUE_SHAPE,
LAYER_FRONT_TRANSPARENT_SHAPE,
LAYER_HUD_OPAQUE_SHAPE,

View file

@ -167,11 +167,9 @@ public:
// Access the spatialized items
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
// Access non-spatialized items (overlays, backgrounds)
// Access non-spatialized items (layered objects, backgrounds)
const ItemIDSet& getNonspatialSet() const { return _masterNonspatialSet; }
// Access a particular Stage (empty if doesn't exist)
// Thread safe
StagePointer getStage(const Stage::Name& name) const;

View file

@ -19,7 +19,7 @@
#include <QtScript/QScriptable>
/**jsdoc
* A UUID (Universally Unique IDentifier) is used to uniquely identify entities, overlays, avatars, and the like. It is
* A UUID (Universally Unique IDentifier) is used to uniquely identify entities, avatars, and the like. It is
* represented in JavaScript as a string in the format, <code>{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}</code>, where the "n"s are
* hexadecimal digits.
*

View file

@ -68,7 +68,7 @@ public:
// Helpers for RayPickManager
Flags getEntityFlags() const {
unsigned int toReturn = 0;
for (int i = DOMAIN_ENTITIES; i < LOCAL_ENTITIES; i++) {
for (int i = DOMAIN_ENTITIES; i <= LOCAL_ENTITIES; i++) {
if (_flags[i]) {
toReturn |= getBitMask(FlagBit(i));
}
@ -80,15 +80,6 @@ public:
}
return Flags(toReturn);
}
Flags getOverlayFlags() const {
unsigned int toReturn = getBitMask(LOCAL_ENTITIES);
for (int i = HUD + 1; i < NUM_FLAGS; i++) {
if (_flags[i]) {
toReturn |= getBitMask(FlagBit(i));
}
}
return Flags(toReturn);
}
Flags getAvatarFlags() const { return Flags(getBitMask(AVATARS)); }
Flags getHUDFlags() const { return Flags(getBitMask(HUD)); }

View file

@ -72,8 +72,8 @@ void PointerEvent::setButton(Button button) {
* <code>"Move"</code>.
* @property {number} id - Integer number used to identify the pointer: <code>0</code> = hardware mouse, <code>1</code> = left
* controller, <code>2</code> = right controller.
* @property {Vec2} pos2D - The 2D position of the event on the intersected overlay or entity XY plane, where applicable.
* @property {Vec3} pos3D - The 3D position of the event on the intersected overlay or entity, where applicable.
* @property {Vec2} pos2D - The 2D position of the event on the intersected object XY plane, where applicable.
* @property {Vec3} pos3D - The 3D position of the event on the intersected object, where applicable.
* @property {Vec3} normal - The surface normal at the intersection point.
* @property {Vec3} direction - The direction of the intersection ray.
* @property {string} button - The name of the button pressed: <code>None</code>, <code>Primary</code>, <code>Secondary</code>,

View file

@ -232,7 +232,7 @@ public:
};
/**jsdoc
* A PickRay defines a vector with a starting point. It is used, for example, when finding entities or overlays that lie under a
* A PickRay defines a vector with a starting point. It is used, for example, when finding entities or avatars that lie under a
* mouse click or intersect a laser beam.
*
* @typedef {object} PickRay
@ -351,7 +351,7 @@ public:
* The depth is measured in world space, but will scale with the parent if defined.
* @property {CollisionMask} [collisionGroup=8] - The type of object this collision pick collides as. Objects whose collision masks overlap with the pick's collision group
* will be considered colliding with the pick.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay.
* @property {Uuid} parentID - The ID of the parent, either an avatar or an entity.
* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
*/