Merge branch 'master' of https://github.com/highfidelity/hifi into brown

This commit is contained in:
Sam Gateau 2019-02-14 21:01:44 -08:00
commit 13b5390243
28 changed files with 332 additions and 187 deletions

View file

@ -2308,8 +2308,30 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value); DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
}); });
EntityTreeRenderer::setGetAvatarUpOperator([] { EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) {
return DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP; if (billboardMode == BillboardMode::YAW) {
//rotate about vertical to face the camera
ViewFrustum frustum;
copyViewFrustum(frustum);
glm::vec3 dPosition = frustum.getPosition() - position;
// 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);
return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
} else if (billboardMode == BillboardMode::FULL) {
ViewFrustum frustum;
copyViewFrustum(frustum);
glm::vec3 cameraPos = frustum.getPosition();
// use the referencial from the avatar, y isn't always up
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
// check to see if glm::lookAt will work / using glm::lookAt variable name
glm::highp_vec3 s(glm::cross(position - cameraPos, avatarUP));
// make sure s is not NaN for any component
if (glm::length2(s) > 0.0f) {
return glm::conjugate(glm::toQuat(glm::lookAt(cameraPos, position, avatarUP)));
}
}
return rotation;
}); });
render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) { render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
@ -6228,40 +6250,57 @@ void Application::update(float deltaTime) {
PROFILE_RANGE(simulation_physics, "PrePhysics"); PROFILE_RANGE(simulation_physics, "PrePhysics");
PerformanceTimer perfTimer("prePhysics)"); PerformanceTimer perfTimer("prePhysics)");
{ {
PROFILE_RANGE(simulation_physics, "RemoveEntities");
const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics(); const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics();
_physicsEngine->removeObjects(motionStates); {
PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
_physicsEngine->removeObjects(motionStates);
}
_entitySimulation->deleteObjectsRemovedFromPhysics(); _entitySimulation->deleteObjectsRemovedFromPhysics();
} }
VectorOfMotionStates motionStates; {
getEntities()->getTree()->withReadLock([&] { PROFILE_RANGE(simulation_physics, "AddEntities");
_entitySimulation->getObjectsToAddToPhysics(motionStates); VectorOfMotionStates motionStates;
_physicsEngine->addObjects(motionStates); getEntities()->getTree()->withReadLock([&] {
_entitySimulation->getObjectsToAddToPhysics(motionStates);
}); PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
getEntities()->getTree()->withReadLock([&] { _physicsEngine->addObjects(motionStates);
_entitySimulation->getObjectsToChange(motionStates); });
VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates); }
_entitySimulation->setObjectsToChange(stillNeedChange); {
}); VectorOfMotionStates motionStates;
PROFILE_RANGE(simulation_physics, "ChangeEntities");
getEntities()->getTree()->withReadLock([&] {
_entitySimulation->getObjectsToChange(motionStates);
VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
_entitySimulation->setObjectsToChange(stillNeedChange);
});
}
_entitySimulation->applyDynamicChanges(); _entitySimulation->applyDynamicChanges();
t1 = std::chrono::high_resolution_clock::now(); t1 = std::chrono::high_resolution_clock::now();
PhysicsEngine::Transaction transaction; {
avatarManager->buildPhysicsTransaction(transaction); PROFILE_RANGE(simulation_physics, "Avatars");
_physicsEngine->processTransaction(transaction); PhysicsEngine::Transaction transaction;
avatarManager->handleProcessedPhysicsTransaction(transaction); avatarManager->buildPhysicsTransaction(transaction);
myAvatar->getCharacterController()->buildPhysicsTransaction(transaction); _physicsEngine->processTransaction(transaction);
_physicsEngine->processTransaction(transaction); avatarManager->handleProcessedPhysicsTransaction(transaction);
myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction); myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
myAvatar->prepareForPhysicsSimulation(); _physicsEngine->processTransaction(transaction);
_physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying()); myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction);
myAvatar->prepareForPhysicsSimulation();
_physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying());
}
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { {
dynamic->prepareForPhysicsSimulation(); PROFILE_RANGE(simulation_physics, "PrepareActions");
}); _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
dynamic->prepareForPhysicsSimulation();
});
}
} }
auto t2 = std::chrono::high_resolution_clock::now(); auto t2 = std::chrono::high_resolution_clock::now();
{ {

View file

@ -90,7 +90,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
} }
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
PROFILE_RANGE(app, __FUNCTION__); PROFILE_RANGE(render, __FUNCTION__);
if (!_uiTexture) { if (!_uiTexture) {
_uiTexture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda()); _uiTexture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda());
@ -119,7 +119,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
} }
void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
PROFILE_RANGE(app, __FUNCTION__); PROFILE_RANGE(render, __FUNCTION__);
gpu::Batch& batch = *renderArgs->_batch; gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
@ -176,7 +176,7 @@ static const auto DEFAULT_SAMPLER = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LI
static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
void ApplicationOverlay::buildFramebufferObject() { void ApplicationOverlay::buildFramebufferObject() {
PROFILE_RANGE(app, __FUNCTION__); PROFILE_RANGE(render, __FUNCTION__);
auto uiSize = glm::uvec2(qApp->getUiSize()); auto uiSize = glm::uvec2(qApp->getUiSize());
if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) { if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) {

View file

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

View file

@ -118,9 +118,6 @@ public:
// Access the workload Space // Access the workload Space
workload::SpacePointer getWorkloadSpace() const { return _space; } workload::SpacePointer getWorkloadSpace() const { return _space; }
static void setGetAvatarUpOperator(std::function<glm::vec3()> getAvatarUpOperator) { _getAvatarUpOperator = getAvatarUpOperator; }
static glm::vec3 getAvatarUp() { return _getAvatarUpOperator(); }
EntityEditPacketSender* getPacketSender(); EntityEditPacketSender* getPacketSender();
signals: signals:
@ -258,7 +255,6 @@ private:
workload::SpacePointer _space{ new workload::Space() }; workload::SpacePointer _space{ new workload::Space() };
workload::Transaction::Updates _spaceUpdates; workload::Transaction::Updates _spaceUpdates;
static std::function<glm::vec3()> _getAvatarUpOperator;
}; };

View file

@ -96,12 +96,12 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
_emissive = entity->getEmissive(); _emissive = entity->getEmissive();
_keepAspectRatio = entity->getKeepAspectRatio(); _keepAspectRatio = entity->getKeepAspectRatio();
_billboardMode = entity->getBillboardMode();
_subImage = entity->getSubImage(); _subImage = entity->getSubImage();
_color = entity->getColor(); _color = entity->getColor();
_alpha = entity->getAlpha(); _alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties(); _pulseProperties = entity->getPulseProperties();
_billboardMode = entity->getBillboardMode();
if (!_textureIsLoaded && _texture && _texture->isLoaded()) { if (!_textureIsLoaded && _texture && _texture->isLoaded()) {
_textureIsLoaded = true; _textureIsLoaded = true;
@ -118,6 +118,17 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}); });
} }
Item::Bound ImageEntityRenderer::getBound() {
auto bound = Parent::getBound();
if (_billboardMode != BillboardMode::NONE) {
glm::vec3 dimensions = bound.getScale();
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
const float SQRT_2 = 1.41421356237f;
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
}
return bound;
}
ShapeKey ImageEntityRenderer::getShapeKey() { ShapeKey ImageEntityRenderer::getShapeKey() {
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
if (isTransparent()) { if (isTransparent()) {
@ -159,27 +170,7 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
gpu::Batch* batch = args->_batch; gpu::Batch* batch = args->_batch;
if (_billboardMode == BillboardMode::YAW) { transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode));
//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); transform.postScale(dimensions);
batch->setModelTransform(transform); batch->setModelTransform(transform);

View file

@ -23,6 +23,7 @@ public:
~ImageEntityRenderer(); ~ImageEntityRenderer();
protected: protected:
Item::Bound getBound() override;
ShapeKey getShapeKey() override; ShapeKey getShapeKey() override;
bool isTransparent() const override; bool isTransparent() const override;
@ -39,12 +40,12 @@ private:
bool _emissive; bool _emissive;
bool _keepAspectRatio; bool _keepAspectRatio;
BillboardMode _billboardMode;
QRect _subImage; QRect _subImage;
glm::u8vec3 _color; glm::u8vec3 _color;
float _alpha; float _alpha;
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
glm::vec3 _dimensions; glm::vec3 _dimensions;

View file

@ -47,6 +47,17 @@ bool TextEntityRenderer::isTransparent() const {
return Parent::isTransparent() || _textAlpha < 1.0f || _backgroundAlpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE; return Parent::isTransparent() || _textAlpha < 1.0f || _backgroundAlpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
} }
Item::Bound TextEntityRenderer::getBound() {
auto bound = Parent::getBound();
if (_billboardMode != BillboardMode::NONE) {
glm::vec3 dimensions = bound.getScale();
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
const float SQRT_2 = 1.41421356237f;
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
}
return bound;
}
ShapeKey TextEntityRenderer::getShapeKey() { ShapeKey TextEntityRenderer::getShapeKey() {
auto builder = render::ShapeKey::Builder().withOwnPipeline(); auto builder = render::ShapeKey::Builder().withOwnPipeline();
if (isTransparent()) { if (isTransparent()) {
@ -170,27 +181,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
auto transformToTopLeft = modelTransform; auto transformToTopLeft = modelTransform;
if (_billboardMode == BillboardMode::YAW) { transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), _billboardMode));
//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.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 transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed

View file

@ -26,11 +26,13 @@ public:
TextEntityRenderer(const EntityItemPointer& entity); TextEntityRenderer(const EntityItemPointer& entity);
~TextEntityRenderer(); ~TextEntityRenderer();
bool isTransparent() const override;
ShapeKey getShapeKey() override;
QSizeF textSize(const QString& text) const; QSizeF textSize(const QString& text) const;
protected:
bool isTransparent() const override;
Item::Bound getBound() override;
ShapeKey getShapeKey() override;
private: private:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;

View file

@ -124,6 +124,10 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
return true; return true;
} }
if (_billboardMode != entity->getBillboardMode()) {
return true;
}
if (_sourceURL != entity->getSourceUrl()) { if (_sourceURL != entity->getSourceUrl()) {
return true; return true;
} }
@ -209,6 +213,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_color = entity->getColor(); _color = entity->getColor();
_alpha = entity->getAlpha(); _alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties(); _pulseProperties = entity->getPulseProperties();
_billboardMode = entity->getBillboardMode();
if (_contentType == ContentType::NoContent) { if (_contentType == ContentType::NoContent) {
return; return;
@ -271,6 +276,17 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
}); });
} }
Item::Bound WebEntityRenderer::getBound() {
auto bound = Parent::getBound();
if (_billboardMode != BillboardMode::NONE) {
glm::vec3 dimensions = bound.getScale();
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
const float SQRT_2 = 1.41421356237f;
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
}
return bound;
}
void WebEntityRenderer::doRender(RenderArgs* args) { void WebEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("WebEntityRenderer::render"); PerformanceTimer perfTimer("WebEntityRenderer::render");
withWriteLock([&] { withWriteLock([&] {
@ -298,14 +314,18 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
glm::vec4 color; glm::vec4 color;
Transform transform;
withReadLock([&] { withReadLock([&] {
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
color = glm::vec4(toGlm(_color), _alpha * fadeRatio); color = glm::vec4(toGlm(_color), _alpha * fadeRatio);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created); color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
batch.setModelTransform(_renderTransform); transform = _renderTransform;
}); });
batch.setResourceTexture(0, _texture); batch.setResourceTexture(0, _texture);
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode));
batch.setModelTransform(transform);
// Turn off jitter for these entities // Turn off jitter for these entities
batch.pushProjectionJitter(); batch.pushProjectionJitter();
DependencyManager::get<GeometryCache>()->bindWebBrowserProgram(batch, color.a < OPAQUE_ALPHA_THRESHOLD); DependencyManager::get<GeometryCache>()->bindWebBrowserProgram(batch, color.a < OPAQUE_ALPHA_THRESHOLD);

View file

@ -56,6 +56,7 @@ protected:
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override;
virtual bool isTransparent() const override; virtual bool isTransparent() const override;
Item::Bound getBound() override;
virtual bool wantsHandControllerPointerEvents() const override { return true; } virtual bool wantsHandControllerPointerEvents() const override { return true; }
virtual bool wantsKeyboardFocus() const override { return true; } virtual bool wantsKeyboardFocus() const override { return true; }
@ -85,6 +86,7 @@ private:
glm::u8vec3 _color; glm::u8vec3 _color;
float _alpha { 1.0f }; float _alpha { 1.0f };
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
QString _sourceURL; QString _sourceURL;
uint16_t _dpi; uint16_t _dpi;

View file

@ -49,6 +49,8 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
QString EntityItem::_marketplacePublicKey; QString EntityItem::_marketplacePublicKey;
std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode) { return rotation; };
EntityItem::EntityItem(const EntityItemID& entityItemID) : EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableType::Entity, entityItemID) SpatiallyNestable(NestableType::Entity, entityItemID)
{ {

View file

@ -563,6 +563,9 @@ public:
virtual void removeGrab(GrabPointer grab) override; virtual void removeGrab(GrabPointer grab) override;
virtual void disableGrab(GrabPointer grab) override; virtual void disableGrab(GrabPointer grab) override;
static void setBillboardRotationOperator(std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; }
static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) { return _getBillboardRotationOperator(position, rotation, billboardMode); }
signals: signals:
void requestRenderUpdate(); void requestRenderUpdate();
void spaceUpdate(std::pair<int32_t, glm::vec4> data); void spaceUpdate(std::pair<int32_t, glm::vec4> data);
@ -754,6 +757,8 @@ private:
std::unordered_map<std::string, graphics::MultiMaterial> _materials; std::unordered_map<std::string, graphics::MultiMaterial> _materials;
std::mutex _materialsLock; std::mutex _materialsLock;
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> _getBillboardRotationOperator;
}; };
#endif // hifi_EntityItem_h #endif // hifi_EntityItem_h

View file

@ -543,6 +543,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
changedProperties += _pulse.getChangedProperties(); changedProperties += _pulse.getChangedProperties();
CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures);
CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
// Particles // Particles
CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles); CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles);
@ -601,7 +602,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_TEXT_ALPHA, textAlpha); CHECK_PROPERTY_CHANGE(PROP_TEXT_ALPHA, textAlpha);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor); CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_ALPHA, backgroundAlpha); CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_ALPHA, backgroundAlpha);
CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
CHECK_PROPERTY_CHANGE(PROP_LEFT_MARGIN, leftMargin); CHECK_PROPERTY_CHANGE(PROP_LEFT_MARGIN, leftMargin);
CHECK_PROPERTY_CHANGE(PROP_RIGHT_MARGIN, rightMargin); CHECK_PROPERTY_CHANGE(PROP_RIGHT_MARGIN, rightMargin);
CHECK_PROPERTY_CHANGE(PROP_TOP_MARGIN, topMargin); CHECK_PROPERTY_CHANGE(PROP_TOP_MARGIN, topMargin);
@ -1337,6 +1337,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity.
* @property {Color} color=255,255,255 - The color of the web surface. * @property {Color} color=255,255,255 - The color of the web surface.
* @property {number} alpha=1 - The alpha of the web surface. * @property {number} alpha=1 - The alpha of the web surface.
* @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 {string} sourceUrl="" - The URL of the Web page to display. This value does not change as you or others navigate * @property {string} sourceUrl="" - The URL of the Web page to display. This value does not change as you or others navigate
* on the Web entity. * on the Web entity.
* @property {number} dpi=30 - The resolution to display the page at, in dots per inch. If you convert this to dots per meter * @property {number} dpi=30 - The resolution to display the page at, in dots per inch. If you convert this to dots per meter
@ -1718,6 +1722,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
// Text only // Text only
if (_type == EntityTypes::Text) { if (_type == EntityTypes::Text) {
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight);
@ -1725,7 +1730,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT_ALPHA, textAlpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT_ALPHA, textAlpha);
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_BACKGROUND_COLOR, backgroundColor, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_BACKGROUND_COLOR, backgroundColor, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BACKGROUND_ALPHA, backgroundAlpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BACKGROUND_ALPHA, backgroundAlpha);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LEFT_MARGIN, leftMargin); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LEFT_MARGIN, leftMargin);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RIGHT_MARGIN, rightMargin); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RIGHT_MARGIN, rightMargin);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TOP_MARGIN, topMargin); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TOP_MARGIN, topMargin);
@ -1761,6 +1765,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DPI, dpi); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DPI, dpi);
@ -1827,11 +1832,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); 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(PROP_SUB_IMAGE, subImage);
// Handle conversions to old 'textures' property from "imageURL" // Handle conversions to old 'textures' property from "imageURL"
@ -2036,6 +2041,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
_pulse.copyFromScriptValue(object, _defaultSettings); _pulse.copyFromScriptValue(object, _defaultSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures); COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
// Particles // Particles
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles); COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles);
@ -2094,7 +2100,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(textAlpha, float, setTextAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(textAlpha, float, setTextAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, u8vec3Color, setBackgroundColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, u8vec3Color, setBackgroundColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundAlpha, float, setBackgroundAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundAlpha, float, setBackgroundAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(leftMargin, float, setLeftMargin); COPY_PROPERTY_FROM_QSCRIPTVALUE(leftMargin, float, setLeftMargin);
COPY_PROPERTY_FROM_QSCRIPTVALUE(rightMargin, float, setRightMargin); COPY_PROPERTY_FROM_QSCRIPTVALUE(rightMargin, float, setRightMargin);
COPY_PROPERTY_FROM_QSCRIPTVALUE(topMargin, float, setTopMargin); COPY_PROPERTY_FROM_QSCRIPTVALUE(topMargin, float, setTopMargin);
@ -2315,6 +2320,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(alpha); COPY_PROPERTY_IF_CHANGED(alpha);
_pulse.merge(other._pulse); _pulse.merge(other._pulse);
COPY_PROPERTY_IF_CHANGED(textures); COPY_PROPERTY_IF_CHANGED(textures);
COPY_PROPERTY_IF_CHANGED(billboardMode);
// Particles // Particles
COPY_PROPERTY_IF_CHANGED(maxParticles); COPY_PROPERTY_IF_CHANGED(maxParticles);
@ -2373,7 +2379,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(textAlpha); COPY_PROPERTY_IF_CHANGED(textAlpha);
COPY_PROPERTY_IF_CHANGED(backgroundColor); COPY_PROPERTY_IF_CHANGED(backgroundColor);
COPY_PROPERTY_IF_CHANGED(backgroundAlpha); COPY_PROPERTY_IF_CHANGED(backgroundAlpha);
COPY_PROPERTY_IF_CHANGED(billboardMode);
COPY_PROPERTY_IF_CHANGED(leftMargin); COPY_PROPERTY_IF_CHANGED(leftMargin);
COPY_PROPERTY_IF_CHANGED(rightMargin); COPY_PROPERTY_IF_CHANGED(rightMargin);
COPY_PROPERTY_IF_CHANGED(topMargin); COPY_PROPERTY_IF_CHANGED(topMargin);
@ -2634,6 +2639,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode); ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode);
} }
ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString); ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString);
ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
// Particles // Particles
ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32,
@ -2727,7 +2733,6 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_TEXT_ALPHA, TextAlpha, textAlpha, float); ADD_PROPERTY_TO_MAP(PROP_TEXT_ALPHA, TextAlpha, textAlpha, float);
ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, u8vec3Color); ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, u8vec3Color);
ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_ALPHA, BackgroundAlpha, backgroundAlpha, float); ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_ALPHA, BackgroundAlpha, backgroundAlpha, float);
ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
ADD_PROPERTY_TO_MAP(PROP_LEFT_MARGIN, LeftMargin, leftMargin, float); ADD_PROPERTY_TO_MAP(PROP_LEFT_MARGIN, LeftMargin, leftMargin, float);
ADD_PROPERTY_TO_MAP(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float); ADD_PROPERTY_TO_MAP(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float);
ADD_PROPERTY_TO_MAP(PROP_TOP_MARGIN, TopMargin, topMargin, float); ADD_PROPERTY_TO_MAP(PROP_TOP_MARGIN, TopMargin, topMargin, float);
@ -3137,6 +3142,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticPulse.setProperties(properties); _staticPulse.setProperties(properties);
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState); propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText()); APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight());
@ -3144,7 +3150,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_TEXT_ALPHA, properties.getTextAlpha()); APPEND_ENTITY_PROPERTY(PROP_TEXT_ALPHA, properties.getTextAlpha());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, properties.getBackgroundAlpha()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, properties.getBackgroundAlpha());
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_LEFT_MARGIN, properties.getLeftMargin()); APPEND_ENTITY_PROPERTY(PROP_LEFT_MARGIN, properties.getLeftMargin());
APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, properties.getRightMargin()); APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, properties.getRightMargin());
APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, properties.getTopMargin()); APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, properties.getTopMargin());
@ -3202,6 +3207,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticPulse.setProperties(properties); _staticPulse.setProperties(properties);
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState); propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl()); APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI()); APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI());
@ -3263,11 +3269,11 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticPulse.setProperties(properties); _staticPulse.setProperties(properties);
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState); propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL());
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive()); APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive());
APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, properties.getKeepAspectRatio()); 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_SUB_IMAGE, properties.getSubImage());
} }
@ -3609,6 +3615,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
if (properties.getType() == EntityTypes::Text) { if (properties.getType() == EntityTypes::Text) {
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight);
@ -3616,7 +3623,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_ALPHA, float, setTextAlpha); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_ALPHA, float, setTextAlpha);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, u8vec3Color, setBackgroundColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, u8vec3Color, setBackgroundColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_ALPHA, float, setBackgroundAlpha); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_ALPHA, float, setBackgroundAlpha);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LEFT_MARGIN, float, setLeftMargin); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LEFT_MARGIN, float, setLeftMargin);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RIGHT_MARGIN, float, setRightMargin); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RIGHT_MARGIN, float, setRightMargin);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TOP_MARGIN, float, setTopMargin); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TOP_MARGIN, float, setTopMargin);
@ -3663,6 +3669,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI);
@ -3721,11 +3728,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); 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_EMISSIVE, bool, setEmissive);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); 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_SUB_IMAGE, QRect, setSubImage);
} }
@ -3940,11 +3947,12 @@ void EntityItemProperties::markAllChanged() {
// Common // Common
_shapeTypeChanged = true; _shapeTypeChanged = true;
_compoundShapeURLChanged = true;
_colorChanged = true; _colorChanged = true;
_alphaChanged = true; _alphaChanged = true;
_pulse.markAllChanged(); _pulse.markAllChanged();
_texturesChanged = true; _texturesChanged = true;
_compoundShapeURLChanged = true; _billboardModeChanged = true;
// Particles // Particles
_maxParticlesChanged = true; _maxParticlesChanged = true;
@ -4003,7 +4011,6 @@ void EntityItemProperties::markAllChanged() {
_textAlphaChanged = true; _textAlphaChanged = true;
_backgroundColorChanged = true; _backgroundColorChanged = true;
_backgroundAlphaChanged = true; _backgroundAlphaChanged = true;
_billboardModeChanged = true;
_leftMarginChanged = true; _leftMarginChanged = true;
_rightMarginChanged = true; _rightMarginChanged = true;
_topMarginChanged = true; _topMarginChanged = true;
@ -4416,6 +4423,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (texturesChanged()) { if (texturesChanged()) {
out += "textures"; out += "textures";
} }
if (billboardModeChanged()) {
out += "billboardMode";
}
// Particles // Particles
if (maxParticlesChanged()) { if (maxParticlesChanged()) {
@ -4572,9 +4582,6 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (backgroundAlphaChanged()) { if (backgroundAlphaChanged()) {
out += "backgroundAlpha"; out += "backgroundAlpha";
} }
if (billboardModeChanged()) {
out += "billboardMode";
}
if (leftMarginChanged()) { if (leftMarginChanged()) {
out += "leftMargin"; out += "leftMargin";
} }

View file

@ -242,6 +242,7 @@ public:
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float, ENTITY_ITEM_DEFAULT_ALPHA); DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float, ENTITY_ITEM_DEFAULT_ALPHA);
DEFINE_PROPERTY_GROUP(Pulse, pulse, PulsePropertyGroup); DEFINE_PROPERTY_GROUP(Pulse, pulse, PulsePropertyGroup);
DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString, ""); DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString, "");
DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
// Particles // Particles
DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, particle::DEFAULT_MAX_PARTICLES); DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, particle::DEFAULT_MAX_PARTICLES);
@ -300,7 +301,6 @@ public:
DEFINE_PROPERTY_REF(PROP_TEXT_ALPHA, TextAlpha, textAlpha, float, TextEntityItem::DEFAULT_TEXT_ALPHA); DEFINE_PROPERTY_REF(PROP_TEXT_ALPHA, TextAlpha, textAlpha, float, TextEntityItem::DEFAULT_TEXT_ALPHA);
DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, u8vec3Color, TextEntityItem::DEFAULT_BACKGROUND_COLOR); DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, u8vec3Color, TextEntityItem::DEFAULT_BACKGROUND_COLOR);
DEFINE_PROPERTY_REF(PROP_BACKGROUND_ALPHA, BackgroundAlpha, backgroundAlpha, float, TextEntityItem::DEFAULT_TEXT_ALPHA); DEFINE_PROPERTY_REF(PROP_BACKGROUND_ALPHA, BackgroundAlpha, backgroundAlpha, float, TextEntityItem::DEFAULT_TEXT_ALPHA);
DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
DEFINE_PROPERTY_REF(PROP_LEFT_MARGIN, LeftMargin, leftMargin, float, TextEntityItem::DEFAULT_MARGIN); DEFINE_PROPERTY_REF(PROP_LEFT_MARGIN, LeftMargin, leftMargin, float, TextEntityItem::DEFAULT_MARGIN);
DEFINE_PROPERTY_REF(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float, TextEntityItem::DEFAULT_MARGIN); DEFINE_PROPERTY_REF(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float, TextEntityItem::DEFAULT_MARGIN);
DEFINE_PROPERTY_REF(PROP_TOP_MARGIN, TopMargin, topMargin, float, TextEntityItem::DEFAULT_MARGIN); DEFINE_PROPERTY_REF(PROP_TOP_MARGIN, TopMargin, topMargin, float, TextEntityItem::DEFAULT_MARGIN);

View file

@ -118,6 +118,7 @@ enum EntityPropertyList {
PROP_PULSE_COLOR_MODE, PROP_PULSE_COLOR_MODE,
PROP_PULSE_ALPHA_MODE, PROP_PULSE_ALPHA_MODE,
PROP_TEXTURES, PROP_TEXTURES,
PROP_BILLBOARD_MODE,
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new shared EntityItem properties to the list ABOVE this line // ATTENTION: add new shared EntityItem properties to the list ABOVE this line
@ -232,11 +233,10 @@ enum EntityPropertyList {
PROP_TEXT_ALPHA = PROP_DERIVED_3, PROP_TEXT_ALPHA = PROP_DERIVED_3,
PROP_BACKGROUND_COLOR = PROP_DERIVED_4, PROP_BACKGROUND_COLOR = PROP_DERIVED_4,
PROP_BACKGROUND_ALPHA = PROP_DERIVED_5, PROP_BACKGROUND_ALPHA = PROP_DERIVED_5,
PROP_BILLBOARD_MODE = PROP_DERIVED_6, PROP_LEFT_MARGIN = PROP_DERIVED_6,
PROP_LEFT_MARGIN = PROP_DERIVED_7, PROP_RIGHT_MARGIN = PROP_DERIVED_7,
PROP_RIGHT_MARGIN = PROP_DERIVED_8, PROP_TOP_MARGIN = PROP_DERIVED_8,
PROP_TOP_MARGIN = PROP_DERIVED_9, PROP_BOTTOM_MARGIN = PROP_DERIVED_9,
PROP_BOTTOM_MARGIN = PROP_DERIVED_10,
// Zone // Zone
// Keylight // Keylight

View file

@ -35,11 +35,11 @@ EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& d
withReadLock([&] { withReadLock([&] {
_pulseProperties.getProperties(properties); _pulseProperties.getProperties(properties);
}); });
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keepAspectRatio, getKeepAspectRatio); 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(subImage, getSubImage);
return properties; return properties;
@ -54,11 +54,11 @@ bool ImageEntityItem::setProperties(const EntityItemProperties& properties) {
bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); bool pulsePropertiesChanged = _pulseProperties.setProperties(properties);
somethingChanged |= pulsePropertiesChanged; somethingChanged |= pulsePropertiesChanged;
}); });
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); 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(subImage, setSubImage);
if (somethingChanged) { if (somethingChanged) {
@ -91,11 +91,11 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesRead += bytesFromPulse; bytesRead += bytesFromPulse;
dataAt += bytesFromPulse; dataAt += bytesFromPulse;
}); });
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL); READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL);
READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive); READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive);
READ_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); 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_SUB_IMAGE, QRect, setSubImage);
return bytesRead; return bytesRead;
@ -107,11 +107,11 @@ EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_COLOR; requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA; requestedProperties += PROP_ALPHA;
requestedProperties += _pulseProperties.getEntityProperties(params); requestedProperties += _pulseProperties.getEntityProperties(params);
requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_IMAGE_URL; requestedProperties += PROP_IMAGE_URL;
requestedProperties += PROP_EMISSIVE; requestedProperties += PROP_EMISSIVE;
requestedProperties += PROP_KEEP_ASPECT_RATIO; requestedProperties += PROP_KEEP_ASPECT_RATIO;
requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_SUB_IMAGE; requestedProperties += PROP_SUB_IMAGE;
return requestedProperties; return requestedProperties;
@ -133,14 +133,24 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState); propertyFlags, propertiesDidntFit, propertyCount, appendState);
}); });
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL()); APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL());
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive()); APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive());
APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, getKeepAspectRatio()); 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_SUB_IMAGE, getSubImage());
} }
glm::vec3 ImageEntityItem::getRaycastDimensions() const {
glm::vec3 dimensions = getScaledDimensions();
if (getBillboardMode() != BillboardMode::NONE) {
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
const float SQRT_2 = 1.41421356237f;
return glm::vec3(SQRT_2 * max);
}
return dimensions;
}
bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, OctreeElementPointer& element,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
@ -149,6 +159,7 @@ bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation(); glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode);
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT; glm::vec3 forward = rotation * Vectors::FRONT;

View file

@ -43,6 +43,7 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override; bool& somethingChanged) override;
glm::vec3 getRaycastDimensions() const override;
virtual bool supportsDetailedIntersection() const override { return true; } virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance, OctreeElementPointer& element, float& distance,
@ -77,15 +78,15 @@ public:
PulsePropertyGroup getPulseProperties() const; PulsePropertyGroup getPulseProperties() const;
protected: protected:
QString _imageURL;
bool _emissive { false };
bool _keepAspectRatio { true };
BillboardMode _billboardMode;
QRect _subImage;
glm::u8vec3 _color; glm::u8vec3 _color;
float _alpha; float _alpha;
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
QString _imageURL;
bool _emissive { false };
bool _keepAspectRatio { true };
QRect _subImage;
}; };
#endif // hifi_ImageEntityItem_h #endif // hifi_ImageEntityItem_h

View file

@ -52,6 +52,7 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de
withReadLock([&] { withReadLock([&] {
_pulseProperties.getProperties(properties); _pulseProperties.getProperties(properties);
}); });
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText); COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight); COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight);
@ -59,7 +60,6 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textAlpha, getTextAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textAlpha, getTextAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundColor, getBackgroundColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundColor, getBackgroundColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundAlpha, getBackgroundAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundAlpha, getBackgroundAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(leftMargin, getLeftMargin); COPY_ENTITY_PROPERTY_TO_PROPERTIES(leftMargin, getLeftMargin);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rightMargin, getRightMargin); COPY_ENTITY_PROPERTY_TO_PROPERTIES(rightMargin, getRightMargin);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(topMargin, getTopMargin); COPY_ENTITY_PROPERTY_TO_PROPERTIES(topMargin, getTopMargin);
@ -75,6 +75,7 @@ bool TextEntityItem::setProperties(const EntityItemProperties& properties) {
bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); bool pulsePropertiesChanged = _pulseProperties.setProperties(properties);
somethingChanged |= pulsePropertiesChanged; somethingChanged |= pulsePropertiesChanged;
}); });
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(text, setText); SET_ENTITY_PROPERTY_FROM_PROPERTIES(text, setText);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight);
@ -82,7 +83,6 @@ bool TextEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textAlpha, setTextAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textAlpha, setTextAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundColor, setBackgroundColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundColor, setBackgroundColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundAlpha, setBackgroundAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundAlpha, setBackgroundAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(leftMargin, setLeftMargin); SET_ENTITY_PROPERTY_FROM_PROPERTIES(leftMargin, setLeftMargin);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rightMargin, setRightMargin); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rightMargin, setRightMargin);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(topMargin, setTopMargin); SET_ENTITY_PROPERTY_FROM_PROPERTIES(topMargin, setTopMargin);
@ -117,6 +117,7 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesRead += bytesFromPulse; bytesRead += bytesFromPulse;
dataAt += bytesFromPulse; dataAt += bytesFromPulse;
}); });
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_TEXT, QString, setText); READ_ENTITY_PROPERTY(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight); READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight);
@ -124,7 +125,6 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_TEXT_ALPHA, float, setTextAlpha); READ_ENTITY_PROPERTY(PROP_TEXT_ALPHA, float, setTextAlpha);
READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, glm::u8vec3, setBackgroundColor); READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, glm::u8vec3, setBackgroundColor);
READ_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, float, setBackgroundAlpha); READ_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, float, setBackgroundAlpha);
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_LEFT_MARGIN, float, setLeftMargin); READ_ENTITY_PROPERTY(PROP_LEFT_MARGIN, float, setLeftMargin);
READ_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, float, setRightMargin); READ_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, float, setRightMargin);
READ_ENTITY_PROPERTY(PROP_TOP_MARGIN, float, setTopMargin); READ_ENTITY_PROPERTY(PROP_TOP_MARGIN, float, setTopMargin);
@ -137,13 +137,14 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += _pulseProperties.getEntityProperties(params); requestedProperties += _pulseProperties.getEntityProperties(params);
requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_TEXT; requestedProperties += PROP_TEXT;
requestedProperties += PROP_LINE_HEIGHT; requestedProperties += PROP_LINE_HEIGHT;
requestedProperties += PROP_TEXT_COLOR; requestedProperties += PROP_TEXT_COLOR;
requestedProperties += PROP_TEXT_ALPHA; requestedProperties += PROP_TEXT_ALPHA;
requestedProperties += PROP_BACKGROUND_COLOR; requestedProperties += PROP_BACKGROUND_COLOR;
requestedProperties += PROP_BACKGROUND_ALPHA; requestedProperties += PROP_BACKGROUND_ALPHA;
requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_LEFT_MARGIN; requestedProperties += PROP_LEFT_MARGIN;
requestedProperties += PROP_RIGHT_MARGIN; requestedProperties += PROP_RIGHT_MARGIN;
requestedProperties += PROP_TOP_MARGIN; requestedProperties += PROP_TOP_MARGIN;
@ -166,6 +167,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState); propertyFlags, propertiesDidntFit, propertyCount, appendState);
}); });
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_TEXT, getText()); APPEND_ENTITY_PROPERTY(PROP_TEXT, getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight());
@ -173,12 +175,20 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
APPEND_ENTITY_PROPERTY(PROP_TEXT_ALPHA, getTextAlpha()); APPEND_ENTITY_PROPERTY(PROP_TEXT_ALPHA, getTextAlpha());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, getBackgroundAlpha()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, getBackgroundAlpha());
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_LEFT_MARGIN, getLeftMargin()); APPEND_ENTITY_PROPERTY(PROP_LEFT_MARGIN, getLeftMargin());
APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, getRightMargin()); APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, getRightMargin());
APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, getTopMargin()); APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, getTopMargin());
APPEND_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, getBottomMargin()); APPEND_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, getBottomMargin());
}
glm::vec3 TextEntityItem::getRaycastDimensions() const {
glm::vec3 dimensions = getScaledDimensions();
if (getBillboardMode() != BillboardMode::NONE) {
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
const float SQRT_2 = 1.41421356237f;
return glm::vec3(SQRT_2 * max);
}
return dimensions;
} }
bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@ -189,6 +199,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation(); glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode);
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT; glm::vec3 forward = rotation * Vectors::FRONT;

View file

@ -47,6 +47,7 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override; bool& somethingChanged) override;
glm::vec3 getRaycastDimensions() const override;
virtual bool supportsDetailedIntersection() const override { return true; } virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance, OctreeElementPointer& element, float& distance,
@ -99,6 +100,8 @@ public:
PulsePropertyGroup getPulseProperties() const; PulsePropertyGroup getPulseProperties() const;
private: private:
BillboardMode _billboardMode;
QString _text; QString _text;
float _lineHeight; float _lineHeight;
glm::u8vec3 _textColor; glm::u8vec3 _textColor;
@ -106,7 +109,6 @@ private:
glm::u8vec3 _backgroundColor; glm::u8vec3 _backgroundColor;
float _backgroundAlpha; float _backgroundAlpha;
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
float _leftMargin; float _leftMargin;
float _rightMargin; float _rightMargin;
float _topMargin; float _topMargin;

View file

@ -48,6 +48,7 @@ EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& des
withReadLock([&] { withReadLock([&] {
_pulseProperties.getProperties(properties); _pulseProperties.getProperties(properties);
}); });
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl); COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dpi, getDPI); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dpi, getDPI);
@ -68,6 +69,7 @@ bool WebEntityItem::setProperties(const EntityItemProperties& properties) {
bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); bool pulsePropertiesChanged = _pulseProperties.setProperties(properties);
somethingChanged |= pulsePropertiesChanged; somethingChanged |= pulsePropertiesChanged;
}); });
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(sourceUrl, setSourceUrl); SET_ENTITY_PROPERTY_FROM_PROPERTIES(sourceUrl, setSourceUrl);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dpi, setDPI); SET_ENTITY_PROPERTY_FROM_PROPERTIES(dpi, setDPI);
@ -107,6 +109,7 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
bytesRead += bytesFromPulse; bytesRead += bytesFromPulse;
dataAt += bytesFromPulse; dataAt += bytesFromPulse;
}); });
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_SOURCE_URL, QString, setSourceUrl); READ_ENTITY_PROPERTY(PROP_SOURCE_URL, QString, setSourceUrl);
READ_ENTITY_PROPERTY(PROP_DPI, uint16_t, setDPI); READ_ENTITY_PROPERTY(PROP_DPI, uint16_t, setDPI);
@ -123,6 +126,7 @@ EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& pa
requestedProperties += PROP_COLOR; requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA; requestedProperties += PROP_ALPHA;
requestedProperties += _pulseProperties.getEntityProperties(params); requestedProperties += _pulseProperties.getEntityProperties(params);
requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_SOURCE_URL; requestedProperties += PROP_SOURCE_URL;
requestedProperties += PROP_DPI; requestedProperties += PROP_DPI;
@ -148,6 +152,7 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState); propertyFlags, propertiesDidntFit, propertyCount, appendState);
}); });
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, getSourceUrl()); APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, getSourceUrl());
APPEND_ENTITY_PROPERTY(PROP_DPI, getDPI()); APPEND_ENTITY_PROPERTY(PROP_DPI, getDPI());
@ -157,6 +162,16 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, getShowKeyboardFocusHighlight()); APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, getShowKeyboardFocusHighlight());
} }
glm::vec3 WebEntityItem::getRaycastDimensions() const {
glm::vec3 dimensions = getScaledDimensions();
if (getBillboardMode() != BillboardMode::NONE) {
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
const float SQRT_2 = 1.41421356237f;
return glm::vec3(SQRT_2 * max);
}
return dimensions;
}
bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, BoxFace& face, glm::vec3& surfaceNormal,
@ -165,6 +180,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g
glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation(); glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode);
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT; glm::vec3 forward = rotation * Vectors::FRONT;
@ -235,6 +251,18 @@ float WebEntityItem::getAlpha() const {
}); });
} }
BillboardMode WebEntityItem::getBillboardMode() const {
return resultWithReadLock<BillboardMode>([&] {
return _billboardMode;
});
}
void WebEntityItem::setBillboardMode(BillboardMode value) {
withWriteLock([&] {
_billboardMode = value;
});
}
void WebEntityItem::setSourceUrl(const QString& value) { void WebEntityItem::setSourceUrl(const QString& value) {
withWriteLock([&] { withWriteLock([&] {
_sourceUrl = value; _sourceUrl = value;

View file

@ -44,6 +44,7 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override; bool& somethingChanged) override;
glm::vec3 getRaycastDimensions() const override;
virtual bool supportsDetailedIntersection() const override { return true; } virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance, OctreeElementPointer& element, float& distance,
@ -60,6 +61,9 @@ public:
float getAlpha() const; float getAlpha() const;
void setAlpha(float alpha); void setAlpha(float alpha);
void setBillboardMode(BillboardMode value);
BillboardMode getBillboardMode() const;
static const QString DEFAULT_SOURCE_URL; static const QString DEFAULT_SOURCE_URL;
void setSourceUrl(const QString& value); void setSourceUrl(const QString& value);
QString getSourceUrl() const; QString getSourceUrl() const;
@ -86,6 +90,7 @@ protected:
glm::u8vec3 _color; glm::u8vec3 _color;
float _alpha { 1.0f }; float _alpha { 1.0f };
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
QString _sourceUrl; QString _sourceUrl;
uint16_t _dpi; uint16_t _dpi;

View file

@ -261,6 +261,7 @@ enum class EntityVersion : PacketVersion {
PulseProperties, PulseProperties,
RingGizmoEntities, RingGizmoEntities,
ShowKeyboardFocusHighlight, ShowKeyboardFocusHighlight,
WebBillboardMode,
// Add new versions above here // Add new versions above here
NUM_PACKET_TYPE, NUM_PACKET_TYPE,

View file

@ -17,7 +17,10 @@
#include "ShapeFactory.h" #include "ShapeFactory.h"
const int MAX_RING_SIZE = 256;
ShapeManager::ShapeManager() { ShapeManager::ShapeManager() {
_garbageRing.reserve(MAX_RING_SIZE);
} }
ShapeManager::~ShapeManager() { ShapeManager::~ShapeManager() {
@ -33,8 +36,8 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
if (info.getType() == SHAPE_TYPE_NONE) { if (info.getType() == SHAPE_TYPE_NONE) {
return nullptr; return nullptr;
} }
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
ShapeReference* shapeRef = _shapeMap.find(key); ShapeReference* shapeRef = _shapeMap.find(hashKey);
if (shapeRef) { if (shapeRef) {
shapeRef->refCount++; shapeRef->refCount++;
return shapeRef->shape; return shapeRef->shape;
@ -44,23 +47,43 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
ShapeReference newRef; ShapeReference newRef;
newRef.refCount = 1; newRef.refCount = 1;
newRef.shape = shape; newRef.shape = shape;
newRef.key = key; newRef.key = info.getHash();
_shapeMap.insert(key, newRef); _shapeMap.insert(hashKey, newRef);
} }
return shape; return shape;
} }
// private helper method // private helper method
bool ShapeManager::releaseShapeByKey(const HashKey& key) { bool ShapeManager::releaseShapeByKey(uint64_t key) {
ShapeReference* shapeRef = _shapeMap.find(key); HashKey hashKey(key);
ShapeReference* shapeRef = _shapeMap.find(hashKey);
if (shapeRef) { if (shapeRef) {
if (shapeRef->refCount > 0) { if (shapeRef->refCount > 0) {
shapeRef->refCount--; shapeRef->refCount--;
if (shapeRef->refCount == 0) { if (shapeRef->refCount == 0) {
_pendingGarbage.push_back(key); // look for existing entry in _garbageRing
const int MAX_SHAPE_GARBAGE_CAPACITY = 255; int32_t ringSize = (int32_t)(_garbageRing.size());
if (_pendingGarbage.size() > MAX_SHAPE_GARBAGE_CAPACITY) { for (int32_t i = 0; i < ringSize; ++i) {
collectGarbage(); int32_t j = (_ringIndex + ringSize) % ringSize;
if (_garbageRing[j] == key) {
// already on the list, don't add it again
return true;
}
}
if (ringSize == MAX_RING_SIZE) {
// remove one
HashKey hashKeyToRemove(_garbageRing[_ringIndex]);
ShapeReference* shapeRef = _shapeMap.find(hashKeyToRemove);
if (shapeRef && shapeRef->refCount == 0) {
ShapeFactory::deleteShape(shapeRef->shape);
_shapeMap.remove(hashKeyToRemove);
}
// replace at _ringIndex and advance
_garbageRing[_ringIndex] = key;
_ringIndex = (_ringIndex + 1) % ringSize;
} else {
// add one
_garbageRing.push_back(key);
} }
} }
return true; return true;
@ -87,21 +110,22 @@ bool ShapeManager::releaseShape(const btCollisionShape* shape) {
} }
void ShapeManager::collectGarbage() { void ShapeManager::collectGarbage() {
int numShapes = _pendingGarbage.size(); int numShapes = (int32_t)(_garbageRing.size());
for (int i = 0; i < numShapes; ++i) { for (int i = 0; i < numShapes; ++i) {
HashKey& key = _pendingGarbage[i]; HashKey key(_garbageRing[i]);
ShapeReference* shapeRef = _shapeMap.find(key); ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef && shapeRef->refCount == 0) { if (shapeRef && shapeRef->refCount == 0) {
ShapeFactory::deleteShape(shapeRef->shape); ShapeFactory::deleteShape(shapeRef->shape);
_shapeMap.remove(key); _shapeMap.remove(key);
} }
} }
_pendingGarbage.clear(); _ringIndex = 0;
_garbageRing.clear();
} }
int ShapeManager::getNumReferences(const ShapeInfo& info) const { int ShapeManager::getNumReferences(const ShapeInfo& info) const {
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
const ShapeReference* shapeRef = _shapeMap.find(key); const ShapeReference* shapeRef = _shapeMap.find(hashKey);
if (shapeRef) { if (shapeRef) {
return shapeRef->refCount; return shapeRef->refCount;
} }

View file

@ -12,6 +12,8 @@
#ifndef hifi_ShapeManager_h #ifndef hifi_ShapeManager_h
#define hifi_ShapeManager_h #define hifi_ShapeManager_h
#include <vector>
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <LinearMath/btHashMap.h> #include <LinearMath/btHashMap.h>
@ -41,6 +43,7 @@
// later. When that list grows big enough the ShapeManager will remove any matching // later. When that list grows big enough the ShapeManager will remove any matching
// entries that still have zero ref-count. // entries that still have zero ref-count.
class ShapeManager { class ShapeManager {
public: public:
@ -63,19 +66,20 @@ public:
bool hasShape(const btCollisionShape* shape) const; bool hasShape(const btCollisionShape* shape) const;
private: private:
bool releaseShapeByKey(const HashKey& key); bool releaseShapeByKey(uint64_t key);
class ShapeReference { class ShapeReference {
public: public:
int refCount; int refCount;
const btCollisionShape* shape; const btCollisionShape* shape;
HashKey key; uint64_t key { 0 };
ShapeReference() : refCount(0), shape(nullptr) {} ShapeReference() : refCount(0), shape(nullptr) {}
}; };
// btHashMap is required because it supports memory alignment of the btCollisionShapes // btHashMap is required because it supports memory alignment of the btCollisionShapes
btHashMap<HashKey, ShapeReference> _shapeMap; btHashMap<HashKey, ShapeReference> _shapeMap;
btAlignedObjectArray<HashKey> _pendingGarbage; std::vector<uint64_t> _garbageRing;
uint32_t _ringIndex { 0 };
}; };
#endif // hifi_ShapeManager_h #endif // hifi_ShapeManager_h

View file

@ -32,17 +32,19 @@ class HashKey {
public: public:
static float getNumQuantizedValuesPerMeter(); static float getNumQuantizedValuesPerMeter();
HashKey() {}
HashKey(uint64_t hash) : _hash(hash) {}
// These two methods are required by btHashMap. // These two methods are required by btHashMap.
bool equals(const HashKey& other) const { return _hash == other._hash; } bool equals(const HashKey& other) const { return _hash == other._hash; }
int32_t getHash() const { return (int32_t)((uint32_t)_hash); } int32_t getHash() const { return (int32_t)((uint32_t)_hash); }
void clear() { _hash = _hashCount = 0; } // These methods for accumulating a hash.
bool isNull() const { return _hash == 0 && _hashCount == 0; }
void hashUint64(uint64_t data); void hashUint64(uint64_t data);
void hashFloat(float data); void hashFloat(float data);
void hashVec3(const glm::vec3& data); void hashVec3(const glm::vec3& data);
uint64_t getHash64() const { return _hash; } // for debug/test purposes uint64_t getHash64() const { return _hash; }
private: private:
uint64_t _hash { 0 }; uint64_t _hash { 0 };

View file

@ -13,6 +13,7 @@
#include <math.h> #include <math.h>
#include "HashKey.h"
#include "NumericalConstants.h" // for MILLIMETERS_PER_METER #include "NumericalConstants.h" // for MILLIMETERS_PER_METER
/**jsdoc /**jsdoc
@ -96,7 +97,7 @@ void ShapeInfo::clear() {
_sphereCollection.clear(); _sphereCollection.clear();
_halfExtents = glm::vec3(0.0f); _halfExtents = glm::vec3(0.0f);
_offset = glm::vec3(0.0f); _offset = glm::vec3(0.0f);
_hashKey.clear(); _hash64 = 0;
_type = SHAPE_TYPE_NONE; _type = SHAPE_TYPE_NONE;
} }
@ -131,14 +132,14 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
default: default:
break; break;
} }
_hashKey.clear(); _hash64 = 0;
} }
void ShapeInfo::setBox(const glm::vec3& halfExtents) { void ShapeInfo::setBox(const glm::vec3& halfExtents) {
_url = ""; _url = "";
_type = SHAPE_TYPE_BOX; _type = SHAPE_TYPE_BOX;
setHalfExtents(halfExtents); setHalfExtents(halfExtents);
_hashKey.clear(); _hash64 = 0;
} }
void ShapeInfo::setSphere(float radius) { void ShapeInfo::setSphere(float radius) {
@ -146,7 +147,7 @@ void ShapeInfo::setSphere(float radius) {
_type = SHAPE_TYPE_SPHERE; _type = SHAPE_TYPE_SPHERE;
radius = glm::max(radius, MIN_HALF_EXTENT); radius = glm::max(radius, MIN_HALF_EXTENT);
_halfExtents = glm::vec3(radius); _halfExtents = glm::vec3(radius);
_hashKey.clear(); _hash64 = 0;
} }
void ShapeInfo::setMultiSphere(const std::vector<glm::vec3>& centers, const std::vector<float>& radiuses) { void ShapeInfo::setMultiSphere(const std::vector<glm::vec3>& centers, const std::vector<float>& radiuses) {
@ -158,12 +159,12 @@ void ShapeInfo::setMultiSphere(const std::vector<glm::vec3>& centers, const std:
SphereData sphere = SphereData(centers[i], radiuses[i]); SphereData sphere = SphereData(centers[i], radiuses[i]);
_sphereCollection.push_back(sphere); _sphereCollection.push_back(sphere);
} }
_hashKey.clear(); _hash64 = 0;
} }
void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) { void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) {
_pointCollection = pointCollection; _pointCollection = pointCollection;
_hashKey.clear(); _hash64 = 0;
} }
void ShapeInfo::setCapsuleY(float radius, float cylinderHalfHeight) { void ShapeInfo::setCapsuleY(float radius, float cylinderHalfHeight) {
@ -172,12 +173,12 @@ void ShapeInfo::setCapsuleY(float radius, float cylinderHalfHeight) {
radius = glm::max(radius, MIN_HALF_EXTENT); radius = glm::max(radius, MIN_HALF_EXTENT);
cylinderHalfHeight = glm::max(cylinderHalfHeight, 0.0f); cylinderHalfHeight = glm::max(cylinderHalfHeight, 0.0f);
_halfExtents = glm::vec3(radius, cylinderHalfHeight + radius, radius); _halfExtents = glm::vec3(radius, cylinderHalfHeight + radius, radius);
_hashKey.clear(); _hash64 = 0;
} }
void ShapeInfo::setOffset(const glm::vec3& offset) { void ShapeInfo::setOffset(const glm::vec3& offset) {
_offset = offset; _offset = offset;
_hashKey.clear(); _hash64 = 0;
} }
uint32_t ShapeInfo::getNumSubShapes() const { uint32_t ShapeInfo::getNumSubShapes() const {
@ -269,20 +270,21 @@ float ShapeInfo::computeVolume() const {
return volume; return volume;
} }
const HashKey& ShapeInfo::getHash() const { uint64_t ShapeInfo::getHash() const {
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance. // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
if (_hashKey.isNull() && _type != SHAPE_TYPE_NONE) { if (_hash64 == 0 && _type != SHAPE_TYPE_NONE) {
HashKey hashKey;
// The key is not yet cached therefore we must compute it. // The key is not yet cached therefore we must compute it.
_hashKey.hashUint64((uint64_t)_type); hashKey.hashUint64((uint64_t)_type);
if (_type == SHAPE_TYPE_MULTISPHERE) { if (_type == SHAPE_TYPE_MULTISPHERE) {
for (auto &sphereData : _sphereCollection) { for (auto &sphereData : _sphereCollection) {
_hashKey.hashVec3(glm::vec3(sphereData)); hashKey.hashVec3(glm::vec3(sphereData));
_hashKey.hashFloat(sphereData.w); hashKey.hashFloat(sphereData.w);
} }
} else if (_type != SHAPE_TYPE_SIMPLE_HULL) { } else if (_type != SHAPE_TYPE_SIMPLE_HULL) {
_hashKey.hashVec3(_halfExtents); hashKey.hashVec3(_halfExtents);
_hashKey.hashVec3(_offset); hashKey.hashVec3(_offset);
} else { } else {
// TODO: we could avoid hashing all of these points if we were to supply the ShapeInfo with a unique // TODO: we could avoid hashing all of these points if we were to supply the ShapeInfo with a unique
// descriptive string. Shapes that are uniquely described by their type and URL could just put their // descriptive string. Shapes that are uniquely described by their type and URL could just put their
@ -292,7 +294,7 @@ const HashKey& ShapeInfo::getHash() const {
const int numPoints = (int)points.size(); const int numPoints = (int)points.size();
for (int i = 0; i < numPoints; ++i) { for (int i = 0; i < numPoints; ++i) {
_hashKey.hashVec3(points[i]); hashKey.hashVec3(points[i]);
} }
} }
@ -300,23 +302,24 @@ const HashKey& ShapeInfo::getHash() const {
if (!url.isEmpty()) { if (!url.isEmpty()) {
QByteArray baUrl = url.toLocal8Bit(); QByteArray baUrl = url.toLocal8Bit();
uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size()); uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size());
_hashKey.hashUint64((uint64_t)urlHash); hashKey.hashUint64((uint64_t)urlHash);
} }
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) { if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) {
uint64_t numHulls = (uint64_t)_pointCollection.size(); uint64_t numHulls = (uint64_t)_pointCollection.size();
_hashKey.hashUint64(numHulls); hashKey.hashUint64(numHulls);
} else if (_type == SHAPE_TYPE_MULTISPHERE) { } else if (_type == SHAPE_TYPE_MULTISPHERE) {
uint64_t numSpheres = (uint64_t)_sphereCollection.size(); uint64_t numSpheres = (uint64_t)_sphereCollection.size();
_hashKey.hashUint64(numSpheres); hashKey.hashUint64(numSpheres);
} else if (_type == SHAPE_TYPE_SIMPLE_HULL) { } else if (_type == SHAPE_TYPE_SIMPLE_HULL) {
_hashKey.hashUint64(1); hashKey.hashUint64(1);
} }
_hash64 = hashKey.getHash64();
} }
return _hashKey; return _hash64;
} }
void ShapeInfo::setHalfExtents(const glm::vec3& halfExtents) { void ShapeInfo::setHalfExtents(const glm::vec3& halfExtents) {
_halfExtents = glm::max(halfExtents, glm::vec3(MIN_HALF_EXTENT)); _halfExtents = glm::max(halfExtents, glm::vec3(MIN_HALF_EXTENT));
_hashKey.clear(); _hash64 = 0;
} }

View file

@ -18,8 +18,6 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtx/norm.hpp> #include <glm/gtx/norm.hpp>
#include "HashKey.h"
const float MIN_SHAPE_OFFSET = 0.001f; // offsets less than 1mm will be ignored const float MIN_SHAPE_OFFSET = 0.001f; // offsets less than 1mm will be ignored
// Bullet has a mesh generation util for convex shapes that we used to // Bullet has a mesh generation util for convex shapes that we used to
@ -91,7 +89,7 @@ public:
float computeVolume() const; float computeVolume() const;
const HashKey& getHash() const; uint64_t getHash() const;
protected: protected:
void setHalfExtents(const glm::vec3& halfExtents); void setHalfExtents(const glm::vec3& halfExtents);
@ -102,7 +100,7 @@ protected:
TriangleIndices _triangleIndices; TriangleIndices _triangleIndices;
glm::vec3 _halfExtents = glm::vec3(0.0f); glm::vec3 _halfExtents = glm::vec3(0.0f);
glm::vec3 _offset = glm::vec3(0.0f); glm::vec3 _offset = glm::vec3(0.0f);
mutable HashKey _hashKey; mutable uint64_t _hash64;
ShapeType _type = SHAPE_TYPE_NONE; ShapeType _type = SHAPE_TYPE_NONE;
}; };

View file

@ -55,20 +55,20 @@ void ShapeInfoTests::testHashFunctions() {
// test sphere // test sphere
info.setSphere(radiusX); info.setSphere(radiusX);
++testCount; ++testCount;
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
hashPtr = hashes.find(key); hashPtr = hashes.find(hashKey);
if (hashPtr) { if (hashPtr) {
std::cout << testCount << " hash collision sphere radius = " << radiusX std::cout << testCount << " hash collision sphere radius = " << radiusX
<< " h = 0x" << std::hex << key.getHash() << " : 0x" << *hashPtr << " h = 0x" << std::hex << hashKey.getHash() << " : 0x" << *hashPtr
<< std::dec << std::endl; << std::dec << std::endl;
++numCollisions; ++numCollisions;
assert(false); assert(false);
} else { } else {
hashes.insert(key, key.getHash()); hashes.insert(hashKey, hashKey.getHash());
} }
// track bit distribution counts to evaluate hash function randomness // track bit distribution counts to evaluate hash function randomness
for (int j = 0; j < NUM_HASH_BITS; ++j) { for (int j = 0; j < NUM_HASH_BITS; ++j) {
if (masks[j] & key.getHash()) { if (masks[j] & hashKey.getHash()) {
++bits[j]; ++bits[j];
} }
} }
@ -80,21 +80,21 @@ void ShapeInfoTests::testHashFunctions() {
// test box // test box
info.setBox(glm::vec3(radiusX, radiusY, radiusZ)); info.setBox(glm::vec3(radiusX, radiusY, radiusZ));
++testCount; ++testCount;
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
hashPtr = hashes.find(key); hashPtr = hashes.find(hashKey);
if (hashPtr) { if (hashPtr) {
std::cout << testCount << " hash collision box dimensions = < " << radiusX std::cout << testCount << " hash collision box dimensions = < " << radiusX
<< ", " << radiusY << ", " << radiusZ << " >" << ", " << radiusY << ", " << radiusZ << " >"
<< " h = 0x" << std::hex << key.getHash() << " : 0x" << *hashPtr << " : 0x" << key.getHash64() << " h = 0x" << std::hex << hashKey.getHash() << " : 0x" << *hashPtr << " : 0x" << hashKey.getHash64()
<< std::dec << std::endl; << std::dec << std::endl;
++numCollisions; ++numCollisions;
assert(false); assert(false);
} else { } else {
hashes.insert(key, key.getHash()); hashes.insert(hashKey, hashKey.getHash());
} }
// track bit distribution counts to evaluate hash function randomness // track bit distribution counts to evaluate hash function randomness
for (int k = 0; k < NUM_HASH_BITS; ++k) { for (int k = 0; k < NUM_HASH_BITS; ++k) {
if (masks[k] & key.getHash()) { if (masks[k] & hashKey.getHash()) {
++bits[k]; ++bits[k];
} }
} }
@ -117,14 +117,14 @@ void ShapeInfoTests::testBoxShape() {
ShapeInfo info; ShapeInfo info;
glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); glm::vec3 halfExtents(1.23f, 4.56f, 7.89f);
info.setBox(halfExtents); info.setBox(halfExtents);
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
QCOMPARE(shape != nullptr, true); QCOMPARE(shape != nullptr, true);
ShapeInfo otherInfo = info; ShapeInfo otherInfo = info;
HashKey otherKey = otherInfo.getHash(); HashKey otherKey = otherInfo.getHash();
QCOMPARE(key.getHash(), otherKey.getHash()); QCOMPARE(hashKey.getHash(), otherKey.getHash());
delete shape; delete shape;
} }
@ -133,14 +133,14 @@ void ShapeInfoTests::testSphereShape() {
ShapeInfo info; ShapeInfo info;
float radius = 1.23f; float radius = 1.23f;
info.setSphere(radius); info.setSphere(radius);
HashKey key = info.getHash(); HashKey hashKey = info.getHash();
const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
QCOMPARE(shape != nullptr, true); QCOMPARE(shape != nullptr, true);
ShapeInfo otherInfo = info; ShapeInfo otherInfo = info;
HashKey otherKey = otherInfo.getHash(); HashKey otherKey = otherInfo.getHash();
QCOMPARE(key.getHash(), otherKey.getHash()); QCOMPARE(hashKey.getHash(), otherKey.getHash());
delete shape; delete shape;
} }
@ -151,14 +151,14 @@ void ShapeInfoTests::testCylinderShape() {
float radius = 1.23f; float radius = 1.23f;
float height = 4.56f; float height = 4.56f;
info.setCylinder(radius, height); info.setCylinder(radius, height);
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
QCOMPARE(shape != nullptr, true); QCOMPARE(shape != nullptr, true);
ShapeInfo otherInfo = info; ShapeInfo otherInfo = info;
HashKey otherKey = otherInfo.getHash(); HashKey otherKey = otherInfo.getHash();
QCOMPARE(key.getHash(), otherKey.getHash()); QCOMPARE(hashKey.getHash(), otherKey.getHash());
delete shape; delete shape;
*/ */
@ -170,14 +170,14 @@ void ShapeInfoTests::testCapsuleShape() {
float radius = 1.23f; float radius = 1.23f;
float height = 4.56f; float height = 4.56f;
info.setCapsule(radius, height); info.setCapsule(radius, height);
HashKey key = info.getHash(); HashKey hashKey(info.getHash());
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
QCOMPARE(shape != nullptr, true); QCOMPARE(shape != nullptr, true);
ShapeInfo otherInfo = info; ShapeInfo otherInfo = info;
HashKey otherKey = otherInfo.getHash(); HashKey otherKey = otherInfo.getHash();
QCOMPARE(key.getHash(), otherKey.getHash()); QCOMPARE(hashKey.getHash(), otherKey.getHash());
delete shape; delete shape;
*/ */