real image entities

This commit is contained in:
SamGondelman 2018-12-03 11:50:59 -08:00
parent 1fd8a21f8e
commit 3ce6f7f3d6
41 changed files with 1453 additions and 238 deletions

View file

@ -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;

View file

@ -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;

View file

@ -2367,6 +2367,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
});
EntityTreeRenderer::setGetAvatarUpOperator([] {
return DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
});
// Preload Tablet sounds
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
DependencyManager::get<Keyboard>()->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);
}

View file

@ -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;
}

View file

@ -41,6 +41,7 @@
#include <PointerManager.h>
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction = []() { return true; };
std::function<glm::vec3()> EntityTreeRenderer::_getAvatarUpOperator = []() { return Vectors::UP; };
QString resolveScriptURL(const QString& scriptUrl) {
auto normalizedScriptUrl = DependencyManager::get<ResourceManager>()->normalizeURL(scriptUrl);

View file

@ -117,6 +117,9 @@ public:
// Access the workload Space
workload::SpacePointer getWorkloadSpace() const { return _space; }
static void setGetAvatarUpOperator(std::function<glm::vec3()> 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<glm::vec3()> _getAvatarUpOperator;
};

View file

@ -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<LightEntityRenderer>(entity);
break;
case Type::Line:
result = make_renderer<LineEntityRenderer>(entity);
case Type::Shape:
case Type::Box:
case Type::Sphere:
result = make_renderer<ShapeEntityRenderer>(entity);
break;
case Type::Model:
result = make_renderer<ModelEntityRenderer>(entity);
break;
case Type::Text:
result = make_renderer<TextEntityRenderer>(entity);
break;
case Type::Image:
result = make_renderer<ImageEntityRenderer>(entity);
break;
case Type::Web:
if (!nsightActive()) {
result = make_renderer<WebEntityRenderer>(entity);
}
break;
case Type::ParticleEffect:
result = make_renderer<ParticleEffectEntityRenderer>(entity);
break;
case Type::Line:
result = make_renderer<LineEntityRenderer>(entity);
break;
case Type::PolyLine:
result = make_renderer<PolyLineEntityRenderer>(entity);
break;
@ -238,20 +257,12 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer,
result = make_renderer<PolyVoxEntityRenderer>(entity);
break;
case Type::Shape:
case Type::Box:
case Type::Sphere:
result = make_renderer<ShapeEntityRenderer>(entity);
case Type::Grid:
result = make_renderer<GridEntityRenderer>(entity);
break;
case Type::Text:
result = make_renderer<TextEntityRenderer>(entity);
break;
case Type::Web:
if (!nsightActive()) {
result = make_renderer<WebEntityRenderer>(entity);
}
case Type::Light:
result = make_renderer<LightEntityRenderer>(entity);
break;
case Type::Zone:

View file

@ -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) {
}

View file

@ -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 <GridEntityItem.h>
namespace render { namespace entities {
class GridEntityRenderer : public TypedEntityRenderer<GridEntityItem> {
using Parent = TypedEntityRenderer<GridEntityItem>;
using Pointer = std::shared_ptr<GridEntityRenderer>;
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

View file

@ -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 <DependencyManager.h>
#include <GeometryCache.h>
using namespace render;
using namespace render::entities;
ImageEntityRenderer::ImageEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
ImageEntityRenderer::~ImageEntityRenderer() {
auto geometryCache = DependencyManager::get<GeometryCache>();
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<bool>([&] {
return (!_textureIsLoaded && _texture && _texture->isLoaded());
});
if (textureLoadedChanged) {
return true;
}
return Parent::needsRenderUpdate();
}
bool ImageEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
bool needsUpdate = resultWithReadLock<bool>([&] {
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<TextureCache>()->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<GeometryCache>()->renderQuad(
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
imageColor, _geometryId
);
batch->setResourceTexture(0, nullptr);
}

View file

@ -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 <ImageEntityItem.h>
namespace render {
namespace entities {
class ImageEntityRenderer : public TypedEntityRenderer<ImageEntityItem> {
using Parent = TypedEntityRenderer<ImageEntityItem>;
using Pointer = std::shared_ptr<ImageEntityRenderer>;
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

View file

@ -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();

View file

@ -15,7 +15,6 @@
#include <GeometryCache.h>
#include <PerfStat.h>
#include <Transform.h>
#include <TextEntityItem.h>
#include <TextRenderer3D.h>
#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

View file

@ -32,7 +32,7 @@ private:
virtual void doRender(RenderArgs* args) override;
int _geometryID{ 0 };
std::shared_ptr<TextRenderer3D> _textRenderer;
bool _faceCamera;
BillboardMode _billboardMode;
glm::vec3 _dimensions;
glm::vec3 _textColor;
glm::vec3 _backgroundColor;

View file

@ -297,6 +297,33 @@ void EntityItemProperties::setMaterialMappingModeFromString(const QString& mater
}
}
QHash<QString, BillboardMode> 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 {
* <code>{@link Entities.EntityProperties|naturalDimensions}</code>.
* @property {Color} color=255,255,255 - <em>Currently not used.</em>
* @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".<br />
* Note: If the name ends with <code>"default-image-model.fbx"</code> then the entity is considered to be an "Image"
* entity, in which case the <code>textures</code> 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 <code>originalTextures</code> 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 <caption>Create an "Image" entity like you can in the Create app.</caption>
* 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 <code>true</code>, the entity is oriented to face each user's camera (i.e., it
* differs for each user present).
* @property {BillboardMode} billboardMode="none" - If <code>"none"</code>, the entity is not billboarded. If <code>"yaw"</code>, the entity will be
* oriented to follow your camera around the y-axis. If <code>"full"</code> the entity will be oriented to face your camera. The following deprecated
* behavior is also supported: you can also set <code>"faceCamera"</code> to <code>true</code> to set <code>billboardMode</code> to "yaw", and you can set
* <code>"isFacingAvatar"</code> to <code>true</code> to set <code>billboardMode</code> to "full". Setting either to <code>false</code> sets the mode to "none"
* @example <caption>Create a text entity.</caption>
* 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 <code>"Image"</code> {@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 <code>"none"</code>, the entity is not billboarded. If <code>"yaw"</code>, the entity will be
* oriented to follow your camera around the y-axis. If <code>"full"</code> the entity will be oriented to face your camera. The following deprecated
* behavior is also supported: you can also set <code>"faceCamera"</code> to <code>true</code> to set <code>billboardMode</code> to "yaw", and you can set
* <code>"isFacingAvatar"</code> to <code>true</code> to set <code>billboardMode</code> to "full". Setting either to <code>false</code> 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 <caption>Create a image entity.</caption>
* 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<vec3>);
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<vec3>);
ADD_PROPERTY_TO_MAP(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector<vec3>);
@ -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<QString> 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);

View file

@ -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<glm::vec3>, 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<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);
DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector<glm::vec3>, 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);

View file

@ -122,6 +122,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<glm::quat
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<bool>& v) {return qVectorBoolToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<float>& 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) { \

View file

@ -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;

View file

@ -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
};

View file

@ -32,6 +32,8 @@ namespace EntityPsuedoPropertyFlag {
RenderInfo,
ClientOnly,
OwningAvatarID,
FaceCamera,
IsFacingAvatar,
NumFlags
};

View file

@ -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);
}
};

View file

@ -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::EntityType, QString> EntityTypes::_typeToNameMap;
QMap<QString, EntityTypes::EntityType> 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) {

View file

@ -49,25 +49,6 @@ public:
* <code>"Cube"</code>. If an entity of type <code>Shape</code> or <code>Sphere</code> has its <code>shape</code> set
* to <code>"Cube"</code> then its <code>type</code> will be reported as <code>"Box"</code>.
* <td>{@link Entities.EntityProperties-Box|EntityProperties-Box}</td></tr>
* <tr><td><code>"Light"</code></td><td>A local lighting effect.</td>
* <td>{@link Entities.EntityProperties-Light|EntityProperties-Light}</td></tr>
* <tr><td><code>"Line"</code></td><td>A sequence of one or more simple straight lines.</td>
* <td>{@link Entities.EntityProperties-Line|EntityProperties-Line}</td></tr>
* <tr><td><code>"Material"</code></td><td>Modifies the existing materials on Model entities, Shape entities (albedo
* only), {@link Overlays.OverlayType|model overlays}, and avatars.</td>
* <td>{@link Entities.EntityProperties-Material|EntityProperties-Material}</td></tr>
* <tr><td><code>"Model"</code></td><td>A mesh model from an FBX or OBJ file.</td>
* <td>{@link Entities.EntityProperties-Model|EntityProperties-Model}</td></tr>
* <tr><td><code>"ParticleEffect"</code></td><td>A particle system that can be used to simulate things such as fire,
* smoke, snow, magic spells, etc.</td>
* <td>{@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect}</td></tr>
* <tr><td><code>"PolyLine"</code></td><td>A sequence of one or more textured straight lines.</td>
* <td>{@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine}</td></tr>
* <tr><td><code>"PolyVox"</code></td><td>A set of textured voxels.</td>
* <td>{@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox}</td></tr>
* <tr><td><code>"Shape"</code></td><td>A basic entity such as a cube.
* See also, the <code>"Box"</code> and <code>"Sphere"</code> entity types.</td>
* <td>{@link Entities.EntityProperties-Shape|EntityProperties-Shape}</td></tr>
* <tr><td><code>"Sphere"</code></td><td>A sphere. This is a synonym of <code>"Shape"</code> for the case
* where the entity's <code>shape</code> property value is <code>"Sphere"</code>.<br />
* If an entity is created with its <code>type</code>
@ -75,32 +56,57 @@ public:
* <code>"Sphere"</code>. If an entity of type <code>Box</code> or <code>Shape</code> has its <code>shape</code> set
* to <code>"Sphere"</code> then its <code>type</code> will be reported as <code>"Sphere"</code>.
* <td>{@link Entities.EntityProperties-Sphere|EntityProperties-Sphere}</td></tr>
* <tr><td><code>"Shape"</code></td><td>A basic entity such as a cube.
* See also, the <code>"Box"</code> and <code>"Sphere"</code> entity types.</td>
* <td>{@link Entities.EntityProperties-Shape|EntityProperties-Shape}</td></tr>
* <tr><td><code>"Model"</code></td><td>A mesh model from an FBX or OBJ file.</td>
* <td>{@link Entities.EntityProperties-Model|EntityProperties-Model}</td></tr>
* <tr><td><code>"Text"</code></td><td>A pane of text oriented in space.</td>
* <td>{@link Entities.EntityProperties-Text|EntityProperties-Text}</td></tr>
* <tr><td><code>"Image"</code></td><td>An image oriented in space.</td>
* <td>{@link Entities.EntityProperties-Image|EntityProperties-Image}</td></tr>
* <tr><td><code>"Web"</code></td><td>A browsable Web page.</td>
* <td>{@link Entities.EntityProperties-Web|EntityProperties-Web}</td></tr>
* <tr><td><code>"ParticleEffect"</code></td><td>A particle system that can be used to simulate things such as fire,
* smoke, snow, magic spells, etc.</td>
* <td>{@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect}</td></tr>
* <tr><td><code>"Line"</code></td><td>A sequence of one or more simple straight lines.</td>
* <td>{@link Entities.EntityProperties-Line|EntityProperties-Line}</td></tr>
* <tr><td><code>"PolyLine"</code></td><td>A sequence of one or more textured straight lines.</td>
* <td>{@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine}</td></tr>
* <tr><td><code>"PolyVox"</code></td><td>A set of textured voxels.</td>
* <td>{@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox}</td></tr>
* <tr><td><code>"Grid"</code></td><td>A grid.</td>
* <td>{@link Entities.EntityProperties-Grid|EntityProperties-Grid}</td></tr>
* <tr><td><code>"Light"</code></td><td>A local lighting effect.</td>
* <td>{@link Entities.EntityProperties-Light|EntityProperties-Light}</td></tr>
* <tr><td><code>"Zone"</code></td><td>A volume of lighting effects and avatar permissions.</td>
* <td>{@link Entities.EntityProperties-Zone|EntityProperties-Zone}</td></tr>
* <tr><td><code>"Material"</code></td><td>Modifies the existing materials on Model entities, Shape entities,
* {@link Overlays.OverlayType|model overlays}, and avatars.</td>
* <td>{@link Entities.EntityProperties-Material|EntityProperties-Material}</td></tr>
* </tbody>
* </table>
* @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<EntityType, QString> _typeToNameMap;
static QMap<QString, EntityTypes::EntityType> _nameToTypeMap;
static EntityTypeFactory _factories[LAST + 1];
static EntityTypeFactory _factories[NUM_TYPES];
static bool _factoriesInitialized;
};

View file

@ -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;
}

View file

@ -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<GridEntityItem>;
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

View file

@ -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<glm::u8vec3>([&] {
return _color;
});
}
void ImageEntityItem::setAlpha(float alpha) {
withWriteLock([&] {
_alpha = alpha;
});
}
float ImageEntityItem::getAlpha() const {
return resultWithReadLock<float>([&] {
return _alpha;
});
}

View file

@ -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<ImageEntityItem>;
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

View file

@ -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;
});
}

View file

@ -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

View file

@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::CleanupProperties);
return static_cast<PacketVersion>(EntityVersion::ImageEntities);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity:

View file

@ -245,7 +245,8 @@ enum class EntityVersion : PacketVersion {
GrabProperties,
ScriptGlmVectors,
FixedLightSerialization,
CleanupProperties
CleanupProperties,
ImageEntities
};
enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -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);
}

View file

@ -34,6 +34,7 @@
#include <udt/PacketHeaders.h>
#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<bool>& 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

View file

@ -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];
}

View file

@ -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

View file

@ -24,6 +24,7 @@
#include <QtNetwork/QAbstractSocket>
#include <QtScript/QScriptValue>
#include <QtScript/QScriptValueIterator>
#include <QJsonDocument>
int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();
int u8vec3MetaTypeId = qRegisterMetaType<u8vec3>();
@ -1245,3 +1246,31 @@ void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>
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();
}

View file

@ -705,5 +705,7 @@ void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResul
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector);
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result);
QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures);
#endif // hifi_RegisteredMetaTypes_h

View file

@ -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.

View file

@ -11,7 +11,6 @@ const DESCENDING_SORT = -1;
const ASCENDING_STRING = '&#x25B4;';
const DESCENDING_STRING = '&#x25BE;';
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,

View file

@ -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");

View file

@ -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],