From 3ce6f7f3d647e36e94fb936a57c5241e1185e0a7 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 3 Dec 2018 11:50:59 -0800 Subject: [PATCH 1/4] real image entities --- interface/resources/qml/hifi/AssetServer.qml | 20 +- .../qml/hifi/dialogs/TabletAssetServer.qml | 20 +- interface/src/Application.cpp | 15 +- interface/src/ui/overlays/Image3DOverlay.cpp | 18 +- .../src/EntityTreeRenderer.cpp | 1 + .../src/EntityTreeRenderer.h | 5 + .../src/RenderableEntityItem.cpp | 45 +-- .../src/RenderableGridEntityItem.cpp | 51 ++++ .../src/RenderableGridEntityItem.h | 36 +++ .../src/RenderableImageEntityItem.cpp | 218 ++++++++++++++ .../src/RenderableImageEntityItem.h | 56 ++++ .../src/RenderableModelEntityItem.cpp | 28 -- .../src/RenderableTextEntityItem.cpp | 20 +- .../src/RenderableTextEntityItem.h | 2 +- .../entities/src/EntityItemProperties.cpp | 246 +++++++++++++--- libraries/entities/src/EntityItemProperties.h | 28 +- .../entities/src/EntityItemPropertiesMacros.h | 9 + .../entities/src/EntityPropertyFlags.cpp | 2 +- libraries/entities/src/EntityPropertyFlags.h | 10 +- .../entities/src/EntityPsuedoPropertyFlags.h | 2 + .../entities/src/EntityScriptingInterface.cpp | 4 + libraries/entities/src/EntityTypes.cpp | 38 +-- libraries/entities/src/EntityTypes.h | 66 +++-- libraries/entities/src/GridEntityItem.cpp | 154 ++++++++++ libraries/entities/src/GridEntityItem.h | 56 ++++ libraries/entities/src/ImageEntityItem.cpp | 269 ++++++++++++++++++ libraries/entities/src/ImageEntityItem.h | 86 ++++++ libraries/entities/src/TextEntityItem.cpp | 24 +- libraries/entities/src/TextEntityItem.h | 7 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/octree/src/OctreePacketData.cpp | 16 ++ libraries/octree/src/OctreePacketData.h | 6 + libraries/shared/src/BillboardMode.cpp | 25 ++ libraries/shared/src/BillboardMode.h | 26 ++ libraries/shared/src/RegisteredMetaTypes.cpp | 29 ++ libraries/shared/src/RegisteredMetaTypes.h | 2 + scripts/system/edit.js | 10 +- scripts/system/html/js/entityList.js | 4 - scripts/system/html/js/entityProperties.js | 28 +- scripts/system/libraries/entityList.js | 4 +- 41 files changed, 1453 insertions(+), 238 deletions(-) create mode 100644 libraries/entities-renderer/src/RenderableGridEntityItem.cpp create mode 100644 libraries/entities-renderer/src/RenderableGridEntityItem.h create mode 100644 libraries/entities-renderer/src/RenderableImageEntityItem.cpp create mode 100644 libraries/entities-renderer/src/RenderableImageEntityItem.h create mode 100644 libraries/entities/src/GridEntityItem.cpp create mode 100644 libraries/entities/src/GridEntityItem.h create mode 100644 libraries/entities/src/ImageEntityItem.cpp create mode 100644 libraries/entities/src/ImageEntityItem.h create mode 100644 libraries/shared/src/BillboardMode.cpp create mode 100644 libraries/shared/src/BillboardMode.h diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index ad337a6361..247a42428a 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -189,15 +189,17 @@ Windows.ScrollingWindow { var grabbable = MenuInterface.isOptionChecked("Create Entities As Grabbable (except Zones, Particles, and Lights)"); if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { - var name = assetProxyModel.data(treeView.selection.currentIndex); - var modelURL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; - var textures = JSON.stringify({ "tex.picture": defaultURL}); - var shapeType = "box"; - var dynamic = false; - var collisionless = true; - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); - var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, grabbable, position, gravity); + Entities.addEntity({ + type: "Image", + name: assetProxyModel.data(treeView.selection.currentIndex), + imageURL: defaultURL, + keepAspectRatio: false, + dynamic: false, + collisionless: true, + grabbable: grabbable, + position: Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))), + gravity: Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0) + }); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index f665032b01..b5374b2fe0 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -189,15 +189,17 @@ Rectangle { var grabbable = MenuInterface.isOptionChecked("Create Entities As Grabbable (except Zones, Particles, and Lights)"); if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { - var name = assetProxyModel.data(treeView.selection.currentIndex); - var modelURL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; - var textures = JSON.stringify({ "tex.picture": defaultURL}); - var shapeType = "box"; - var dynamic = false; - var collisionless = true; - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); - var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, grabbable, position, gravity); + Entities.addEntity({ + type: "Image", + name: assetProxyModel.data(treeView.selection.currentIndex), + imageURL: defaultURL, + keepAspectRatio: false, + dynamic: false, + collisionless: true, + grabbable: grabbable, + position: Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))), + gravity: Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0) + }); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21af28ffcb..46b25a8f03 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2367,6 +2367,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); + EntityTreeRenderer::setGetAvatarUpOperator([] { + return DependencyManager::get()->getMyAvatar()->getWorldOrientation() * Vectors::UP; + }); + // Preload Tablet sounds DependencyManager::get()->preloadSounds(); DependencyManager::get()->createKeyboard(); @@ -7623,16 +7627,13 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { EntityItemProperties properties; - properties.setType(EntityTypes::Model); properties.setName(mapping.right(mapping.length() - 1)); if (filePath.toLower().endsWith(PNG_EXTENSION) || filePath.toLower().endsWith(JPG_EXTENSION)) { - QJsonObject textures { - {"tex.picture", QString("atp:" + mapping) } - }; - properties.setModelURL("https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"); - properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); - properties.setShapeType(SHAPE_TYPE_BOX); + properties.setType(EntityTypes::Image); + properties.setImageURL(QString("atp:" + mapping)); + properties.setKeepAspectRatio(false); } else { + properties.setType(EntityTypes::Model); properties.setModelURL("atp:" + mapping); properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); } diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index e24e3b3ed8..d3d0c873a4 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -82,18 +82,21 @@ void Image3DOverlay::render(RenderArgs* args) { float imageHeight = _texture->getHeight(); QRect fromImage; - if (_fromImage.isNull()) { + if (_fromImage.width() <= 0) { fromImage.setX(0); - fromImage.setY(0); fromImage.setWidth(imageWidth); - fromImage.setHeight(imageHeight); } else { float scaleX = imageWidth / _texture->getOriginalWidth(); - float scaleY = imageHeight / _texture->getOriginalHeight(); - fromImage.setX(scaleX * _fromImage.x()); - fromImage.setY(scaleY * _fromImage.y()); 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()); } @@ -247,9 +250,6 @@ QVariant Image3DOverlay::getProperty(const QString& property) { if (property == "subImage") { return _fromImage; } - if (property == "offsetPosition") { - return vec3toVariant(getOffsetPosition()); - } if (property == "emissive") { return _emissive; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 980ff8834c..5fb94dd323 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -41,6 +41,7 @@ #include std::function EntityTreeRenderer::_entitiesShouldFadeFunction = []() { return true; }; +std::function EntityTreeRenderer::_getAvatarUpOperator = []() { return Vectors::UP; }; QString resolveScriptURL(const QString& scriptUrl) { auto normalizedScriptUrl = DependencyManager::get()->normalizeURL(scriptUrl); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 4ba1a0060b..243dfd9813 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -117,6 +117,9 @@ public: // Access the workload Space workload::SpacePointer getWorkloadSpace() const { return _space; } + static void setGetAvatarUpOperator(std::function getAvatarUpOperator) { _getAvatarUpOperator = getAvatarUpOperator; } + static glm::vec3 getAvatarUp() { return _getAvatarUpOperator(); } + signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); @@ -262,6 +265,8 @@ private: mutable std::mutex _spaceLock; workload::SpacePointer _space{ new workload::Space() }; workload::Transaction::Updates _spaceUpdates; + + static std::function _getAvatarUpOperator; }; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index aa335bb7d5..92387dafa6 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -25,6 +25,8 @@ #include "RenderableWebEntityItem.h" #include "RenderableZoneEntityItem.h" #include "RenderableMaterialEntityItem.h" +#include "RenderableImageEntityItem.h" +#include "RenderableGridEntityItem.h" using namespace render; @@ -214,22 +216,39 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, using Type = EntityTypes::EntityType_t; auto type = entity->getType(); switch (type) { - case Type::Light: - result = make_renderer(entity); - break; - case Type::Line: - result = make_renderer(entity); + case Type::Shape: + case Type::Box: + case Type::Sphere: + result = make_renderer(entity); break; case Type::Model: result = make_renderer(entity); break; + case Type::Text: + result = make_renderer(entity); + break; + + case Type::Image: + result = make_renderer(entity); + break; + + case Type::Web: + if (!nsightActive()) { + result = make_renderer(entity); + } + break; + case Type::ParticleEffect: result = make_renderer(entity); break; + case Type::Line: + result = make_renderer(entity); + break; + case Type::PolyLine: result = make_renderer(entity); break; @@ -238,20 +257,12 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, result = make_renderer(entity); break; - case Type::Shape: - case Type::Box: - case Type::Sphere: - result = make_renderer(entity); + case Type::Grid: + result = make_renderer(entity); break; - case Type::Text: - result = make_renderer(entity); - break; - - case Type::Web: - if (!nsightActive()) { - result = make_renderer(entity); - } + case Type::Light: + result = make_renderer(entity); break; case Type::Zone: diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp new file mode 100644 index 0000000000..bd42a722fb --- /dev/null +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -0,0 +1,51 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RenderableGridEntityItem.h" + +using namespace render; +using namespace render::entities; + +GridEntityRenderer::GridEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { +} + +bool GridEntityRenderer::needsRenderUpdate() const { + return Parent::needsRenderUpdate(); +} + +bool GridEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + return false; +} + +void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + +} + +ItemKey GridEntityRenderer::getKey() { + ItemKey::Builder builder; + builder.withTypeShape().withTypeMeta().withTagBits(getTagMask()); + + withReadLock([&] { + if (isTransparent()) { + builder.withTransparent(); + } else if (_canCastShadow) { + builder.withShadowCaster(); + } + }); + + return builder.build(); +} + +ShapeKey GridEntityRenderer::getShapeKey() { + ShapeKey::Builder builder; + return builder.build(); +} + +void GridEntityRenderer::doRender(RenderArgs* args) { + +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.h b/libraries/entities-renderer/src/RenderableGridEntityItem.h new file mode 100644 index 0000000000..09c0de1d0d --- /dev/null +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.h @@ -0,0 +1,36 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RenderableGridEntityItem_h +#define hifi_RenderableGridEntityItem_h + +#include "RenderableEntityItem.h" + +#include + +namespace render { namespace entities { + +class GridEntityRenderer : public TypedEntityRenderer { + using Parent = TypedEntityRenderer; + using Pointer = std::shared_ptr; +public: + GridEntityRenderer(const EntityItemPointer& entity); + +protected: + ItemKey getKey() override; + ShapeKey getShapeKey() override; + +private: + virtual bool needsRenderUpdate() const override; + virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRender(RenderArgs* args) override; +}; + +} } +#endif // hifi_RenderableGridEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp new file mode 100644 index 0000000000..7c5b7fc0da --- /dev/null +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -0,0 +1,218 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RenderableImageEntityItem.h" + +#include +#include + +using namespace render; +using namespace render::entities; + +ImageEntityRenderer::ImageEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { + _geometryId = DependencyManager::get()->allocateID(); +} + +ImageEntityRenderer::~ImageEntityRenderer() { + auto geometryCache = DependencyManager::get(); + if (geometryCache) { + geometryCache->releaseID(_geometryId); + } +} + +bool ImageEntityRenderer::isTransparent() const { + return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f; +} + +bool ImageEntityRenderer::needsRenderUpdate() const { + bool textureLoadedChanged = resultWithReadLock([&] { + return (!_textureIsLoaded && _texture && _texture->isLoaded()); + }); + + if (textureLoadedChanged) { + return true; + } + + return Parent::needsRenderUpdate(); +} + +bool ImageEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + bool needsUpdate = resultWithReadLock([&] { + if (_imageURL != entity->getImageURL()) { + return true; + } + + if (_emissive != entity->getEmissive()) { + return true; + } + + if (_keepAspectRatio != entity->getKeepAspectRatio()) { + return true; + } + + if (_billboardMode != entity->getBillboardMode()) { + return true; + } + + if (_subImage != entity->getSubImage()) { + return true; + } + + if (_color != entity->getColor()) { + return true; + } + + if (_alpha != entity->getAlpha()) { + return true; + } + + return false; + }); + + return needsUpdate; +} + +void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + withWriteLock([&] { + auto imageURL = entity->getImageURL(); + if (_imageURL != imageURL) { + _imageURL = imageURL; + if (imageURL.isEmpty()) { + _texture.reset(); + } else { + _texture = DependencyManager::get()->getTexture(_imageURL); + } + _textureIsLoaded = false; + } + + _emissive = entity->getEmissive(); + _keepAspectRatio = entity->getKeepAspectRatio(); + _billboardMode = entity->getBillboardMode(); + _subImage = entity->getSubImage(); + + _color = entity->getColor(); + _alpha = entity->getAlpha(); + + if (!_textureIsLoaded && _texture && _texture->isLoaded()) { + _textureIsLoaded = true; + } + }); + + void* key = (void*)this; + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() { + withWriteLock([&] { + _dimensions = entity->getScaledDimensions(); + updateModelTransformAndBound(); + _renderTransform = getModelTransform(); + }); + }); +} + +ShapeKey ImageEntityRenderer::getShapeKey() { + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); + if (isTransparent()) { + builder.withTranslucent(); + } + + withReadLock([&] { + if (_emissive) { + builder.withUnlit(); + } + }); + + return builder.build(); +} + +void ImageEntityRenderer::doRender(RenderArgs* args) { + NetworkTexturePointer texture; + QRect subImage; + glm::u8vec3 color; + glm::vec3 dimensions; + Transform transform; + withReadLock([&] { + texture = _texture; + subImage = _subImage; + color = _color; + dimensions = _dimensions; + transform = _renderTransform; + }); + + if (!_visible || !texture || !texture->isLoaded()) { + return; + } + + Q_ASSERT(args->_batch); + gpu::Batch* batch = args->_batch; + + if (_billboardMode == BillboardMode::YAW) { + //rotate about vertical to face the camera + glm::vec3 dPosition = args->getViewFrustum().getPosition() - transform.getTranslation(); + // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees + float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); + glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); + transform.setRotation(orientation); + } else if (_billboardMode == BillboardMode::FULL) { + glm::vec3 billboardPos = transform.getTranslation(); + glm::vec3 cameraPos = args->getViewFrustum().getPosition(); + // use the referencial from the avatar, y isn't always up + glm::vec3 avatarUP = EntityTreeRenderer::getAvatarUp(); + // 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.postScale(dimensions); + + batch->setModelTransform(transform); + batch->setResourceTexture(0, texture->getGPUTexture()); + + float imageWidth = texture->getWidth(); + float imageHeight = texture->getHeight(); + + QRect fromImage; + if (subImage.width() <= 0) { + fromImage.setX(0); + fromImage.setWidth(imageWidth); + } else { + float scaleX = imageWidth / texture->getOriginalWidth(); + fromImage.setX(scaleX * subImage.x()); + fromImage.setWidth(scaleX * subImage.width()); + } + + if (subImage.height() <= 0) { + fromImage.setY(0); + fromImage.setHeight(imageHeight); + } else { + float scaleY = imageHeight / texture->getOriginalHeight(); + fromImage.setY(scaleY * subImage.y()); + fromImage.setHeight(scaleY * subImage.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); + + glm::vec4 imageColor(toGlm(color), _alpha); + + DependencyManager::get()->renderQuad( + *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, + imageColor, _geometryId + ); + + batch->setResourceTexture(0, nullptr); +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.h b/libraries/entities-renderer/src/RenderableImageEntityItem.h new file mode 100644 index 0000000000..669db13a22 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.h @@ -0,0 +1,56 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RenderableImageEntityItem_h +#define hifi_RenderableImageEntityItem_h + +#include "RenderableEntityItem.h" + +#include + +namespace render { + namespace entities { + + class ImageEntityRenderer : public TypedEntityRenderer { + using Parent = TypedEntityRenderer; + using Pointer = std::shared_ptr; + public: + ImageEntityRenderer(const EntityItemPointer& entity); + ~ImageEntityRenderer(); + + protected: + ShapeKey getShapeKey() override; + + bool isTransparent() const override; + + private: + virtual bool needsRenderUpdate() const override; + virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRender(RenderArgs* args) override; + + QString _imageURL; + NetworkTexturePointer _texture; + bool _textureIsLoaded { false }; + + bool _emissive; + bool _keepAspectRatio; + BillboardMode _billboardMode; + QRect _subImage; + + glm::u8vec3 _color; + float _alpha; + + glm::vec3 _dimensions; + + int _geometryId { 0 }; + }; + + } +} +#endif // hifi_RenderableImageEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2b1d70f4d0..62aaf6f3a8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -83,34 +83,6 @@ void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) { } } -QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures) { - // If textures are unset, revert to original textures - if (textures.isEmpty()) { - return defaultTextures; - } - - // Legacy: a ,\n-delimited list of filename:"texturepath" - if (*textures.cbegin() != '{') { - textures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}"; - } - - QJsonParseError error; - QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error); - // If textures are invalid, revert to original textures - if (error.error != QJsonParseError::NoError) { - qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << textures; - return defaultTextures; - } - - QVariantMap texturesMap = texturesJson.toVariant().toMap(); - // If textures are unset, revert to original textures - if (texturesMap.isEmpty()) { - return defaultTextures; - } - - return texturesJson.toVariant().toMap(); -} - void RenderableModelEntityItem::doInitialModelSimulation() { DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__); ModelPointer model = getModel(); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index ce9e7ab764..6e281081d2 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "GLMHelpers.h" @@ -59,7 +58,7 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint return true; } - if (_faceCamera != entity->getFaceCamera()) { + if (_billboardMode != entity->getBillboardMode()) { return true; } return false; @@ -79,7 +78,7 @@ void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { _textColor = toGlm(entity->getTextColor()); _backgroundColor = toGlm(entity->getBackgroundColor()); - _faceCamera = entity->getFaceCamera(); + _billboardMode = entity->getBillboardMode(); _lineHeight = entity->getLineHeight(); _text = entity->getText(); } @@ -110,13 +109,26 @@ void TextEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; auto transformToTopLeft = modelTransform; - if (_faceCamera) { + if (_billboardMode == BillboardMode::YAW) { //rotate about vertical to face the camera glm::vec3 dPosition = args->getViewFrustum().getPosition() - modelTransform.getTranslation(); // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); transformToTopLeft.setRotation(orientation); + } else if (_billboardMode == BillboardMode::FULL) { + glm::vec3 billboardPos = transformToTopLeft.getTranslation(); + glm::vec3 cameraPos = args->getViewFrustum().getPosition(); + // use the referencial from the avatar, y isn't always up + glm::vec3 avatarUP = EntityTreeRenderer::getAvatarUp(); + // 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)))); + transformToTopLeft.setRotation(rotation); + } } transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index ac7f2b620f..a368f280c5 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -32,7 +32,7 @@ private: virtual void doRender(RenderArgs* args) override; int _geometryID{ 0 }; std::shared_ptr _textRenderer; - bool _faceCamera; + BillboardMode _billboardMode; glm::vec3 _dimensions; glm::vec3 _textColor; glm::vec3 _backgroundColor; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8970aed01a..f24b14d3b7 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -297,6 +297,33 @@ void EntityItemProperties::setMaterialMappingModeFromString(const QString& mater } } +QHash stringToBillboardModeLookup; + +void addBillboardMode(BillboardMode mode) { + stringToBillboardModeLookup[BillboardModeHelpers::getNameForBillboardMode(mode)] = mode; +} + +void buildStringToBillboardModeLookup() { + addBillboardMode(BillboardMode::NONE); + addBillboardMode(BillboardMode::YAW); + addBillboardMode(BillboardMode::FULL); +} + +QString EntityItemProperties::getBillboardModeAsString() const { + return BillboardModeHelpers::getNameForBillboardMode(_billboardMode); +} + +void EntityItemProperties::setBillboardModeFromString(const QString& materialMappingMode) { + if (stringToBillboardModeLookup.empty()) { + buildStringToBillboardModeLookup(); + } + auto billboardModeItr = stringToBillboardModeLookup.find(materialMappingMode.toLower()); + if (billboardModeItr != stringToBillboardModeLookup.end()) { + _billboardMode = billboardModeItr.value(); + _billboardModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -383,6 +410,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SPIN_FINISH, spinFinish); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_ROTATE_WITH_ENTITY, rotateWithEntity); + CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); + CHECK_PROPERTY_CHANGE(PROP_EMISSIVE, emissive); + CHECK_PROPERTY_CHANGE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); + CHECK_PROPERTY_CHANGE(PROP_SUB_IMAGE, subImage); + // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription); @@ -412,7 +444,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints); CHECK_PROPERTY_CHANGE(PROP_HREF, href); CHECK_PROPERTY_CHANGE(PROP_DESCRIPTION, description); - CHECK_PROPERTY_CHANGE(PROP_FACE_CAMERA, faceCamera); + CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode); CHECK_PROPERTY_CHANGE(PROP_ACTION_DATA, actionData); CHECK_PROPERTY_CHANGE(PROP_NORMALS, normals); CHECK_PROPERTY_CHANGE(PROP_STROKE_COLORS, strokeColors); @@ -642,18 +674,20 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * * @see The different entity types have additional properties as follows: * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} - * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} - * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} - * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} + * @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} + * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} * @see {@link Entities.EntityProperties-Model|EntityProperties-Model} + * @see {@link Entities.EntityProperties-Text|EntityProperties-Text} + * @see {@link Entities.EntityProperties-Image|EntityProperties-Image} + * @see {@link Entities.EntityProperties-Web|EntityProperties-Web} * @see {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} + * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} * @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} * @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} - * @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} - * @see {@link Entities.EntityProperties-Text|EntityProperties-Text} - * @see {@link Entities.EntityProperties-Web|EntityProperties-Web} + * @see {@link Entities.EntityProperties-Grid|EntityProperties-Grid} + * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} * @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone} + * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} */ /**jsdoc @@ -786,8 +820,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {@link Entities.EntityProperties|naturalDimensions}. * @property {Color} color=255,255,255 - Currently not used. * @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".
- * Note: If the name ends with "default-image-model.fbx" then the entity is considered to be an "Image" - * entity, in which case the textures property should be set per the example. * @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the * model's original textures. Use a texture name from the originalTextures property to override that texture. * Only the texture names and URLs to be overridden need be specified; original textures are used where there are no @@ -833,24 +865,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * dimensions: { x: 0.0945, y: 0.0921, z: 0.0423 }, * lifetime: 300 // Delete after 5 minutes. * }); - * @example Create an "Image" entity like you can in the Create app. - * var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; - * var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg"; - * var entity = Entities.addEntity({ - * type: "Model", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -3 })), - * rotation: MyAvatar.orientation, - * dimensions: { - * x: 0.5385, - * y: 0.2819, - * z: 0.0092 - * }, - * shapeType: "box", - * collisionless: true, - * modelURL: IMAGE_MODEL, - * textures: JSON.stringify({ "tex.picture": DEFAULT_IMAGE }), - * lifetime: 300 // Delete after 5 minutes - * }); */ /**jsdoc @@ -1091,8 +1105,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {number} lineHeight=0.1 - The height of each line of text (thus determining the font size). * @property {Color} textColor=255,255,255 - The color of the text. * @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. - * @property {boolean} faceCamera=false - If true, the entity is oriented to face each user's camera (i.e., it - * differs for each user present). + * @property {BillboardMode} billboardMode="none" - If "none", the entity is not billboarded. If "yaw", the entity will be + * oriented to follow your camera around the y-axis. If "full" the entity will be oriented to face your camera. The following deprecated + * behavior is also supported: you can also set "faceCamera" to true to set billboardMode to "yaw", and you can set + * "isFacingAvatar" to true to set billboardMode to "full". Setting either to false sets the mode to "none" * @example Create a text entity. * var text = Entities.addEntity({ * type: "Text", @@ -1100,7 +1116,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, * lineHeight: 0.12, * text: "Hello\nthere!", - * faceCamera: true, + * billboardMode: "yaw", * lifetime: 300 // Delete after 5 minutes. * }); */ @@ -1211,6 +1227,32 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * }); */ +/**jsdoc + * The "Image" {@link Entities.EntityType|EntityType} displays an image on a 2D rectangle in the domain. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * @typedef {object} Entities.EntityProperties-Image + * @property {string} imageURL="" - The URL of the image to use. + * @property {boolean} emissive=false - Whether or not the image should be emissive (unlit). + * @property {boolean} keepAspectRatio=true - Whether or not the image should maintain its aspect ratio. + * @property {BillboardMode} billboardMode="none" - If "none", the entity is not billboarded. If "yaw", the entity will be + * oriented to follow your camera around the y-axis. If "full" the entity will be oriented to face your camera. The following deprecated + * behavior is also supported: you can also set "faceCamera" to true to set billboardMode to "yaw", and you can set + * "isFacingAvatar" to true to set billboardMode to "full". Setting either to false sets the mode to "none" + * @property {Rect} subImage={ x: 0, y: 0, width: -1, height: -1 } - The portion of the image to display. If width or height are -1, defaults to + * the full image in that dimension. + * @property {Color} color=255,255,255 - The color of image. + * @property {number} alpha=1 - The alpha of the image. + * @example Create a image entity. + * var image = Entities.addEntity({ + * type: "Image", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, + * imageURL: "https://images.pexels.com/photos/1020315/pexels-photo-1020315.jpeg", + * billboardMode: "yaw", + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics, EntityPsuedoPropertyFlags psueudoPropertyFlags) const { @@ -1401,7 +1443,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(PROP_TEXT_COLOR, textColor, getTextColor(), u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(PROP_BACKGROUND_COLOR, backgroundColor, getBackgroundColor(), u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); } // Zones only @@ -1482,6 +1524,26 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_DATA, materialData); } + // Image only + if (_type == EntityTypes::Image) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SUB_IMAGE, subImage); + + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); + + // Handle conversions to old 'textures' property from "imageURL" + if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) && + (!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) { + QScriptValue textures = engine->newObject(); + textures.setProperty("tex.picture", _imageURL); + properties.setProperty("textures", textures); + } + } + /**jsdoc * The axis-aligned bounding box of an entity. * @typedef {object} Entities.BoundingBox @@ -1570,6 +1632,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID())); } + if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FaceCamera)) { + properties.setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); + } + if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::IsFacingAvatar)) { + properties.setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); + } + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -1698,13 +1767,17 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(href, QString, setHref); COPY_PROPERTY_FROM_QSCRIPTVALUE(description, QString, setDescription); - COPY_PROPERTY_FROM_QSCRIPTVALUE(faceCamera, bool, setFaceCamera); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(actionData, QByteArray, setActionData); COPY_PROPERTY_FROM_QSCRIPTVALUE(normals, qVectorVec3, setNormals); COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeColors, qVectorVec3, setStrokeColors); COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths, qVectorFloat, setStrokeWidths); COPY_PROPERTY_FROM_QSCRIPTVALUE(isUVModeStretch, bool, setIsUVModeStretch); + COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE(emissive, bool, setEmissive); + COPY_PROPERTY_FROM_QSCRIPTVALUE(keepAspectRatio, bool, setKeepAspectRatio); + COPY_PROPERTY_FROM_QSCRIPTVALUE(subImage, QRect, setSubImage); if (!honorReadOnly) { // this is used by the json reader to set things that we don't want javascript to able to affect. @@ -1768,6 +1841,47 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneAvatarEntity, bool, setCloneAvatarEntity); COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneOriginID, QUuid, setCloneOriginID); + // Handle conversions from old 'textures' property to "imageURL" + { + QScriptValue V = object.property("textures"); + if (V.isValid()) { + bool isValid = false; + QString textures = QString_convertFromScriptValue(V, isValid); + if (isValid) { + QVariantMap texturesMap = parseTexturesToMap(textures, QVariantMap()); + auto texPicture = texturesMap.find("tex.picture"); + if (texPicture != texturesMap.end()) { + auto imageURL = texPicture.value().toString(); + if (_defaultSettings || imageURL != _imageURL) { + setImageURL(imageURL); + } + } + } + } + } + + // Handle old "faceCamera" and "isFacingAvatar" props + { + QScriptValue P = object.property("faceCamera"); + if (P.isValid()) { + bool newValue = P.toVariant().toBool(); + bool oldValue = getBillboardMode() == BillboardMode::YAW; + if (_defaultSettings || newValue != oldValue) { + setBillboardMode(newValue ? BillboardMode::YAW : BillboardMode::NONE); + } + } + } + { + QScriptValue P = object.property("isFacingAvatar"); + if (P.isValid()) { + bool newValue = P.toVariant().toBool(); + bool oldValue = getBillboardMode() == BillboardMode::FULL; + if (_defaultSettings || newValue != oldValue) { + setBillboardMode(newValue ? BillboardMode::FULL : BillboardMode::NONE); + } + } + } + _lastEdited = usecTimestampNow(); } @@ -1844,6 +1958,11 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(spinFinish); COPY_PROPERTY_IF_CHANGED(rotateWithEntity); + COPY_PROPERTY_IF_CHANGED(imageURL); + COPY_PROPERTY_IF_CHANGED(emissive); + COPY_PROPERTY_IF_CHANGED(keepAspectRatio); + COPY_PROPERTY_IF_CHANGED(subImage); + // Certifiable Properties COPY_PROPERTY_IF_CHANGED(itemName); COPY_PROPERTY_IF_CHANGED(itemDescription); @@ -1874,7 +1993,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(linePoints); COPY_PROPERTY_IF_CHANGED(href); COPY_PROPERTY_IF_CHANGED(description); - COPY_PROPERTY_IF_CHANGED(faceCamera); + COPY_PROPERTY_IF_CHANGED(billboardMode); COPY_PROPERTY_IF_CHANGED(actionData); COPY_PROPERTY_IF_CHANGED(normals); COPY_PROPERTY_IF_CHANGED(strokeColors); @@ -2092,7 +2211,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); ADD_PROPERTY_TO_MAP(PROP_DESCRIPTION, Description, description, QString); - ADD_PROPERTY_TO_MAP(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool); + ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode); ADD_PROPERTY_TO_MAP(PROP_ACTION_DATA, ActionData, actionData, QByteArray); ADD_PROPERTY_TO_MAP(PROP_NORMALS, Normals, normals, QVector); ADD_PROPERTY_TO_MAP(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector); @@ -2198,6 +2317,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, EquippableIndicatorOffset, equippableIndicatorOffset); + ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); + ADD_PROPERTY_TO_MAP(PROP_EMISSIVE, Emissive, emissive, bool); + ADD_PROPERTY_TO_MAP(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool); + ADD_PROPERTY_TO_MAP(PROP_SUB_IMAGE, SubImage, subImage, QRect); + // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2361,7 +2485,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, properties.getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor()); - APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, properties.getFaceCamera()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode()); } if (properties.getType() == EntityTypes::Model) { @@ -2519,6 +2643,18 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, properties.getMaterialData()); } + // Image + if (properties.getType() == EntityTypes::Image) { + APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); + APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive()); + APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, properties.getKeepAspectRatio()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode()); + APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, properties.getSubImage()); + + APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); + } + APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); @@ -2764,7 +2900,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_COLOR, u8vec3Color, setTextColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, u8vec3Color, setBackgroundColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FACE_CAMERA, bool, setFaceCamera); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); } if (properties.getType() == EntityTypes::Model) { @@ -2914,6 +3050,18 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_DATA, QString, setMaterialData); } + // Image + if (properties.getType() == EntityTypes::Image) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMISSIVE, bool, setEmissive); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SUB_IMAGE, QRect, setSubImage); + + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); + } + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); @@ -3190,7 +3338,7 @@ void EntityItemProperties::markAllChanged() { _hrefChanged = true; _descriptionChanged = true; - _faceCameraChanged = true; + _billboardModeChanged = true; _actionDataChanged = true; _normalsChanged = true; @@ -3240,6 +3388,11 @@ void EntityItemProperties::markAllChanged() { _cloneOriginIDChanged = true; _isVisibleInSecondaryCameraChanged = true; + + _imageURLChanged = true; + _emissiveChanged = true; + _keepAspectRatioChanged = true; + _subImageChanged = true; } // The minimum bounding box for the entity. @@ -3776,6 +3929,23 @@ QList EntityItemProperties::listChangedProperties() { out += "cloneOriginID"; } + if (imageURLChanged()) { + out += "imageURL"; + } + if (emissiveChanged()) { + out += "emissive"; + } + if (keepAspectRatioChanged()) { + out += "keepAspectRatio"; + } + if (subImageChanged()) { + out += "subImage"; + } + + if (billboardModeChanged()) { + out += "billboardMode"; + } + getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 4d45f280e2..a34af703fb 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -48,6 +48,7 @@ #include "ZoneEntityItem.h" #include "MaterialMappingMode.h" +#include "BillboardMode.h" const quint64 UNKNOWN_CREATED_TIME = 0; @@ -68,18 +69,20 @@ using u8vec3Color = glm::u8vec3; class EntityItemProperties { // TODO: consider removing these friend relationship and use public methods friend class EntityItem; - friend class ModelEntityItem; friend class BoxEntityItem; friend class SphereEntityItem; - friend class LightEntityItem; - friend class TextEntityItem; - friend class ParticleEffectEntityItem; - friend class ZoneEntityItem; - friend class WebEntityItem; - friend class LineEntityItem; - friend class PolyVoxEntityItem; - friend class PolyLineEntityItem; friend class ShapeEntityItem; + friend class ModelEntityItem; + friend class TextEntityItem; + friend class ImageEntityItem; + friend class WebEntityItem; + friend class ParticleEffectEntityItem; + friend class LineEntityItem; + friend class PolyLineEntityItem; + friend class PolyVoxEntityItem; + friend class GridEntityItem; + friend class LightEntityItem; + friend class ZoneEntityItem; friend class MaterialEntityItem; public: EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); @@ -213,7 +216,7 @@ public: DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString, ""); - DEFINE_PROPERTY(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool, TextEntityItem::DEFAULT_FACE_CAMERA); + DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE); DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray, QByteArray()); DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); @@ -250,6 +253,11 @@ public: DEFINE_PROPERTY(PROP_SPIN_FINISH, SpinFinish, spinFinish, float, particle::DEFAULT_SPIN_FINISH); DEFINE_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, RotateWithEntity, rotateWithEntity, bool, particle::DEFAULT_ROTATE_WITH_ENTITY); + DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); + DEFINE_PROPERTY_REF(PROP_EMISSIVE, Emissive, emissive, bool, false); + DEFINE_PROPERTY_REF(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool, true); + DEFINE_PROPERTY_REF(PROP_SUB_IMAGE, SubImage, subImage, QRect, QRect()); + // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index d3a2dc6cec..225b77bd97 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -122,6 +122,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } + inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); return QScriptValue(QString(b64)); @@ -323,6 +325,13 @@ inline glm::quat quat_convertFromScriptValue(const QScriptValue& v, bool& isVali return glm::quat(); } +inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = true; + QRect rect; + qRectFromScriptValue(v, rect); + return rect; +} + #define COPY_PROPERTY_IF_CHANGED(P) \ { \ if (other._##P##Changed) { \ diff --git a/libraries/entities/src/EntityPropertyFlags.cpp b/libraries/entities/src/EntityPropertyFlags.cpp index c077b153b8..d4aeac3a78 100644 --- a/libraries/entities/src/EntityPropertyFlags.cpp +++ b/libraries/entities/src/EntityPropertyFlags.cpp @@ -67,7 +67,7 @@ QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) { result = f.getHasProperty(PROP_LINE_POINTS) ? result + "linePoints " : result; result = f.getHasProperty(PROP_HREF) ? result + "href " : result; result = f.getHasProperty(PROP_DESCRIPTION) ? result + "description " : result; - result = f.getHasProperty(PROP_FACE_CAMERA) ? result + "faceCamera " : result; + result = f.getHasProperty(PROP_BILLBOARD_MODE) ? result + "billboardMode " : result; result = f.getHasProperty(PROP_SCRIPT_TIMESTAMP) ? result + "scriptTimestamp " : result; result = f.getHasProperty(PROP_ACTION_DATA) ? result + "actionData " : result; result = f.getHasProperty(PROP_X_TEXTURE_URL) ? result + "xTextureUrl " : result; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index d2f687fbd3..803d391e11 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -99,7 +99,7 @@ enum EntityPropertyList { PROP_HREF, PROP_DESCRIPTION, // 61 - PROP_FACE_CAMERA, + PROP_BILLBOARD_MODE, PROP_SCRIPT_TIMESTAMP, PROP_ACTION_DATA, @@ -275,6 +275,9 @@ enum EntityPropertyList { PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, + PROP_EMISSIVE, + PROP_SUB_IMAGE, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, @@ -308,6 +311,11 @@ enum EntityPropertyList { // other properties which will never overlap with each other. PROP_EMITTING_PARTICLES = PROP_ANIMATION_PLAYING, + // Aliases/Piggyback properties for Image. These properties intentionally reuse the enum values for + // other properties which will never overlap with each other. + PROP_IMAGE_URL = PROP_MODEL_URL, + PROP_KEEP_ASPECT_RATIO = PROP_ANIMATION_PLAYING, + // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; diff --git a/libraries/entities/src/EntityPsuedoPropertyFlags.h b/libraries/entities/src/EntityPsuedoPropertyFlags.h index 0b051a4c74..cb5f4ebfba 100644 --- a/libraries/entities/src/EntityPsuedoPropertyFlags.h +++ b/libraries/entities/src/EntityPsuedoPropertyFlags.h @@ -32,6 +32,8 @@ namespace EntityPsuedoPropertyFlag { RenderInfo, ClientOnly, OwningAvatarID, + FaceCamera, + IsFacingAvatar, NumFlags }; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 3d68a27bc9..8ad1efd36e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -681,6 +681,10 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ClientOnly); } else if (extendedPropertyString == "owningAvatarID") { psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::OwningAvatarID); + } else if (extendedPropertyString == "faceCamera") { + psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FaceCamera); + } else if (extendedPropertyString == "isFacingAvatar") { + psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::IsFacingAvatar); } }; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 9611063f8b..e511af83b0 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -20,38 +20,42 @@ #include "EntityItemProperties.h" #include "EntitiesLogging.h" -#include "LightEntityItem.h" +#include "ShapeEntityItem.h" #include "ModelEntityItem.h" #include "ParticleEffectEntityItem.h" #include "TextEntityItem.h" +#include "ImageEntityItem.h" #include "WebEntityItem.h" -#include "ZoneEntityItem.h" #include "LineEntityItem.h" -#include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" -#include "ShapeEntityItem.h" +#include "PolyVoxEntityItem.h" +#include "GridEntityItem.h" +#include "LightEntityItem.h" +#include "ZoneEntityItem.h" #include "MaterialEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; -EntityTypeFactory EntityTypes::_factories[EntityTypes::LAST + 1]; +EntityTypeFactory EntityTypes::_factories[EntityTypes::NUM_TYPES]; bool EntityTypes::_factoriesInitialized = false; const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown"; // Register Entity the default implementations of entity types here... -REGISTER_ENTITY_TYPE(Model) -REGISTER_ENTITY_TYPE(Web) -REGISTER_ENTITY_TYPE(Light) -REGISTER_ENTITY_TYPE(Text) -REGISTER_ENTITY_TYPE(ParticleEffect) -REGISTER_ENTITY_TYPE(Zone) -REGISTER_ENTITY_TYPE(Line) -REGISTER_ENTITY_TYPE(PolyVox) -REGISTER_ENTITY_TYPE(PolyLine) -REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) +REGISTER_ENTITY_TYPE(Shape) +REGISTER_ENTITY_TYPE(Model) +REGISTER_ENTITY_TYPE(Text) +REGISTER_ENTITY_TYPE(Image) +REGISTER_ENTITY_TYPE(Web) +REGISTER_ENTITY_TYPE(ParticleEffect) +REGISTER_ENTITY_TYPE(Line) +REGISTER_ENTITY_TYPE(PolyLine) +REGISTER_ENTITY_TYPE(PolyVox) +REGISTER_ENTITY_TYPE(Grid) +REGISTER_ENTITY_TYPE(Light) +REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Material) const QString& EntityTypes::getEntityTypeName(EntityType entityType) { @@ -80,7 +84,7 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En memset(&_factories,0,sizeof(_factories)); _factoriesInitialized = true; } - if (entityType >= 0 && entityType <= LAST) { + if (entityType >= 0 && entityType < NUM_TYPES) { _factories[entityType] = factoryMethod; return true; } @@ -91,7 +95,7 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const const EntityItemProperties& properties) { EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; - if (entityType >= 0 && entityType <= LAST) { + if (entityType >= 0 && entityType < NUM_TYPES) { factory = _factories[entityType]; } if (factory) { diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 954bdf8f17..604f2fe905 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -49,25 +49,6 @@ public: * "Cube". If an entity of type Shape or Sphere has its shape set * to "Cube" then its type will be reported as "Box". * {@link Entities.EntityProperties-Box|EntityProperties-Box} - * "Light"A local lighting effect. - * {@link Entities.EntityProperties-Light|EntityProperties-Light} - * "Line"A sequence of one or more simple straight lines. - * {@link Entities.EntityProperties-Line|EntityProperties-Line} - * "Material"Modifies the existing materials on Model entities, Shape entities (albedo - * only), {@link Overlays.OverlayType|model overlays}, and avatars. - * {@link Entities.EntityProperties-Material|EntityProperties-Material} - * "Model"A mesh model from an FBX or OBJ file. - * {@link Entities.EntityProperties-Model|EntityProperties-Model} - * "ParticleEffect"A particle system that can be used to simulate things such as fire, - * smoke, snow, magic spells, etc. - * {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} - * "PolyLine"A sequence of one or more textured straight lines. - * {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} - * "PolyVox"A set of textured voxels. - * {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * "Shape"A basic entity such as a cube. - * See also, the "Box" and "Sphere" entity types. - * {@link Entities.EntityProperties-Shape|EntityProperties-Shape} * "Sphere"A sphere. This is a synonym of "Shape" for the case * where the entity's shape property value is "Sphere".
* If an entity is created with its type @@ -75,32 +56,57 @@ public: * "Sphere". If an entity of type Box or Shape has its shape set * to "Sphere" then its type will be reported as "Sphere". * {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} + * "Shape"A basic entity such as a cube. + * See also, the "Box" and "Sphere" entity types. + * {@link Entities.EntityProperties-Shape|EntityProperties-Shape} + * "Model"A mesh model from an FBX or OBJ file. + * {@link Entities.EntityProperties-Model|EntityProperties-Model} * "Text"A pane of text oriented in space. * {@link Entities.EntityProperties-Text|EntityProperties-Text} + * "Image"An image oriented in space. + * {@link Entities.EntityProperties-Image|EntityProperties-Image} * "Web"A browsable Web page. * {@link Entities.EntityProperties-Web|EntityProperties-Web} + * "ParticleEffect"A particle system that can be used to simulate things such as fire, + * smoke, snow, magic spells, etc. + * {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} + * "Line"A sequence of one or more simple straight lines. + * {@link Entities.EntityProperties-Line|EntityProperties-Line} + * "PolyLine"A sequence of one or more textured straight lines. + * {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} + * "PolyVox"A set of textured voxels. + * {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} + * "Grid"A grid. + * {@link Entities.EntityProperties-Grid|EntityProperties-Grid} + * "Light"A local lighting effect. + * {@link Entities.EntityProperties-Light|EntityProperties-Light} * "Zone"A volume of lighting effects and avatar permissions. * {@link Entities.EntityProperties-Zone|EntityProperties-Zone} + * "Material"Modifies the existing materials on Model entities, Shape entities, + * {@link Overlays.OverlayType|model overlays}, and avatars. + * {@link Entities.EntityProperties-Material|EntityProperties-Material} * * * @typedef {string} Entities.EntityType */ typedef enum EntityType_t { Unknown, - Model, Box, Sphere, - Light, - Text, - ParticleEffect, - Zone, - Web, - Line, - PolyVox, - PolyLine, Shape, + Model, + Text, + Image, + Web, + ParticleEffect, + Line, + PolyLine, + PolyVox, + Grid, + Light, + Zone, Material, - LAST = Material + NUM_TYPES } EntityType; static const QString& getEntityTypeName(EntityType entityType); @@ -112,7 +118,7 @@ public: private: static QMap _typeToNameMap; static QMap _nameToTypeMap; - static EntityTypeFactory _factories[LAST + 1]; + static EntityTypeFactory _factories[NUM_TYPES]; static bool _factoriesInitialized; }; diff --git a/libraries/entities/src/GridEntityItem.cpp b/libraries/entities/src/GridEntityItem.cpp new file mode 100644 index 0000000000..cc59135e8d --- /dev/null +++ b/libraries/entities/src/GridEntityItem.cpp @@ -0,0 +1,154 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GridEntityItem.h" + +#include "EntityItemProperties.h" + +EntityItemPointer GridEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new GridEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +GridEntityItem::GridEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Grid; +} + +EntityItemProperties GridEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + + //COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getGridURL); + //COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive); + //COPY_ENTITY_PROPERTY_TO_PROPERTIES(keepAspectRatio, getKeepAspectRatio); + //COPY_ENTITY_PROPERTY_TO_PROPERTIES(faceCamera, getFaceCamera); + //COPY_ENTITY_PROPERTY_TO_PROPERTIES(subGrid, getSubGrid); + + return properties; +} + +bool GridEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setGridURL); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(faceCamera, setFaceCamera); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(subGrid, setSubGrid); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "GridEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +int GridEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + //READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setGridURL); + //READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive); + //READ_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); + //READ_ENTITY_PROPERTY(PROP_FACE_CAMERA, bool, setFaceCamera); + //READ_ENTITY_PROPERTY(PROP_SUB_IMAGE, QRect, setSubGrid); + + return bytesRead; +} + +EntityPropertyFlags GridEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + + //requestedProperties += PROP_IMAGE_URL; + //requestedProperties += PROP_EMISSIVE; + //requestedProperties += PROP_KEEP_ASPECT_RATIO; + //requestedProperties += PROP_FACE_CAMERA; + //requestedProperties += PROP_SUB_IMAGE; + + return requestedProperties; +} + +void GridEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + //APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getGridURL()); + //APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive()); + //APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, getKeepAspectRatio()); + //APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, getFaceCamera()); + //APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubGrid()); +} + +bool GridEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, + float& distance, BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + glm::vec3 dimensions = getScaledDimensions(); + glm::vec2 xyDimensions(dimensions.x, dimensions.y); + glm::quat rotation = getWorldOrientation(); + glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); + + 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 GridEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, + OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + glm::vec3 dimensions = getScaledDimensions(); + glm::vec2 xyDimensions(dimensions.x, dimensions.y); + glm::quat rotation = getWorldOrientation(); + glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); + + 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; +} \ No newline at end of file diff --git a/libraries/entities/src/GridEntityItem.h b/libraries/entities/src/GridEntityItem.h new file mode 100644 index 0000000000..4704d96f3d --- /dev/null +++ b/libraries/entities/src/GridEntityItem.h @@ -0,0 +1,56 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GridEntityItem_h +#define hifi_GridEntityItem_h + +#include "EntityItem.h" + +class GridEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + GridEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + + // methods for getting/setting all properties of an entity + EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; + bool setProperties(const EntityItemProperties& properties) override; + + EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + virtual bool supportsDetailedIntersection() const override { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, + const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + +protected: + +}; + +#endif // hifi_GridEntityItem_h diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp new file mode 100644 index 0000000000..98817a63ba --- /dev/null +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -0,0 +1,269 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ImageEntityItem.h" + +#include "EntityItemProperties.h" + +EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new ImageEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Image; +} + +void ImageEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float IMAGE_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + // NOTE: Image Entities always have a "depth" of 1cm. + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, IMAGE_ENTITY_ITEM_FIXED_DEPTH)); +} + +EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(keepAspectRatio, getKeepAspectRatio); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(subImage, getSubImage); + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); + + return properties; +} + +bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(subImage, setSubImage); + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "ImageEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL); + READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive); + READ_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); + READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); + READ_ENTITY_PROPERTY(PROP_SUB_IMAGE, QRect, setSubImage); + + READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor); + READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); + + return bytesRead; +} + +EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + + requestedProperties += PROP_IMAGE_URL; + requestedProperties += PROP_EMISSIVE; + requestedProperties += PROP_KEEP_ASPECT_RATIO; + requestedProperties += PROP_BILLBOARD_MODE; + requestedProperties += PROP_SUB_IMAGE; + + requestedProperties += PROP_COLOR; + requestedProperties += PROP_ALPHA; + + return requestedProperties; +} + +void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL()); + APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive()); + APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, getKeepAspectRatio()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode()); + APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubImage()); + + APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); +} + +bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, + float& distance, BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + glm::vec3 dimensions = getScaledDimensions(); + glm::vec2 xyDimensions(dimensions.x, dimensions.y); + glm::quat rotation = getWorldOrientation(); + glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); + + 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 ImageEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, + OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + glm::vec3 dimensions = getScaledDimensions(); + glm::vec2 xyDimensions(dimensions.x, dimensions.y); + glm::quat rotation = getWorldOrientation(); + glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); + + 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; +} + +QString ImageEntityItem::getImageURL() const { + QString result; + withReadLock([&] { + result = _imageURL; + }); + return result; +} + +void ImageEntityItem::setImageURL(const QString& url) { + withWriteLock([&] { + _imageURL = url; + }); +} + +bool ImageEntityItem::getEmissive() const { + bool result; + withReadLock([&] { + result = _emissive; + }); + return result; +} + +void ImageEntityItem::setEmissive(bool emissive) { + withWriteLock([&] { + _emissive = emissive; + }); +} + +bool ImageEntityItem::getKeepAspectRatio() const { + bool result; + withReadLock([&] { + result = _keepAspectRatio; + }); + return result; +} + +void ImageEntityItem::setKeepAspectRatio(bool keepAspectRatio) { + withWriteLock([&] { + _keepAspectRatio = keepAspectRatio; + }); +} + +BillboardMode ImageEntityItem::getBillboardMode() const { + BillboardMode result; + withReadLock([&] { + result = _billboardMode; + }); + return result; +} + +void ImageEntityItem::setBillboardMode(BillboardMode value) { + withWriteLock([&] { + _billboardMode = value; + }); +} + +QRect ImageEntityItem::getSubImage() const { + QRect result; + withReadLock([&] { + result = _subImage; + }); + return result; +} + +void ImageEntityItem::setSubImage(const QRect& subImage) { + withWriteLock([&] { + _subImage = subImage; + }); +} + +void ImageEntityItem::setColor(const glm::u8vec3& color) { + withWriteLock([&] { + _color = color; + }); +} + +glm::u8vec3 ImageEntityItem::getColor() const { + return resultWithReadLock([&] { + return _color; + }); +} + +void ImageEntityItem::setAlpha(float alpha) { + withWriteLock([&] { + _alpha = alpha; + }); +} + +float ImageEntityItem::getAlpha() const { + return resultWithReadLock([&] { + return _alpha; + }); +} \ No newline at end of file diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h new file mode 100644 index 0000000000..228f86ca03 --- /dev/null +++ b/libraries/entities/src/ImageEntityItem.h @@ -0,0 +1,86 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ImageEntityItem_h +#define hifi_ImageEntityItem_h + +#include "EntityItem.h" + +class ImageEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + ImageEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + + virtual void setUnscaledDimensions(const glm::vec3& value) override; + + // methods for getting/setting all properties of an entity + EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; + bool setProperties(const EntityItemProperties& properties) override; + + EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + virtual bool supportsDetailedIntersection() const override { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, + const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + + void setImageURL(const QString& imageUrl); + QString getImageURL() const; + + void setEmissive(bool emissive); + bool getEmissive() const; + + void setKeepAspectRatio(bool keepAspectRatio); + bool getKeepAspectRatio() const; + + void setBillboardMode(BillboardMode value); + BillboardMode getBillboardMode() const; + + void setSubImage(const QRect& subImage); + QRect getSubImage() const; + + void setColor(const glm::u8vec3& color); + glm::u8vec3 getColor() const; + + void setAlpha(float alpha); + float getAlpha() const; + +protected: + QString _imageURL; + bool _emissive { false }; + bool _keepAspectRatio { true }; + BillboardMode _billboardMode; + QRect _subImage; + + glm::u8vec3 _color; + float _alpha; +}; + +#endif // hifi_ImageEntityItem_h diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 8dd4877ce2..b178ce33c3 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -27,7 +27,6 @@ const QString TextEntityItem::DEFAULT_TEXT(""); const float TextEntityItem::DEFAULT_LINE_HEIGHT = 0.1f; const glm::u8vec3 TextEntityItem::DEFAULT_TEXT_COLOR = { 255, 255, 255 }; const glm::u8vec3 TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0}; -const bool TextEntityItem::DEFAULT_FACE_CAMERA = false; EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity(new TextEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); @@ -39,9 +38,8 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en _type = EntityTypes::Text; } -const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; - void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; // NOTE: Text Entities always have a "depth" of 1cm. EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } @@ -53,7 +51,7 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textColor, getTextColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundColor, getBackgroundColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(faceCamera, getFaceCamera); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode); return properties; } @@ -65,7 +63,7 @@ bool TextEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textColor, setTextColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundColor, setBackgroundColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(faceCamera, setFaceCamera); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode); if (somethingChanged) { bool wantDebug = false; @@ -93,7 +91,7 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight); READ_ENTITY_PROPERTY(PROP_TEXT_COLOR, glm::u8vec3, setTextColor); READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, glm::u8vec3, setBackgroundColor); - READ_ENTITY_PROPERTY(PROP_FACE_CAMERA, bool, setFaceCamera); + READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); return bytesRead; } @@ -104,7 +102,7 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_LINE_HEIGHT; requestedProperties += PROP_TEXT_COLOR; requestedProperties += PROP_BACKGROUND_COLOR; - requestedProperties += PROP_FACE_CAMERA; + requestedProperties += PROP_BILLBOARD_MODE; return requestedProperties; } @@ -122,7 +120,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor()); - APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, getFaceCamera()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode()); } @@ -230,17 +228,17 @@ glm::u8vec3 TextEntityItem::getBackgroundColor() const { }); } -bool TextEntityItem::getFaceCamera() const { - bool result; +BillboardMode TextEntityItem::getBillboardMode() const { + BillboardMode result; withReadLock([&] { - result = _faceCamera; + result = _billboardMode; }); return result; } -void TextEntityItem::setFaceCamera(bool value) { +void TextEntityItem::setBillboardMode(BillboardMode value) { withWriteLock([&] { - _faceCamera = value; + _billboardMode = value; }); } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 357697fdec..9abef4d198 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -71,16 +71,15 @@ public: glm::u8vec3 getBackgroundColor() const; void setBackgroundColor(const glm::u8vec3& value); - static const bool DEFAULT_FACE_CAMERA; - bool getFaceCamera() const; - void setFaceCamera(bool value); + BillboardMode getBillboardMode() const; + void setBillboardMode(BillboardMode value); private: QString _text; float _lineHeight; glm::u8vec3 _textColor; glm::u8vec3 _backgroundColor; - bool _faceCamera; + BillboardMode _billboardMode; }; #endif // hifi_TextEntityItem_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 9e3ecdfb39..3325faa95c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::CleanupProperties); + return static_cast(EntityVersion::ImageEntities); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 800ce7bbe7..421c9a96c1 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -245,7 +245,8 @@ enum class EntityVersion : PacketVersion { GrabProperties, ScriptGlmVectors, FixedLightSerialization, - CleanupProperties + CleanupProperties, + ImageEntities }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 88e83c01c8..6c0bba5ec6 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -546,6 +546,17 @@ bool OctreePacketData::appendValue(const AACube& aaCube) { return success; } +bool OctreePacketData::appendValue(const QRect& value) { + const unsigned char* data = (const unsigned char*)&value; + int length = sizeof(QRect); + bool success = append(data, length); + if (success) { + _bytesOfValues += length; + _totalBytesOfValues += length; + } + return success; +} + bool OctreePacketData::appendPosition(const glm::vec3& value) { const unsigned char* data = (const unsigned char*)&value; int length = sizeof(value); @@ -804,3 +815,8 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, AACube result = AACube(cube.corner, cube.scale); return sizeof(aaCubeData); } + +int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QRect& result) { + memcpy(&result, dataBytes, sizeof(result)); + return sizeof(result); +} \ No newline at end of file diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 46726d83a6..bd1abf8744 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -34,6 +34,7 @@ #include #include "MaterialMappingMode.h" +#include "BillboardMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -197,6 +198,9 @@ public: /// appends an AACube value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const AACube& aaCube); + /// appends an QRect value to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QRect& rect); + /// appends a position to the end of the stream, may fail if new data stream is too long to fit in packet bool appendPosition(const glm::vec3& value); @@ -258,6 +262,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; } static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMappingMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, BillboardMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); @@ -269,6 +274,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); static int unpackDataFromBytes(const unsigned char* dataBytes, AACube& result); + static int unpackDataFromBytes(const unsigned char* dataBytes, QRect& result); private: /// appends raw bytes, might fail if byte would cause packet to be too large diff --git a/libraries/shared/src/BillboardMode.cpp b/libraries/shared/src/BillboardMode.cpp new file mode 100644 index 0000000000..56251f53f2 --- /dev/null +++ b/libraries/shared/src/BillboardMode.cpp @@ -0,0 +1,25 @@ +// +// Created by Sam Gondelman on 11/30/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BillboardMode.h" + +const char* billboardModeNames[] = { + "none", + "yaw", + "full" +}; + +static const size_t MATERIAL_MODE_NAMES = (sizeof(billboardModeNames) / sizeof((billboardModeNames)[0])); + +QString BillboardModeHelpers::getNameForBillboardMode(BillboardMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { + mode = (BillboardMode)0; + } + + return billboardModeNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/BillboardMode.h b/libraries/shared/src/BillboardMode.h new file mode 100644 index 0000000000..7f3e79d453 --- /dev/null +++ b/libraries/shared/src/BillboardMode.h @@ -0,0 +1,26 @@ +// +// Created by Sam Gondelman on 11/30/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BillboardMode_h +#define hifi_BillboardMode_h + +#include "QString" + +enum class BillboardMode { + NONE = 0, + YAW, + FULL +}; + +class BillboardModeHelpers { +public: + static QString getNameForBillboardMode(BillboardMode mode); +}; + +#endif // hifi_BillboardMode_h + diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index dc84afff93..5394a0f448 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -24,6 +24,7 @@ #include #include #include +#include int vec2MetaTypeId = qRegisterMetaType(); int u8vec3MetaTypeId = qRegisterMetaType(); @@ -1245,3 +1246,31 @@ void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector result << meshFace; } } + +QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures) { + // If textures are unset, revert to original textures + if (textures.isEmpty()) { + return defaultTextures; + } + + // Legacy: a ,\n-delimited list of filename:"texturepath" + if (*textures.cbegin() != '{') { + textures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}"; + } + + QJsonParseError error; + QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error); + // If textures are invalid, revert to original textures + if (error.error != QJsonParseError::NoError) { + qWarning() << "Could not evaluate textures property value:" << textures; + return defaultTextures; + } + + QVariantMap texturesMap = texturesJson.toVariant().toMap(); + // If textures are unset, revert to original textures + if (texturesMap.isEmpty()) { + return defaultTextures; + } + + return texturesJson.toVariant().toMap(); +} \ No newline at end of file diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index ed637fe771..9d5bca6b9f 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -705,5 +705,7 @@ void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResul QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector& result); +QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures); + #endif // hifi_RegisteredMetaTypes_h diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 077d50ddde..8d5271093e 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -42,7 +42,6 @@ var TITLE_OFFSET = 60; var CREATE_TOOLS_WIDTH = 490; var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942; -var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg"; var createToolsWindow = new CreateWindow( @@ -398,8 +397,8 @@ const DEFAULT_ENTITY_PROPERTIES = { }, shapeType: "box", collisionless: true, - modelURL: IMAGE_MODEL, - textures: JSON.stringify({ "tex.picture": "" }) + keepAspectRatio: false, + imageURL: DEFAULT_IMAGE }, Web: { dimensions: { @@ -495,9 +494,6 @@ var toolBar = (function () { var type = requestedProperties.type; if (type === "Box" || type === "Sphere") { applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape); - } else if (type === "Image") { - requestedProperties.type = "Model"; - applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Image); } else { applyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]); } @@ -515,7 +511,7 @@ var toolBar = (function () { } direction = Vec3.multiplyQbyV(direction, Vec3.UNIT_Z); - var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"]; + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web", "Material"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 84ad59df36..a0520cda4f 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -11,7 +11,6 @@ const DESCENDING_SORT = -1; const ASCENDING_STRING = '▴'; const DESCENDING_STRING = '▾'; const BYTES_PER_MEGABYTE = 1024 * 1024; -const IMAGE_MODEL_NAME = 'default-image-model.fbx'; const COLLAPSE_EXTRA_INFO = "E"; const EXPAND_EXTRA_INFO = "D"; const FILTER_IN_VIEW_ATTRIBUTE = "pressed"; @@ -625,9 +624,6 @@ function loaded() { entityData.forEach(function(entity) { let type = entity.type; let filename = getFilename(entity.url); - if (filename === IMAGE_MODEL_NAME) { - type = "Image"; - } let entityData = { id: entity.id, diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 78e3cd4dc8..da16f6c504 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -471,7 +471,7 @@ const GROUPS = [ label: "Image", type: "string", placeholder: "URL", - propertyID: "image", + propertyID: "imageURL", }, ] }, @@ -1783,14 +1783,6 @@ function updateCheckedSubProperty(propertyName, propertyValue, subPropertyElemen updateProperty(propertyName, propertyValue, isParticleProperty); } -function createImageURLUpdateFunction(property) { - return function () { - let newTextures = JSON.stringify({ "tex.picture": this.value }); - updateProperty(property.name, newTextures, property.isParticleProperty); - }; -} - - /** * PROPERTY ELEMENT CREATION FUNCTIONS */ @@ -3035,17 +3027,6 @@ function loaded() { // the event bridge and json parsing handle our avatar id string differently. lastEntityID = '"' + selectedEntityProperties.id + '"'; - // HTML workaround since image is not yet a separate entity type - let IMAGE_MODEL_NAME = 'default-image-model.fbx'; - if (selectedEntityProperties.type === "Model") { - let urlParts = selectedEntityProperties.modelURL.split('/'); - let propsFilename = urlParts[urlParts.length - 1]; - - if (propsFilename === IMAGE_MODEL_NAME) { - selectedEntityProperties.type = "Image"; - } - } - showGroupsForType(selectedEntityProperties.type); for (let propertyID in properties) { @@ -3171,10 +3152,7 @@ function loaded() { updateVisibleSpaceModeProperties(); - if (selectedEntityProperties.type === "Image") { - let imageLink = JSON.parse(selectedEntityProperties.textures)["tex.picture"]; - getPropertyInputElement("image").value = imageLink; - } else if (selectedEntityProperties.type === "Material") { + if (selectedEntityProperties.type === "Material") { let elParentMaterialNameString = getPropertyInputElement("materialNameToReplace"); let elParentMaterialNameNumber = getPropertyInputElement("submeshToReplace"); let elParentMaterialNameCheckbox = getPropertyInputElement("selectSubmesh"); @@ -3340,8 +3318,6 @@ function loaded() { } }); - getPropertyInputElement("image").addEventListener('change', createImageURLUpdateFunction(properties['textures'])); - // Collapsible sections let elCollapsible = document.getElementsByClassName("collapse-icon"); diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index eeb16fd60d..edc6bc3845 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -164,7 +164,7 @@ EntityListTool = function(shouldUseEditTabletApp) { var cameraPosition = Camera.position; PROFILE("getMultipleProperties", function () { var multipleProperties = Entities.getMultipleEntityProperties(ids, ['name', 'type', 'locked', - 'visible', 'renderInfo', 'modelURL', 'materialURL', 'script']); + 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script']); for (var i = 0; i < multipleProperties.length; i++) { var properties = multipleProperties[i]; @@ -174,6 +174,8 @@ EntityListTool = function(shouldUseEditTabletApp) { url = properties.modelURL; } else if (properties.type === "Material") { url = properties.materialURL; + } else if (properties.type === "Image") { + url = properties.imageURL; } entities.push({ id: ids[i], From 98f9dc0ca4f5f0056ec683c2b3344b1477bd44f3 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 3 Dec 2018 11:59:19 -0800 Subject: [PATCH 2/4] remove grid entity files --- .../src/RenderableEntityItem.cpp | 5 - .../src/RenderableGridEntityItem.cpp | 51 ------ .../src/RenderableGridEntityItem.h | 36 ---- .../entities/src/EntityItemProperties.cpp | 1 - libraries/entities/src/EntityItemProperties.h | 1 - libraries/entities/src/EntityTypes.cpp | 2 - libraries/entities/src/EntityTypes.h | 3 - libraries/entities/src/GridEntityItem.cpp | 154 ------------------ libraries/entities/src/GridEntityItem.h | 56 ------- 9 files changed, 309 deletions(-) delete mode 100644 libraries/entities-renderer/src/RenderableGridEntityItem.cpp delete mode 100644 libraries/entities-renderer/src/RenderableGridEntityItem.h delete mode 100644 libraries/entities/src/GridEntityItem.cpp delete mode 100644 libraries/entities/src/GridEntityItem.h diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 92387dafa6..6c979f8afe 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -26,7 +26,6 @@ #include "RenderableZoneEntityItem.h" #include "RenderableMaterialEntityItem.h" #include "RenderableImageEntityItem.h" -#include "RenderableGridEntityItem.h" using namespace render; @@ -257,10 +256,6 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, result = make_renderer(entity); break; - case Type::Grid: - result = make_renderer(entity); - break; - case Type::Light: result = make_renderer(entity); break; diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp deleted file mode 100644 index bd42a722fb..0000000000 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "RenderableGridEntityItem.h" - -using namespace render; -using namespace render::entities; - -GridEntityRenderer::GridEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { -} - -bool GridEntityRenderer::needsRenderUpdate() const { - return Parent::needsRenderUpdate(); -} - -bool GridEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { - return false; -} - -void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { - -} - -ItemKey GridEntityRenderer::getKey() { - ItemKey::Builder builder; - builder.withTypeShape().withTypeMeta().withTagBits(getTagMask()); - - withReadLock([&] { - if (isTransparent()) { - builder.withTransparent(); - } else if (_canCastShadow) { - builder.withShadowCaster(); - } - }); - - return builder.build(); -} - -ShapeKey GridEntityRenderer::getShapeKey() { - ShapeKey::Builder builder; - return builder.build(); -} - -void GridEntityRenderer::doRender(RenderArgs* args) { - -} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.h b/libraries/entities-renderer/src/RenderableGridEntityItem.h deleted file mode 100644 index 09c0de1d0d..0000000000 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_RenderableGridEntityItem_h -#define hifi_RenderableGridEntityItem_h - -#include "RenderableEntityItem.h" - -#include - -namespace render { namespace entities { - -class GridEntityRenderer : public TypedEntityRenderer { - using Parent = TypedEntityRenderer; - using Pointer = std::shared_ptr; -public: - GridEntityRenderer(const EntityItemPointer& entity); - -protected: - ItemKey getKey() override; - ShapeKey getShapeKey() override; - -private: - virtual bool needsRenderUpdate() const override; - virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; - virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; - virtual void doRender(RenderArgs* args) override; -}; - -} } -#endif // hifi_RenderableGridEntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f24b14d3b7..6f451f937a 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -684,7 +684,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} * @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} * @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * @see {@link Entities.EntityProperties-Grid|EntityProperties-Grid} * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} * @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone} * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a34af703fb..8a9e22f28c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -80,7 +80,6 @@ class EntityItemProperties { friend class LineEntityItem; friend class PolyLineEntityItem; friend class PolyVoxEntityItem; - friend class GridEntityItem; friend class LightEntityItem; friend class ZoneEntityItem; friend class MaterialEntityItem; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index e511af83b0..30f9d9b541 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -29,7 +29,6 @@ #include "LineEntityItem.h" #include "PolyLineEntityItem.h" #include "PolyVoxEntityItem.h" -#include "GridEntityItem.h" #include "LightEntityItem.h" #include "ZoneEntityItem.h" #include "MaterialEntityItem.h" @@ -53,7 +52,6 @@ REGISTER_ENTITY_TYPE(ParticleEffect) REGISTER_ENTITY_TYPE(Line) REGISTER_ENTITY_TYPE(PolyLine) REGISTER_ENTITY_TYPE(PolyVox) -REGISTER_ENTITY_TYPE(Grid) REGISTER_ENTITY_TYPE(Light) REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Material) diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 604f2fe905..c85cb5b2dd 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -76,8 +76,6 @@ public: * {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} * "PolyVox"A set of textured voxels. * {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * "Grid"A grid. - * {@link Entities.EntityProperties-Grid|EntityProperties-Grid} * "Light"A local lighting effect. * {@link Entities.EntityProperties-Light|EntityProperties-Light} * "Zone"A volume of lighting effects and avatar permissions. @@ -102,7 +100,6 @@ public: Line, PolyLine, PolyVox, - Grid, Light, Zone, Material, diff --git a/libraries/entities/src/GridEntityItem.cpp b/libraries/entities/src/GridEntityItem.cpp deleted file mode 100644 index cc59135e8d..0000000000 --- a/libraries/entities/src/GridEntityItem.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "GridEntityItem.h" - -#include "EntityItemProperties.h" - -EntityItemPointer GridEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - Pointer entity(new GridEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -// our non-pure virtual subclass for now... -GridEntityItem::GridEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Grid; -} - -EntityItemProperties GridEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getGridURL); - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive); - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(keepAspectRatio, getKeepAspectRatio); - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(faceCamera, getFaceCamera); - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(subGrid, getSubGrid); - - return properties; -} - -bool GridEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setGridURL); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(faceCamera, setFaceCamera); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(subGrid, setSubGrid); - - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "GridEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } - return somethingChanged; -} - -int GridEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) { - - int bytesRead = 0; - const unsigned char* dataAt = data; - - //READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setGridURL); - //READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive); - //READ_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); - //READ_ENTITY_PROPERTY(PROP_FACE_CAMERA, bool, setFaceCamera); - //READ_ENTITY_PROPERTY(PROP_SUB_IMAGE, QRect, setSubGrid); - - return bytesRead; -} - -EntityPropertyFlags GridEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - //requestedProperties += PROP_IMAGE_URL; - //requestedProperties += PROP_EMISSIVE; - //requestedProperties += PROP_KEEP_ASPECT_RATIO; - //requestedProperties += PROP_FACE_CAMERA; - //requestedProperties += PROP_SUB_IMAGE; - - return requestedProperties; -} - -void GridEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - //APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getGridURL()); - //APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive()); - //APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, getKeepAspectRatio()); - //APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, getFaceCamera()); - //APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubGrid()); -} - -bool GridEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& element, - float& distance, BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const { - glm::vec3 dimensions = getScaledDimensions(); - glm::vec2 xyDimensions(dimensions.x, dimensions.y); - glm::quat rotation = getWorldOrientation(); - glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); - - 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 GridEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, - OctreeElementPointer& element, float& parabolicDistance, - BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const { - glm::vec3 dimensions = getScaledDimensions(); - glm::vec2 xyDimensions(dimensions.x, dimensions.y); - glm::quat rotation = getWorldOrientation(); - glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); - - 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; -} \ No newline at end of file diff --git a/libraries/entities/src/GridEntityItem.h b/libraries/entities/src/GridEntityItem.h deleted file mode 100644 index 4704d96f3d..0000000000 --- a/libraries/entities/src/GridEntityItem.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_GridEntityItem_h -#define hifi_GridEntityItem_h - -#include "EntityItem.h" - -class GridEntityItem : public EntityItem { - using Pointer = std::shared_ptr; -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - GridEntityItem(const EntityItemID& entityItemID); - - ALLOW_INSTANTIATION // This class can be instantiated - - // methods for getting/setting all properties of an entity - EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setProperties(const EntityItemProperties& properties) override; - - EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const override; - - int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; - - virtual bool supportsDetailedIntersection() const override { return true; } - virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const override; - virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, - const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, - BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const override; - -protected: - -}; - -#endif // hifi_GridEntityItem_h From abef5c4d6178b3e2ed7fa61c99df3c60ae6748d2 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 5 Dec 2018 15:05:01 -0800 Subject: [PATCH 3/4] fix grab billboarding bug --- libraries/entities/src/EntityItemProperties.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 6f451f937a..7af70b4da0 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1843,7 +1843,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool // Handle conversions from old 'textures' property to "imageURL" { QScriptValue V = object.property("textures"); - if (V.isValid()) { + if (_type == EntityTypes::Image && V.isValid() && !object.property("imageURL").isValid()) { bool isValid = false; QString textures = QString_convertFromScriptValue(V, isValid); if (isValid) { @@ -1862,7 +1862,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool // Handle old "faceCamera" and "isFacingAvatar" props { QScriptValue P = object.property("faceCamera"); - if (P.isValid()) { + if (P.isValid() && !object.property("billboardMode").isValid()) { bool newValue = P.toVariant().toBool(); bool oldValue = getBillboardMode() == BillboardMode::YAW; if (_defaultSettings || newValue != oldValue) { @@ -1872,7 +1872,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool } { QScriptValue P = object.property("isFacingAvatar"); - if (P.isValid()) { + if (P.isValid() && !object.property("billboardMode").isValid() && !object.property("faceCamera").isValid()) { bool newValue = P.toVariant().toBool(); bool oldValue = getBillboardMode() == BillboardMode::FULL; if (_defaultSettings || newValue != oldValue) { From 645508de042037f15dbd25212e08649db1340038 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 6 Dec 2018 09:59:24 -0800 Subject: [PATCH 4/4] add jsdocs for BillboardMode --- libraries/shared/src/BillboardMode.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libraries/shared/src/BillboardMode.h b/libraries/shared/src/BillboardMode.h index 7f3e79d453..050f939941 100644 --- a/libraries/shared/src/BillboardMode.h +++ b/libraries/shared/src/BillboardMode.h @@ -11,6 +11,21 @@ #include "QString" +/**jsdoc + *

How an entity is billboarded.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
noneThe entity will not be billboarded.
yawThe entity will yaw, but not pitch, to face the camera. Its actual rotation will be ignored.
fullThe entity will be billboarded to face the camera. Its actual rotation will be ignored.
+ * @typedef {string} BillboardMode + */ + enum class BillboardMode { NONE = 0, YAW,