diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3c8133af8f..42d4555e2e 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -55,6 +55,7 @@ class EntityItemProperties { friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods + friend class HyperlinkEntityItem; // TODO: consider removing this friend relationship and use public methods public: EntityItemProperties(); virtual ~EntityItemProperties(); @@ -148,6 +149,9 @@ public: DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float); DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector); + DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString); + DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString); + static QString getBackgroundModeString(BackgroundMode mode); @@ -295,6 +299,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelData, voxelData, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelSurfaceStyle, voxelSurfaceStyle, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Href, href, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Description, description, ""); properties.getStage().debugDump(); properties.getAtmosphere().debugDump(); diff --git a/libraries/entities/src/Hyperlink.h b/libraries/entities/src/Hyperlink.h new file mode 100644 index 0000000000..7e2e2261e7 --- /dev/null +++ b/libraries/entities/src/Hyperlink.h @@ -0,0 +1,5 @@ + + + + +entityItem \ No newline at end of file diff --git a/libraries/entities/src/HyperlinkEntityItem.cpp b/libraries/entities/src/HyperlinkEntityItem.cpp new file mode 100644 index 0000000000..af9a4003b1 --- /dev/null +++ b/libraries/entities/src/HyperlinkEntityItem.cpp @@ -0,0 +1,174 @@ +// +// HyperlinkEntityItem.cpp +// libraries/entities/src +// +// Created by Niraj Venkat on 6/8/15. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include + +#include + +#include +#include + +#include "EntityTree.h" +#include "EntityTreeElement.h" +#include "EntitiesLogging.h" +#include "HyperlinkEntityItem.h" + + +const QString HyperlinkEntityItem::DEFAULT_HREF(""); +const QString HyperlinkEntityItem::DEFAULT_DESCRIPTION(""); + +const float HyperlinkEntityItem::DEFAULT_LINE_HEIGHT = 0.1f; +const xColor HyperlinkEntityItem::DEFAULT_TEXT_COLOR = { 255, 255, 255 }; +const xColor HyperlinkEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 }; + +EntityItemPointer HyperlinkEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + return EntityItemPointer(new HyperlinkEntityItem(entityID, properties)); +} + +HyperlinkEntityItem::HyperlinkEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +EntityItem(entityItemID) +{ + _type = EntityTypes::Text; + _created = properties.getCreated(); + setProperties(properties); +} + +const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + +void HyperlinkEntityItem::setDimensions(const glm::vec3& value) { + // NOTE: Text Entities always have a "depth" of 1cm. + _dimensions = glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH); +} + +EntityItemProperties HyperlinkEntityItem::getProperties() const { + EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(textColor, getTextColorX); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundColor, getBackgroundColorX); + return properties; +} + +bool HyperlinkEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(textColor, setTextColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundColor, setBackgroundColor); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "HyperlinkEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties._lastEdited); + } + + return somethingChanged; +} + +int HyperlinkEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref); + READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); + READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight); + READ_ENTITY_PROPERTY(PROP_TEXT_COLOR, rgbColor, setTextColor); + READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, rgbColor, setBackgroundColor); + + return bytesRead; +} + + +// TODO: eventually only include properties changed since the params.lastViewFrustumSent time +EntityPropertyFlags HyperlinkEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + requestedProperties += PROP_HREF; + requestedProperties += PROP_DESCRIPTION; + requestedProperties += PROP_LINE_HEIGHT; + requestedProperties += PROP_TEXT_COLOR; + requestedProperties += PROP_BACKGROUND_COLOR; + return requestedProperties; +} + +void HyperlinkEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); + APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); + APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight()); + APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, getTextColor()); + APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor()); +} + + +bool HyperlinkEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const { + + RayIntersectionInfo rayInfo; + rayInfo._rayStart = origin; + rayInfo._rayDirection = direction; + rayInfo._rayLength = std::numeric_limits::max(); + + PlaneShape plane; + + const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); + glm::vec3 normal = _rotation * UNROTATED_NORMAL; + plane.setNormal(normal); + plane.setPoint(getPosition()); // the position is definitely a point on our plane + + bool intersects = plane.findRayIntersection(rayInfo); + + if (intersects) { + glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance); + // now we know the point the ray hit our plane + + glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 dimensions = getDimensions(); + glm::vec3 registrationPoint = getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint); + AABox entityFrameBox(corner, dimensions); + + glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f)); + + intersects = entityFrameBox.contains(entityFrameHitAt); + } + + if (intersects) { + distance = rayInfo._hitDistance; + } + return intersects; +} diff --git a/libraries/entities/src/HyperlinkEntityItem.h b/libraries/entities/src/HyperlinkEntityItem.h new file mode 100644 index 0000000000..2d522d6cfb --- /dev/null +++ b/libraries/entities/src/HyperlinkEntityItem.h @@ -0,0 +1,95 @@ +// +// HyperlinkEntityItem.h +// libraries/entities/src +// +// Created by Niraj Venkat on 6/8/15. +// Copyright 2013 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_HyperlinkEntityItem_h +#define hifi_HyperlinkEntityItem_h + +#include "EntityItem.h" + +class HyperlinkEntityItem : public EntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + HyperlinkEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + + ALLOW_INSTANTIATION // This class can be instantiated + + /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately + virtual void setDimensions(const glm::vec3& value); + virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } + + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties() const; + virtual bool setProperties(const EntityItemProperties& properties); + + // TODO: eventually only include properties changed since the params.lastViewFrustumSent time + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const; + + static const QString DEFAULT_HREF; + void setHref(const QString& value) { _href = value; } + const QString& getHref() const { return _href; } + + static const QString DEFAULT_DESCRIPTION; + void setDescription(const QString& value) { _description = value; } + const QString& getDescription() const { return _description; } + + static const float DEFAULT_LINE_HEIGHT; + void setLineHeight(float value) { _lineHeight = value; } + float getLineHeight() const { return _lineHeight; } + + static const xColor DEFAULT_TEXT_COLOR; + const rgbColor& getTextColor() const { return _textColor; } + xColor getTextColorX() const { xColor color = { _textColor[RED_INDEX], _textColor[GREEN_INDEX], _textColor[BLUE_INDEX] }; return color; } + + void setTextColor(const rgbColor& value) { memcpy(_textColor, value, sizeof(_textColor)); } + void setTextColor(const xColor& value) { + _textColor[RED_INDEX] = value.red; + _textColor[GREEN_INDEX] = value.green; + _textColor[BLUE_INDEX] = value.blue; + } + + static const xColor DEFAULT_BACKGROUND_COLOR; + const rgbColor& getBackgroundColor() const { return _backgroundColor; } + xColor getBackgroundColorX() const { xColor color = { _backgroundColor[RED_INDEX], _backgroundColor[GREEN_INDEX], _backgroundColor[BLUE_INDEX] }; return color; } + + void setBackgroundColor(const rgbColor& value) { memcpy(_backgroundColor, value, sizeof(_backgroundColor)); } + void setBackgroundColor(const xColor& value) { + _backgroundColor[RED_INDEX] = value.red; + _backgroundColor[GREEN_INDEX] = value.green; + _backgroundColor[BLUE_INDEX] = value.blue; + } + +protected: + QString _href; + QString _description; + float _lineHeight; + rgbColor _textColor; + rgbColor _backgroundColor; +}; + +#endif // hifi_HyperlinkEntityItem_h