mirror of
https://github.com/overte-org/overte.git
synced 2025-04-15 12:28:51 +02:00
real image entities
This commit is contained in:
parent
1fd8a21f8e
commit
3ce6f7f3d6
41 changed files with 1453 additions and 238 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
51
libraries/entities-renderer/src/RenderableGridEntityItem.cpp
Normal file
51
libraries/entities-renderer/src/RenderableGridEntityItem.cpp
Normal 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) {
|
||||
|
||||
}
|
36
libraries/entities-renderer/src/RenderableGridEntityItem.h
Normal file
36
libraries/entities-renderer/src/RenderableGridEntityItem.h
Normal 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
|
218
libraries/entities-renderer/src/RenderableImageEntityItem.cpp
Normal file
218
libraries/entities-renderer/src/RenderableImageEntityItem.cpp
Normal 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);
|
||||
}
|
56
libraries/entities-renderer/src/RenderableImageEntityItem.h
Normal file
56
libraries/entities-renderer/src/RenderableImageEntityItem.h
Normal 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
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) { \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace EntityPsuedoPropertyFlag {
|
|||
RenderInfo,
|
||||
ClientOnly,
|
||||
OwningAvatarID,
|
||||
FaceCamera,
|
||||
IsFacingAvatar,
|
||||
|
||||
NumFlags
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
154
libraries/entities/src/GridEntityItem.cpp
Normal file
154
libraries/entities/src/GridEntityItem.cpp
Normal 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;
|
||||
}
|
56
libraries/entities/src/GridEntityItem.h
Normal file
56
libraries/entities/src/GridEntityItem.h
Normal 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
|
269
libraries/entities/src/ImageEntityItem.cpp
Normal file
269
libraries/entities/src/ImageEntityItem.cpp
Normal 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;
|
||||
});
|
||||
}
|
86
libraries/entities/src/ImageEntityItem.h
Normal file
86
libraries/entities/src/ImageEntityItem.h
Normal 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
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -245,7 +245,8 @@ enum class EntityVersion : PacketVersion {
|
|||
GrabProperties,
|
||||
ScriptGlmVectors,
|
||||
FixedLightSerialization,
|
||||
CleanupProperties
|
||||
CleanupProperties,
|
||||
ImageEntities
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
25
libraries/shared/src/BillboardMode.cpp
Normal file
25
libraries/shared/src/BillboardMode.cpp
Normal 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];
|
||||
}
|
26
libraries/shared/src/BillboardMode.h
Normal file
26
libraries/shared/src/BillboardMode.h
Normal 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
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in a new issue