DELETE IT ALL

This commit is contained in:
SamGondelman 2019-01-25 16:06:59 -08:00
parent a2083d949e
commit becc9f4f8d
44 changed files with 600 additions and 5963 deletions

View file

@ -1,392 +0,0 @@
//
// Base3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Base3DOverlay.h"
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h>
#include "Application.h"
const bool DEFAULT_IS_SOLID = false;
const bool DEFAULT_IS_DASHED_LINE = false;
Base3DOverlay::Base3DOverlay() :
SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()),
_isSolid(DEFAULT_IS_SOLID),
_isDashedLine(DEFAULT_IS_DASHED_LINE),
_ignorePickIntersection(false),
_drawInFront(false),
_drawHUDLayer(false)
{
// HACK: queryAACube stuff not actually relevant for 3DOverlays, and by setting _queryAACubeSet true here
// we can avoid incorrect evaluation for sending updates for entities with 3DOverlays children.
_queryAACubeSet = true;
}
Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
Overlay(base3DOverlay),
SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()),
_isSolid(base3DOverlay->_isSolid),
_isDashedLine(base3DOverlay->_isDashedLine),
_ignorePickIntersection(base3DOverlay->_ignorePickIntersection),
_drawInFront(base3DOverlay->_drawInFront),
_drawHUDLayer(base3DOverlay->_drawHUDLayer),
_isGrabbable(base3DOverlay->_isGrabbable),
_isVisibleInSecondaryCamera(base3DOverlay->_isVisibleInSecondaryCamera)
{
setTransform(base3DOverlay->getTransform());
// HACK: queryAACube stuff not actually relevant for 3DOverlays, and by setting _queryAACubeSet true here
// we can avoid incorrect evaluation for sending updates for entities with 3DOverlays children.
_queryAACubeSet = true;
}
QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties, bool scalesWithParent) {
// the position and rotation in _transform are relative to the parent (aka local). The versions coming from
// scripts are in world-frame, unless localPosition or localRotation are used. Patch up the properties
// so that "position" and "rotation" are relative-to-parent values.
QVariantMap result = properties;
QUuid parentID = result["parentID"].isValid() ? QUuid(result["parentID"].toString()) : QUuid();
int parentJointIndex = result["parentJointIndex"].isValid() ? result["parentJointIndex"].toInt() : -1;
bool success;
// make "position" and "orientation" be relative-to-parent
if (result["localPosition"].isValid()) {
result["position"] = result["localPosition"];
} else if (result["position"].isValid()) {
glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]),
parentID, parentJointIndex, scalesWithParent, success);
if (success) {
result["position"] = vec3toVariant(localPosition);
}
}
if (result["localOrientation"].isValid()) {
result["orientation"] = result["localOrientation"];
} else if (result["orientation"].isValid()) {
glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]),
parentID, parentJointIndex, scalesWithParent, success);
if (success) {
result["orientation"] = quatToVariant(localOrientation);
}
}
return result;
}
void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
QVariantMap properties = originalProperties;
if (properties["name"].isValid()) {
setName(properties["name"].toString());
}
// carry over some legacy keys
if (!properties["position"].isValid() && !properties["localPosition"].isValid()) {
if (properties["p1"].isValid()) {
properties["position"] = properties["p1"];
} else if (properties["point"].isValid()) {
properties["position"] = properties["point"];
} else if (properties["start"].isValid()) {
properties["position"] = properties["start"];
}
}
if (!properties["orientation"].isValid() && properties["rotation"].isValid()) {
properties["orientation"] = properties["rotation"];
}
if (!properties["localOrientation"].isValid() && properties["localRotation"].isValid()) {
properties["localOrientation"] = properties["localRotation"];
}
// All of parentID, parentJointIndex, position, orientation are needed to make sense of any of them.
// If any of these changed, pull any missing properties from the overlay.
if (properties["parentID"].isValid() || properties["parentJointIndex"].isValid() ||
properties["position"].isValid() || properties["localPosition"].isValid() ||
properties["orientation"].isValid() || properties["localOrientation"].isValid()) {
if (!properties["parentID"].isValid()) {
properties["parentID"] = getParentID();
}
if (!properties["parentJointIndex"].isValid()) {
properties["parentJointIndex"] = getParentJointIndex();
}
if (!properties["position"].isValid() && !properties["localPosition"].isValid()) {
properties["position"] = vec3toVariant(getWorldPosition());
}
if (!properties["orientation"].isValid() && !properties["localOrientation"].isValid()) {
properties["orientation"] = quatToVariant(getWorldOrientation());
}
}
properties = convertOverlayLocationFromScriptSemantics(properties, getScalesWithParent());
Overlay::setProperties(properties);
bool needRenderItemUpdate = false;
auto drawInFront = properties["drawInFront"];
if (drawInFront.isValid()) {
bool value = drawInFront.toBool();
setDrawInFront(value);
needRenderItemUpdate = true;
}
auto drawHUDLayer = properties["drawHUDLayer"];
if (drawHUDLayer.isValid()) {
bool value = drawHUDLayer.toBool();
setDrawHUDLayer(value);
needRenderItemUpdate = true;
}
auto isGrabbable = properties["grabbable"];
if (isGrabbable.isValid()) {
setIsGrabbable(isGrabbable.toBool());
}
auto isVisibleInSecondaryCamera = properties["isVisibleInSecondaryCamera"];
if (isVisibleInSecondaryCamera.isValid()) {
bool value = isVisibleInSecondaryCamera.toBool();
setIsVisibleInSecondaryCamera(value);
needRenderItemUpdate = true;
}
if (properties["position"].isValid()) {
setLocalPosition(vec3FromVariant(properties["position"]));
needRenderItemUpdate = true;
}
if (properties["orientation"].isValid()) {
setLocalOrientation(quatFromVariant(properties["orientation"]));
needRenderItemUpdate = true;
}
if (properties["isSolid"].isValid()) {
setIsSolid(properties["isSolid"].toBool());
}
if (properties["isFilled"].isValid()) {
setIsSolid(properties["isSolid"].toBool());
}
if (properties["isWire"].isValid()) {
setIsSolid(!properties["isWire"].toBool());
}
if (properties["solid"].isValid()) {
setIsSolid(properties["solid"].toBool());
}
if (properties["filled"].isValid()) {
setIsSolid(properties["filled"].toBool());
}
if (properties["wire"].isValid()) {
setIsSolid(!properties["wire"].toBool());
}
if (properties["isDashedLine"].isValid()) {
qDebug() << "isDashed is deprecated and will be removed in RC79!";
setIsDashedLine(properties["isDashedLine"].toBool());
}
if (properties["dashed"].isValid()) {
qDebug() << "dashed is deprecated and will be removed in RC79!";
setIsDashedLine(properties["dashed"].toBool());
}
if (properties["ignorePickIntersection"].isValid()) {
setIgnorePickIntersection(properties["ignorePickIntersection"].toBool());
} else if (properties["ignoreRayIntersection"].isValid()) {
setIgnorePickIntersection(properties["ignoreRayIntersection"].toBool());
}
if (properties["parentID"].isValid()) {
setParentID(QUuid(properties["parentID"].toString()));
needRenderItemUpdate = true;
}
if (properties["parentJointIndex"].isValid()) {
setParentJointIndex(properties["parentJointIndex"].toInt());
needRenderItemUpdate = true;
}
// Communicate changes to the renderItem if needed
if (needRenderItemUpdate) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
_queryAACubeSet = true; // HACK: just in case some SpatiallyNestable code accidentally set it false
}
}
// JSDoc for copying to @typedefs of overlay types that inherit Base3DOverlay.
/**jsdoc
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {boolean} isVisibleInSecondaryCamera=false - If <code>true</code>, the overlay is rendered in secondary
* camera views.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*/
QVariant Base3DOverlay::getProperty(const QString& property) {
if (property == "name") {
return _nameLock.resultWithReadLock<QString>([&] {
return _name;
});
}
if (property == "position" || property == "start" || property == "p1" || property == "point") {
return vec3toVariant(getWorldPosition());
}
if (property == "localPosition") {
return vec3toVariant(getLocalPosition());
}
if (property == "rotation" || property == "orientation") {
return quatToVariant(getWorldOrientation());
}
if (property == "localRotation" || property == "localOrientation") {
return quatToVariant(getLocalOrientation());
}
if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled") {
return _isSolid;
}
if (property == "isWire" || property == "wire") {
return !_isSolid;
}
if (property == "isDashedLine" || property == "dashed") {
qDebug() << "isDashedLine/dashed are deprecated and will be removed in RC79!";
return _isDashedLine;
}
if (property == "ignorePickIntersection" || property == "ignoreRayIntersection") {
return _ignorePickIntersection;
}
if (property == "drawInFront") {
return _drawInFront;
}
if (property == "grabbable") {
return _isGrabbable;
}
if (property == "isVisibleInSecondaryCamera") {
return _isVisibleInSecondaryCamera;
}
if (property == "parentID") {
return getParentID();
}
if (property == "parentJointIndex") {
return getParentJointIndex();
}
return Overlay::getProperty(property);
}
void Base3DOverlay::locationChanged(bool tellPhysics) {
SpatiallyNestable::locationChanged(tellPhysics);
// Force the actual update of the render transform through the notify call
notifyRenderVariableChange();
}
// FIXME: Overlays shouldn't be deleted when their parents are
void Base3DOverlay::parentDeleted() {
qApp->getOverlays().deleteOverlay(Overlay::getID());
}
void Base3DOverlay::update(float duration) {
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
// then the correct transform used for rendering is computed in the update transaction and assigned.
if (_renderVariableDirty) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
// Capture the render transform value in game loop before
auto latestTransform = evalRenderTransform();
bool latestVisible = getVisible();
_renderVariableDirty = false;
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
transaction.updateItem<Overlay>(itemID, [latestTransform, latestVisible](Overlay& data) {
auto overlay3D = dynamic_cast<Base3DOverlay*>(&data);
if (overlay3D) {
// TODO: overlays need to communicate all relavent render properties through transactions
overlay3D->setRenderTransform(latestTransform);
overlay3D->setRenderVisible(latestVisible);
}
});
scene->enqueueTransaction(transaction);
}
}
}
void Base3DOverlay::notifyRenderVariableChange() const {
_renderVariableDirty = true;
}
Transform Base3DOverlay::evalRenderTransform() {
return getTransform();
}
void Base3DOverlay::setRenderTransform(const Transform& transform) {
_renderTransform = transform;
}
void Base3DOverlay::setRenderVisible(bool visible) {
_renderVisible = visible;
}
SpatialParentTree* Base3DOverlay::getParentTree() const {
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
return entityTree.get();
}
void Base3DOverlay::setVisible(bool visible) {
Parent::setVisible(visible);
notifyRenderVariableChange();
}
QString Base3DOverlay::getName() const {
return _nameLock.resultWithReadLock<QString>([&] {
return QString("Overlay:") + _name;
});
}
void Base3DOverlay::setName(QString name) {
_nameLock.withWriteLock([&] {
_name = name;
});
}
render::ItemKey Base3DOverlay::getKey() {
auto builder = render::ItemKey::Builder(Overlay::getKey());
if (getDrawInFront()) {
builder.withLayer(render::hifi::LAYER_3D_FRONT);
} else if (getDrawHUDLayer()) {
builder.withLayer(render::hifi::LAYER_3D_HUD);
} else {
builder.withoutLayer();
}
builder.withoutViewSpace();
if (isTransparent()) {
builder.withTransparent();
}
return builder.build();
}

View file

@ -1,106 +0,0 @@
//
// Base3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Base3DOverlay_h
#define hifi_Base3DOverlay_h
#include <Transform.h>
#include <SpatiallyNestable.h>
#include <graphics-scripting/Forward.h>
#include "Overlay.h"
class Base3DOverlay : public Overlay, public SpatiallyNestable, public scriptable::ModelProvider {
Q_OBJECT
using Parent = Overlay;
public:
Base3DOverlay();
Base3DOverlay(const Base3DOverlay* base3DOverlay);
void setVisible(bool visible) override;
bool queryAACubeNeedsUpdate() const override { return false; } // HACK: queryAACube not relevant for Overlays
virtual QString getName() const override;
void setName(QString name);
virtual render::ItemKey getKey() override;
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return (uint32_t) subItems.size(); }
virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); }
// TODO: consider implementing registration points in this class
glm::vec3 getCenter() const { return getWorldPosition(); }
bool getIsSolid() const { return _isSolid; }
bool getIsDashedLine() const { return _isDashedLine; }
bool getIsSolidLine() const { return !_isDashedLine; }
bool getIgnorePickIntersection() const { return _ignorePickIntersection; }
bool getDrawInFront() const { return _drawInFront; }
bool getDrawHUDLayer() const { return _drawHUDLayer; }
bool getIsGrabbable() const { return _isGrabbable; }
virtual bool getIsVisibleInSecondaryCamera() const override { return _isVisibleInSecondaryCamera; }
void setIsSolid(bool isSolid) { _isSolid = isSolid; }
void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; }
void setIgnorePickIntersection(bool value) { _ignorePickIntersection = value; }
virtual void setDrawInFront(bool value) { _drawInFront = value; }
virtual void setDrawHUDLayer(bool value) { _drawHUDLayer = value; }
void setIsGrabbable(bool value) { _isGrabbable = value; }
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
void update(float deltatime) override;
void notifyRenderVariableChange() const;
virtual void setProperties(const QVariantMap& properties) override;
virtual QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) { return false; }
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking = false) {
return findRayIntersection(origin, direction, distance, face, surfaceNormal, precisionPicking);
}
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) { return false; }
virtual bool findParabolaIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking = false) {
return findParabolaIntersection(origin, velocity, acceleration, parabolicDistance, face, surfaceNormal, precisionPicking);
}
virtual SpatialParentTree* getParentTree() const override;
protected:
virtual void locationChanged(bool tellPhysics = true) override;
virtual void parentDeleted() override;
mutable Transform _renderTransform;
mutable bool _renderVisible;
virtual Transform evalRenderTransform();
virtual void setRenderTransform(const Transform& transform);
void setRenderVisible(bool visible);
const Transform& getRenderTransform() const { return _renderTransform; }
bool _isSolid;
bool _isDashedLine;
bool _ignorePickIntersection;
bool _drawInFront;
bool _drawHUDLayer;
bool _isGrabbable { false };
bool _isVisibleInSecondaryCamera { false };
mutable bool _renderVariableDirty { true };
QString _name;
mutable ReadWriteLockable _nameLock;
};
#endif // hifi_Base3DOverlay_h

View file

@ -1,65 +0,0 @@
//
// Billboard3DOverlay.cpp
// hifi/interface/src/ui/overlays
//
// Created by Zander Otavka on 8/4/15.
// Copyright 2014 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 "Billboard3DOverlay.h"
Billboard3DOverlay::Billboard3DOverlay(const Billboard3DOverlay* billboard3DOverlay) :
Planar3DOverlay(billboard3DOverlay),
PanelAttachable(*billboard3DOverlay),
Billboardable(*billboard3DOverlay)
{
}
void Billboard3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
PanelAttachable::setProperties(properties);
Billboardable::setProperties(properties);
}
QVariant Billboard3DOverlay::getProperty(const QString &property) {
QVariant value;
value = Billboardable::getProperty(property);
if (value.isValid()) {
return value;
}
value = PanelAttachable::getProperty(property);
if (value.isValid()) {
return value;
}
return Planar3DOverlay::getProperty(property);
}
bool Billboard3DOverlay::applyTransformTo(Transform& transform, bool force) {
bool transformChanged = false;
if (force || usecTimestampNow() > _transformExpiry) {
transformChanged = PanelAttachable::applyTransformTo(transform, true);
transformChanged |= pointTransformAtCamera(transform, getOffsetRotation());
}
return transformChanged;
}
void Billboard3DOverlay::update(float duration) {
if (isFacingAvatar()) {
_renderVariableDirty = true;
}
Parent::update(duration);
}
Transform Billboard3DOverlay::evalRenderTransform() {
Transform transform = getTransform();
bool transformChanged = applyTransformTo(transform, true);
// If the transform is not modified, setting the transform to
// itself will cause drift over time due to floating point errors.
if (transformChanged) {
setTransform(transform);
}
return transform;
}

View file

@ -1,38 +0,0 @@
//
// Billboard3DOverlay.h
// hifi/interface/src/ui/overlays
//
// Created by Zander Otavka on 8/4/15.
// Copyright 2014 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_Billboard3DOverlay_h
#define hifi_Billboard3DOverlay_h
#include "Planar3DOverlay.h"
#include "PanelAttachable.h"
#include "Billboardable.h"
class Billboard3DOverlay : public Planar3DOverlay, public PanelAttachable, public Billboardable {
Q_OBJECT
using Parent = Planar3DOverlay;
public:
Billboard3DOverlay() {}
Billboard3DOverlay(const Billboard3DOverlay* billboard3DOverlay);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
void update(float duration) override;
protected:
virtual bool applyTransformTo(Transform& transform, bool force = false) override;
Transform evalRenderTransform() override;
};
#endif // hifi_Billboard3DOverlay_h

View file

@ -1,56 +0,0 @@
//
// Billboardable.cpp
// interface/src/ui/overlays
//
// Created by Zander Otavka on 8/7/15.
// Modified by Daniela Fontes on 24/10/17.
// Copyright 2014 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 "Billboardable.h"
#include <Application.h>
#include <Transform.h>
#include "avatar/AvatarManager.h"
void Billboardable::setProperties(const QVariantMap& properties) {
auto isFacingAvatar = properties["isFacingAvatar"];
if (isFacingAvatar.isValid()) {
setIsFacingAvatar(isFacingAvatar.toBool());
}
}
// JSDoc for copying to @typedefs of overlay types that inherit Billboardable.
/**jsdoc
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
*/
QVariant Billboardable::getProperty(const QString &property) {
if (property == "isFacingAvatar") {
return isFacingAvatar();
}
return QVariant();
}
bool Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offsetRotation) {
if (isFacingAvatar()) {
glm::vec3 billboardPos = transform.getTranslation();
glm::vec3 cameraPos = qApp->getCamera().getPosition();
// use the referencial from the avatar, y isn't always up
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation()*Vectors::UP;
// check to see if glm::lookAt will work / using glm::lookAt variable name
glm::highp_vec3 s(glm::cross(billboardPos - cameraPos, avatarUP));
// make sure s is not NaN for any component
if(glm::length2(s) > 0.0f) {
glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP))));
transform.setRotation(rotation);
transform.postRotate(offsetRotation);
return true;
}
}
return false;
}

View file

@ -1,36 +0,0 @@
//
// Billboardable.h
// interface/src/ui/overlays
//
// Created by Zander Otavka on 8/7/15.
// Copyright 2014 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_Billboardable_h
#define hifi_Billboardable_h
#include <glm/gtc/quaternion.hpp>
#include <QVariant>
class QString;
class Transform;
class Billboardable {
public:
bool isFacingAvatar() const { return _isFacingAvatar; }
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
protected:
void setProperties(const QVariantMap& properties);
QVariant getProperty(const QString& property);
bool pointTransformAtCamera(Transform& transform, glm::quat offsetRotation = {1, 0, 0, 0});
private:
bool _isFacingAvatar = false;
};
#endif // hifi_Billboardable_h

View file

@ -1,589 +0,0 @@
//
// Circle3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Circle3DOverlay.h"
#include <GeometryUtil.h>
#include <GeometryCache.h>
#include <RegisteredMetaTypes.h>
QString const Circle3DOverlay::TYPE = "circle3d";
Circle3DOverlay::Circle3DOverlay() {}
Circle3DOverlay::Circle3DOverlay(const Circle3DOverlay* circle3DOverlay) :
Planar3DOverlay(circle3DOverlay),
_startAt(circle3DOverlay->_startAt),
_endAt(circle3DOverlay->_endAt),
_outerRadius(circle3DOverlay->_outerRadius),
_innerRadius(circle3DOverlay->_innerRadius),
_innerStartColor(circle3DOverlay->_innerStartColor),
_innerEndColor(circle3DOverlay->_innerEndColor),
_outerStartColor(circle3DOverlay->_outerStartColor),
_outerEndColor(circle3DOverlay->_outerEndColor),
_innerStartAlpha(circle3DOverlay->_innerStartAlpha),
_innerEndAlpha(circle3DOverlay->_innerEndAlpha),
_outerStartAlpha(circle3DOverlay->_outerStartAlpha),
_outerEndAlpha(circle3DOverlay->_outerEndAlpha),
_hasTickMarks(circle3DOverlay->_hasTickMarks),
_majorTickMarksAngle(circle3DOverlay->_majorTickMarksAngle),
_minorTickMarksAngle(circle3DOverlay->_minorTickMarksAngle),
_majorTickMarksLength(circle3DOverlay->_majorTickMarksLength),
_minorTickMarksLength(circle3DOverlay->_minorTickMarksLength),
_majorTickMarksColor(circle3DOverlay->_majorTickMarksColor),
_minorTickMarksColor(circle3DOverlay->_minorTickMarksColor)
{
}
Circle3DOverlay::~Circle3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
if (_quadVerticesID) {
geometryCache->releaseID(_quadVerticesID);
}
if (_lineVerticesID) {
geometryCache->releaseID(_lineVerticesID);
}
if (_majorTicksVerticesID) {
geometryCache->releaseID(_majorTicksVerticesID);
}
if (_minorTicksVerticesID) {
geometryCache->releaseID(_minorTicksVerticesID);
}
}
}
void Circle3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
if (alpha == 0.0f) {
return; // do nothing if our alpha is 0, we're not visible
}
bool geometryChanged = _dirty;
_dirty = false;
const float FULL_CIRCLE = 360.0f;
const float SLICES = 180.0f; // The amount of segment to create the circle
const float SLICE_ANGLE_RADIANS = glm::radians(FULL_CIRCLE / SLICES);
auto geometryCache = DependencyManager::get<GeometryCache>();
Q_ASSERT(args->_batch);
auto& batch = *args->_batch;
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, isTransparent(), false, !getIsSolid(), true);
batch.setModelTransform(getRenderTransform());
// for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
// we just draw a line...
if (getIsSolid()) {
if (!_quadVerticesID) {
_quadVerticesID = geometryCache->allocateID();
}
if (geometryChanged) {
QVector<glm::vec2> points;
QVector<glm::vec4> colors;
float pulseLevel = updatePulse();
vec4 pulseModifier = vec4(1);
if (_alphaPulse != 0.0f) {
pulseModifier.a = (_alphaPulse >= 0.0f) ? pulseLevel : (1.0f - pulseLevel);
}
if (_colorPulse != 0.0f) {
float pulseValue = (_colorPulse >= 0.0f) ? pulseLevel : (1.0f - pulseLevel);
pulseModifier = vec4(vec3(pulseValue), pulseModifier.a);
}
vec4 innerStartColor = vec4(toGlm(_innerStartColor), _innerStartAlpha) * pulseModifier;
vec4 outerStartColor = vec4(toGlm(_outerStartColor), _outerStartAlpha) * pulseModifier;
vec4 innerEndColor = vec4(toGlm(_innerEndColor), _innerEndAlpha) * pulseModifier;
vec4 outerEndColor = vec4(toGlm(_outerEndColor), _outerEndAlpha) * pulseModifier;
const auto startAtRadians = glm::radians(_startAt);
const auto endAtRadians = glm::radians(_endAt);
const auto totalRange = _endAt - _startAt;
if (_innerRadius <= 0) {
_solidPrimitive = gpu::TRIANGLE_FAN;
points << vec2();
colors << innerStartColor;
for (float angleRadians = startAtRadians; angleRadians < endAtRadians; angleRadians += SLICE_ANGLE_RADIANS) {
float range = (angleRadians - startAtRadians) / totalRange;
points << glm::vec2(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
colors << glm::mix(outerStartColor, outerEndColor, range);
}
points << glm::vec2(cosf(endAtRadians) * _outerRadius, sinf(endAtRadians) * _outerRadius);
colors << outerEndColor;
} else {
_solidPrimitive = gpu::TRIANGLE_STRIP;
for (float angleRadians = startAtRadians; angleRadians < endAtRadians; angleRadians += SLICE_ANGLE_RADIANS) {
float range = (angleRadians - startAtRadians) / totalRange;
points << glm::vec2(cosf(angleRadians) * _innerRadius, sinf(angleRadians) * _innerRadius);
colors << glm::mix(innerStartColor, innerEndColor, range);
points << glm::vec2(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
colors << glm::mix(outerStartColor, outerEndColor, range);
}
points << glm::vec2(cosf(endAtRadians) * _innerRadius, sinf(endAtRadians) * _innerRadius);
colors << innerEndColor;
points << glm::vec2(cosf(endAtRadians) * _outerRadius, sinf(endAtRadians) * _outerRadius);
colors << outerEndColor;
}
geometryCache->updateVertices(_quadVerticesID, points, colors);
}
geometryCache->renderVertices(batch, _solidPrimitive, _quadVerticesID);
} else {
if (!_lineVerticesID) {
_lineVerticesID = geometryCache->allocateID();
}
if (geometryChanged) {
QVector<glm::vec2> points;
const auto startAtRadians = glm::radians(_startAt);
const auto endAtRadians = glm::radians(_endAt);
float angleRadians = startAtRadians;
glm::vec2 firstPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << firstPoint;
while (angleRadians < endAtRadians) {
angleRadians += SLICE_ANGLE_RADIANS;
glm::vec2 thisPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << thisPoint;
if (getIsDashedLine()) {
angleRadians += SLICE_ANGLE_RADIANS / 2.0f; // short gap
glm::vec2 dashStartPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << dashStartPoint;
}
}
// get the last slice portion....
angleRadians = endAtRadians;
glm::vec2 lastPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << lastPoint;
geometryCache->updateVertices(_lineVerticesID, points, vec4(toGlm(getColor()), getAlpha()));
}
if (getIsDashedLine()) {
geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID);
} else {
geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
}
}
// draw our tick marks
// for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
// we just draw a line...
if (getHasTickMarks()) {
if (!_majorTicksVerticesID) {
_majorTicksVerticesID = geometryCache->allocateID();
}
if (!_minorTicksVerticesID) {
_minorTicksVerticesID = geometryCache->allocateID();
}
if (geometryChanged) {
QVector<glm::vec2> majorPoints;
QVector<glm::vec2> minorPoints;
// draw our major tick marks
if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) {
float tickMarkAngle = getMajorTickMarksAngle();
float angle = _startAt - fmodf(_startAt, tickMarkAngle) + tickMarkAngle;
float tickMarkLength = getMajorTickMarksLength();
float startRadius = (tickMarkLength > 0.0f) ? _innerRadius : _outerRadius;
float endRadius = startRadius + tickMarkLength;
while (angle <= _endAt) {
float angleInRadians = glm::radians(angle);
glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
majorPoints << thisPointA << thisPointB;
angle += tickMarkAngle;
}
}
// draw our minor tick marks
if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) {
float tickMarkAngle = getMinorTickMarksAngle();
float angle = _startAt - fmodf(_startAt, tickMarkAngle) + tickMarkAngle;
float tickMarkLength = getMinorTickMarksLength();
float startRadius = (tickMarkLength > 0.0f) ? _innerRadius : _outerRadius;
float endRadius = startRadius + tickMarkLength;
while (angle <= _endAt) {
float angleInRadians = glm::radians(angle);
glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
minorPoints << thisPointA << thisPointB;
angle += tickMarkAngle;
}
}
glm::vec4 majorColor(toGlm(getMajorTickMarksColor()), alpha);
geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor);
glm::vec4 minorColor(toGlm(getMinorTickMarksColor()), alpha);
geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor);
}
geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID);
geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID);
}
}
const render::ShapeKey Circle3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder().withoutCullFace();
if (isTransparent()) {
builder.withTranslucent();
}
if (!getIsSolid()) {
builder.withUnlit().withDepthBias();
}
return builder.build();
}
template<typename T> T fromVariant(const QVariant& v, bool& valid) {
valid = v.isValid();
return qvariant_cast<T>(v);
}
template<> glm::u8vec3 fromVariant(const QVariant& v, bool& valid) {
return u8vec3FromVariant(v, valid);
}
template<typename T>
bool updateIfValid(const QVariantMap& properties, const char* key, T& output) {
bool valid;
T result = fromVariant<T>(properties[key], valid);
if (!valid) {
return false;
}
// Don't signal updates if the value was already set
if (result == output) {
return false;
}
output = result;
return true;
}
// Multicast, many outputs
template<typename T>
bool updateIfValid(const QVariantMap& properties, const char* key, std::initializer_list<std::reference_wrapper<T>> outputs) {
bool valid;
T value = fromVariant<T>(properties[key], valid);
if (!valid) {
return false;
}
bool updated = false;
for (T& output : outputs) {
if (output != value) {
output = value;
updated = true;
}
}
return updated;
}
// Multicast, multiple possible inputs, in order of preference
template<typename T>
bool updateIfValid(const QVariantMap& properties, const std::initializer_list<const char*> keys, T& output) {
for (const char* key : keys) {
if (updateIfValid<T>(properties, key, output)) {
return true;
}
}
return false;
}
void Circle3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
_dirty |= updateIfValid<float>(properties, "alpha", { _innerStartAlpha, _innerEndAlpha, _outerStartAlpha, _outerEndAlpha });
_dirty |= updateIfValid<float>(properties, "Alpha", { _innerStartAlpha, _innerEndAlpha, _outerStartAlpha, _outerEndAlpha });
_dirty |= updateIfValid<float>(properties, "startAlpha", { _innerStartAlpha, _outerStartAlpha });
_dirty |= updateIfValid<float>(properties, "endAlpha", { _innerEndAlpha, _outerEndAlpha });
_dirty |= updateIfValid<float>(properties, "innerAlpha", { _innerStartAlpha, _innerEndAlpha });
_dirty |= updateIfValid<float>(properties, "outerAlpha", { _outerStartAlpha, _outerEndAlpha });
_dirty |= updateIfValid(properties, "innerStartAlpha", _innerStartAlpha);
_dirty |= updateIfValid(properties, "innerEndAlpha", _innerEndAlpha);
_dirty |= updateIfValid(properties, "outerStartAlpha", _outerStartAlpha);
_dirty |= updateIfValid(properties, "outerEndAlpha", _outerEndAlpha);
_dirty |= updateIfValid<glm::u8vec3>(properties, "color", { _innerStartColor, _innerEndColor, _outerStartColor, _outerEndColor });
_dirty |= updateIfValid<glm::u8vec3>(properties, "startColor", { _innerStartColor, _outerStartColor } );
_dirty |= updateIfValid<glm::u8vec3>(properties, "endColor", { _innerEndColor, _outerEndColor } );
_dirty |= updateIfValid<glm::u8vec3>(properties, "innerColor", { _innerStartColor, _innerEndColor } );
_dirty |= updateIfValid<glm::u8vec3>(properties, "outerColor", { _outerStartColor, _outerEndColor } );
_dirty |= updateIfValid(properties, "innerStartColor", _innerStartColor);
_dirty |= updateIfValid(properties, "innerEndColor", _innerEndColor);
_dirty |= updateIfValid(properties, "outerStartColor", _outerStartColor);
_dirty |= updateIfValid(properties, "outerEndColor", _outerEndColor);
_dirty |= updateIfValid(properties, "startAt", _startAt);
_dirty |= updateIfValid(properties, "endAt", _endAt);
_dirty |= updateIfValid(properties, { "radius", "outerRadius" }, _outerRadius);
_dirty |= updateIfValid(properties, "innerRadius", _innerRadius);
_dirty |= updateIfValid(properties, "hasTickMarks", _hasTickMarks);
_dirty |= updateIfValid(properties, "majorTickMarksAngle", _majorTickMarksAngle);
_dirty |= updateIfValid(properties, "minorTickMarksAngle", _minorTickMarksAngle);
_dirty |= updateIfValid(properties, "majorTickMarksLength", _majorTickMarksLength);
_dirty |= updateIfValid(properties, "minorTickMarksLength", _minorTickMarksLength);
_dirty |= updateIfValid(properties, "majorTickMarksColor", _majorTickMarksColor);
_dirty |= updateIfValid(properties, "minorTickMarksColor", _minorTickMarksColor);
if (_innerStartAlpha < 1.0f || _innerEndAlpha < 1.0f || _outerStartAlpha < 1.0f || _outerEndAlpha < 1.0f) {
// Force the alpha to 0.5, since we'll ignore it in the presence of these other values, but we need
// it to be non-1 in order to get the right pipeline and non-0 in order to render at all.
_alpha = 0.5f;
}
}
// Overlay's color and alpha properties are overridden. And the dimensions property is not used.
/**jsdoc
* These are the properties of a <code>circle3d</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.Circle3DProperties
*
* @property {string} type=circle3d - Has the value <code>"circle3d"</code>. <em>Read-only.</em>
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec2} dimensions=1,1 - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* <em>Not used.</em>
*
* @property {number} startAt=0 - The counter-clockwise angle from the overlay's x-axis that drawing starts at, in degrees.
* @property {number} endAt=360 - The counter-clockwise angle from the overlay's x-axis that drawing ends at, in degrees.
* @property {number} outerRadius=1 - The outer radius of the overlay, in meters. Synonym: <code>radius</code>.
* @property {number} innerRadius=0 - The inner radius of the overlay, in meters.
* @property {Color} color=255,255,255 - The color of the overlay. Setting this value also sets the values of
* <code>innerStartColor</code>, <code>innerEndColor</code>, <code>outerStartColor</code>, and <code>outerEndColor</code>.
* @property {Color} startColor - Sets the values of <code>innerStartColor</code> and <code>outerStartColor</code>.
* <em>Write-only.</em>
* @property {Color} endColor - Sets the values of <code>innerEndColor</code> and <code>outerEndColor</code>.
* <em>Write-only.</em>
* @property {Color} innerColor - Sets the values of <code>innerStartColor</code> and <code>innerEndColor</code>.
* <em>Write-only.</em>
* @property {Color} outerColor - Sets the values of <code>outerStartColor</code> and <code>outerEndColor</code>.
* <em>Write-only.</em>
* @property {Color} innerStartcolor - The color at the inner start point of the overlay.
* @property {Color} innerEndColor - The color at the inner end point of the overlay.
* @property {Color} outerStartColor - The color at the outer start point of the overlay.
* @property {Color} outerEndColor - The color at the outer end point of the overlay.
* @property {number} alpha=0.5 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. Setting this value also sets
* the values of <code>innerStartAlpha</code>, <code>innerEndAlpha</code>, <code>outerStartAlpha</code>, and
* <code>outerEndAlpha</code>. Synonym: <code>Alpha</code>; <em>write-only</em>.
* @property {number} startAlpha - Sets the values of <code>innerStartAlpha</code> and <code>outerStartAlpha</code>.
* <em>Write-only.</em>
* @property {number} endAlpha - Sets the values of <code>innerEndAlpha</code> and <code>outerEndAlpha</code>.
* <em>Write-only.</em>
* @property {number} innerAlpha - Sets the values of <code>innerStartAlpha</code> and <code>innerEndAlpha</code>.
* <em>Write-only.</em>
* @property {number} outerAlpha - Sets the values of <code>outerStartAlpha</code> and <code>outerEndAlpha</code>.
* <em>Write-only.</em>
* @property {number} innerStartAlpha=0 - The alpha at the inner start point of the overlay.
* @property {number} innerEndAlpha=0 - The alpha at the inner end point of the overlay.
* @property {number} outerStartAlpha=0 - The alpha at the outer start point of the overlay.
* @property {number} outerEndAlpha=0 - The alpha at the outer end point of the overlay.
* @property {boolean} hasTickMarks=false - If <code>true</code>, tick marks are drawn.
* @property {number} majorTickMarksAngle=0 - The angle between major tick marks, in degrees.
* @property {number} minorTickMarksAngle=0 - The angle between minor tick marks, in degrees.
* @property {number} majorTickMarksLength=0 - The length of the major tick marks, in meters. A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {number} minorTickMarksLength=0 - The length of the minor tick marks, in meters. A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {Color} majorTickMarksColor=0,0,0 - The color of the major tick marks.
* @property {Color} minorTickMarksColor=0,0,0 - The color of the minor tick marks.
*/
QVariant Circle3DOverlay::getProperty(const QString& property) {
if (property == "startAt") {
return _startAt;
}
if (property == "endAt") {
return _endAt;
}
if (property == "radius") {
return _outerRadius;
}
if (property == "outerRadius") {
return _outerRadius;
}
if (property == "innerRadius") {
return _innerRadius;
}
if (property == "innerStartColor") {
return u8vec3ColortoVariant(_innerStartColor);
}
if (property == "innerEndColor") {
return u8vec3ColortoVariant(_innerEndColor);
}
if (property == "outerStartColor") {
return u8vec3ColortoVariant(_outerStartColor);
}
if (property == "outerEndColor") {
return u8vec3ColortoVariant(_outerEndColor);
}
if (property == "innerStartAlpha") {
return _innerStartAlpha;
}
if (property == "innerEndAlpha") {
return _innerEndAlpha;
}
if (property == "outerStartAlpha") {
return _outerStartAlpha;
}
if (property == "outerEndAlpha") {
return _outerEndAlpha;
}
if (property == "hasTickMarks") {
return _hasTickMarks;
}
if (property == "majorTickMarksAngle") {
return _majorTickMarksAngle;
}
if (property == "minorTickMarksAngle") {
return _minorTickMarksAngle;
}
if (property == "majorTickMarksLength") {
return _majorTickMarksLength;
}
if (property == "minorTickMarksLength") {
return _minorTickMarksLength;
}
if (property == "majorTickMarksColor") {
return u8vec3ColortoVariant(_majorTickMarksColor);
}
if (property == "minorTickMarksColor") {
return u8vec3ColortoVariant(_minorTickMarksColor);
}
return Planar3DOverlay::getProperty(property);
}
bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
// Scale the dimensions by the diameter
glm::vec2 dimensions = getOuterRadius() * 2.0f * getDimensions();
glm::quat rotation = getWorldOrientation();
if (findRayRectangleIntersection(origin, direction, rotation, getWorldPosition(), dimensions, distance)) {
glm::vec3 hitPosition = origin + (distance * direction);
glm::vec3 localHitPosition = glm::inverse(getWorldOrientation()) * (hitPosition - getWorldPosition());
localHitPosition.x /= getDimensions().x;
localHitPosition.y /= getDimensions().y;
float distanceToHit = glm::length(localHitPosition);
if (getInnerRadius() <= distanceToHit && distanceToHit <= getOuterRadius()) {
glm::vec3 forward = rotation * Vectors::FRONT;
if (glm::dot(forward, direction) > 0.0f) {
face = MAX_Z_FACE;
surfaceNormal = -forward;
} else {
face = MIN_Z_FACE;
surfaceNormal = forward;
}
return true;
}
}
return false;
}
bool Circle3DOverlay::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
// Scale the dimensions by the diameter
glm::vec2 xyDimensions = getOuterRadius() * 2.0f * getDimensions();
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition();
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);
glm::vec3 localVelocity = inverseRot * velocity;
glm::vec3 localAcceleration = inverseRot * acceleration;
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
glm::vec3 localHitPosition = localOrigin + localVelocity * parabolicDistance + 0.5f * localAcceleration * parabolicDistance * parabolicDistance;
localHitPosition.x /= getDimensions().x;
localHitPosition.y /= getDimensions().y;
float distanceToHit = glm::length(localHitPosition);
if (getInnerRadius() <= distanceToHit && distanceToHit <= getOuterRadius()) {
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
glm::vec3 forward = rotation * Vectors::FRONT;
if (localIntersectionVelocityZ > 0.0f) {
face = MIN_Z_FACE;
surfaceNormal = forward;
} else {
face = MAX_Z_FACE;
surfaceNormal = -forward;
}
return true;
}
}
return false;
}
Circle3DOverlay* Circle3DOverlay::createClone() const {
return new Circle3DOverlay(this);
}

View file

@ -1,96 +0,0 @@
//
// Circle3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Circle3DOverlay_h
#define hifi_Circle3DOverlay_h
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "Planar3DOverlay.h"
class Circle3DOverlay : public Planar3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Circle3DOverlay();
Circle3DOverlay(const Circle3DOverlay* circle3DOverlay);
~Circle3DOverlay();
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
float getStartAt() const { return _startAt; }
float getEndAt() const { return _endAt; }
float getOuterRadius() const { return _outerRadius; }
float getInnerRadius() const { return _innerRadius; }
bool getHasTickMarks() const { return _hasTickMarks; }
float getMajorTickMarksAngle() const { return _majorTickMarksAngle; }
float getMinorTickMarksAngle() const { return _minorTickMarksAngle; }
float getMajorTickMarksLength() const { return _majorTickMarksLength; }
float getMinorTickMarksLength() const { return _minorTickMarksLength; }
glm::u8vec3 getMajorTickMarksColor() const { return _majorTickMarksColor; }
glm::u8vec3 getMinorTickMarksColor() const { return _minorTickMarksColor; }
void setStartAt(float value) { _startAt = value; }
void setEndAt(float value) { _endAt = value; }
void setOuterRadius(float value) { _outerRadius = value; }
void setInnerRadius(float value) { _innerRadius = value; }
void setHasTickMarks(bool value) { _hasTickMarks = value; }
void setMajorTickMarksAngle(float value) { _majorTickMarksAngle = value; }
void setMinorTickMarksAngle(float value) { _minorTickMarksAngle = value; }
void setMajorTickMarksLength(float value) { _majorTickMarksLength = value; }
void setMinorTickMarksLength(float value) { _minorTickMarksLength = value; }
void setMajorTickMarksColor(const glm::u8vec3& value) { _majorTickMarksColor = value; }
void setMinorTickMarksColor(const glm::u8vec3& value) { _minorTickMarksColor = value; }
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual Circle3DOverlay* createClone() const override;
protected:
float _startAt { 0 };
float _endAt { 360 };
float _outerRadius { 1 };
float _innerRadius { 0 };
glm::u8vec3 _innerStartColor { DEFAULT_OVERLAY_COLOR };
glm::u8vec3 _innerEndColor { DEFAULT_OVERLAY_COLOR };
glm::u8vec3 _outerStartColor { DEFAULT_OVERLAY_COLOR };
glm::u8vec3 _outerEndColor { DEFAULT_OVERLAY_COLOR };
float _innerStartAlpha { DEFAULT_ALPHA };
float _innerEndAlpha { DEFAULT_ALPHA };
float _outerStartAlpha { DEFAULT_ALPHA };
float _outerEndAlpha { DEFAULT_ALPHA };
bool _hasTickMarks { false };
float _majorTickMarksAngle { 0 };
float _minorTickMarksAngle { 0 };
float _majorTickMarksLength { 0 };
float _minorTickMarksLength { 0 };
glm::u8vec3 _majorTickMarksColor { DEFAULT_OVERLAY_COLOR };
glm::u8vec3 _minorTickMarksColor { DEFAULT_OVERLAY_COLOR };
gpu::Primitive _solidPrimitive { gpu::TRIANGLE_FAN };
int _quadVerticesID { 0 };
int _lineVerticesID { 0 };
int _majorTicksVerticesID { 0 };
int _minorTicksVerticesID { 0 };
bool _dirty { true };
};
#endif // hifi_Circle3DOverlay_h

View file

@ -1,196 +0,0 @@
//
// Cube3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 this before QGLWidget, which includes an earlier version of OpenGL
#include "Cube3DOverlay.h"
#include <SharedUtil.h>
#include <StreamUtils.h>
#include <GeometryCache.h>
#include <DependencyManager.h>
QString const Cube3DOverlay::TYPE = "cube";
Cube3DOverlay::Cube3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
for (size_t i = 0; i < _geometryIds.size(); ++i) {
_geometryIds[i] = geometryCache->allocateID();
}
}
Cube3DOverlay::Cube3DOverlay(const Cube3DOverlay* cube3DOverlay) :
Volume3DOverlay(cube3DOverlay)
{
auto geometryCache = DependencyManager::get<GeometryCache>();
for (size_t i = 0; i < _geometryIds.size(); ++i) {
_geometryIds[i] = geometryCache->allocateID();
}
}
Cube3DOverlay::~Cube3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
for (size_t i = 0; i < _geometryIds.size(); ++i) {
geometryCache->releaseID(_geometryIds[i]);
}
}
}
void Cube3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 cubeColor(toGlm(color), alpha);
auto batch = args->_batch;
if (batch) {
Transform transform = getRenderTransform();
auto geometryCache = DependencyManager::get<GeometryCache>();
auto shapePipeline = args->_shapePipeline;
if (!shapePipeline) {
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
}
if (_isSolid) {
batch->setModelTransform(transform);
geometryCache->renderSolidCubeInstance(args, *batch, cubeColor, shapePipeline);
} else {
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
if (getIsDashedLine()) {
auto dimensions = transform.getScale();
transform.setScale(1.0f);
batch->setModelTransform(transform);
glm::vec3 halfDimensions = dimensions / 2.0f;
glm::vec3 bottomLeftNear(-halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
glm::vec3 bottomRightNear(halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
glm::vec3 topLeftNear(-halfDimensions.x, halfDimensions.y, -halfDimensions.z);
glm::vec3 topRightNear(halfDimensions.x, halfDimensions.y, -halfDimensions.z);
glm::vec3 bottomLeftFar(-halfDimensions.x, -halfDimensions.y, halfDimensions.z);
glm::vec3 bottomRightFar(halfDimensions.x, -halfDimensions.y, halfDimensions.z);
glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z);
glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z);
geometryCache->renderDashedLine(*batch, bottomLeftNear, bottomRightNear, cubeColor, _geometryIds[0]);
geometryCache->renderDashedLine(*batch, bottomRightNear, bottomRightFar, cubeColor, _geometryIds[1]);
geometryCache->renderDashedLine(*batch, bottomRightFar, bottomLeftFar, cubeColor, _geometryIds[2]);
geometryCache->renderDashedLine(*batch, bottomLeftFar, bottomLeftNear, cubeColor, _geometryIds[3]);
geometryCache->renderDashedLine(*batch, topLeftNear, topRightNear, cubeColor, _geometryIds[4]);
geometryCache->renderDashedLine(*batch, topRightNear, topRightFar, cubeColor, _geometryIds[5]);
geometryCache->renderDashedLine(*batch, topRightFar, topLeftFar, cubeColor, _geometryIds[6]);
geometryCache->renderDashedLine(*batch, topLeftFar, topLeftNear, cubeColor, _geometryIds[7]);
geometryCache->renderDashedLine(*batch, bottomLeftNear, topLeftNear, cubeColor, _geometryIds[8]);
geometryCache->renderDashedLine(*batch, bottomRightNear, topRightNear, cubeColor, _geometryIds[9]);
geometryCache->renderDashedLine(*batch, bottomLeftFar, topLeftFar, cubeColor, _geometryIds[10]);
geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor, _geometryIds[11]);
} else {
batch->setModelTransform(transform);
geometryCache->renderWireCubeInstance(args, *batch, cubeColor, shapePipeline);
}
}
}
}
const render::ShapeKey Cube3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
if (isTransparent()) {
builder.withTranslucent();
}
if (!getIsSolid()) {
builder.withUnlit().withDepthBias();
}
return builder.build();
}
Cube3DOverlay* Cube3DOverlay::createClone() const {
return new Cube3DOverlay(this);
}
void Cube3DOverlay::setProperties(const QVariantMap& properties) {
Volume3DOverlay::setProperties(properties);
}
/**jsdoc
* These are the properties of a <code>cube</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.CubeProperties
*
* @property {string} type=cube - Has the value <code>"cube"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*/
QVariant Cube3DOverlay::getProperty(const QString& property) {
return Volume3DOverlay::getProperty(property);
}
Transform Cube3DOverlay::evalRenderTransform() {
// TODO: handle registration point??
glm::vec3 position = getWorldPosition();
glm::vec3 dimensions = getDimensions();
glm::quat rotation = getWorldOrientation();
Transform transform;
transform.setScale(dimensions);
transform.setTranslation(position);
transform.setRotation(rotation);
return transform;
}
scriptable::ScriptableModelBase Cube3DOverlay::getScriptableModel() {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto vertexColor = ColorUtils::toVec3(_color);
scriptable::ScriptableModelBase result;
if (auto mesh = geometryCache->meshFromShape(GeometryCache::Cube, vertexColor)) {
result.objectID = Overlay::getID();
result.append(mesh);
}
return result;
}

View file

@ -1,45 +0,0 @@
//
// Cube3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Cube3DOverlay_h
#define hifi_Cube3DOverlay_h
#include "Volume3DOverlay.h"
class Cube3DOverlay : public Volume3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Cube3DOverlay();
Cube3DOverlay(const Cube3DOverlay* cube3DOverlay);
~Cube3DOverlay();
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
virtual Cube3DOverlay* createClone() const override;
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual scriptable::ScriptableModelBase getScriptableModel() override;
protected:
Transform evalRenderTransform() override;
private:
// edges on a cube
std::array<int, 12> _geometryIds;
};
#endif // hifi_Cube3DOverlay_h

View file

@ -1,200 +0,0 @@
//
// Grid3DOverlay.cpp
// interface/src/ui/overlays
//
// Created by Ryan Huffman on 11/06/14.
// Copyright 2014 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 "Grid3DOverlay.h"
#include <OctreeConstants.h>
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <PathUtils.h>
#include <ViewFrustum.h>
QString const Grid3DOverlay::TYPE = "grid";
const float DEFAULT_SCALE = 100.0f;
Grid3DOverlay::Grid3DOverlay() {
setDimensions(DEFAULT_SCALE);
updateGrid();
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) :
Planar3DOverlay(grid3DOverlay),
_majorGridEvery(grid3DOverlay->_majorGridEvery),
_minorGridEvery(grid3DOverlay->_minorGridEvery)
{
updateGrid();
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Grid3DOverlay::~Grid3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
AABox Grid3DOverlay::getBounds() const {
if (_followCamera) {
// This is a UI element that should always be in view, lie to the octree to avoid culling
const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
return DOMAIN_BOX;
}
return Planar3DOverlay::getBounds();
}
void Grid3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 gridColor(toGlm(color), alpha);
auto batch = args->_batch;
if (batch) {
auto minCorner = glm::vec2(-0.5f, -0.5f);
auto maxCorner = glm::vec2(0.5f, 0.5f);
auto position = getWorldPosition();
if (_followCamera) {
// Get the camera position rounded to the nearest major grid line
// This grid is for UI and should lie on worldlines
auto cameraPosition =
(float)_majorGridEvery * glm::round(args->getViewFrustum().getPosition() / (float)_majorGridEvery);
position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
}
Transform transform = getRenderTransform();
transform.setTranslation(position);
batch->setModelTransform(transform);
const float MINOR_GRID_EDGE = 0.0025f;
const float MAJOR_GRID_EDGE = 0.005f;
DependencyManager::get<GeometryCache>()->renderGrid(*batch, minCorner, maxCorner,
_minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE,
_majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE,
gridColor, _geometryId);
}
}
const render::ShapeKey Grid3DOverlay::getShapeKey() {
return render::ShapeKey::Builder().withOwnPipeline().withUnlit().withDepthBias();
}
void Grid3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
if (properties["followCamera"].isValid()) {
_followCamera = properties["followCamera"].toBool();
}
if (properties["majorGridEvery"].isValid()) {
_majorGridEvery = properties["majorGridEvery"].toInt();
}
if (properties["minorGridEvery"].isValid()) {
_minorGridEvery = properties["minorGridEvery"].toFloat();
}
updateGrid();
}
/**jsdoc
* These are the properties of a <code>grid</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.GridProperties
*
* @property {string} type=grid - Has the value <code>"grid"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec2} dimensions=1,1 - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*
* @property {boolean} followCamera=true - If <code>true</code>, the grid is always visible even as the camera moves to another
* position.
* @property {number} majorGridEvery=5 - Integer number of <code>minorGridEvery</code> intervals at which to draw a thick grid
* line. Minimum value = <code>1</code>.
* @property {number} minorGridEvery=1 - Real number of meters at which to draw thin grid lines. Minimum value =
* <code>0.001</code>.
*/
QVariant Grid3DOverlay::getProperty(const QString& property) {
if (property == "followCamera") {
return _followCamera;
}
if (property == "majorGridEvery") {
return _majorGridEvery;
}
if (property == "minorGridEvery") {
return _minorGridEvery;
}
return Planar3DOverlay::getProperty(property);
}
Grid3DOverlay* Grid3DOverlay::createClone() const {
return new Grid3DOverlay(this);
}
void Grid3DOverlay::updateGrid() {
const int MAJOR_GRID_EVERY_MIN = 1;
const float MINOR_GRID_EVERY_MIN = 0.01f;
_majorGridEvery = std::max(_majorGridEvery, MAJOR_GRID_EVERY_MIN);
_minorGridEvery = std::max(_minorGridEvery, MINOR_GRID_EVERY_MIN);
_majorGridRowDivisions = getDimensions().x / _majorGridEvery;
_majorGridColDivisions = getDimensions().y / _majorGridEvery;
_minorGridRowDivisions = getDimensions().x / _minorGridEvery;
_minorGridColDivisions = getDimensions().y / _minorGridEvery;
}
Transform Grid3DOverlay::evalRenderTransform() {
Transform transform;
transform.setRotation(getWorldOrientation());
transform.setScale(glm::vec3(getDimensions(), 1.0f));
return transform;
}

View file

@ -1,61 +0,0 @@
//
// Grid3DOverlay.h
// interface/src/ui/overlays
//
// Created by Ryan Huffman on 11/06/14.
// Copyright 2014 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_Grid3DOverlay_h
#define hifi_Grid3DOverlay_h
#include "Planar3DOverlay.h"
class Grid3DOverlay : public Planar3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Grid3DOverlay();
Grid3DOverlay(const Grid3DOverlay* grid3DOverlay);
~Grid3DOverlay();
virtual AABox getBounds() const override;
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual Grid3DOverlay* createClone() const override;
// Grids are UI tools, and may not be intersected (pickable)
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face,
glm::vec3& surfaceNormal, bool precisionPicking = false) override { return false; }
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override { return false; }
protected:
Transform evalRenderTransform() override;
private:
void updateGrid();
bool _followCamera { true };
int _majorGridEvery { 5 };
float _majorGridRowDivisions;
float _majorGridColDivisions;
float _minorGridEvery { 1.0f };
float _minorGridRowDivisions;
float _minorGridColDivisions;
int _geometryId { 0 };
};
#endif // hifi_Grid3DOverlay_h

View file

@ -1,341 +0,0 @@
//
// Image3DOverlay.cpp
//
//
// Created by Clement on 7/1/14.
// Modified and renamed by Zander Otavka on 8/4/15
// Copyright 2014 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 "Image3DOverlay.h"
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <gpu/Batch.h>
#include <RegisteredMetaTypes.h>
#include "GeometryUtil.h"
#include "AbstractViewStateInterface.h"
QString const Image3DOverlay::TYPE = "image3d";
Image3DOverlay::Image3DOverlay() {
_isLoaded = false;
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) :
Billboard3DOverlay(image3DOverlay),
_url(image3DOverlay->_url),
_texture(image3DOverlay->_texture),
_emissive(image3DOverlay->_emissive),
_fromImage(image3DOverlay->_fromImage)
{
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Image3DOverlay::~Image3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
void Image3DOverlay::update(float deltatime) {
if (!_isLoaded) {
_isLoaded = true;
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
_textureIsLoaded = false;
}
Parent::update(deltatime);
}
void Image3DOverlay::render(RenderArgs* args) {
if (!_renderVisible || !getParentVisible() || !_texture || !_texture->isLoaded()) {
return;
}
// Once the texture has loaded, check if we need to update the render item because of transparency
if (!_textureIsLoaded && _texture && _texture->getGPUTexture()) {
_textureIsLoaded = true;
bool prevAlphaTexture = _alphaTexture;
_alphaTexture = _texture->getGPUTexture()->getUsage().isAlpha();
if (_alphaTexture != prevAlphaTexture) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
}
}
Q_ASSERT(args->_batch);
gpu::Batch* batch = args->_batch;
float imageWidth = _texture->getWidth();
float imageHeight = _texture->getHeight();
QRect fromImage;
if (_fromImage.width() <= 0) {
fromImage.setX(0);
fromImage.setWidth(imageWidth);
} else {
float scaleX = imageWidth / _texture->getOriginalWidth();
fromImage.setX(scaleX * _fromImage.x());
fromImage.setWidth(scaleX * _fromImage.width());
}
if (_fromImage.height() <= 0) {
fromImage.setY(0);
fromImage.setHeight(imageHeight);
} else {
float scaleY = imageHeight / _texture->getOriginalHeight();
fromImage.setY(scaleY * _fromImage.y());
fromImage.setHeight(scaleY * _fromImage.height());
}
float maxSize = glm::max(fromImage.width(), fromImage.height());
float x = _keepAspectRatio ? fromImage.width() / (2.0f * maxSize) : 0.5f;
float y = _keepAspectRatio ? -fromImage.height() / (2.0f * maxSize) : -0.5f;
glm::vec2 topLeft(-x, -y);
glm::vec2 bottomRight(x, y);
glm::vec2 texCoordTopLeft((fromImage.x() + 0.5f) / imageWidth, (fromImage.y() + 0.5f) / imageHeight);
glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth,
(fromImage.y() + fromImage.height() - 0.5f) / imageHeight);
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 imageColor(toGlm(color), alpha);
batch->setModelTransform(getRenderTransform());
batch->setResourceTexture(0, _texture->getGPUTexture());
DependencyManager::get<GeometryCache>()->renderQuad(
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
imageColor, _geometryId
);
batch->setResourceTexture(0, nullptr); // restore default white color after me
}
const render::ShapeKey Image3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
if (_emissive) {
builder.withUnlit();
}
if (isTransparent()) {
builder.withTranslucent();
}
return builder.build();
}
void Image3DOverlay::setProperties(const QVariantMap& properties) {
Billboard3DOverlay::setProperties(properties);
auto urlValue = properties["url"];
if (urlValue.isValid()) {
QString newURL = urlValue.toString();
if (newURL != _url) {
setURL(newURL);
}
}
auto subImageBoundsVar = properties["subImage"];
if (subImageBoundsVar.isValid()) {
if (subImageBoundsVar.isNull()) {
_fromImage = QRect();
} else {
QRect oldSubImageRect = _fromImage;
QRect subImageRect = _fromImage;
auto subImageBounds = subImageBoundsVar.toMap();
if (subImageBounds["x"].isValid()) {
subImageRect.setX(subImageBounds["x"].toInt());
} else {
subImageRect.setX(oldSubImageRect.x());
}
if (subImageBounds["y"].isValid()) {
subImageRect.setY(subImageBounds["y"].toInt());
} else {
subImageRect.setY(oldSubImageRect.y());
}
if (subImageBounds["width"].isValid()) {
subImageRect.setWidth(subImageBounds["width"].toInt());
} else {
subImageRect.setWidth(oldSubImageRect.width());
}
if (subImageBounds["height"].isValid()) {
subImageRect.setHeight(subImageBounds["height"].toInt());
} else {
subImageRect.setHeight(oldSubImageRect.height());
}
setClipFromSource(subImageRect);
}
}
auto keepAspectRatioValue = properties["keepAspectRatio"];
if (keepAspectRatioValue.isValid()) {
_keepAspectRatio = keepAspectRatioValue.toBool();
}
auto emissiveValue = properties["emissive"];
if (emissiveValue.isValid()) {
_emissive = emissiveValue.toBool();
}
}
/**jsdoc
* These are the properties of an <code>image3d</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.Image3DProperties
*
* @property {string} type=image3d - Has the value <code>"image3d"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec2} dimensions=1,1 - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*
* @property {bool} keepAspectRatio=true - overlays will maintain the aspect ratio when the subImage is applied.
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
*
* @property {string} url - The URL of the PNG or JPG image to display.
* @property {Rect} subImage - The portion of the image to display. Defaults to the full image.
* @property {boolean} emissive - If <code>true</code>, the overlay is displayed at full brightness, otherwise it is rendered
* with scene lighting.
*/
QVariant Image3DOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url;
}
if (property == "subImage") {
return _fromImage;
}
if (property == "emissive") {
return _emissive;
}
if (property == "keepAspectRatio") {
return _keepAspectRatio;
}
return Billboard3DOverlay::getProperty(property);
}
void Image3DOverlay::setURL(const QString& url) {
_url = url;
_isLoaded = false;
}
bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
if (_texture && _texture->isLoaded()) {
Transform transform = getTransform();
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
bool isNull = _fromImage.isNull();
float width = isNull ? _texture->getWidth() : _fromImage.width();
float height = isNull ? _texture->getHeight() : _fromImage.height();
float maxSize = glm::max(width, height);
glm::vec2 dimensions = _dimensions * glm::vec2(width / maxSize, height / maxSize);
glm::quat rotation = transform.getRotation();
if (findRayRectangleIntersection(origin, direction, rotation, transform.getTranslation(), dimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT;
if (glm::dot(forward, direction) > 0.0f) {
face = MAX_Z_FACE;
surfaceNormal = -forward;
} else {
face = MIN_Z_FACE;
surfaceNormal = forward;
}
return true;
}
}
return false;
}
bool Image3DOverlay::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
if (_texture && _texture->isLoaded()) {
Transform transform = getTransform();
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
bool isNull = _fromImage.isNull();
float width = isNull ? _texture->getWidth() : _fromImage.width();
float height = isNull ? _texture->getHeight() : _fromImage.height();
float maxSize = glm::max(width, height);
glm::vec2 dimensions = _dimensions * glm::vec2(width / maxSize, height / maxSize);
glm::quat rotation = transform.getRotation();
glm::vec3 position = getWorldPosition();
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);
glm::vec3 localVelocity = inverseRot * velocity;
glm::vec3 localAcceleration = inverseRot * acceleration;
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, dimensions, parabolicDistance)) {
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
glm::vec3 forward = rotation * Vectors::FRONT;
if (localIntersectionVelocityZ > 0.0f) {
face = MIN_Z_FACE;
surfaceNormal = forward;
} else {
face = MAX_Z_FACE;
surfaceNormal = -forward;
}
return true;
}
}
return false;
}
Image3DOverlay* Image3DOverlay::createClone() const {
return new Image3DOverlay(this);
}
Transform Image3DOverlay::evalRenderTransform() {
auto transform = Parent::evalRenderTransform();
transform.postScale(glm::vec3(getDimensions(), 1.0f));
return transform;
}

View file

@ -1,67 +0,0 @@
//
// Image3DOverlay.h
//
//
// Created by Clement on 7/1/14.
// Modified and renamed by Zander Otavka on 8/4/15
// Copyright 2014 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_Image3DOverlay_h
#define hifi_Image3DOverlay_h
#include <TextureCache.h>
#include "Billboard3DOverlay.h"
class Image3DOverlay : public Billboard3DOverlay {
Q_OBJECT
using Parent = Billboard3DOverlay;
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Image3DOverlay();
Image3DOverlay(const Image3DOverlay* image3DOverlay);
~Image3DOverlay();
virtual void render(RenderArgs* args) override;
virtual void update(float deltatime) override;
virtual const render::ShapeKey getShapeKey() override;
// setters
void setURL(const QString& url);
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; }
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
bool isTransparent() override { return Base3DOverlay::isTransparent() || _alphaTexture; }
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual Image3DOverlay* createClone() const override;
protected:
Transform evalRenderTransform() override;
private:
QString _url;
NetworkTexturePointer _texture;
bool _textureIsLoaded { false };
bool _alphaTexture { false };
bool _emissive { false };
bool _keepAspectRatio { true };
QRect _fromImage; // where from in the image to sample
int _geometryId { 0 };
};
#endif // hifi_Image3DOverlay_h

View file

@ -19,29 +19,6 @@
QString const ImageOverlay::TYPE = "image";
QUrl const ImageOverlay::URL(QString("hifi/overlays/ImageOverlay.qml"));
// ImageOverlay's properties are defined in the QML file specified above.
/**jsdoc
* These are the properties of an <code>image</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.ImageProperties
*
* @property {Rect} bounds - The position and size of the image display area, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value of the image display area = <code>bounds.x</code>.
* <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value of the image display area = <code>bounds.y</code>.
* <em>Write-only.</em>
* @property {number} width - Integer width of the image display area = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the image display area = <code>bounds.height</code>. <em>Write-only.</em>
* @property {string} imageURL - The URL of the image file to display. The image is scaled to fit to the <code>bounds</code>.
* <em>Write-only.</em>
* @property {Vec2} subImage=0,0 - Integer coordinates of the top left pixel to start using image content from.
* <em>Write-only.</em>
* @property {Color} color=0,0,0 - The color to apply over the top of the image to colorize it. <em>Write-only.</em>
* @property {number} alpha=0.0 - The opacity of the color applied over the top of the image, <code>0.0</code> -
* <code>1.0</code>. <em>Write-only.</em>
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
* <em>Write-only.</em>
*/
ImageOverlay::ImageOverlay()
: QmlOverlay(URL) { }
@ -50,5 +27,4 @@ ImageOverlay::ImageOverlay(const ImageOverlay* imageOverlay) :
ImageOverlay* ImageOverlay::createClone() const {
return new ImageOverlay(this);
}
}

View file

@ -1,366 +0,0 @@
//
// Line3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Line3DOverlay.h"
#include <GeometryCache.h>
#include <RegisteredMetaTypes.h>
#include "AbstractViewStateInterface.h"
QString const Line3DOverlay::TYPE = "line3d";
Line3DOverlay::Line3DOverlay() :
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
{
}
Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
Base3DOverlay(line3DOverlay),
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
{
setParentID(line3DOverlay->getParentID());
setParentJointIndex(line3DOverlay->getParentJointIndex());
setLocalTransform(line3DOverlay->getLocalTransform());
_direction = line3DOverlay->getDirection();
_length = line3DOverlay->getLength();
_endParentID = line3DOverlay->getEndParentID();
_endParentJointIndex = line3DOverlay->getEndJointIndex();
_lineWidth = line3DOverlay->getLineWidth();
_glow = line3DOverlay->getGlow();
}
Line3DOverlay::~Line3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (_geometryCacheID && geometryCache) {
geometryCache->releaseID(_geometryCacheID);
}
}
glm::vec3 Line3DOverlay::getStart() const {
return getWorldPosition();
}
glm::vec3 Line3DOverlay::getEnd() const {
bool success;
glm::vec3 localEnd;
glm::vec3 worldEnd;
if (_endParentID != QUuid()) {
glm::vec3 localOffset = _direction * _length;
bool success;
worldEnd = localToWorld(localOffset, _endParentID, _endParentJointIndex, getScalesWithParent(), success);
return worldEnd;
}
localEnd = getLocalEnd();
worldEnd = localToWorld(localEnd, getParentID(), getParentJointIndex(), getScalesWithParent(), success);
if (!success) {
qDebug() << "Line3DOverlay::getEnd failed, parentID = " << getParentID();
}
return worldEnd;
}
void Line3DOverlay::setStart(const glm::vec3& start) {
setWorldPosition(start);
}
void Line3DOverlay::setEnd(const glm::vec3& end) {
bool success;
glm::vec3 localStart;
glm::vec3 localEnd;
glm::vec3 offset;
if (_endParentID != QUuid()) {
offset = worldToLocal(end, _endParentID, _endParentJointIndex, getScalesWithParent(), success);
} else {
localStart = getLocalStart();
localEnd = worldToLocal(end, getParentID(), getParentJointIndex(), getScalesWithParent(), success);
offset = localEnd - localStart;
}
if (!success) {
qDebug() << "Line3DOverlay::setEnd failed";
return;
}
_length = glm::length(offset);
if (_length > 0.0f) {
_direction = glm::normalize(offset);
} else {
_direction = glm::vec3(0.0f);
}
notifyRenderVariableChange();
}
void Line3DOverlay::setLocalEnd(const glm::vec3& localEnd) {
glm::vec3 offset;
if (_endParentID != QUuid()) {
offset = localEnd;
} else {
glm::vec3 localStart = getLocalStart();
offset = localEnd - localStart;
}
_length = glm::length(offset);
if (_length > 0.0f) {
_direction = glm::normalize(offset);
} else {
_direction = glm::vec3(0.0f);
}
}
AABox Line3DOverlay::getBounds() const {
auto extents = Extents{};
extents.addPoint(getStart());
extents.addPoint(getEnd());
return AABox(extents);
}
void Line3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 colorv4(toGlm(color), alpha);
auto batch = args->_batch;
if (batch) {
batch->setModelTransform(Transform());
auto& renderTransform = getRenderTransform();
glm::vec3 start = renderTransform.getTranslation();
glm::vec3 end = renderTransform.transform(vec3(0.0, 0.0, -1.0));
auto geometryCache = DependencyManager::get<GeometryCache>();
if (getIsDashedLine()) {
// TODO: add support for color to renderDashedLine()
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
geometryCache->renderDashedLine(*batch, start, end, colorv4, _geometryCacheID);
} else {
// renderGlowLine handles both glow = 0 and glow > 0 cases
geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _lineWidth, _geometryCacheID);
}
}
}
const render::ShapeKey Line3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder().withOwnPipeline();
if (isTransparent()) {
builder.withTranslucent();
}
return builder.build();
}
void Line3DOverlay::setProperties(const QVariantMap& originalProperties) {
QVariantMap properties = originalProperties;
glm::vec3 newStart(0.0f);
bool newStartSet { false };
glm::vec3 newEnd(0.0f);
bool newEndSet { false };
auto start = properties["start"];
// If "start" property was not there, check to see if they included aliases: startPoint, p1
if (!start.isValid()) {
start = properties["startPoint"];
}
if (!start.isValid()) {
start = properties["p1"];
}
if (start.isValid()) {
newStart = vec3FromVariant(start);
newStartSet = true;
}
properties.remove("start"); // so that Base3DOverlay doesn't respond to it
properties.remove("startPoint");
properties.remove("p1");
auto end = properties["end"];
// If "end" property was not there, check to see if they included aliases: endPoint, p2
if (!end.isValid()) {
end = properties["endPoint"];
}
if (!end.isValid()) {
end = properties["p2"];
}
if (end.isValid()) {
newEnd = vec3FromVariant(end);
newEndSet = true;
}
properties.remove("end"); // so that Base3DOverlay doesn't respond to it
properties.remove("endPoint");
properties.remove("p2");
auto length = properties["length"];
if (length.isValid()) {
_length = length.toFloat();
}
Base3DOverlay::setProperties(properties);
auto endParentIDProp = properties["endParentID"];
if (endParentIDProp.isValid()) {
_endParentID = QUuid(endParentIDProp.toString());
}
auto endParentJointIndexProp = properties["endParentJointIndex"];
if (endParentJointIndexProp.isValid()) {
_endParentJointIndex = endParentJointIndexProp.toInt();
}
auto localStart = properties["localStart"];
if (localStart.isValid()) {
glm::vec3 tmpLocalEnd = getLocalEnd();
setLocalStart(vec3FromVariant(localStart));
setLocalEnd(tmpLocalEnd);
}
auto localEnd = properties["localEnd"];
if (localEnd.isValid()) {
setLocalEnd(vec3FromVariant(localEnd));
}
// these are saved until after Base3DOverlay::setProperties so parenting infomation can be set, first
if (newStartSet) {
setStart(newStart);
}
if (newEndSet) {
setEnd(newEnd);
}
auto glow = properties["glow"];
if (glow.isValid()) {
float prevGlow = _glow;
setGlow(glow.toFloat());
// Update our payload key if necessary to handle transparency
if ((prevGlow <= 0.0f && _glow > 0.0f) || (prevGlow > 0.0f && _glow <= 0.0f)) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
}
}
auto lineWidth = properties["lineWidth"];
if (lineWidth.isValid()) {
setLineWidth(lineWidth.toFloat());
}
}
/**jsdoc
* These are the properties of a <code>line3d</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.Line3DProperties
*
* @property {string} type=line3d - Has the value <code>"line3d"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Uuid} endParentID=null - The avatar, entity, or overlay that the end point of the line is parented to.
* @property {number} endParentJointIndex=65535 - Integer value specifying the skeleton joint that the end point of the line is
* attached to if <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
* @property {Vec3} start - The start point of the line. Synonyms: <code>startPoint</code>, <code>p1</code>, and
* <code>position</code>.
* @property {Vec3} end - The end point of the line. Synonyms: <code>endPoint</code> and <code>p2</code>.
* @property {Vec3} localStart - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>start</code>. Synonym: <code>localPosition</code>.
* @property {Vec3} localEnd - The local position of the overlay relative to its parent if the overlay has a
* <code>endParentID</code> set, otherwise the same value as <code>end</code>.
* @property {number} length - The length of the line, in meters. This can be set after creating a line with start and end
* points.
* @property {number} glow=0 - If <code>glow > 0</code>, the line is rendered with a glow.
* @property {number} lineWidth=0.02 - If <code>glow > 0</code>, this is the width of the glow, in meters.
*/
QVariant Line3DOverlay::getProperty(const QString& property) {
if (property == "start" || property == "startPoint" || property == "p1") {
return vec3toVariant(getStart());
}
if (property == "end" || property == "endPoint" || property == "p2") {
return vec3toVariant(getEnd());
}
if (property == "length") {
return QVariant(getLength());
}
if (property == "endParentID") {
return _endParentID;
}
if (property == "endParentJointIndex") {
return _endParentJointIndex;
}
if (property == "localStart") {
return vec3toVariant(getLocalStart());
}
if (property == "localEnd") {
return vec3toVariant(getLocalEnd());
}
if (property == "glow") {
return getGlow();
}
if (property == "lineWidth") {
return _lineWidth;
}
return Base3DOverlay::getProperty(property);
}
Line3DOverlay* Line3DOverlay::createClone() const {
return new Line3DOverlay(this);
}
Transform Line3DOverlay::evalRenderTransform() {
// Capture start and endin the renderTransform:
// start is the origin
// end is at the tip of the front axis aka -Z
Transform transform;
transform.setTranslation( getStart());
auto endPos = getEnd();
auto vec = endPos - transform.getTranslation();
const float MIN_LINE_LENGTH = 0.0001f;
auto scale = glm::max(glm::length(vec), MIN_LINE_LENGTH);
auto dir = vec / scale;
auto orientation = glm::rotation(glm::vec3(0.0f, 0.0f, -1.0f), dir);
transform.setRotation(orientation);
transform.setScale(scale);
return transform;
}

View file

@ -1,79 +0,0 @@
//
// Line3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Line3DOverlay_h
#define hifi_Line3DOverlay_h
#include "Base3DOverlay.h"
class Line3DOverlay : public Base3DOverlay {
Q_OBJECT
using Parent = Base3DOverlay;
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Line3DOverlay();
Line3DOverlay(const Line3DOverlay* line3DOverlay);
~Line3DOverlay();
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
virtual AABox getBounds() const override;
// getters
glm::vec3 getStart() const;
glm::vec3 getEnd() const;
const float& getLineWidth() const { return _lineWidth; }
const float& getGlow() const { return _glow; }
// setters
void setStart(const glm::vec3& start);
void setEnd(const glm::vec3& end);
void setLocalStart(const glm::vec3& localStart) { setLocalPosition(localStart); }
void setLocalEnd(const glm::vec3& localEnd);
void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; }
void setGlow(const float& glow) { _glow = glow; }
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
bool isTransparent() override { return Base3DOverlay::isTransparent() || _glow > 0.0f; }
virtual Line3DOverlay* createClone() const override;
glm::vec3 getDirection() const { return _direction; }
float getLength() const { return _length; }
glm::vec3 getLocalStart() const { return getLocalPosition(); }
glm::vec3 getLocalEnd() const { return getLocalStart() + _direction * _length; }
QUuid getEndParentID() const { return _endParentID; }
quint16 getEndJointIndex() const { return _endParentJointIndex; }
protected:
Transform evalRenderTransform() override;
private:
QUuid _endParentID;
quint16 _endParentJointIndex { INVALID_JOINT_INDEX };
// _direction and _length are in the parent's frame. If _endParentID is set, they are
// relative to that. Otherwise, they are relative to the local-start-position (which is the
// same as localPosition)
glm::vec3 _direction; // in parent frame
float _length { 1.0 }; // in parent frame
const float DEFAULT_LINE_WIDTH = 0.02f;
float _lineWidth { DEFAULT_LINE_WIDTH };
float _glow { 0.0 };
int _geometryCacheID;
};
#endif // hifi_Line3DOverlay_h

View file

@ -1,735 +0,0 @@
//
// ModelOverlay.cpp
//
//
// Created by Clement on 6/30/14.
// Copyright 2014 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 "ModelOverlay.h"
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include <Rig.h>
#include "Application.h"
QString const ModelOverlay::TYPE = "model";
ModelOverlay::ModelOverlay()
: _model(std::make_shared<Model>(nullptr, this)),
_modelTextures(QVariantMap())
{
_model->setLoadingPriority(_loadPriority);
_isLoaded = false;
render::ScenePointer scene = qApp->getMain3DScene();
_model->setVisibleInScene(false, scene);
}
ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) :
Volume3DOverlay(modelOverlay),
_model(std::make_shared<Model>(nullptr, this)),
_modelTextures(QVariantMap()),
_url(modelOverlay->_url),
_updateModel(false),
_scaleToFit(modelOverlay->_scaleToFit),
_loadPriority(modelOverlay->_loadPriority),
_animationURL(modelOverlay->_animationURL),
_animationFPS(modelOverlay->_animationFPS),
_animationCurrentFrame(modelOverlay->_animationCurrentFrame),
_animationRunning(modelOverlay->_animationRunning),
_animationLoop(modelOverlay->_animationLoop),
_animationFirstFrame(modelOverlay->_animationFirstFrame),
_animationLastFrame(modelOverlay->_animationLastFrame),
_animationHold(modelOverlay->_animationHold),
_animationAllowTranslation(modelOverlay->_animationAllowTranslation)
// Joint translations and rotations aren't copied because the model needs to load before they can be applied.
{
_model->setLoadingPriority(_loadPriority);
if (_url.isValid()) {
_updateModel = true;
_isLoaded = false;
}
}
void ModelOverlay::update(float deltatime) {
Base3DOverlay::update(deltatime);
if (_updateModel) {
_updateModel = false;
_model->setSnapModelToCenter(true);
Transform transform = evalRenderTransform();
if (_scaleToFit) {
_model->setScaleToFit(true, transform.getScale() * getDimensions());
} else {
_model->setScale(transform.getScale());
}
_model->setRotation(transform.getRotation());
_model->setTranslation(transform.getTranslation());
_model->setURL(_url);
_model->simulate(deltatime, true);
} else {
_model->simulate(deltatime);
}
_isLoaded = _model->isActive();
if (isAnimatingSomething()) {
if (!jointsMapped()) {
mapAnimationJoints(_model->getJointNames());
}
animate();
}
// check to see if when we added our model to the scene they were ready, if they were not ready, then
// fix them up in the scene
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
if (_model->needsFixupInScene()) {
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(Overlay::getID(), NestableType::Overlay, _model);
_model->removeFromScene(scene, transaction);
_model->addToScene(scene, transaction);
auto newRenderItemIDs{ _model->fetchRenderItemIDs() };
transaction.updateItem<Overlay>(getRenderItemID(), [newRenderItemIDs](Overlay& data) {
auto modelOverlay = static_cast<ModelOverlay*>(&data);
modelOverlay->setSubRenderItemIDs(newRenderItemIDs);
});
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(Overlay::getID(), NestableType::Overlay, _model);
}
bool metaDirty = false;
if (_visibleDirty && _texturesLoaded) {
_visibleDirty = false;
// don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true
uint8_t modelRenderTagMask = (_isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW);
_model->setTagMask(modelRenderTagMask, scene);
_model->setVisibleInScene(getVisible(), scene);
metaDirty = true;
}
if (_renderLayerDirty) {
_renderLayerDirty = false;
_model->setHifiRenderLayer(_drawHUDLayer ? render::hifi::LAYER_3D_HUD : (_drawInFront ? render::hifi::LAYER_3D_FRONT : render::hifi::LAYER_3D), scene);
metaDirty = true;
}
if (_groupCulledDirty) {
_groupCulledDirty = false;
_model->setGroupCulled(_isGroupCulled, scene);
metaDirty = true;
}
if (metaDirty) {
transaction.updateItem<Overlay>(getRenderItemID(), [](Overlay& data) {});
}
scene->enqueueTransaction(transaction);
if (_texturesDirty && !_modelTextures.isEmpty()) {
_texturesDirty = false;
_model->setTextures(_modelTextures);
}
if (!_texturesLoaded && _model->getGeometry() && _model->getGeometry()->areTexturesLoaded()) {
_texturesLoaded = true;
_model->setVisibleInScene(getVisible(), scene);
_model->updateRenderItems();
}
}
bool ModelOverlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
Volume3DOverlay::addToScene(overlay, scene, transaction);
_model->addToScene(scene, transaction);
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(Overlay::getID(), NestableType::Overlay, _model);
return true;
}
void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
Volume3DOverlay::removeFromScene(overlay, scene, transaction);
_model->removeFromScene(scene, transaction);
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(Overlay::getID(), NestableType::Overlay, _model);
transaction.updateItem<Overlay>(getRenderItemID(), [](Overlay& data) {
auto modelOverlay = static_cast<ModelOverlay*>(&data);
modelOverlay->clearSubRenderItemIDs();
});
}
void ModelOverlay::setVisible(bool visible) {
if (visible != getVisible()) {
Overlay::setVisible(visible);
_visibleDirty = true;
}
}
void ModelOverlay::setDrawInFront(bool drawInFront) {
if (drawInFront != getDrawInFront()) {
Base3DOverlay::setDrawInFront(drawInFront);
_renderLayerDirty = true;
}
}
void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) {
if (drawHUDLayer != getDrawHUDLayer()) {
Base3DOverlay::setDrawHUDLayer(drawHUDLayer);
_renderLayerDirty = true;
}
}
void ModelOverlay::setGroupCulled(bool groupCulled) {
if (groupCulled != _isGroupCulled) {
_isGroupCulled = groupCulled;
_groupCulledDirty = true;
}
}
void ModelOverlay::setProperties(const QVariantMap& properties) {
auto origPosition = getWorldPosition();
auto origRotation = getWorldOrientation();
auto origDimensions = getDimensions();
auto origScale = getSNScale();
Base3DOverlay::setProperties(properties);
auto scale = properties["scale"];
if (scale.isValid()) {
setSNScale(vec3FromVariant(scale));
}
auto dimensions = properties["dimensions"];
if (!dimensions.isValid()) {
dimensions = properties["size"];
}
if (dimensions.isValid()) {
_scaleToFit = true;
setDimensions(vec3FromVariant(dimensions));
} else if (scale.isValid()) {
// if "scale" property is set but "dimensions" is not.
// do NOT scale to fit.
_scaleToFit = false;
}
if (origPosition != getWorldPosition() || origRotation != getWorldOrientation() || origDimensions != getDimensions() || origScale != getSNScale()) {
_updateModel = true;
}
auto loadPriorityProperty = properties["loadPriority"];
if (loadPriorityProperty.isValid()) {
_loadPriority = loadPriorityProperty.toFloat();
_model->setLoadingPriority(_loadPriority);
}
auto urlValue = properties["url"];
if (urlValue.isValid() && urlValue.canConvert<QString>()) {
_url = urlValue.toString();
_updateModel = true;
_isLoaded = false;
_texturesLoaded = false;
}
auto texturesValue = properties["textures"];
if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) {
_texturesLoaded = false;
QVariantMap textureMap = texturesValue.toMap();
_modelTextures = textureMap;
_texturesDirty = true;
}
auto groupCulledValue = properties["isGroupCulled"];
if (groupCulledValue.isValid() && groupCulledValue.canConvert(QVariant::Bool)) {
setGroupCulled(groupCulledValue.toBool());
}
// jointNames is read-only.
// jointPositions is read-only.
// jointOrientations is read-only.
// relative
auto jointTranslationsValue = properties["jointTranslations"];
if (jointTranslationsValue.canConvert(QVariant::List)) {
const QVariantList& jointTranslations = jointTranslationsValue.toList();
int translationCount = jointTranslations.size();
int jointCount = _model->getJointStateCount();
if (translationCount < jointCount) {
jointCount = translationCount;
}
for (int i=0; i < jointCount; i++) {
const auto& translationValue = jointTranslations[i];
if (translationValue.isValid()) {
_model->setJointTranslation(i, true, vec3FromVariant(translationValue), 1.0f);
}
}
_updateModel = true;
}
// relative
auto jointRotationsValue = properties["jointRotations"];
if (jointRotationsValue.canConvert(QVariant::List)) {
const QVariantList& jointRotations = jointRotationsValue.toList();
int rotationCount = jointRotations.size();
int jointCount = _model->getJointStateCount();
if (rotationCount < jointCount) {
jointCount = rotationCount;
}
for (int i=0; i < jointCount; i++) {
const auto& rotationValue = jointRotations[i];
if (rotationValue.isValid()) {
_model->setJointRotation(i, true, quatFromVariant(rotationValue), 1.0f);
}
}
_updateModel = true;
}
auto animationSettings = properties["animationSettings"];
if (animationSettings.canConvert(QVariant::Map)) {
QVariantMap animationSettingsMap = animationSettings.toMap();
auto animationURL = animationSettingsMap["url"];
auto animationFPS = animationSettingsMap["fps"];
auto animationCurrentFrame = animationSettingsMap["currentFrame"];
auto animationFirstFrame = animationSettingsMap["firstFrame"];
auto animationLastFrame = animationSettingsMap["lastFrame"];
auto animationRunning = animationSettingsMap["running"];
auto animationLoop = animationSettingsMap["loop"];
auto animationHold = animationSettingsMap["hold"];
auto animationAllowTranslation = animationSettingsMap["allowTranslation"];
if (animationURL.canConvert(QVariant::Url)) {
_animationURL = animationURL.toUrl();
}
if (animationFPS.isValid()) {
_animationFPS = animationFPS.toFloat();
}
if (animationCurrentFrame.isValid()) {
_animationCurrentFrame = animationCurrentFrame.toFloat();
}
if (animationFirstFrame.isValid()) {
_animationFirstFrame = animationFirstFrame.toFloat();
}
if (animationLastFrame.isValid()) {
_animationLastFrame = animationLastFrame.toFloat();
}
if (animationRunning.canConvert(QVariant::Bool)) {
_animationRunning = animationRunning.toBool();
}
if (animationLoop.canConvert(QVariant::Bool)) {
_animationLoop = animationLoop.toBool();
}
if (animationHold.canConvert(QVariant::Bool)) {
_animationHold = animationHold.toBool();
}
if (animationAllowTranslation.canConvert(QVariant::Bool)) {
_animationAllowTranslation = animationAllowTranslation.toBool();
}
}
}
template <typename vectorType, typename itemType>
vectorType ModelOverlay::mapJoints(mapFunction<itemType> function) const {
vectorType result;
if (_model && _model->isActive()) {
const int jointCount = _model->getJointStateCount();
result.reserve(jointCount);
for (int i = 0; i < jointCount; i++) {
result << function(i);
}
}
return result;
}
// Note: ModelOverlay overrides Volume3DOverlay's "dimensions" and "scale" properties.
/**jsdoc
* These are the properties of a <code>model</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.ModelProperties
*
* @property {string} type=sphere - Has the value <code>"model"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} isGroupCulled=false - If <code>true</code>, the mesh parts of the model are LOD culled as a group.
* If <code>false</code>, separate mesh parts will be LOD culled individually.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {string} url - The URL of the FBX or OBJ model used for the overlay.
* @property {number} loadPriority=0.0 - The priority for loading and displaying the overlay. Overlays with higher values load
* first.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonym: <code>size</code>.
* @property {Vec3} scale - The scale factor applied to the model's dimensions.
* @property {object.<name, url>} textures - Maps the named textures in the model to the JPG or PNG images in the urls.
* @property {Array.<string>} jointNames - The names of the joints - if any - in the model. <em>Read-only.</em>
* @property {Array.<Quat>} jointRotations - The relative rotations of the model's joints. <em>Not copied if overlay is
* cloned.</em>
* @property {Array.<Vec3>} jointTranslations - The relative translations of the model's joints. <em>Not copied if overlay is
* cloned.</em>
* @property {Array.<Quat>} jointOrientations - The absolute orientations of the model's joints, in world coordinates.
* <em>Read-only.</em>
* @property {Array.<Vec3>} jointPositions - The absolute positions of the model's joints, in world coordinates.
* <em>Read-only.</em>
* @property {string} animationSettings.url="" - The URL of an FBX file containing an animation to play.
* @property {number} animationSettings.fps=0 - The frame rate (frames/sec) to play the animation at.
* @property {number} animationSettings.firstFrame=0 - The frame to start playing at.
* @property {number} animationSettings.lastFrame=0 - The frame to finish playing at.
* @property {number} animationSettings.currentFrame=0 - The current frame being played.
* @property {boolean} animationSettings.running=false - Whether or not the animation is playing.
* @property {boolean} animationSettings.loop=false - Whether or not the animation should repeat in a loop.
* @property {boolean} animationSettings.hold=false - Whether or not when the animation finishes, the rotations and
* translations of the last frame played should be maintained.
* @property {boolean} animationSettings.allowTranslation=false - Whether or not translations contained in the animation should
* be played.
*/
QVariant ModelOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url.toString();
}
if (property == "dimensions" || property == "size") {
return vec3toVariant(getDimensions());
}
if (property == "scale") {
return vec3toVariant(getSNScale());
}
if (property == "textures") {
if (_modelTextures.size() > 0) {
QVariantMap textures;
foreach(const QString& key, _modelTextures.keys()) {
textures[key] = _modelTextures[key].toString();
}
return textures;
} else {
return QVariant();
}
}
if (property == "loadPriority") {
return _loadPriority;
}
if (property == "jointNames") {
if (_model && _model->isActive()) {
// note: going through Rig because Model::getJointNames() (which proxies to HFMModel) was always empty
const Rig* rig = &(_model->getRig());
return mapJoints<QStringList, QString>([rig](int jointIndex) -> QString {
return rig->nameOfJoint(jointIndex);
});
}
}
// relative
if (property == "jointRotations") {
return mapJoints<QVariantList, QVariant>(
[this](int jointIndex) -> QVariant {
glm::quat rotation;
_model->getJointRotation(jointIndex, rotation);
return quatToVariant(rotation);
});
}
// relative
if (property == "jointTranslations") {
return mapJoints<QVariantList, QVariant>(
[this](int jointIndex) -> QVariant {
glm::vec3 translation;
_model->getJointTranslation(jointIndex, translation);
return vec3toVariant(translation);
});
}
// absolute
if (property == "jointOrientations") {
return mapJoints<QVariantList, QVariant>(
[this](int jointIndex) -> QVariant {
glm::quat orientation;
_model->getJointRotationInWorldFrame(jointIndex, orientation);
return quatToVariant(orientation);
});
}
// absolute
if (property == "jointPositions") {
return mapJoints<QVariantList, QVariant>(
[this](int jointIndex) -> QVariant {
glm::vec3 position;
_model->getJointPositionInWorldFrame(jointIndex, position);
return vec3toVariant(position);
});
}
// animation properties
if (property == "animationSettings") {
QVariantMap animationSettingsMap;
animationSettingsMap["url"] = _animationURL;
animationSettingsMap["fps"] = _animationFPS;
animationSettingsMap["currentFrame"] = _animationCurrentFrame;
animationSettingsMap["firstFrame"] = _animationFirstFrame;
animationSettingsMap["lastFrame"] = _animationLastFrame;
animationSettingsMap["running"] = _animationRunning;
animationSettingsMap["loop"] = _animationLoop;
animationSettingsMap["hold"]= _animationHold;
animationSettingsMap["allowTranslation"] = _animationAllowTranslation;
return animationSettingsMap;
}
return Volume3DOverlay::getProperty(property);
}
bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
QVariantMap extraInfo;
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo, precisionPicking);
}
bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) {
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo, precisionPicking);
}
bool ModelOverlay::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
QVariantMap extraInfo;
return _model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, parabolicDistance, face, surfaceNormal, extraInfo, precisionPicking);
}
bool ModelOverlay::findParabolaIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) {
return _model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, parabolicDistance, face, surfaceNormal, extraInfo, precisionPicking);
}
ModelOverlay* ModelOverlay::createClone() const {
return new ModelOverlay(this);
}
Transform ModelOverlay::evalRenderTransform() {
Transform transform = getTransform();
transform.setScale(1.0f); // disable inherited scale
return transform;
}
void ModelOverlay::locationChanged(bool tellPhysics) {
Base3DOverlay::locationChanged(tellPhysics);
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
if (_model && _model->isActive()) {
_model->setRotation(getWorldOrientation());
_model->setTranslation(getWorldPosition());
_updateModel = true;
}
}
QString ModelOverlay::getName() const {
if (_name != "") {
return QString("Overlay:") + getType() + ":" + _name;
}
return QString("Overlay:") + getType() + ":" + _url.toString();
}
void ModelOverlay::animate() {
if (!_animation || !_animation->isLoaded() || !_model || !_model->isLoaded()) {
return;
}
QVector<JointData> jointsData;
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
int frameCount = frames.size();
if (frameCount <= 0) {
return;
}
if (!_lastAnimated) {
_lastAnimated = usecTimestampNow();
return;
}
auto now = usecTimestampNow();
auto interval = now - _lastAnimated;
_lastAnimated = now;
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
_animationCurrentFrame += (deltaTime * _animationFPS);
int animationCurrentFrame = (int)(glm::floor(_animationCurrentFrame)) % frameCount;
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
animationCurrentFrame = 0;
}
if (animationCurrentFrame == _lastKnownCurrentFrame) {
return;
}
_lastKnownCurrentFrame = animationCurrentFrame;
if (_jointMapping.size() != _model->getJointStateCount()) {
return;
}
QStringList animationJointNames = _animation->getHFMModel().getJointNames();
auto& hfmJoints = _animation->getHFMModel().joints;
auto& originalHFMJoints = _model->getHFMModel().joints;
auto& originalHFMIndices = _model->getHFMModel().jointIndices;
const QVector<glm::quat>& rotations = frames[_lastKnownCurrentFrame].rotations;
const QVector<glm::vec3>& translations = frames[_lastKnownCurrentFrame].translations;
jointsData.resize(_jointMapping.size());
for (int j = 0; j < _jointMapping.size(); j++) {
int index = _jointMapping[j];
if (index >= 0) {
glm::mat4 translationMat;
if (_animationAllowTranslation) {
if (index < translations.size()) {
translationMat = glm::translate(translations[index]);
}
} else if (index < animationJointNames.size()) {
QString jointName = hfmJoints[index].name;
if (originalHFMIndices.contains(jointName)) {
// Making sure the joint names exist in the original model the animation is trying to apply onto. If they do, then remap and get its translation.
int remappedIndex = originalHFMIndices[jointName] - 1; // JointIndeces seem to always start from 1 and the found index is always 1 higher than actual.
translationMat = glm::translate(originalHFMJoints[remappedIndex].translation);
}
}
glm::mat4 rotationMat;
if (index < rotations.size()) {
rotationMat = glm::mat4_cast(hfmJoints[index].preRotation * rotations[index] * hfmJoints[index].postRotation);
} else {
rotationMat = glm::mat4_cast(hfmJoints[index].preRotation * hfmJoints[index].postRotation);
}
glm::mat4 finalMat = (translationMat * hfmJoints[index].preTransform *
rotationMat * hfmJoints[index].postTransform);
auto& jointData = jointsData[j];
jointData.translation = extractTranslation(finalMat);
jointData.translationIsDefaultPose = false;
jointData.rotation = glmExtractRotation(finalMat);
jointData.rotationIsDefaultPose = false;
}
}
// Set the data in the model
copyAnimationJointDataToModel(jointsData);
}
void ModelOverlay::mapAnimationJoints(const QStringList& modelJointNames) {
// if we don't have animation, or we're already joint mapped then bail early
if (!hasAnimation() || jointsMapped()) {
return;
}
if (!_animation || _animation->getURL() != _animationURL) {
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_animationURL);
}
if (_animation && _animation->isLoaded()) {
QStringList animationJointNames = _animation->getJointNames();
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
_jointMapping.resize(modelJointNames.size());
for (int i = 0; i < modelJointNames.size(); i++) {
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
}
_jointMappingCompleted = true;
_jointMappingURL = _animationURL;
}
}
}
void ModelOverlay::copyAnimationJointDataToModel(QVector<JointData> jointsData) {
if (!_model || !_model->isLoaded()) {
return;
}
// relay any inbound joint changes from scripts/animation/network to the model/rig
for (int index = 0; index < jointsData.size(); ++index) {
auto& jointData = jointsData[index];
_model->setJointRotation(index, true, jointData.rotation, 1.0f);
_model->setJointTranslation(index, true, jointData.translation, 1.0f);
}
_updateModel = true;
}
void ModelOverlay::clearSubRenderItemIDs() {
_subRenderItemIDs.clear();
}
void ModelOverlay::setSubRenderItemIDs(const render::ItemIDs& ids) {
_subRenderItemIDs = ids;
}
uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const {
if (_model) {
auto metaSubItems = _subRenderItemIDs;
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t)metaSubItems.size();
}
return 0;
}
bool ModelOverlay::canReplaceModelMeshPart(int meshIndex, int partIndex) {
// TODO: bounds checking; for now just used to indicate provider generally supports mesh updates
return _model && _model->isLoaded();
}
bool ModelOverlay::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer newModel, int meshIndex, int partIndex) {
return canReplaceModelMeshPart(meshIndex, partIndex) &&
_model->replaceScriptableModelMeshPart(newModel, meshIndex, partIndex);
}
scriptable::ScriptableModelBase ModelOverlay::getScriptableModel() {
if (!_model || !_model->isLoaded()) {
return Base3DOverlay::getScriptableModel();
}
auto result = _model->getScriptableModel();
result.objectID = Overlay::getID();
return result;
}
render::ItemKey ModelOverlay::getKey() {
auto builder = render::ItemKey::Builder(Base3DOverlay::getKey());
if (_isGroupCulled) {
builder.withMetaCullGroup();
}
return builder.build();
}

View file

@ -1,132 +0,0 @@
//
// ModelOverlay.h
//
//
// Created by Clement on 6/30/14.
// Copyright 2014 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_ModelOverlay_h
#define hifi_ModelOverlay_h
#include <Model.h>
#include <AnimationCache.h>
#include "Volume3DOverlay.h"
class ModelOverlay : public Volume3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
virtual QString getName() const override;
ModelOverlay();
ModelOverlay(const ModelOverlay* modelOverlay);
virtual void update(float deltatime) override;
virtual void render(RenderArgs* args) override {};
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override;
render::ItemKey getKey() override;
void clearSubRenderItemIDs();
void setSubRenderItemIDs(const render::ItemIDs& ids);
virtual void setIsVisibleInSecondaryCamera(bool value) override {
Base3DOverlay::setIsVisibleInSecondaryCamera(value);
_visibleDirty = true;
}
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking = false) override;
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual bool findParabolaIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking = false) override;
virtual ModelOverlay* createClone() const override;
virtual bool addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) override;
virtual void removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) override;
void locationChanged(bool tellPhysics) override;
float getLoadPriority() const { return _loadPriority; }
bool hasAnimation() const { return !_animationURL.isEmpty(); }
bool jointsMapped() const { return _jointMappingURL == _animationURL && _jointMappingCompleted; }
void setVisible(bool visible) override;
void setDrawInFront(bool drawInFront) override;
void setDrawHUDLayer(bool drawHUDLayer) override;
void setGroupCulled(bool groupCulled);
virtual scriptable::ScriptableModelBase getScriptableModel() override;
virtual bool canReplaceModelMeshPart(int meshIndex, int partIndex) override;
virtual bool replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer model, int meshIndex, int partIndex) override;
protected:
Transform evalRenderTransform() override;
// helper to extract metadata from our Model's rigged joints
template <typename itemType> using mapFunction = std::function<itemType(int jointIndex)>;
template <typename vectorType, typename itemType>
vectorType mapJoints(mapFunction<itemType> function) const;
void animate();
void mapAnimationJoints(const QStringList& modelJointNames);
bool isAnimatingSomething() const {
return !_animationURL.isEmpty() && _animationRunning && _animationFPS != 0.0f;
}
void copyAnimationJointDataToModel(QVector<JointData> jointsData);
private:
ModelPointer _model;
QVariantMap _modelTextures;
bool _texturesLoaded { false };
bool _texturesDirty { false };
render::ItemIDs _subRenderItemIDs;
QUrl _url;
bool _updateModel { false };
bool _scaleToFit { false };
float _loadPriority { 0.0f };
AnimationPointer _animation;
QUrl _animationURL;
float _animationFPS { 0.0f };
float _animationCurrentFrame { 0.0f };
bool _animationRunning { false };
bool _animationLoop { false };
float _animationFirstFrame { 0.0f };
float _animationLastFrame { 0.0f };
bool _animationHold { false };
bool _animationAllowTranslation { false };
uint64_t _lastAnimated { 0 };
int _lastKnownCurrentFrame { -1 };
QUrl _jointMappingURL;
bool _jointMappingCompleted { false };
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
bool _visibleDirty { true };
bool _renderLayerDirty { false };
bool _isGroupCulled { false };
bool _groupCulledDirty { false };
};
#endif // hifi_ModelOverlay_h

View file

@ -15,126 +15,31 @@
#include "Application.h"
const glm::u8vec3 Overlay::DEFAULT_OVERLAY_COLOR = { 255, 255, 255 };
const float Overlay::DEFAULT_ALPHA = 0.7f;
Overlay::Overlay() :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(true),
_alpha(DEFAULT_ALPHA),
_pulse(1.0f),
_pulseMax(0.0f),
_pulseMin(0.0f),
_pulsePeriod(1.0f),
_pulseDirection(1.0f),
_lastPulseUpdate(usecTimestampNow()),
_alphaPulse(0.0f),
_colorPulse(0.0f),
_color(DEFAULT_OVERLAY_COLOR),
_visible(true)
{
}
Overlay::Overlay(const Overlay* overlay) :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(overlay->_isLoaded),
_alpha(overlay->_alpha),
_pulse(overlay->_pulse),
_pulseMax(overlay->_pulseMax),
_pulseMin(overlay->_pulseMin),
_pulsePeriod(overlay->_pulsePeriod),
_pulseDirection(overlay->_pulseDirection),
_lastPulseUpdate(usecTimestampNow()),
_alphaPulse(overlay->_alphaPulse),
_colorPulse(overlay->_colorPulse),
_color(overlay->_color),
_visible(overlay->_visible)
{
}
Overlay::~Overlay() {
}
void Overlay::setProperties(const QVariantMap& properties) {
bool valid;
auto color = u8vec3FromVariant(properties["color"], valid);
if (valid) {
_color = color;
}
if (properties["alpha"].isValid()) {
setAlpha(properties["alpha"].toFloat());
}
if (properties["pulseMax"].isValid()) {
setPulseMax(properties["pulseMax"].toFloat());
}
if (properties["pulseMin"].isValid()) {
setPulseMin(properties["pulseMin"].toFloat());
}
if (properties["pulsePeriod"].isValid()) {
setPulsePeriod(properties["pulsePeriod"].toFloat());
}
if (properties["alphaPulse"].isValid()) {
setAlphaPulse(properties["alphaPulse"].toFloat());
}
if (properties["colorPulse"].isValid()) {
setColorPulse(properties["colorPulse"].toFloat());
}
if (properties["visible"].isValid()) {
bool visible = properties["visible"].toBool();
setVisible(visible);
}
}
// JSDoc for copying to @typedefs of overlay types that inherit Overlay.
/**jsdoc
* @property {string} type=TODO - Has the value <code>"TODO"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*/
QVariant Overlay::getProperty(const QString& property) {
if (property == "type") {
return QVariant(getType());
}
if (property == "color") {
return u8vec3ColortoVariant(_color);
}
if (property == "alpha") {
return _alpha;
}
if (property == "pulseMax") {
return _pulseMax;
}
if (property == "pulseMin") {
return _pulseMin;
}
if (property == "pulsePeriod") {
return _pulsePeriod;
}
if (property == "alphaPulse") {
return _alphaPulse;
}
if (property == "colorPulse") {
return _colorPulse;
if (property == "id") {
return getID();
}
if (property == "visible") {
return _visible;
@ -143,67 +48,6 @@ QVariant Overlay::getProperty(const QString& property) {
return QVariant();
}
glm::u8vec3 Overlay::getColor() {
if (_colorPulse == 0.0f) {
return _color;
}
float pulseLevel = updatePulse();
glm::u8vec3 result = _color;
if (_colorPulse < 0.0f) {
result.x *= (1.0f - pulseLevel);
result.y *= (1.0f - pulseLevel);
result.z *= (1.0f - pulseLevel);
} else {
result.x *= pulseLevel;
result.y *= pulseLevel;
result.z *= pulseLevel;
}
return result;
}
float Overlay::getAlpha() {
if (_alphaPulse == 0.0f) {
return _alpha;
}
float pulseLevel = updatePulse();
return (_alphaPulse >= 0.0f) ? _alpha * pulseLevel : _alpha * (1.0f - pulseLevel);
}
// pulse travels from min to max, then max to min in one period.
float Overlay::updatePulse() {
if (_pulsePeriod <= 0.0f) {
return _pulse;
}
quint64 now = usecTimestampNow();
quint64 elapsedUSecs = (now - _lastPulseUpdate);
float elapsedSeconds = (float)elapsedUSecs / (float)USECS_PER_SECOND;
float elapsedPeriods = elapsedSeconds / _pulsePeriod;
// we can safely remove any "full" periods, since those just rotate us back
// to our final pulse level
elapsedPeriods = fmod(elapsedPeriods, 1.0f);
_lastPulseUpdate = now;
float pulseDistance = (_pulseMax - _pulseMin);
float pulseDistancePerPeriod = pulseDistance * 2.0f;
float pulseDelta = _pulseDirection * pulseDistancePerPeriod * elapsedPeriods;
float newPulse = _pulse + pulseDelta;
float limit = (_pulseDirection > 0.0f) ? _pulseMax : _pulseMin;
float passedLimit = (_pulseDirection > 0.0f) ? (newPulse >= limit) : (newPulse <= limit);
if (passedLimit) {
float pulseDeltaToLimit = newPulse - limit;
float pulseDeltaFromLimitBack = pulseDelta - pulseDeltaToLimit;
pulseDelta = -pulseDeltaFromLimitBack;
_pulseDirection *= -1.0f;
}
_pulse += pulseDelta;
return _pulse;
}
bool Overlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
_renderItemID = scene->allocateID();
transaction.resetItem(_renderItemID, std::make_shared<Overlay::Payload>(overlay));
@ -225,8 +69,7 @@ render::ItemKey Overlay::getKey() {
builder.withInvisible();
}
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
render::hifi::Tag viewTagBits = getIsVisibleInSecondaryCamera() ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
render::hifi::Tag viewTagBits = render::hifi::TAG_ALL_VIEWS;
builder.withTagBits(viewTagBits);
return builder.build();

View file

@ -23,12 +23,10 @@ public:
Overlay();
Overlay(const Overlay* overlay);
~Overlay();
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;
virtual render::ItemKey getKey();
@ -44,35 +42,13 @@ public:
// getters
virtual QString getType() const = 0;
bool isLoaded() { return _isLoaded; }
bool isLoaded() { return true; }
bool getVisible() const { return _visible; }
virtual bool isTransparent() { return getAlphaPulse() != 0.0f || getAlpha() != 1.0f; };
virtual bool getIsVisibleInSecondaryCamera() const { return false; }
glm::u8vec3 getColor();
float getAlpha();
float getPulseMax() const { return _pulseMax; }
float getPulseMin() const { return _pulseMin; }
float getPulsePeriod() const { return _pulsePeriod; }
float getPulseDirection() const { return _pulseDirection; }
float getColorPulse() const { return _colorPulse; }
float getAlphaPulse() const { return _alphaPulse; }
// setters
virtual void setVisible(bool visible) { _visible = visible; }
void setDrawHUDLayer(bool drawHUDLayer);
void setColor(const glm::u8vec3& color) { _color = color; }
void setAlpha(float alpha) { _alpha = alpha; }
void setPulseMax(float value) { _pulseMax = value; }
void setPulseMin(float value) { _pulseMin = value; }
void setPulsePeriod(float value) { _pulsePeriod = value; }
void setPulseDirection(float value) { _pulseDirection = value; }
void setColorPulse(float value) { _colorPulse = value; }
void setAlphaPulse(float value) { _alphaPulse = value; }
unsigned int getStackOrder() const { return _stackOrder; }
void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; }
Q_INVOKABLE virtual void setProperties(const QVariantMap& properties);
Q_INVOKABLE virtual Overlay* createClone() const = 0;
@ -81,35 +57,12 @@ public:
render::ItemID getRenderItemID() const { return _renderItemID; }
void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }
unsigned int getStackOrder() const { return _stackOrder; }
void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; }
protected:
float updatePulse();
render::ItemID _renderItemID{ render::Item::INVALID_ITEM_ID };
bool _isLoaded;
float _alpha;
float _pulse;
float _pulseMax;
float _pulseMin;
float _pulsePeriod;
float _pulseDirection;
quint64 _lastPulseUpdate;
float _alphaPulse; // ratio of the pulse to the alpha
float _colorPulse; // ratio of the pulse to the color
glm::u8vec3 _color;
bool _visible; // should the overlay be drawn at all
render::ItemID _renderItemID { render::Item::INVALID_ITEM_ID };
bool _visible;
unsigned int _stackOrder { 0 };
static const glm::u8vec3 DEFAULT_OVERLAY_COLOR;
static const float DEFAULT_ALPHA;
private:
QUuid _id;
};

View file

@ -17,13 +17,12 @@
class Overlay2D : public Overlay {
Q_OBJECT
public:
Overlay2D() {}
Overlay2D(const Overlay2D* overlay2D);
virtual AABox getBounds() const override;
virtual AABox getBounds() const override;
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return 1; }
// getters
@ -32,7 +31,7 @@ public:
int getWidth() const { return _bounds.width(); }
int getHeight() const { return _bounds.height(); }
const QRect& getBoundingRect() const { return _bounds; }
// setters
void setX(int x) { _bounds.setX(x); }
void setY(int y) { _bounds.setY(y); }

View file

@ -79,13 +79,6 @@ void Overlays::init() {
}
void Overlays::update(float deltatime) {
{
QMutexLocker locker(&_mutex);
foreach(const auto& thisOverlay, _overlays) {
thisOverlay->update(deltatime);
}
}
cleanupOverlaysToDelete();
}
@ -948,3 +941,589 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
}
return result;
}
/**jsdoc
* Different overlay types have different properties: some common to all overlays (listed below) and some specific to each
* {@link Overlays.OverlayType|OverlayType} (linked to below). The properties are accessed as an object of property names and
* values.
*
* @typedef {object} Overlays.OverlayProperties
* @property {Uuid} id - The ID of the overlay. <em>Read-only.</em>
* @property {string} type=TODO - Has the value <code>"TODO"</code>. <em>Read-only.</em>
* @property {Overlays.OverlayType} type - The overlay type. <em>Read-only.</em>
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @see The different entity types have additional properties as follows:
* @see {@link Overlays.OverlayProperties-Image|OverlayProperties-Image}
* @see {@link Overlays.OverlayProperties-Text|OverlayProperties-Text}
* @see {@link Overlays.OverlayProperties-Rectangle|OverlayProperties-Rectangle}
* @see {@link Overlays.OverlayProperties-Cube|OverlayProperties-Cube}
* @see {@link Overlays.OverlayProperties-Sphere|OverlayProperties-Sphere}
* @see {@link Overlays.OverlayProperties-Shape|OverlayProperties-Shape}
* @see {@link Overlays.OverlayProperties-Model|OverlayProperties-Model}
* @see {@link Overlays.OverlayProperties-Text3D|OverlayProperties-Text3D}
* @see {@link Overlays.OverlayProperties-Image3D|OverlayProperties-Image3D}
* @see {@link Overlays.OverlayProperties-Web|OverlayProperties-Web}
* @see {@link Overlays.OverlayProperties-Line|OverlayProperties-Line}
* @see {@link Overlays.OverlayProperties-Grid|OverlayProperties-Grid}
* @see {@link Overlays.OverlayProperties-Circle|OverlayProperties-Circle}
*/
/**jsdoc
* The <code>"Image"</code> {@link Overlays.OverlayType|OverlayType} is a 2D image.
* @typedef {object} Overlays.OverlayProperties-Image
* @property {Rect} bounds - The position and size of the image display area, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value of the image display area = <code>bounds.x</code>.
* <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value of the image display area = <code>bounds.y</code>.
* <em>Write-only.</em>
* @property {number} width - Integer width of the image display area = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the image display area = <code>bounds.height</code>. <em>Write-only.</em>
* @property {string} imageURL - The URL of the image file to display. The image is scaled to fit to the <code>bounds</code>.
* <em>Write-only.</em>
* @property {Vec2} subImage=0,0 - Integer coordinates of the top left pixel to start using image content from.
* <em>Write-only.</em>
* @property {Color} color=0,0,0 - The color to apply over the top of the image to colorize it. <em>Write-only.</em>
* @property {number} alpha=0.0 - The opacity of the color applied over the top of the image, <code>0.0</code> -
* <code>1.0</code>. <em>Write-only.</em>
*/
/**jsdoc
* The <code>"Text"</code> {@link Overlays.OverlayType|OverlayType} is for 2D text.
* @typedef {object} Overlays.OverlayProperties-Text
* @property {Rect} bounds - The position and size of the rectangle, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value = <code>bounds.x</code>. <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value = <code>bounds.y</code>. <em>Write-only.</em>
* @property {number} width - Integer width of the rectangle = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the rectangle = <code>bounds.height</code>. <em>Write-only.</em>
*
* @property {number} margin=0 - Sets the <code>leftMargin</code> and <code>topMargin</code> values, in pixels.
* <em>Write-only.</em>
* @property {number} leftMargin=0 - The left margin's size, in pixels. This value is also used for the right margin.
* <em>Write-only.</em>
* @property {number} topMargin=0 - The top margin's size, in pixels. This value is also used for the bottom margin.
* <em>Write-only.</em>
* @property {string} text="" - The text to display. Text does not automatically wrap; use <code>\n</code> for a line break. Text
* is clipped to the <code>bounds</code>. <em>Write-only.</em>
* @property {number} font.size=18 - The size of the text, in pixels. <em>Write-only.</em>
* @property {number} lineHeight=18 - The height of a line of text, in pixels. <em>Write-only.</em>
* @property {Color} color=255,255,255 - The color of the text. Synonym: <code>textColor</code>. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. <em>Write-only.</em>
* @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. <em>Write-only.</em>
* @property {number} backgroundAlpha=0.7 - The opacity of the background rectangle. <em>Write-only.</em>
*/
/**jsdoc
* The <code>"Text"</code> {@link Overlays.OverlayType|OverlayType} is for 2D rectangles.
* @typedef {object} Overlays.OverlayProperties-Rectangle
* @property {Rect} bounds - The position and size of the rectangle, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value = <code>bounds.x</code>. <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value = <code>bounds.y</code>. <em>Write-only.</em>
* @property {number} width - Integer width of the rectangle = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the rectangle = <code>bounds.height</code>. <em>Write-only.</em>
*
* @property {Color} color=0,0,0 - The color of the overlay. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. <em>Write-only.</em>
* @property {number} borderWidth=1 - Integer width of the border, in pixels. The border is drawn within the rectangle's bounds.
* It is not drawn unless either <code>borderColor</code> or <code>borderAlpha</code> are specified. <em>Write-only.</em>
* @property {number} radius=0 - Integer corner radius, in pixels. <em>Write-only.</em>
* @property {Color} borderColor=0,0,0 - The color of the border. <em>Write-only.</em>
* @property {number} borderAlpha=1.0 - The opacity of the border, <code>0.0</code> - <code>1.0</code>.
* <em>Write-only.</em>
*/
/**jsdoc
* The <code>"Cube"</code> {@link Overlays.OverlayType|OverlayType} is for 3D cubes.
* @typedef {object} Overlays.OverlayProperties-Cube
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
*/
/**jsdoc
* The <code>"Sphere"</code> {@link Overlays.OverlayType|OverlayType} is for 3D spheres.
* @typedef {object} Overlays.OverlayProperties-Sphere
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
*/
/**jsdoc
* <p>A <code>shape</code> {@link Overlays.OverlayType|OverlayType} may display as one of the following geometrical shapes:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Dimensions</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"Circle"</code></td><td>2D</td><td>A circle oriented in 3D.</td></td></tr>
* <tr><td><code>"Cone"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cube"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cylinder"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Dodecahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Hexagon"</code></td><td>3D</td><td>A hexagonal prism.</td></tr>
* <tr><td><code>"Icosahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Line"</code></td><td>1D</td><td>A line oriented in 3D.</td></tr>
* <tr><td><code>"Octagon"</code></td><td>3D</td><td>An octagonal prism.</td></tr>
* <tr><td><code>"Octahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Quad"</code></td><td>2D</td><td>A square oriented in 3D.</tr>
* <tr><td><code>"Sphere"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Tetrahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Torus"</code></td><td>3D</td><td><em>Not implemented.</em></td></tr>
* <tr><td><code>"Triangle"</code></td><td>3D</td><td>A triangular prism.</td></tr>
* </tbody>
* </table>
* @typedef {string} Overlays.Shape
*/
/**jsdoc
* The <code>"Shape"</code> {@link Overlays.OverlayType|OverlayType} is for 3D shapes.
* @typedef {object} Overlays.OverlayProperties-Shape
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Overlays.Shape} shape=Hexagon - The geometrical shape of the overlay.
*/
/**jsdoc
* The <code>"Model"</code> {@link Overlays.OverlayType|OverlayType} is for 3D models.
* @typedef {object} Overlays.OverlayProperties-Model
* @property {string} name - The name of the overlay.
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {string} url - The URL of the FBX or OBJ model used for the overlay.
* @property {number} loadPriority=0.0 - The priority for loading and displaying the overlay. Overlays with higher values load
* first. <CURRENTLY NOT USED>
* @property {object.<name, url>} textures - Maps the named textures in the model to the JPG or PNG images in the urls.
* @property {string[]} jointNames - The names of the joints - if any - in the model. <em>Read-only.</em>
* @property {Quat[]} jointRotations - The relative rotations of the model's joints.
* @property {Vec3[]} jointTranslations - The relative translations of the model's joints.
* @property {Quat[]} jointOrientations - The absolute orientations of the model's joints, in world coordinates. <em>Read-only.</em>
* @property {Vec3[]} jointPositions - The absolute positions of the model's joints, in world coordinates. <em>Read-only.</em>
* @property {string} animationSettings.url="" - The URL of an FBX file containing an animation to play.
* @property {number} animationSettings.fps=0 - The frame rate (frames/sec) to play the animation at.
* @property {number} animationSettings.firstFrame=0 - The frame to start playing at.
* @property {number} animationSettings.lastFrame=0 - The frame to finish playing at.
* @property {number} animationSettings.currentFrame=0 - The current frame being played.
* @property {boolean} animationSettings.running=false - Whether or not the animation is playing.
* @property {boolean} animationSettings.loop=false - Whether or not the animation should repeat in a loop.
* @property {boolean} animationSettings.hold=false - Whether or not when the animation finishes, the rotations and
* translations of the last frame played should be maintained.
* @property {boolean} animationSettings.allowTranslation=false - Whether or not translations contained in the animation should
* be played.
*/
/**jsdoc
* The <code>"Text3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D text.
* @typedef {object} Overlays.OverlayProperties-Text3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} isFacingAvatar - If <code>true< / code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
* @property {string} text="" - The text to display.Text does not automatically wrap; use <code>\n< / code> for a line break.
* @property {number} textAlpha=1 - The text alpha value.
* @property {Color} backgroundColor=0,0,0 - The background color.
* @property {number} backgroundAlpha=0.7 - The background alpha value.
* @property {number} lineHeight=1 - The height of a line of text in meters.
* @property {number} leftMargin=0.1 - The left margin, in meters.
* @property {number} topMargin=0.1 - The top margin, in meters.
* @property {number} rightMargin=0.1 - The right margin, in meters.
* @property {number} bottomMargin=0.1 - The bottom margin, in meters.
*/
/**jsdoc
* The <code>"Image3D"</code> {@link Overlays.OverlayType|OverlayType} is for 3D images.
* @typedef {object} Overlays.OverlayProperties-Image3D
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
* @property {string} url - The URL of the PNG or JPG image to display.
* @property {Rect} subImage - The portion of the image to display. Defaults to the full image.
* @property {boolean} emissive - If <code>true</code>, the overlay is displayed at full brightness, otherwise it is rendered
* with scene lighting.
* @property {bool} keepAspectRatio=true - overlays will maintain the aspect ratio when the subImage is applied.
*/
/**jsdoc
* The <code>"Web"</code> {@link Overlays.OverlayType|OverlayType} is for 3D web surfaces.
* @typedef {object} Overlays.OverlayProperties-Web
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
* @property {string} url - The URL of the Web page to display.
* @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page.
* @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay.
* @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second.
* @property {string} inputMode=Touch - The user input mode to use - either <code>"Touch"</code> or <code>"Mouse"</code>.
*/
/**jsdoc
* The <code>"Line"</code> {@link Overlays.OverlayType|OverlayType} is for 3D lines.
* @typedef {object} Overlays.OverlayProperties-Line
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Uuid} endParentID=null - The avatar, entity, or overlay that the end point of the line is parented to.
* @property {number} endParentJointIndex=65535 - Integer value specifying the skeleton joint that the end point of the line is
* attached to if <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint". <CURRENTLY BROKEN>
* @property {Vec3} start - The start point of the line. Synonyms: <code>startPoint</code> and <code>p1</code>.
* @property {Vec3} end - The end point of the line. Synonyms: <code>endPoint</code> and <code>p2</code>.
* @property {Vec3} localStart - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>start</code>. Synonym: <code>localPosition</code>.
* @property {Vec3} localEnd - The local position of the overlay relative to its parent if the overlay has a
* <code>endParentID</code> set, otherwise the same value as <code>end</code>. <CURRENTLY BROKEN>
* @property {number} length - The length of the line, in meters. This can be set after creating a line with start and end
* points. <CURRENTLY BROKEN>
* @property {number} glow=0 - If <code>glow > 0</code>, the line is rendered with a glow.
* @property {number} lineWidth=0.02 - Width of the line, in meters.
*/
/**jsdoc
* The <code>"Grid"</code> {@link Overlays.OverlayType|OverlayType} is for 3D grid.
* @typedef {object} Overlays.OverlayProperties-Grid
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} followCamera=true - If <code>true</code>, the grid is always visible even as the camera moves to another position.
* @property {number} majorGridEvery=5 - Integer number of <code>minorGridEvery</code> intervals at which to draw a thick grid line. Minimum value = <code>1</code>.
* @property {number} minorGridEvery=1 - Real number of meters at which to draw thin grid lines. Minimum value = <code>0.001</code>.
*/
/**jsdoc
* The <code>"Circle"</code> {@link Overlays.OverlayType|OverlayType} is for 3D circle.
* @typedef {object} Overlays.OverlayProperties-Circle
* @property {string} name - The name of the overlay.
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
*
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>. Synonym: <code>localOrientation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If <code>true</code>, the overlay is rendered in front of everything, including the HUD.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {number} startAt = 0 - The counter - clockwise angle from the overlay's x-axis that drawing starts at, in degrees.
* @property {number} endAt = 360 - The counter - clockwise angle from the overlay's x-axis that drawing ends at, in degrees.
* @property {number} outerRadius = 1 - The outer radius of the overlay, in meters.Synonym: <code>radius< / code>.
* @property {number} innerRadius = 0 - The inner radius of the overlay, in meters.
* @property {Color} color = 255, 255, 255 - The color of the overlay.Setting this value also sets the values of
* <code>innerStartColor< / code>, <code>innerEndColor< / code>, <code>outerStartColor< / code>, and <code>outerEndColor< / code>.
* @property {Color} startColor - Sets the values of <code>innerStartColor< / code> and <code>outerStartColor< / code>.
* <em>Write - only.< / em>
* @property {Color} endColor - Sets the values of <code>innerEndColor< / code> and <code>outerEndColor< / code>.
* <em>Write - only.< / em>
* @property {Color} innerColor - Sets the values of <code>innerStartColor< / code> and <code>innerEndColor< / code>.
* <em>Write - only.< / em>
* @property {Color} outerColor - Sets the values of <code>outerStartColor< / code> and <code>outerEndColor< / code>.
* <em>Write - only.< / em>
* @property {Color} innerStartcolor - The color at the inner start point of the overlay.
* @property {Color} innerEndColor - The color at the inner end point of the overlay.
* @property {Color} outerStartColor - The color at the outer start point of the overlay.
* @property {Color} outerEndColor - The color at the outer end point of the overlay.
* @property {number} alpha = 0.5 - The opacity of the overlay, <code>0.0< / code> -<code>1.0< / code>.Setting this value also sets
* the values of <code>innerStartAlpha< / code>, <code>innerEndAlpha< / code>, <code>outerStartAlpha< / code>, and
* <code>outerEndAlpha< / code>.Synonym: <code>Alpha< / code>; <em>write - only< / em>.
* @property {number} startAlpha - Sets the values of <code>innerStartAlpha< / code> and <code>outerStartAlpha< / code>.
* <em>Write - only.< / em>
* @property {number} endAlpha - Sets the values of <code>innerEndAlpha< / code> and <code>outerEndAlpha< / code>.
* <em>Write - only.< / em>
* @property {number} innerAlpha - Sets the values of <code>innerStartAlpha< / code> and <code>innerEndAlpha< / code>.
* <em>Write - only.< / em>
* @property {number} outerAlpha - Sets the values of <code>outerStartAlpha< / code> and <code>outerEndAlpha< / code>.
* <em>Write - only.< / em>
* @property {number} innerStartAlpha = 0 - The alpha at the inner start point of the overlay.
* @property {number} innerEndAlpha = 0 - The alpha at the inner end point of the overlay.
* @property {number} outerStartAlpha = 0 - The alpha at the outer start point of the overlay.
* @property {number} outerEndAlpha = 0 - The alpha at the outer end point of the overlay.
*
* @property {boolean} hasTickMarks = false - If <code>true< / code>, tick marks are drawn.
* @property {number} majorTickMarksAngle = 0 - The angle between major tick marks, in degrees.
* @property {number} minorTickMarksAngle = 0 - The angle between minor tick marks, in degrees.
* @property {number} majorTickMarksLength = 0 - The length of the major tick marks, in meters.A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {number} minorTickMarksLength = 0 - The length of the minor tick marks, in meters.A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {Color} majorTickMarksColor = 0, 0, 0 - The color of the major tick marks.
* @property {Color} minorTickMarksColor = 0, 0, 0 - The color of the minor tick marks.
*/

View file

@ -1,62 +0,0 @@
//
// PanelAttachable.cpp
// interface/src/ui/overlays
//
// Created by Zander Otavka on 7/15/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "PanelAttachable.h"
#include <RegisteredMetaTypes.h>
bool PanelAttachable::getParentVisible() const {
return true;
}
// JSDoc for copying to @typedefs of overlay types that inherit PanelAttachable.
// No JSDoc because these properties are not actually used.
QVariant PanelAttachable::getProperty(const QString& property) {
if (property == "offsetPosition") {
return vec3toVariant(getOffsetPosition());
}
if (property == "offsetRotation") {
return quatToVariant(getOffsetRotation());
}
if (property == "offsetScale") {
return vec3toVariant(getOffsetScale());
}
return QVariant();
}
void PanelAttachable::setProperties(const QVariantMap& properties) {
auto offsetPosition = properties["offsetPosition"];
bool valid;
if (offsetPosition.isValid()) {
glm::vec3 newPosition = vec3FromVariant(offsetPosition, valid);
if (valid) {
setOffsetPosition(newPosition);
}
}
auto offsetRotation = properties["offsetRotation"];
if (offsetRotation.isValid()) {
setOffsetRotation(quatFromVariant(offsetRotation));
}
auto offsetScale = properties["offsetScale"];
if (offsetScale.isValid()) {
setOffsetScale(vec3FromVariant(offsetScale));
}
}
bool PanelAttachable::applyTransformTo(Transform& transform, bool force) {
if (force || usecTimestampNow() > _transformExpiry) {
const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz
_transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD;
}
return false;
}

View file

@ -1,69 +0,0 @@
//
// PanelAttachable.h
// interface/src/ui/overlays
//
// Created by Zander Otavka on 7/1/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Base class for anything that can attach itself to an `OverlayPanel` as a child.
// `PanelAttachable keeps an `std::shared_ptr` to it's parent panel, and sets its
// transformations and visibility based on the parent.
//
// When subclassing `PanelAttachable`, make sure `applyTransformTo`, `getProperty`, and
// `setProperties are all called in the appropriate places. Look through `Image3DOverlay` and
// `Billboard3DOverlay` for examples. Pay special attention to `applyTransformTo`; it should
// be called in three places for `Overlay`s: `render`, `update`, and `findRayIntersection`.
//
// When overriding `applyTransformTo`, make sure to wrap all of your code, including the call
// to the superclass method, with the following `if` block. Then call the superclass method
// with force = true.
//
// if (force || usecTimestampNow() > _transformExpiry) {
// PanelAttachable::applyTransformTo(transform, true);
// ...
// }
//
#ifndef hifi_PanelAttachable_h
#define hifi_PanelAttachable_h
#include <memory>
#include <glm/glm.hpp>
#include <Transform.h>
#include <QScriptValue>
#include <QScriptEngine>
#include <QUuid>
class OverlayPanel;
class PanelAttachable {
public:
// getters
glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); }
glm::quat getOffsetRotation() const { return _offset.getRotation(); }
glm::vec3 getOffsetScale() const { return _offset.getScale(); }
bool getParentVisible() const;
// setters
void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); }
void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); }
void setOffsetScale(float scale) { _offset.setScale(scale); }
void setOffsetScale(const glm::vec3& scale) { _offset.setScale(scale); }
protected:
void setProperties(const QVariantMap& properties);
QVariant getProperty(const QString& property);
/// set position, rotation and scale on transform based on offsets, and parent panel offsets
/// if force is false, only apply transform if it hasn't been applied in the last .1 seconds
virtual bool applyTransformTo(Transform& transform, bool force = false);
quint64 _transformExpiry = 0;
private:
Transform _offset;
};
#endif // hifi_PanelAttachable_h

View file

@ -1,126 +0,0 @@
//
// Planar3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Planar3DOverlay.h"
#include <Extents.h>
#include <GeometryUtil.h>
#include <RegisteredMetaTypes.h>
Planar3DOverlay::Planar3DOverlay() :
Base3DOverlay(),
_dimensions{1.0f, 1.0f}
{
}
Planar3DOverlay::Planar3DOverlay(const Planar3DOverlay* planar3DOverlay) :
Base3DOverlay(planar3DOverlay),
_dimensions(planar3DOverlay->_dimensions)
{
}
AABox Planar3DOverlay::getBounds() const {
auto halfDimensions = glm::vec3{_dimensions / 2.0f, 0.01f};
auto extents = Extents{-halfDimensions, halfDimensions};
extents.transform(getTransform());
return AABox(extents);
}
void Planar3DOverlay::setDimensions(const glm::vec2& value) {
_dimensions = value;
notifyRenderVariableChange();
}
void Planar3DOverlay::setProperties(const QVariantMap& properties) {
Base3DOverlay::setProperties(properties);
auto dimensions = properties["dimensions"];
// if "dimensions" property was not there, check to see if they included aliases: scale
if (!dimensions.isValid()) {
dimensions = properties["scale"];
if (!dimensions.isValid()) {
dimensions = properties["size"];
}
}
if (dimensions.isValid()) {
setDimensions(vec2FromVariant(dimensions));
}
}
// JSDoc for copying to @typedefs of overlay types that inherit Planar3DOverlay.
/**jsdoc
* @property {Vec2} dimensions=1,1 - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*/
QVariant Planar3DOverlay::getProperty(const QString& property) {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec2ToVariant(getDimensions());
}
return Base3DOverlay::getProperty(property);
}
bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
glm::vec2 xyDimensions = getDimensions();
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition();
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT;
if (glm::dot(forward, direction) > 0.0f) {
face = MAX_Z_FACE;
surfaceNormal = -forward;
} else {
face = MIN_Z_FACE;
surfaceNormal = forward;
}
return true;
}
return false;
}
bool Planar3DOverlay::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
glm::vec2 xyDimensions = getDimensions();
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition();
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);
glm::vec3 localVelocity = inverseRot * velocity;
glm::vec3 localAcceleration = inverseRot * acceleration;
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
glm::vec3 forward = rotation * Vectors::FRONT;
if (localIntersectionVelocityZ > 0.0f) {
face = MIN_Z_FACE;
surfaceNormal = forward;
} else {
face = MAX_Z_FACE;
surfaceNormal = -forward;
}
return true;
}
return false;
}
Transform Planar3DOverlay::evalRenderTransform() {
auto transform = getTransform();
transform.setScale(1.0f); // ignore inherited scale factor from parents
if (glm::length2(getDimensions()) != 1.0f) {
transform.postScale(vec3(getDimensions(), 1.0f));
}
return transform;
}

View file

@ -1,45 +0,0 @@
//
// Planar3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Planar3DOverlay_h
#define hifi_Planar3DOverlay_h
#include "Base3DOverlay.h"
class Planar3DOverlay : public Base3DOverlay {
Q_OBJECT
public:
Planar3DOverlay();
Planar3DOverlay(const Planar3DOverlay* planar3DOverlay);
virtual AABox getBounds() const override;
virtual glm::vec2 getSize() const { return _dimensions; };
glm::vec2 getDimensions() const { return _dimensions; }
void setDimensions(float value) { setDimensions(glm::vec2(value)); }
void setDimensions(const glm::vec2& value);
virtual void setProperties(const QVariantMap& properties) override;
virtual QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
protected:
glm::vec2 _dimensions;
Transform evalRenderTransform() override;
};
#endif // hifi_Planar3DOverlay_h

View file

@ -25,7 +25,6 @@ public:
QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay);
~QmlOverlay();
// Cannot fetch properties from QML based overlays due to race conditions
bool supportsGetProperty() const override { return false; }
void setProperties(const QVariantMap& properties) override;

View file

@ -1,158 +0,0 @@
//
// Rectangle3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Rectangle3DOverlay.h"
#include <GeometryCache.h>
#include <SharedUtil.h>
QString const Rectangle3DOverlay::TYPE = "rectangle3d";
Rectangle3DOverlay::Rectangle3DOverlay() :
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
{
auto geometryCache = DependencyManager::get<GeometryCache>();
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
_rectGeometryIds[i] = geometryCache->allocateID();
}
}
Rectangle3DOverlay::Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOverlay) :
Planar3DOverlay(rectangle3DOverlay),
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
{
auto geometryCache = DependencyManager::get<GeometryCache>();
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
_rectGeometryIds[i] = geometryCache->allocateID();
}
}
Rectangle3DOverlay::~Rectangle3DOverlay() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryCacheID);
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
geometryCache->releaseID(_rectGeometryIds[i]);
}
}
}
void Rectangle3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 rectangleColor(toGlm(color), alpha);
auto batch = args->_batch;
if (batch) {
Transform transform = getRenderTransform();
glm::vec2 halfDimensions = transform.getScale() * 0.5f;
transform.setScale(1.0f);
batch->setModelTransform(transform);
auto geometryCache = DependencyManager::get<GeometryCache>();
if (getIsSolid()) {
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
geometryCache->bindSimpleProgram(*batch);
geometryCache->renderQuad(*batch, topLeft, bottomRight, rectangleColor, _geometryCacheID);
} else {
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
if (getIsDashedLine()) {
glm::vec3 point1(-halfDimensions.x, -halfDimensions.y, 0.0f);
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
geometryCache->renderDashedLine(*batch, point1, point2, rectangleColor, _rectGeometryIds[0]);
geometryCache->renderDashedLine(*batch, point2, point3, rectangleColor, _rectGeometryIds[1]);
geometryCache->renderDashedLine(*batch, point3, point4, rectangleColor, _rectGeometryIds[2]);
geometryCache->renderDashedLine(*batch, point4, point1, rectangleColor, _rectGeometryIds[3]);
} else {
if (halfDimensions != _previousHalfDimensions) {
QVector<glm::vec3> border;
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
border << glm::vec3(halfDimensions.x, -halfDimensions.y, 0.0f);
border << glm::vec3(halfDimensions.x, halfDimensions.y, 0.0f);
border << glm::vec3(-halfDimensions.x, halfDimensions.y, 0.0f);
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
geometryCache->updateVertices(_geometryCacheID, border, rectangleColor);
_previousHalfDimensions = halfDimensions;
}
geometryCache->renderVertices(*batch, gpu::LINE_STRIP, _geometryCacheID);
}
}
}
}
const render::ShapeKey Rectangle3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder().withOwnPipeline();
if (isTransparent()) {
builder.withTranslucent();
}
return builder.build();
}
/**jsdoc
* These are the properties of a <code>rectangle3d</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.Rectangle3DProperties
*
* @property {string} type=rectangle3d - Has the value <code>"rectangle3d"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec2} dimensions=1,1 - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*/
void Rectangle3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
}
Rectangle3DOverlay* Rectangle3DOverlay::createClone() const {
return new Rectangle3DOverlay(this);
}

View file

@ -1,39 +0,0 @@
//
// Rectangle3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Rectangle3DOverlay_h
#define hifi_Rectangle3DOverlay_h
#include "Planar3DOverlay.h"
class Rectangle3DOverlay : public Planar3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Rectangle3DOverlay();
Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOverlay);
~Rectangle3DOverlay();
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
void setProperties(const QVariantMap& properties) override;
virtual Rectangle3DOverlay* createClone() const override;
private:
int _geometryCacheID;
std::array<int, 4> _rectGeometryIds;
glm::vec2 _previousHalfDimensions;
};
#endif // hifi_Rectangle3DOverlay_h

View file

@ -11,29 +11,6 @@
QString const RectangleOverlay::TYPE = "rectangle";
QUrl const RectangleOverlay::URL(QString("hifi/overlays/RectangleOverlay.qml"));
// RectangleOverlay's properties are defined in the QML file specified above.
/**jsdoc
* These are the properties of a <code>rectangle</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.RectangleProperties
*
* @property {Rect} bounds - The position and size of the rectangle, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value = <code>bounds.x</code>. <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value = <code>bounds.y</code>. <em>Write-only.</em>
* @property {number} width - Integer width of the rectangle = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the rectangle = <code>bounds.height</code>. <em>Write-only.</em>
*
* @property {Color} color=0,0,0 - The color of the overlay. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. <em>Write-only.</em>
* @property {number} borderWidth=1 - Integer width of the border, in pixels. The border is drawn within the rectangle's bounds.
* It is not drawn unless either <code>borderColor</code> or <code>borderAlpha</code> are specified. <em>Write-only.</em>
* @property {number} radius=0 - Integer corner radius, in pixels. <em>Write-only.</em>
* @property {Color} borderColor=0,0,0 - The color of the border. <em>Write-only.</em>
* @property {number} borderAlpha=1.0 - The opacity of the border, <code>0.0</code> - <code>1.0</code>.
* <em>Write-only.</em>
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
* <em>Write-only.</em>
*/
RectangleOverlay::RectangleOverlay() : QmlOverlay(URL) {}
RectangleOverlay::RectangleOverlay(const RectangleOverlay* rectangleOverlay)

View file

@ -1,204 +0,0 @@
//
// Shape3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 this before QGLWidget, which includes an earlier version of OpenGL
#include "Shape3DOverlay.h"
#include <SharedUtil.h>
#include <StreamUtils.h>
#include <GeometryCache.h>
#include <DependencyManager.h>
QString const Shape3DOverlay::TYPE = "shape";
Shape3DOverlay::Shape3DOverlay(const Shape3DOverlay* shape3DOverlay) :
Volume3DOverlay(shape3DOverlay),
_shape(shape3DOverlay->_shape)
{
}
void Shape3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 shapeColor(toGlm(color), alpha);
auto batch = args->_batch;
if (batch) {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto shapePipeline = args->_shapePipeline;
if (!shapePipeline) {
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
}
batch->setModelTransform(getRenderTransform());
if (_isSolid) {
geometryCache->renderSolidShapeInstance(args, *batch, _shape, shapeColor, shapePipeline);
} else {
geometryCache->renderWireShapeInstance(args, *batch, _shape, shapeColor, shapePipeline);
}
}
}
const render::ShapeKey Shape3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
if (isTransparent()) {
builder.withTranslucent();
}
if (!getIsSolid()) {
builder.withUnlit().withDepthBias();
}
return builder.build();
}
Shape3DOverlay* Shape3DOverlay::createClone() const {
return new Shape3DOverlay(this);
}
/**jsdoc
* <p>A <code>shape</code> {@link Overlays.OverlayType|OverlayType} may display as one of the following geometrical shapes:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Dimensions</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"Circle"</code></td><td>2D</td><td>A circle oriented in 3D.</td></td></tr>
* <tr><td><code>"Cone"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cube"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cylinder"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Dodecahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Hexagon"</code></td><td>3D</td><td>A hexagonal prism.</td></tr>
* <tr><td><code>"Icosahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Line"</code></td><td>1D</td><td>A line oriented in 3D.</td></tr>
* <tr><td><code>"Octagon"</code></td><td>3D</td><td>An octagonal prism.</td></tr>
* <tr><td><code>"Octahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Quad"</code></td><td>2D</td><td>A square oriented in 3D.</tr>
* <tr><td><code>"Sphere"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Tetrahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Torus"</code></td><td>3D</td><td><em>Not implemented.</em></td></tr>
* <tr><td><code>"Triangle"</code></td><td>3D</td><td>A triangular prism.</td></tr>
* </tbody>
* </table>
* @typedef {string} Overlays.Shape
*/
static const std::array<QString, GeometryCache::Shape::NUM_SHAPES> shapeStrings { {
"Line",
"Triangle",
"Quad",
"Hexagon",
"Octagon",
"Circle",
"Cube",
"Sphere",
"Tetrahedron",
"Octahedron",
"Dodecahedron",
"Icosahedron",
"Torus", // Not implemented yet.
"Cone",
"Cylinder"
} };
void Shape3DOverlay::setProperties(const QVariantMap& properties) {
Volume3DOverlay::setProperties(properties);
auto shape = properties["shape"];
if (shape.isValid()) {
const QString shapeStr = shape.toString();
for (size_t i = 0; i < shapeStrings.size(); ++i) {
if (shapeStr == shapeStrings[i]) {
this->_shape = static_cast<GeometryCache::Shape>(i);
break;
}
}
}
}
/**jsdoc
* These are the properties of a <code>shape</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.ShapeProperties
*
* @property {string} type=shape - Has the value <code>"shape"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*
* @property {Overlays.Shape} shape=Hexagon - The geometrical shape of the overlay.
*/
QVariant Shape3DOverlay::getProperty(const QString& property) {
if (property == "shape") {
return shapeStrings[_shape];
}
return Volume3DOverlay::getProperty(property);
}
Transform Shape3DOverlay::evalRenderTransform() {
// TODO: handle registration point??
glm::vec3 position = getWorldPosition();
glm::vec3 dimensions = getDimensions();
glm::quat rotation = getWorldOrientation();
Transform transform;
transform.setScale(dimensions);
transform.setTranslation(position);
transform.setRotation(rotation);
return transform;
}
scriptable::ScriptableModelBase Shape3DOverlay::getScriptableModel() {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto vertexColor = ColorUtils::toVec3(_color);
scriptable::ScriptableModelBase result;
result.objectID = Overlay::getID();
if (auto mesh = geometryCache->meshFromShape(_shape, vertexColor)) {
result.append(mesh);
}
return result;
}

View file

@ -1,45 +0,0 @@
//
// Shape3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Shape3DOverlay_h
#define hifi_Shape3DOverlay_h
#include "Volume3DOverlay.h"
#include <GeometryCache.h>
class Shape3DOverlay : public Volume3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Shape3DOverlay() {}
Shape3DOverlay(const Shape3DOverlay* shape3DOverlay);
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
virtual Shape3DOverlay* createClone() const override;
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual scriptable::ScriptableModelBase getScriptableModel() override;
protected:
Transform evalRenderTransform() override;
private:
GeometryCache::Shape _shape { GeometryCache::Hexagon };
};
#endif // hifi_Shape3DOverlay_h

View file

@ -1,135 +0,0 @@
//
// Sphere3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Sphere3DOverlay.h"
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <gpu/Batch.h>
#include <SharedUtil.h>
QString const Sphere3DOverlay::TYPE = "sphere";
// Sphere overlays should fit inside a cube of the specified dimensions, hence it needs to be a half unit sphere.
// However, the geometry cache renders a UNIT sphere, so we need to scale down.
static const float SPHERE_OVERLAY_SCALE = 0.5f;
Sphere3DOverlay::Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay) :
Volume3DOverlay(Sphere3DOverlay)
{
}
// If Sphere3DOverlay had a getProperty() method then it would go here; do JSDoc here.
/**jsdoc
* These are the properties of a <code>sphere</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.SphereProperties
*
* @property {string} type=sphere - Has the value <code>"sphere"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*/
void Sphere3DOverlay::render(RenderArgs* args) {
if (!_renderVisible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
glm::u8vec3 color = getColor();
glm::vec4 sphereColor(toGlm(color), alpha);
auto batch = args->_batch;
if (batch) {
batch->setModelTransform(getRenderTransform());
auto geometryCache = DependencyManager::get<GeometryCache>();
auto shapePipeline = args->_shapePipeline;
if (!shapePipeline) {
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
}
if (_isSolid) {
geometryCache->renderSolidSphereInstance(args, *batch, sphereColor, shapePipeline);
} else {
geometryCache->renderWireSphereInstance(args, *batch, sphereColor, shapePipeline);
}
}
}
const render::ShapeKey Sphere3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
if (isTransparent()) {
builder.withTranslucent();
}
if (!getIsSolid()) {
builder.withUnlit().withDepthBias();
}
return builder.build();
}
Sphere3DOverlay* Sphere3DOverlay::createClone() const {
return new Sphere3DOverlay(this);
}
Transform Sphere3DOverlay::evalRenderTransform() {
Transform transform = getTransform();
transform.setScale(1.0f); // ignore inherited scale from SpatiallyNestable
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
return transform;
}
scriptable::ScriptableModelBase Sphere3DOverlay::getScriptableModel() {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto vertexColor = ColorUtils::toVec3(_color);
scriptable::ScriptableModelBase result;
if (auto mesh = geometryCache->meshFromShape(GeometryCache::Sphere, vertexColor)) {
result.objectID = Overlay::getID();
result.append(mesh);
}
return result;
}

View file

@ -1,37 +0,0 @@
//
// Sphere3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Sphere3DOverlay_h
#define hifi_Sphere3DOverlay_h
#include "Volume3DOverlay.h"
class Sphere3DOverlay : public Volume3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Sphere3DOverlay() {}
Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay);
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
virtual Sphere3DOverlay* createClone() const override;
virtual scriptable::ScriptableModelBase getScriptableModel() override;
protected:
Transform evalRenderTransform() override;
};
#endif // hifi_Sphere3DOverlay_h

View file

@ -1,295 +0,0 @@
//
// Text3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Text3DOverlay.h"
#include <TextureCache.h>
#include <GeometryCache.h>
#include <RegisteredMetaTypes.h>
#include <RenderDeferredTask.h>
#include <TextRenderer3D.h>
#include <AbstractViewStateInterface.h>
const int FIXED_FONT_POINT_SIZE = 40;
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 92.0f; // Determined through experimentation to fit font to line
// height.
const float LINE_SCALE_RATIO = 1.2f;
QString const Text3DOverlay::TYPE = "text3d";
Text3DOverlay::Text3DOverlay() {
_textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) :
Billboard3DOverlay(text3DOverlay),
_text(text3DOverlay->_text),
_backgroundColor(text3DOverlay->_backgroundColor),
_textAlpha(text3DOverlay->_textAlpha),
_lineHeight(text3DOverlay->_lineHeight),
_leftMargin(text3DOverlay->_leftMargin),
_topMargin(text3DOverlay->_topMargin),
_rightMargin(text3DOverlay->_rightMargin),
_bottomMargin(text3DOverlay->_bottomMargin)
{
_textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Text3DOverlay::~Text3DOverlay() {
delete _textRenderer;
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
const QString Text3DOverlay::getText() const {
QMutexLocker lock(&_mutex);
return _text;
}
void Text3DOverlay::setText(const QString& text) {
QMutexLocker lock(&_mutex);
_text = text;
}
glm::u8vec3 Text3DOverlay::getBackgroundColor() {
if (_colorPulse == 0.0f) {
return _backgroundColor;
}
float pulseLevel = updatePulse();
glm::u8vec3 result = _backgroundColor;
if (_colorPulse < 0.0f) {
result.x *= (1.0f - pulseLevel);
result.y *= (1.0f - pulseLevel);
result.z *= (1.0f - pulseLevel);
} else {
result.x *= pulseLevel;
result.y *= pulseLevel;
result.z *= pulseLevel;
}
return result;
}
void Text3DOverlay::render(RenderArgs* args) {
if (!_renderVisible || !getParentVisible()) {
return; // do nothing if we're not visible
}
Q_ASSERT(args->_batch);
auto& batch = *args->_batch;
auto transform = getRenderTransform();
batch.setModelTransform(transform);
glm::u8vec3 backgroundColor = getBackgroundColor();
glm::vec4 quadColor(toGlm(backgroundColor), getBackgroundAlpha());
glm::vec2 dimensions = getDimensions();
glm::vec2 halfDimensions = dimensions * 0.5f;
const float SLIGHTLY_BEHIND = -0.001f;
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, quadColor.a < 1.0f, false, false, false);
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor, _geometryId);
// Same font properties as textSize()
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
(dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);
transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin),
halfDimensions.y - _topMargin, 0.001f));
transform.setScale(scaleFactor);
batch.setModelTransform(transform);
glm::vec4 textColor = { toGlm(_color), getTextAlpha() };
// FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline for a gpu performance increase.
_textRenderer->draw(batch, 0, 0, getText(), textColor, glm::vec2(-1.0f));
}
const render::ShapeKey Text3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
if (isTransparent()) {
builder.withTranslucent();
}
return builder.build();
}
void Text3DOverlay::setProperties(const QVariantMap& properties) {
Billboard3DOverlay::setProperties(properties);
auto text = properties["text"];
if (text.isValid()) {
setText(text.toString());
}
auto textAlpha = properties["textAlpha"];
if (textAlpha.isValid()) {
float prevTextAlpha = getTextAlpha();
setTextAlpha(textAlpha.toFloat());
// Update our payload key if necessary to handle transparency
if ((prevTextAlpha < 1.0f && _textAlpha >= 1.0f) || (prevTextAlpha >= 1.0f && _textAlpha < 1.0f)) {
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
}
}
bool valid;
auto backgroundColor = properties["backgroundColor"];
if (backgroundColor.isValid()) {
auto color = u8vec3FromVariant(backgroundColor, valid);
if (valid) {
_backgroundColor = color;
}
}
if (properties["backgroundAlpha"].isValid()) {
setAlpha(properties["backgroundAlpha"].toFloat());
}
if (properties["lineHeight"].isValid()) {
setLineHeight(properties["lineHeight"].toFloat());
}
if (properties["leftMargin"].isValid()) {
setLeftMargin(properties["leftMargin"].toFloat());
}
if (properties["topMargin"].isValid()) {
setTopMargin(properties["topMargin"].toFloat());
}
if (properties["rightMargin"].isValid()) {
setRightMargin(properties["rightMargin"].toFloat());
}
if (properties["bottomMargin"].isValid()) {
setBottomMargin(properties["bottomMargin"].toFloat());
}
}
/**jsdoc
* These are the properties of a <code>text3d</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.Text3DProperties
*
* @property {string} type=text3d - Has the value <code>"text3d"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {Vec2} dimensions=1,1 - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
*
* @property {string} text="" - The text to display. Text does not automatically wrap; use <code>\n</code> for a line break.
* @property {number} textAlpha=1 - The text alpha value.
* @property {Color} backgroundColor=0,0,0 - The background color.
* @property {number} backgroundAlpha=0.7 - The background alpha value.
* @property {number} lineHeight=1 - The height of a line of text in meters.
* @property {number} leftMargin=0.1 - The left margin, in meters.
* @property {number} topMargin=0.1 - The top margin, in meters.
* @property {number} rightMargin=0.1 - The right margin, in meters.
* @property {number} bottomMargin=0.1 - The bottom margin, in meters.
*/
QVariant Text3DOverlay::getProperty(const QString& property) {
if (property == "text") {
return getText();
}
if (property == "textAlpha") {
return _textAlpha;
}
if (property == "backgroundColor") {
return u8vec3ColortoVariant(_backgroundColor);
}
if (property == "backgroundAlpha") {
return Billboard3DOverlay::getProperty("alpha");
}
if (property == "lineHeight") {
return _lineHeight;
}
if (property == "leftMargin") {
return _leftMargin;
}
if (property == "topMargin") {
return _topMargin;
}
if (property == "rightMargin") {
return _rightMargin;
}
if (property == "bottomMargin") {
return _bottomMargin;
}
return Billboard3DOverlay::getProperty(property);
}
Text3DOverlay* Text3DOverlay::createClone() const {
return new Text3DOverlay(this);;
}
QSizeF Text3DOverlay::textSize(const QString& text) const {
auto extents = _textRenderer->computeExtent(text);
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
return QSizeF(extents.x, extents.y) * pointToWorldScale;
}

View file

@ -1,78 +0,0 @@
//
// Text3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Text3DOverlay_h
#define hifi_Text3DOverlay_h
#include <QString>
#include <QtCore/QMutex>
#include "Billboard3DOverlay.h"
class TextRenderer3D;
class Text3DOverlay : public Billboard3DOverlay {
Q_OBJECT
using Parent = Billboard3DOverlay;
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Text3DOverlay();
Text3DOverlay(const Text3DOverlay* text3DOverlay);
~Text3DOverlay();
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
// getters
const QString getText() const;
float getLineHeight() const { return _lineHeight; }
float getLeftMargin() const { return _leftMargin; }
float getTopMargin() const { return _topMargin; }
float getRightMargin() const { return _rightMargin; }
float getBottomMargin() const { return _bottomMargin; }
glm::u8vec3 getBackgroundColor();
float getTextAlpha() { return _textAlpha; }
float getBackgroundAlpha() { return getAlpha(); }
bool isTransparent() override { return Overlay::isTransparent() || _textAlpha < 1.0f; }
// setters
void setText(const QString& text);
void setTextAlpha(float alpha) { _textAlpha = alpha; }
void setLineHeight(float value) { _lineHeight = value; }
void setLeftMargin(float margin) { _leftMargin = margin; }
void setTopMargin(float margin) { _topMargin = margin; }
void setRightMargin(float margin) { _rightMargin = margin; }
void setBottomMargin(float margin) { _bottomMargin = margin; }
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
QSizeF textSize(const QString& test) const; // Meters
virtual Text3DOverlay* createClone() const override;
private:
TextRenderer3D* _textRenderer = nullptr;
QString _text;
mutable QMutex _mutex; // used to make get/setText threadsafe, mutable so can be used in const functions
glm::u8vec3 _backgroundColor { 0, 0, 0 };
float _textAlpha { 1.0f };
float _lineHeight { 1.0f };
float _leftMargin { 0.1f };
float _topMargin { 0.1f };
float _rightMargin { 0.1f };
float _bottomMargin { 0.1f };
int _geometryId { 0 };
};
#endif // hifi_Text3DOverlay_h

View file

@ -27,43 +27,12 @@
QString const TextOverlay::TYPE = "text";
QUrl const TextOverlay::URL(QString("hifi/overlays/TextOverlay.qml"));
// TextOverlay's properties are defined in the QML file specified above.
/**jsdoc
* These are the properties of a <code>text</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.TextProperties
*
* @property {Rect} bounds - The position and size of the rectangle, in pixels. <em>Write-only.</em>
* @property {number} x - Integer left, x-coordinate value = <code>bounds.x</code>. <em>Write-only.</em>
* @property {number} y - Integer top, y-coordinate value = <code>bounds.y</code>. <em>Write-only.</em>
* @property {number} width - Integer width of the rectangle = <code>bounds.width</code>. <em>Write-only.</em>
* @property {number} height - Integer height of the rectangle = <code>bounds.height</code>. <em>Write-only.</em>
*
* @property {number} margin=0 - Sets the <code>leftMargin</code> and <code>topMargin</code> values, in pixels.
* <em>Write-only.</em>
* @property {number} leftMargin=0 - The left margin's size, in pixels. This value is also used for the right margin.
* <em>Write-only.</em>
* @property {number} topMargin=0 - The top margin's size, in pixels. This value is also used for the bottom margin.
* <em>Write-only.</em>
* @property {string} text="" - The text to display. Text does not automatically wrap; use <code>\n</code> for a line break. Text
* is clipped to the <code>bounds</code>. <em>Write-only.</em>
* @property {number} font.size=18 - The size of the text, in pixels. <em>Write-only.</em>
* @property {number} lineHeight=18 - The height of a line of text, in pixels. <em>Write-only.</em>
* @property {Color} color=255,255,255 - The color of the text. Synonym: <code>textColor</code>. <em>Write-only.</em>
* @property {number} alpha=1.0 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>. <em>Write-only.</em>
* @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. <em>Write-only.</em>
* @property {number} backgroundAlpha=0.7 - The opacity of the background rectangle. <em>Write-only.</em>
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
* <em>Write-only.</em>
*/
TextOverlay::TextOverlay() : QmlOverlay(URL) { }
TextOverlay::TextOverlay(const TextOverlay* textOverlay)
: QmlOverlay(URL, textOverlay) {
}
TextOverlay::~TextOverlay() { }
TextOverlay* TextOverlay::createClone() const {
return new TextOverlay(this);
}
@ -80,10 +49,4 @@ QSizeF TextOverlay::textSize(const QString& text) const {
QFontMetrics fm(font);
QSizeF result = QSizeF(fm.width(text), 18 * lines);
return result;
}
void TextOverlay::setTopMargin(float margin) {}
void TextOverlay::setLeftMargin(float margin) {}
void TextOverlay::setFontSize(float size) {}
void TextOverlay::setText(const QString& text) {}
}

View file

@ -19,16 +19,8 @@ public:
QString getType() const override { return TYPE; }
static QUrl const URL;
TextOverlay();
TextOverlay(const TextOverlay* textOverlay);
~TextOverlay();
void setTopMargin(float margin);
void setLeftMargin(float margin);
void setFontSize(float size);
void setText(const QString& text);
TextOverlay* createClone() const override;
QSizeF textSize(const QString& text) const; // Pixels

View file

@ -1,117 +0,0 @@
//
// Volume3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 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 "Volume3DOverlay.h"
#include <Extents.h>
#include <RegisteredMetaTypes.h>
Volume3DOverlay::Volume3DOverlay(const Volume3DOverlay* volume3DOverlay) :
Base3DOverlay(volume3DOverlay),
_localBoundingBox(volume3DOverlay->_localBoundingBox)
{
}
AABox Volume3DOverlay::getBounds() const {
AABox bounds = _localBoundingBox;
bounds.transform(getTransform());
return bounds;
}
void Volume3DOverlay::setDimensions(const glm::vec3& value) {
_localBoundingBox.setBox(-value / 2.0f, value);
notifyRenderVariableChange();
}
void Volume3DOverlay::setProperties(const QVariantMap& properties) {
Base3DOverlay::setProperties(properties);
auto dimensions = properties["dimensions"];
// if "dimensions" property was not there, check to see if they included aliases: scale, size
if (!dimensions.isValid()) {
dimensions = properties["scale"];
if (!dimensions.isValid()) {
dimensions = properties["size"];
}
}
if (dimensions.isValid()) {
glm::vec3 scale = vec3FromVariant(dimensions);
// don't allow a zero or negative dimension component to reach the renderTransform
const float MIN_DIMENSION = 0.0001f;
scale = glm::max(scale, MIN_DIMENSION);
setDimensions(scale);
}
}
// JSDoc for copying to @typedefs of overlay types that inherit Volume3DOverlay.
/**jsdoc
* @typedef
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
*/
QVariant Volume3DOverlay::getProperty(const QString& property) {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec3toVariant(getDimensions());
}
return Base3DOverlay::getProperty(property);
}
bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 worldToEntityMatrix;
Transform transform = getTransform();
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
transform.getInverseMatrix(worldToEntityMatrix);
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
// we can use the AABox's ray intersection by mapping our origin and direction into the overlays frame
// and testing intersection there.
bool hit = _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, 1.0f / overlayFrameDirection, distance, face, surfaceNormal);
if (hit) {
surfaceNormal = transform.getRotation() * surfaceNormal;
}
return hit;
}
bool Volume3DOverlay::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking) {
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 worldToEntityMatrix;
Transform transform = getTransform();
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
transform.getInverseMatrix(worldToEntityMatrix);
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 overlayFrameVelocity = glm::vec3(worldToEntityMatrix * glm::vec4(velocity, 0.0f));
glm::vec3 overlayFrameAcceleration = glm::vec3(worldToEntityMatrix * glm::vec4(acceleration, 0.0f));
// we can use the AABox's ray intersection by mapping our origin and direction into the overlays frame
// and testing intersection there.
bool hit = _localBoundingBox.findParabolaIntersection(overlayFrameOrigin, overlayFrameVelocity, overlayFrameAcceleration, parabolicDistance, face, surfaceNormal);
if (hit) {
surfaceNormal = transform.getRotation() * surfaceNormal;
}
return hit;
}
Transform Volume3DOverlay::evalRenderTransform() {
Transform transform = getTransform();
#ifndef USE_SN_SCALE
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
#endif
return transform;
}

View file

@ -1,45 +0,0 @@
//
// Volume3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 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_Volume3DOverlay_h
#define hifi_Volume3DOverlay_h
#include "Base3DOverlay.h"
class Volume3DOverlay : public Base3DOverlay {
Q_OBJECT
using Parent = Base3DOverlay;
public:
Volume3DOverlay() {}
Volume3DOverlay(const Volume3DOverlay* volume3DOverlay);
virtual AABox getBounds() const override;
const glm::vec3& getDimensions() const { return _localBoundingBox.getDimensions(); }
void setDimensions(const glm::vec3& value);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
virtual bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, bool precisionPicking = false) override;
protected:
// Centered local bounding box
AABox _localBoundingBox { vec3(-0.5), 1.0f };
Transform evalRenderTransform() override;
};
#endif // hifi_Volume3DOverlay_h

View file

@ -1,490 +0,0 @@
//
// Web3DOverlay.cpp
//
// Created by Clement on 7/1/14.
// Modified and renamed by Zander Otavka on 8/4/15
// Copyright 2014 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 "Web3DOverlay.h"
#include <Application.h>
#include <QQuickWindow>
#include <QtGui/QOpenGLContext>
#include <QtQuick/QQuickItem>
#include <QtQml/QQmlContext>
#include <QtQml/QQmlEngine>
#include <AbstractViewStateInterface.h>
#include <gpu/Batch.h>
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <GeometryUtil.h>
#include <gl/GLHelpers.h>
#include <scripting/HMDScriptingInterface.h>
#include <scripting/WindowScriptingInterface.h>
#include <ui/OffscreenQmlSurface.h>
#include <ui/OffscreenQmlSurfaceCache.h>
#include <ui/TabletScriptingInterface.h>
#include <PathUtils.h>
#include <RegisteredMetaTypes.h>
#include <TextureCache.h>
#include <UsersScriptingInterface.h>
#include <UserActivityLoggerScriptingInterface.h>
#include <AbstractViewStateInterface.h>
#include <AddressManager.h>
#include "scripting/HMDScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h"
#include "scripting/MenuScriptingInterface.h"
#include "scripting/SettingsScriptingInterface.h"
#include "scripting/KeyboardScriptingInterface.h"
#include <Preferences.h>
#include <AvatarBookmarks.h>
#include <ScriptEngines.h>
#include "FileDialogHelper.h"
#include "avatar/AvatarManager.h"
#include "AudioClient.h"
#include "LODManager.h"
#include "ui/LoginDialog.h"
#include "ui/OctreeStatsProvider.h"
#include "ui/DomainConnectionModel.h"
#include "ui/AvatarInputs.h"
#include "avatar/AvatarManager.h"
#include "scripting/AccountServicesScriptingInterface.h"
#include "scripting/WalletScriptingInterface.h"
#include <plugins/InputConfiguration.h>
#include "ui/Snapshot.h"
#include "SoundCacheScriptingInterface.h"
#include "raypick/PointerScriptingInterface.h"
#include <display-plugins/CompositorHelper.h>
#include "AboutUtil.h"
#include "ResourceRequestObserver.h"
#include <RenderableWebEntityItem.h>
static int MAX_WINDOW_SIZE = 4096;
static const float METERS_TO_INCHES = 39.3701f;
static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
const QString Web3DOverlay::TYPE = "web3d";
Web3DOverlay::Web3DOverlay() {
_touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen);
_touchDevice.setName("Web3DOverlayTouchDevice");
_touchDevice.setMaximumTouchPoints(4);
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
connect(this, &Web3DOverlay::requestWebSurface, this, &Web3DOverlay::buildWebSurface);
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
buildWebSurface(true);
}
Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
Billboard3DOverlay(Web3DOverlay),
_url(Web3DOverlay->_url),
_scriptURL(Web3DOverlay->_scriptURL),
_dpi(Web3DOverlay->_dpi)
{
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Web3DOverlay::~Web3DOverlay() {
destroyWebSurface();
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
void Web3DOverlay::rebuildWebSurface() {
destroyWebSurface();
buildWebSurface();
}
void Web3DOverlay::destroyWebSurface() {
if (_webSurface) {
render::entities::WebEntityRenderer::releaseWebSurface(_webSurface, _cachedWebSurface, _connections);
}
}
void Web3DOverlay::buildWebSurface(bool overrideWeb) {
if (_webSurface) {
return;
}
render::entities::WebEntityRenderer::acquireWebSurface(_url, overrideWeb || isWebContent(), _webSurface, _cachedWebSurface);
onResizeWebSurface();
_webSurface->resume();
_connections.push_back(QObject::connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent));
_connections.push_back(QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived));
}
void Web3DOverlay::update(float deltatime) {
if (_webSurface) {
// update globalPosition
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));
}
Parent::update(deltatime);
}
bool Web3DOverlay::isWebContent() const {
QUrl sourceUrl(_url);
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
_url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
return true;
}
return false;
}
void Web3DOverlay::setMaxFPS(uint8_t maxFPS) {
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces and the current rendering load)
_desiredMaxFPS = maxFPS;
if (_webSurface) {
_webSurface->setMaxFps(_desiredMaxFPS);
_currentMaxFPS = _desiredMaxFPS;
}
}
void Web3DOverlay::onResizeWebSurface() {
glm::vec2 dims = glm::vec2(getDimensions());
dims *= METERS_TO_INCHES * _dpi;
// ensure no side is never larger then MAX_WINDOW_SIZE
float max = (dims.x > dims.y) ? dims.x : dims.y;
if (max > MAX_WINDOW_SIZE) {
dims *= MAX_WINDOW_SIZE / max;
}
_webSurface->resize(QSize(dims.x, dims.y));
}
void Web3DOverlay::render(RenderArgs* args) {
if (!_renderVisible || !getParentVisible()) {
return;
}
if (!_webSurface) {
emit requestWebSurface(false);
return;
}
if (_mayNeedResize) {
emit resizeWebSurface();
}
if (_currentMaxFPS != _desiredMaxFPS) {
setMaxFPS(_desiredMaxFPS);
}
vec4 color(toGlm(getColor()), getAlpha());
if (!_texture) {
_texture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda());
_texture->setSource(__FUNCTION__);
}
OffscreenQmlSurface::TextureAndFence newTextureAndFence;
bool newTextureAvailable = _webSurface->fetchTexture(newTextureAndFence);
if (newTextureAvailable) {
_texture->setExternalTexture(newTextureAndFence.first, newTextureAndFence.second);
}
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setResourceTexture(0, _texture);
auto renderTransform = getRenderTransform();
auto size = renderTransform.getScale();
renderTransform.setScale(1.0f);
batch.setModelTransform(renderTransform);
// Turn off jitter for these entities
batch.pushProjectionJitter();
auto geometryCache = DependencyManager::get<GeometryCache>();
if (color.a < OPAQUE_ALPHA_THRESHOLD) {
geometryCache->bindWebBrowserProgram(batch, true);
} else {
geometryCache->bindWebBrowserProgram(batch);
}
vec2 halfSize = vec2(size.x, size.y) / 2.0f;
geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color, _geometryId);
batch.popProjectionJitter(); // Restore jitter
batch.setResourceTexture(0, nullptr); // restore default white color after me
}
Transform Web3DOverlay::evalRenderTransform() {
Transform transform = Parent::evalRenderTransform();
transform.setScale(1.0f);
transform.postScale(glm::vec3(getDimensions(), 1.0f));
return transform;
}
const render::ShapeKey Web3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias().withOwnPipeline();
if (isTransparent()) {
builder.withTranslucent();
}
return builder.build();
}
QObject* Web3DOverlay::getEventHandler() {
if (!_webSurface) {
return nullptr;
}
return _webSurface->getEventHandler();
}
void Web3DOverlay::setProxyWindow(QWindow* proxyWindow) {
if (!_webSurface) {
return;
}
_webSurface->setProxyWindow(proxyWindow);
}
void Web3DOverlay::hoverEnterOverlay(const PointerEvent& event) {
if (_inputMode == Mouse) {
handlePointerEvent(event);
} else if (_webSurface) {
PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->hoverBeginEvent(webEvent, _touchDevice);
}
}
void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) {
if (_inputMode == Mouse) {
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
handlePointerEvent(endEvent);
// QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited.
PointerEvent endMoveEvent(PointerEvent::Move, event.getID());
handlePointerEvent(endMoveEvent);
} else if (_webSurface) {
PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->hoverEndEvent(webEvent, _touchDevice);
}
}
void Web3DOverlay::handlePointerEvent(const PointerEvent& event) {
if (_inputMode == Touch) {
handlePointerEventAsTouch(event);
} else {
handlePointerEventAsMouse(event);
}
}
void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
if (_webSurface) {
PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->handlePointerEvent(webEvent, _touchDevice);
}
}
void Web3DOverlay::handlePointerEventAsMouse(const PointerEvent& event) {
if (!_webSurface) {
return;
}
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
QPointF windowPoint(windowPos.x, windowPos.y);
Qt::MouseButtons buttons = Qt::NoButton;
if (event.getButtons() & PointerEvent::PrimaryButton) {
buttons |= Qt::LeftButton;
}
Qt::MouseButton button = Qt::NoButton;
if (event.getButton() == PointerEvent::PrimaryButton) {
button = Qt::LeftButton;
}
QEvent::Type type;
switch (event.getType()) {
case PointerEvent::Press:
type = QEvent::MouseButtonPress;
break;
case PointerEvent::Release:
type = QEvent::MouseButtonRelease;
break;
case PointerEvent::Move:
type = QEvent::MouseMove;
break;
default:
return;
}
QMouseEvent mouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
}
void Web3DOverlay::setProperties(const QVariantMap& properties) {
Billboard3DOverlay::setProperties(properties);
auto urlValue = properties["url"];
if (urlValue.isValid()) {
QString newURL = urlValue.toString();
if (newURL != _url) {
setURL(newURL);
}
}
auto scriptURLValue = properties["scriptURL"];
if (scriptURLValue.isValid()) {
QString newScriptURL = scriptURLValue.toString();
if (newScriptURL != _scriptURL) {
setScriptURL(newScriptURL);
}
}
auto dpi = properties["dpi"];
if (dpi.isValid()) {
_dpi = dpi.toFloat();
_mayNeedResize = true;
}
auto maxFPS = properties["maxFPS"];
if (maxFPS.isValid()) {
_desiredMaxFPS = maxFPS.toInt();
}
auto inputModeValue = properties["inputMode"];
if (inputModeValue.isValid()) {
QString inputModeStr = inputModeValue.toString();
if (inputModeStr == "Mouse") {
_inputMode = Mouse;
} else {
_inputMode = Touch;
}
}
}
// Web3DOverlay overrides the meaning of Planar3DOverlay's dimensions property.
/**jsdoc
* These are the properties of a <code>web3d</code> {@link Overlays.OverlayType|OverlayType}.
* @typedef {object} Overlays.Web3DProperties
*
* @property {string} type=web3d - Has the value <code>"web3d"</code>. <em>Read-only.</em>
* @property {Color} color=255,255,255 - The color of the overlay.
* @property {number} alpha=0.7 - The opacity of the overlay, <code>0.0</code> - <code>1.0</code>.
* @property {number} pulseMax=0 - The maximum value of the pulse multiplier.
* @property {number} pulseMin=0 - The minimum value of the pulse multiplier.
* @property {number} pulsePeriod=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from
* <code>pulseMin</code> to <code>pulseMax</code>, then <code>pulseMax</code> to <code>pulseMin</code> in one period.
* @property {number} alphaPulse=0 - If non-zero, the alpha of the overlay is pulsed: the alpha value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {number} colorPulse=0 - If non-zero, the color of the overlay is pulsed: the color value is multiplied by the
* current pulse multiplier value each frame. If > 0 the pulse multiplier is applied in phase with the pulse period; if < 0
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
* used.)
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>rotation</code>.
* @property {boolean} isSolid=false - Synonyms: <ode>solid</code>, <code>isFilled</code>, and <code>filled</code>.
* Antonyms: <code>isWire</code> and <code>wire</code>.
* @property {boolean} isDashedLine=false - If <code>true</code>, a dashed line is drawn on the overlay's edges. Synonym:
* <code>dashed</code>. Deprecated.
* @property {boolean} ignorePickIntersection=false - If <code>true</code>, picks ignore the overlay. <code>ignoreRayIntersection</code> is a synonym.
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* <code>parentID</code> is an avatar skeleton. A value of <code>65535</code> means "no joint".
*
* @property {boolean} isFacingAvatar - If <code>true</code>, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
*
* @property {string} url - The URL of the Web page to display.
* @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page.
* @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay.
* @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms:
* <code>scale</code>, <code>size</code>.
* @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second.
* @property {string} inputMode=Touch - The user input mode to use - either <code>"Touch"</code> or <code>"Mouse"</code>.
*/
QVariant Web3DOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url;
}
if (property == "scriptURL") {
return _scriptURL;
}
if (property == "dpi") {
return _dpi;
}
if (property == "maxFPS") {
return _desiredMaxFPS;
}
if (property == "inputMode") {
if (_inputMode == Mouse) {
return QVariant("Mouse");
} else {
return QVariant("Touch");
}
}
return Billboard3DOverlay::getProperty(property);
}
void Web3DOverlay::setURL(const QString& url) {
if (url != _url) {
bool wasWebContent = isWebContent();
_url = url;
if (_webSurface) {
if (wasWebContent && isWebContent()) {
// If we're just targeting a new web URL, then switch to that without messing around
// with the underlying QML
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
_webSurface->getRootItem()->setProperty(render::entities::WebEntityRenderer::URL_PROPERTY, _url);
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
});
} else {
// If we're switching to or from web content, or between different QML content
// we need to destroy and rebuild the entire QML surface
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
rebuildWebSurface();
});
}
}
}
}
void Web3DOverlay::setScriptURL(const QString& scriptURL) {
_scriptURL = scriptURL;
if (_webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([this, scriptURL] {
if (!_webSurface) {
return;
}
_webSurface->getRootItem()->setProperty("scriptURL", scriptURL);
});
}
}
Web3DOverlay* Web3DOverlay::createClone() const {
return new Web3DOverlay(this);
}
void Web3DOverlay::emitScriptEvent(const QVariant& message) {
QMetaObject::invokeMethod(this, "scriptEventReceived", Q_ARG(QVariant, message));
}

View file

@ -1,99 +0,0 @@
//
// Created by Bradley Austin Davis on 2015/08/31
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_Web3DOverlay_h
#define hifi_Web3DOverlay_h
#include "Billboard3DOverlay.h"
#include <QTouchEvent>
#include <PointerEvent.h>
class OffscreenQmlSurface;
class Web3DOverlay : public Billboard3DOverlay {
Q_OBJECT
using Parent = Billboard3DOverlay;
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Web3DOverlay();
Web3DOverlay(const Web3DOverlay* Web3DOverlay);
virtual ~Web3DOverlay();
void setMaxFPS(uint8_t maxFPS);
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
virtual void update(float deltatime) override;
QObject* getEventHandler();
void setProxyWindow(QWindow* proxyWindow);
Q_INVOKABLE void hoverEnterOverlay(const PointerEvent& event);
Q_INVOKABLE void hoverLeaveOverlay(const PointerEvent& event);
Q_INVOKABLE void handlePointerEvent(const PointerEvent& event);
void handlePointerEventAsTouch(const PointerEvent& event);
void handlePointerEventAsMouse(const PointerEvent& event);
// setters
void setURL(const QString& url);
void setScriptURL(const QString& script);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual Web3DOverlay* createClone() const override;
enum InputMode {
Touch,
Mouse
};
void buildWebSurface(bool overrideWeb = false);
void destroyWebSurface();
void onResizeWebSurface();
public slots:
void emitScriptEvent(const QVariant& scriptMessage);
signals:
void scriptEventReceived(const QVariant& message);
void webEventReceived(const QVariant& message);
void resizeWebSurface();
void requestWebSurface(bool overrideWeb);
protected:
Transform evalRenderTransform() override;
private:
void rebuildWebSurface();
bool isWebContent() const;
InputMode _inputMode { Touch };
QSharedPointer<OffscreenQmlSurface> _webSurface;
bool _cachedWebSurface { false };
gpu::TexturePointer _texture;
QString _url;
QString _scriptURL;
float _dpi { 30.0f };
int _geometryId { 0 };
QTouchDevice _touchDevice;
uint8_t _desiredMaxFPS { 10 };
uint8_t _currentMaxFPS { 0 };
bool _mayNeedResize { false };
std::vector<QMetaObject::Connection> _connections;
};
#endif // hifi_Web3DOverlay_h

View file

@ -61,7 +61,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
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& metas = items[RenderFetchCullSortTask::META];