diff --git a/examples/example/entities/zoneEntityExample.js b/examples/example/entities/zoneEntityExample.js
index 052de06a1d..b5831a2bb5 100644
--- a/examples/example/entities/zoneEntityExample.js
+++ b/examples/example/entities/zoneEntityExample.js
@@ -22,7 +22,8 @@ var zoneEntityA = Entities.addEntity({
dimensions: { x: 10, y: 10, z: 10 },
keyLightColor: { red: 255, green: 0, blue: 0 },
stageSunModelEnabled: false,
- keyLightDirection: { x: 0, y: -1.0, z: 0 }
+ keyLightDirection: { x: 0, y: -1.0, z: 0 },
+ shapeType: "sphere"
});
print("zoneEntityA:" + zoneEntityA);
@@ -51,7 +52,9 @@ var zoneEntityC = Entities.addEntity({
keyLightColor: { red: 0, green: 0, blue: 255 },
keyLightIntensity: 0.75,
keyLightDirection: { x: 0, y: 0, z: -1 },
- stageSunModelEnabled: false
+ stageSunModelEnabled: false,
+ shapeType: "compound",
+ compoundShapeURL: "http://headache.hungry.com/~seth/hifi/cube.fbx"
});
print("zoneEntityC:" + zoneEntityC);
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index 348dc00df4..b1962bc18b 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -162,7 +162,7 @@
var elModelSections = document.querySelectorAll(".model-section");
var elModelURL = document.getElementById("property-model-url");
- var elCollisionModelURL = document.getElementById("property-collision-model-url");
+ var elCompoundShapeURL = document.getElementById("property-compound-shape-url");
var elModelAnimationURL = document.getElementById("property-model-animation-url");
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
@@ -323,7 +323,7 @@
}
elModelURL.value = properties.modelURL;
- elCollisionModelURL.value = properties.collisionModelURL;
+ elCompoundShapeURL.value = properties.compoundShapeURL;
elModelAnimationURL.value = properties.animationURL;
elModelAnimationPlaying.checked = properties.animationIsPlaying;
elModelAnimationFPS.value = properties.animationFPS;
@@ -487,7 +487,7 @@
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL'));
- elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL'));
+ elCompoundShapeURL.addEventListener('change', createEmitTextPropertyUpdateFunction('compoundShapeURL'));
elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL'));
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
@@ -775,9 +775,9 @@
diff --git a/examples/libraries/ToolTip.js b/examples/libraries/ToolTip.js
index 680f617436..2b0e125d4b 100644
--- a/examples/libraries/ToolTip.js
+++ b/examples/libraries/ToolTip.js
@@ -53,7 +53,7 @@ function Tooltip() {
text += "ID: " + properties.id + "\n"
if (properties.type == "Model") {
text += "Model URL: " + properties.modelURL + "\n"
- text += "Collision Model URL: " + properties.collisionModelURL + "\n"
+ text += "Compound Shape URL: " + properties.compoundShapeURL + "\n"
text += "Animation URL: " + properties.animationURL + "\n"
text += "Animation is playing: " + properties.animationIsPlaying + "\n"
if (properties.sittingPoints && properties.sittingPoints.length > 0) {
diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js
index d8a91da8f9..255cec4265 100644
--- a/examples/libraries/entityPropertyDialogBox.js
+++ b/examples/libraries/entityPropertyDialogBox.js
@@ -52,7 +52,7 @@ EntityPropertyDialogBox = (function () {
if (properties.type == "Model") {
array.push({ label: "Model URL:", value: properties.modelURL });
index++;
- array.push({ label: "Collision Model URL:", value: properties.collisionModelURL });
+ array.push({ label: "Compound Shape URL:", value: properties.compoundShapeURL });
index++;
array.push({ label: "Animation URL:", value: properties.animationURL });
index++;
@@ -284,7 +284,7 @@ EntityPropertyDialogBox = (function () {
properties.locked = array[index++].value;
if (properties.type == "Model") {
properties.modelURL = array[index++].value;
- properties.collisionModelURL = array[index++].value;
+ properties.compoundShapeURL = array[index++].value;
properties.animationURL = array[index++].value;
var newAnimationIsPlaying = array[index++].value;
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index f6557b5f9a..dde13552f3 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -34,8 +34,8 @@
#include "RenderableParticleEffectEntityItem.h"
#include "RenderableSphereEntityItem.h"
#include "RenderableTextEntityItem.h"
+#include "RenderableZoneEntityItem.h"
#include "EntitiesRendererLogging.h"
-#include "ZoneEntityItem.h"
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
AbstractScriptingServicesInterface* scriptingServices) :
@@ -57,6 +57,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
+ REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
@@ -496,7 +497,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const Entit
if (entityItem->getType() == EntityTypes::Model) {
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast(entityItem);
- if (constModelEntityItem->hasCollisionModel()) {
+ if (constModelEntityItem->hasCompoundShapeURL()) {
RenderableModelEntityItem* modelEntityItem = const_cast(constModelEntityItem);
Model* model = modelEntityItem->getModel(this);
if (model) {
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 86b0be4dd8..8ca6562505 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -224,10 +224,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
// if we have a previously allocated model, but its URL doesn't match
// then we need to let our renderer update our model for us.
if (_model && QUrl(getModelURL()) != _model->getURL()) {
- result = _model = _myRenderer->updateModel(_model, getModelURL(), getCollisionModelURL());
+ result = _model = _myRenderer->updateModel(_model, getModelURL(), getCompoundShapeURL());
_needsInitialSimulation = true;
} else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one
- result = _model = _myRenderer->allocateModel(getModelURL(), getCollisionModelURL());
+ result = _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL());
_needsInitialSimulation = true;
} else { // we already have the model we want...
result = _model;
@@ -267,8 +267,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
}
-void RenderableModelEntityItem::setCollisionModelURL(const QString& url) {
- ModelEntityItem::setCollisionModelURL(url);
+void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
+ ModelEntityItem::setCompoundShapeURL(url);
if (_model) {
_model->setCollisionModelURL(QUrl(url));
}
@@ -410,8 +410,17 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
glm::vec3 collisionModelDimensions = box.getDimensions();
- info.setParams(type, collisionModelDimensions, _collisionModelURL);
+ info.setParams(type, collisionModelDimensions, _compoundShapeURL);
info.setConvexHulls(_points);
}
}
+bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
+ if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) {
+ const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry();
+ const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
+ return collisionGeometry.convexHullContains(worldToEntity(point));
+ }
+
+ return false;
+}
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h
index b632357942..43f18af0db 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h
@@ -52,10 +52,12 @@ public:
bool needsToCallUpdate() const;
- virtual void setCollisionModelURL(const QString& url);
+ virtual void setCompoundShapeURL(const QString& url);
bool isReadyToComputeShape();
void computeShapeInfo(ShapeInfo& info);
+
+ virtual bool contains(const glm::vec3& point) const;
private:
void remapTextures();
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
new file mode 100644
index 0000000000..e4c56dc419
--- /dev/null
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -0,0 +1,57 @@
+//
+// RenderableZoneEntityItem.cpp
+//
+//
+// Created by Clement on 4/22/15.
+// Copyright 2015 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 "RenderableZoneEntityItem.h"
+
+#include
+#include
+
+EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
+ return new RenderableZoneEntityItem(entityID, properties);
+}
+
+bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) {
+ QString oldShapeURL = getCompoundShapeURL();
+ bool somethingChanged = ZoneEntityItem::setProperties(properties);
+ if (somethingChanged && oldShapeURL != getCompoundShapeURL()) {
+ _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true);
+ }
+ return somethingChanged;
+}
+
+int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
+ ReadBitstreamToTreeParams& args,
+ EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
+ QString oldShapeURL = getCompoundShapeURL();
+ int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead,
+ args, propertyFlags, overwriteLocalData);
+ if (oldShapeURL != getCompoundShapeURL()) {
+ _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true);
+ }
+ return bytesRead;
+}
+
+bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
+ if (getShapeType() != SHAPE_TYPE_COMPOUND) {
+ return EntityItem::contains(point);
+ }
+ if (!_compoundShapeModel && hasCompoundShapeURL()) {
+ const_cast(this)->_compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true);
+ }
+
+ if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) {
+ const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry();
+ glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum;
+ return geometry.convexHullContains(worldToEntity(point) * meshDimensions);
+ }
+
+ return false;
+}
\ No newline at end of file
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h
new file mode 100644
index 0000000000..8d8d8b4b3f
--- /dev/null
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h
@@ -0,0 +1,39 @@
+//
+// RenderableZoneEntityItem.h
+//
+//
+// Created by Clement on 4/22/15.
+// Copyright 2015 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_RenderableZoneEntityItem_h
+#define hifi_RenderableZoneEntityItem_h
+
+#include
+
+class NetworkGeometry;
+
+class RenderableZoneEntityItem : public ZoneEntityItem {
+public:
+ static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
+
+ RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
+ ZoneEntityItem(entityItemID, properties)
+ { }
+
+ virtual bool setProperties(const EntityItemProperties& properties);
+ virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
+ ReadBitstreamToTreeParams& args,
+ EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
+
+ virtual bool contains(const glm::vec3& point) const;
+
+private:
+
+ QSharedPointer _compoundShapeModel;
+};
+
+#endif // hifi_RenderableZoneEntityItem_h
\ No newline at end of file
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 9a4471cce6..b1bf25ae9d 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -11,6 +11,8 @@
#include
+#include
+
#include
#include
#include
@@ -843,7 +845,27 @@ bool EntityItem::isMoving() const {
return hasVelocity() || hasAngularVelocity();
}
-bool EntityItem::lifetimeHasExpired() const {
+glm::mat4 EntityItem::getEntityToWorldMatrix() const {
+ glm::mat4 translation = glm::translate(getPosition());
+ glm::mat4 rotation = glm::mat4_cast(getRotation());
+ glm::mat4 scale = glm::scale(getDimensions());
+ glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
+ return translation * rotation * scale * registration;
+}
+
+glm::mat4 EntityItem::getWorldToEntityMatrix() const {
+ return glm::inverse(getEntityToWorldMatrix());
+}
+
+glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const {
+ return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f));
+}
+
+glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const {
+ return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f));
+}
+
+bool EntityItem::lifetimeHasExpired() const {
return isMortal() && (getAge() > getLifetime());
}
@@ -1033,12 +1055,6 @@ AABox EntityItem::getAABox() const {
return AABox(rotatedExtentsRelativeToRegistrationPoint);
}
-AABox EntityItem::getAABoxInDomainUnits() const {
- AABox box = getAABox();
- box.scale(1.0f / (float)TREE_SCALE);
- return box;
-}
-
// NOTE: This should only be used in cases of old bitstreams which only contain radius data
// 0,0,0 --> maxDimension,maxDimension,maxDimension
// ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension)
@@ -1066,6 +1082,16 @@ float EntityItem::getRadius() const {
return 0.5f * glm::length(_dimensions);
}
+bool EntityItem::contains(const glm::vec3& point) const {
+ if (getShapeType() == SHAPE_TYPE_COMPOUND) {
+ return getAABox().contains(point);
+ } else {
+ ShapeInfo info;
+ info.setParams(getShapeType(), glm::vec3(0.5f));
+ return info.contains(worldToEntity(point));
+ }
+}
+
void EntityItem::computeShapeInfo(ShapeInfo& info) {
info.setParams(getShapeType(), 0.5f * getDimensions());
}
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 28f1c7790b..0ebcd06a77 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -145,25 +145,16 @@ public:
// attributes applicable to all entity types
EntityTypes::EntityType getType() const { return _type; }
- glm::vec3 getPositionInDomainUnits() const { return _position / (float)TREE_SCALE; } /// get position in domain scale units (0.0 - 1.0)
const glm::vec3& getPosition() const { return _position; } /// get position in meters
- /// set position in domain scale units (0.0 - 1.0)
- void setPositionInDomainUnits(const glm::vec3& value)
- { setPosition(glm::clamp(value, 0.0f, 1.0f) * (float)TREE_SCALE); }
void setPosition(const glm::vec3& value) {
_position = value;
}
- glm::vec3 getCenterInDomainUnits() const { return getCenter() / (float) TREE_SCALE; }
glm::vec3 getCenter() const;
- glm::vec3 getDimensionsInDomainUnits() const { return _dimensions / (float)TREE_SCALE; } /// get dimensions in domain scale units (0.0 - 1.0)
const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in meters
- /// set dimensions in domain scale units (0.0 - 1.0)
- virtual void setDimensionsInDomainUnits(const glm::vec3& value) { _dimensions = glm::abs(value) * (float)TREE_SCALE; }
-
/// set dimensions in meter units (0.0 - TREE_SCALE)
virtual void setDimensions(const glm::vec3& value) { _dimensions = glm::abs(value); }
@@ -182,15 +173,11 @@ public:
float getDensity() const { return _density; }
- glm::vec3 getVelocityInDomainUnits() const { return _velocity / (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second
const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters
- void setVelocityInDomainUnits(const glm::vec3& value) { _velocity = value * (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
- glm::vec3 getGravityInDomainUnits() const { return _gravity / (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared
const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters
- void setGravityInDomainUnits(const glm::vec3& value) { _gravity = value * (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
@@ -220,7 +207,6 @@ public:
AACube getMaximumAACube() const;
AACube getMinimumAACube() const;
AABox getAABox() const; /// axis aligned bounding box in world-frame (meters)
- AABox getAABoxInDomainUnits() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
const QString& getScript() const { return _script; }
void setScript(const QString& value) { _script = value; }
@@ -267,8 +253,7 @@ public:
// TODO: get rid of users of getRadius()...
float getRadius() const;
- virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); }
- virtual bool containsInDomainUnits(const glm::vec3& point) const { return getAABoxInDomainUnits().contains(point); }
+ virtual bool contains(const glm::vec3& point) const;
virtual bool isReadyToComputeShape() { return true; }
virtual void computeShapeInfo(ShapeInfo& info);
@@ -312,6 +297,11 @@ public:
static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; }
static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; }
+ glm::mat4 getEntityToWorldMatrix() const;
+ glm::mat4 getWorldToEntityMatrix() const;
+ glm::vec3 worldToEntity(const glm::vec3 point) const;
+ glm::vec3 entityToWorld(const glm::vec3 point) const;
+
protected:
static bool _sendPhysicsUpdates;
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 5c834f71bf..7d5a40f6fd 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -44,7 +44,7 @@ EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(modelURL, ""),
- CONSTRUCT_PROPERTY(collisionModelURL, ""),
+ CONSTRUCT_PROPERTY(compoundShapeURL, ""),
CONSTRUCT_PROPERTY(animationURL, ""),
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
@@ -175,7 +175,7 @@ void EntityItemProperties::debugDump() const {
qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z;
qCDebug(entities) << " _dimensions=" << getDimensions();
qCDebug(entities) << " _modelURL=" << _modelURL;
- qCDebug(entities) << " _collisionModelURL=" << _collisionModelURL;
+ qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL;
qCDebug(entities) << " changed properties...";
EntityPropertyFlags props = getChangedProperties();
props.debugDumpBits();
@@ -245,7 +245,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
- CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL);
+ CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
@@ -322,7 +322,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
- COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
@@ -417,7 +417,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible);
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL);
- COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(collisionModelURL, setCollisionModelURL);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(compoundShapeURL, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS);
@@ -618,7 +618,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
if (properties.getType() == EntityTypes::Model) {
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
- APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL());
+ APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex());
@@ -657,6 +657,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, properties.getStageAltitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, properties.getStageDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, properties.getStageHour());
+
+ APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)properties.getShapeType());
+ APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL());
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID());
@@ -864,7 +867,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
if (properties.getType() == EntityTypes::Model) {
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
- READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
+ READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
@@ -903,6 +906,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_ALTITUDE, float, setStageAltitude);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_DAY, quint16, setStageDay);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_HOUR, float, setStageHour);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
+ READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
}
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID);
@@ -958,7 +963,7 @@ void EntityItemProperties::markAllChanged() {
_visibleChanged = true;
_colorChanged = true;
_modelURLChanged = true;
- _collisionModelURLChanged = true;
+ _compoundShapeURLChanged = true;
_animationURLChanged = true;
_animationIsPlayingChanged = true;
_animationFrameIndexChanged = true;
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 5172b3abba..faec9e1206 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -93,7 +93,7 @@ enum EntityPropertyList {
PROP_LOCAL_GRAVITY,
PROP_PARTICLE_RADIUS,
- PROP_COLLISION_MODEL_URL,
+ PROP_COMPOUND_SHAPE_URL,
PROP_MARKETPLACE_ID,
PROP_ACCELERATION,
PROP_SIMULATOR_ID,
@@ -197,7 +197,7 @@ public:
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
- DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString);
+ DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float);
DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float);
@@ -340,7 +340,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
- DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, "");
+ DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, "");
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index f95eeea8e4..1abb48abcd 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -21,7 +21,7 @@
#include "ModelEntityItem.h"
const QString ModelEntityItem::DEFAULT_MODEL_URL = QString("");
-const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString("");
+const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString("");
const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString("");
const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
@@ -47,7 +47,7 @@ EntityItemProperties ModelEntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
- COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
@@ -65,7 +65,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
- SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
@@ -98,11 +98,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL);
if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) {
- setCollisionModelURL("");
+ setCompoundShapeURL("");
} else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) {
- READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL_OLD_VERSION, setCollisionModelURL);
+ READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
} else {
- READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
+ READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
}
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL);
@@ -140,7 +140,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_MODEL_URL;
- requestedProperties += PROP_COLLISION_MODEL_URL;
+ requestedProperties += PROP_COMPOUND_SHAPE_URL;
requestedProperties += PROP_ANIMATION_URL;
requestedProperties += PROP_ANIMATION_FPS;
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
@@ -164,7 +164,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL());
- APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL());
+ APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
@@ -272,7 +272,7 @@ void ModelEntityItem::debugDump() const {
qCDebug(entities) << " position:" << getPosition();
qCDebug(entities) << " dimensions:" << getDimensions();
qCDebug(entities) << " model URL:" << getModelURL();
- qCDebug(entities) << " collision model URL:" << getCollisionModelURL();
+ qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL();
}
void ModelEntityItem::updateShapeType(ShapeType type) {
@@ -280,8 +280,8 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
// we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug)
// but we are now enforcing the entity properties to be consistent. To make the possible we're
// introducing a temporary workaround: we will ignore ShapeType updates that conflict with the
- // _collisionModelURL.
- if (hasCollisionModel()) {
+ // _compoundShapeURL.
+ if (hasCompoundShapeURL()) {
type = SHAPE_TYPE_COMPOUND;
}
// END_TEMPORARY_WORKAROUND
@@ -295,17 +295,17 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
// virtual
ShapeType ModelEntityItem::getShapeType() const {
if (_shapeType == SHAPE_TYPE_COMPOUND) {
- return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
+ return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
} else {
return _shapeType;
}
}
-void ModelEntityItem::setCollisionModelURL(const QString& url) {
- if (_collisionModelURL != url) {
- _collisionModelURL = url;
+void ModelEntityItem::setCompoundShapeURL(const QString& url) {
+ if (_compoundShapeURL != url) {
+ _compoundShapeURL = url;
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
- _shapeType = _collisionModelURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
+ _shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
}
}
diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h
index 057c5babaf..6fe2adc928 100644
--- a/libraries/entities/src/ModelEntityItem.h
+++ b/libraries/entities/src/ModelEntityItem.h
@@ -57,13 +57,13 @@ public:
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
bool hasModel() const { return !_modelURL.isEmpty(); }
- virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
+ virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
static const QString DEFAULT_MODEL_URL;
const QString& getModelURL() const { return _modelURL; }
- static const QString DEFAULT_COLLISION_MODEL_URL;
- const QString& getCollisionModelURL() const { return _collisionModelURL; }
+ static const QString DEFAULT_COMPOUND_SHAPE_URL;
+ const QString& getCompoundShapeURL() const { return _compoundShapeURL; }
bool hasAnimation() const { return !_animationURL.isEmpty(); }
static const QString DEFAULT_ANIMATION_URL;
@@ -78,7 +78,7 @@ public:
// model related properties
void setModelURL(const QString& url) { _modelURL = url; }
- virtual void setCollisionModelURL(const QString& url);
+ virtual void setCompoundShapeURL(const QString& url);
void setAnimationURL(const QString& url);
static const float DEFAULT_ANIMATION_FRAME_INDEX;
void setAnimationFrameIndex(float value);
@@ -126,7 +126,7 @@ protected:
rgbColor _color;
QString _modelURL;
- QString _collisionModelURL;
+ QString _compoundShapeURL;
quint64 _lastAnimated;
QString _animationURL;
diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp
index 132ad43336..d17e49cb59 100644
--- a/libraries/entities/src/SphereEntityItem.cpp
+++ b/libraries/entities/src/SphereEntityItem.cpp
@@ -96,11 +96,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject, bool precisionPicking) const {
// determine the ray in the frame of the entity transformed from a unit sphere
- glm::mat4 translation = glm::translate(getPosition());
- glm::mat4 rotation = glm::mat4_cast(getRotation());
- glm::mat4 scale = glm::scale(getDimensions());
- glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint());
- glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration;
+ glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)));
@@ -112,7 +108,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance);
// then translate back to work coordinates
glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
- distance = glm::distance(origin,hitAt);
+ distance = glm::distance(origin, hitAt);
return true;
}
return false;
diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h
index f79a2db7ff..b6516b714f 100644
--- a/libraries/entities/src/SphereEntityItem.h
+++ b/libraries/entities/src/SphereEntityItem.h
@@ -50,9 +50,6 @@ public:
_color[BLUE_INDEX] = value.blue;
}
- // TODO: implement proper contains for 3D ellipsoid
- //virtual bool contains(const glm::vec3& point) const;
-
virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; }
virtual bool supportsDetailedRayIntersection() const { return true; }
diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp
index 39a4d48d96..34d0ce051c 100644
--- a/libraries/entities/src/TextEntityItem.cpp
+++ b/libraries/entities/src/TextEntityItem.cpp
@@ -48,11 +48,6 @@ void TextEntityItem::setDimensions(const glm::vec3& value) {
_dimensions = glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH);
}
-void TextEntityItem::setDimensionsInDomainUnits(const glm::vec3& value) {
- // NOTE: Text Entities always have a "depth" of 1cm.
- _dimensions = glm::vec3(value.x * (float)TREE_SCALE, value.y * (float)TREE_SCALE, TEXT_ENTITY_ITEM_FIXED_DEPTH);
-}
-
EntityItemProperties TextEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h
index 044975bdc8..d57b5442d6 100644
--- a/libraries/entities/src/TextEntityItem.h
+++ b/libraries/entities/src/TextEntityItem.h
@@ -24,7 +24,6 @@ public:
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
virtual void setDimensions(const glm::vec3& value);
- virtual void setDimensionsInDomainUnits(const glm::vec3& value);
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 60a61e4e89..b1d440e5e5 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -31,6 +31,8 @@ const float ZoneEntityItem::DEFAULT_STAGE_LONGITUDE = 122.407f;
const float ZoneEntityItem::DEFAULT_STAGE_ALTITUDE = 0.03f;
const quint16 ZoneEntityItem::DEFAULT_STAGE_DAY = 60;
const float ZoneEntityItem::DEFAULT_STAGE_HOUR = 12.0f;
+const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX;
+const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = "";
EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = new ZoneEntityItem(entityID, properties);
@@ -56,6 +58,8 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte
_stageAltitude = DEFAULT_STAGE_ALTITUDE;
_stageDay = DEFAULT_STAGE_DAY;
_stageHour = DEFAULT_STAGE_HOUR;
+ _shapeType = DEFAULT_SHAPE_TYPE;
+ _compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
setProperties(properties);
}
@@ -73,6 +77,8 @@ EntityItemProperties ZoneEntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageAltitude, getStageAltitude);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageDay, getStageDay);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageHour, getStageHour);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
return properties;
}
@@ -91,6 +97,8 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageAltitude, setStageAltitude);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageDay, setStageDay);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageHour, setStageHour);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
if (somethingChanged) {
bool wantDebug = false;
@@ -122,6 +130,8 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _stageAltitude);
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay);
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour);
+ READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
+ READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
return bytesRead;
}
@@ -141,6 +151,8 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
requestedProperties += PROP_STAGE_ALTITUDE;
requestedProperties += PROP_STAGE_DAY;
requestedProperties += PROP_STAGE_HOUR;
+ requestedProperties += PROP_SHAPE_TYPE;
+ requestedProperties += PROP_COMPOUND_SHAPE_URL;
return requestedProperties;
}
@@ -165,6 +177,8 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getStageAltitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getStageDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getStageHour());
+ APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
+ APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
}
void ZoneEntityItem::debugDump() const {
@@ -185,6 +199,23 @@ void ZoneEntityItem::debugDump() const {
qCDebug(entities) << " _stageHour:" << _stageHour;
}
+ShapeType ZoneEntityItem::getShapeType() const {
+ if (_shapeType == SHAPE_TYPE_COMPOUND) {
+ return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
+ } else {
+ return _shapeType;
+ }
+}
+
+void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
+ _compoundShapeURL = url;
+ if (!_compoundShapeURL.isEmpty()) {
+ updateShapeType(SHAPE_TYPE_COMPOUND);
+ } else if (_shapeType == SHAPE_TYPE_COMPOUND) {
+ _shapeType = DEFAULT_SHAPE_TYPE;
+ }
+}
+
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject, bool precisionPicking) const {
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index bc1d77ab65..3577e69162 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -91,6 +91,14 @@ public:
static bool getZonesArePickable() { return _zonesArePickable; }
static void setZonesArePickable(bool value) { _zonesArePickable = value; }
+
+ virtual bool isReadyToComputeShape() { return false; }
+ void updateShapeType(ShapeType type) { _shapeType = type; }
+ virtual ShapeType getShapeType() const;
+
+ virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
+ const QString getCompoundShapeURL() const { return _compoundShapeURL; }
+ virtual void setCompoundShapeURL(const QString& url);
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@@ -109,6 +117,8 @@ public:
static const float DEFAULT_STAGE_ALTITUDE;
static const quint16 DEFAULT_STAGE_DAY;
static const float DEFAULT_STAGE_HOUR;
+ static const ShapeType DEFAULT_SHAPE_TYPE;
+ static const QString DEFAULT_COMPOUND_SHAPE_URL;
protected:
// properties of the "sun" in the zone
@@ -122,6 +132,9 @@ protected:
float _stageAltitude;
uint16_t _stageDay;
float _stageHour;
+
+ ShapeType _shapeType = SHAPE_TYPE_NONE;
+ QString _compoundShapeURL;
static bool _zonesArePickable;
};
diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp
index 25ea9ef8e1..1c89ee4067 100644
--- a/libraries/fbx/src/FBXReader.cpp
+++ b/libraries/fbx/src/FBXReader.cpp
@@ -125,6 +125,51 @@ Extents FBXGeometry::getUnscaledMeshExtents() const {
return scaledExtents;
}
+// TODO: Move to model::Mesh when Sam's ready
+bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
+ if (!getUnscaledMeshExtents().containsPoint(point)) {
+ return false;
+ }
+
+ auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool {
+ // Check whether the point is "behind" all the primitives.
+ for (unsigned int j = 0; j < indices.size(); j += primitiveSize) {
+ if (!isPointBehindTrianglesPlane(point,
+ mesh.vertices[indices[j]],
+ mesh.vertices[indices[j + 1]],
+ mesh.vertices[indices[j + 2]])) {
+ // it's not behind at least one so we bail
+ return false;
+ }
+ }
+ return true;
+ };
+
+ // Check that the point is contained in at least one convex mesh.
+ for (auto mesh : meshes) {
+ bool insideMesh = true;
+
+ // To be considered inside a convex mesh,
+ // the point needs to be "behind" all the primitives respective planes.
+ for (auto part : mesh.parts) {
+ // run through all the triangles and quads
+ if (!checkEachPrimitive(mesh, part.triangleIndices, 3) ||
+ !checkEachPrimitive(mesh, part.quadIndices, 4)) {
+ // If not, the point is outside, bail for this mesh
+ insideMesh = false;
+ continue;
+ }
+ }
+ if (insideMesh) {
+ // It's inside this mesh, return true.
+ return true;
+ }
+ }
+
+ // It wasn't in any mesh, return false.
+ return false;
+}
+
QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
if (meshIndicesToModelNames.contains(meshIndex)) {
return meshIndicesToModelNames.value(meshIndex);
@@ -132,8 +177,6 @@ QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
return QString();
}
-
-
static int fbxGeometryMetaTypeId = qRegisterMetaType();
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType();
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType >();
diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h
index d1576bc02a..871f3d0581 100644
--- a/libraries/fbx/src/FBXReader.h
+++ b/libraries/fbx/src/FBXReader.h
@@ -252,6 +252,7 @@ public:
/// Returns the unscaled extents of the model's mesh
Extents getUnscaledMeshExtents() const;
+ bool convexHullContains(const glm::vec3& point) const;
QHash meshIndicesToModelNames;
diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp
index 8f0cee10cf..8fedc6b979 100644
--- a/libraries/networking/src/PacketHeaders.cpp
+++ b/libraries/networking/src/PacketHeaders.cpp
@@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData:
- return VERSION_ENTITIES_ZONE_ENTITIES_EXIST;
+ return VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:
diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h
index a05df968bd..01302f5568 100644
--- a/libraries/networking/src/PacketHeaders.h
+++ b/libraries/networking/src/PacketHeaders.h
@@ -138,5 +138,6 @@ const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14;
const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15;
const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16;
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17;
+const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18;
#endif // hifi_PacketHeaders_h
diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp
index 4e8fb7d3cd..5d1b70275c 100644
--- a/libraries/shared/src/GLMHelpers.cpp
+++ b/libraries/shared/src/GLMHelpers.cpp
@@ -203,6 +203,13 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
return glm::angleAxis(angle, axis);
}
+bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) {
+ glm::vec3 v1 = p0 - p1, v2 = p2 - p1; // Non-collinear vectors contained in the plane
+ glm::vec3 n = glm::cross(v1, v2); // Plane's normal vector, pointing out of the triangle
+ float d = -glm::dot(n, p0); // Compute plane's equation constant
+ return (glm::dot(n, point) + d) >= 0;
+}
+
glm::vec3 extractTranslation(const glm::mat4& matrix) {
return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]);
}
diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h
index e5d22d67dc..dda57a9cd9 100644
--- a/libraries/shared/src/GLMHelpers.h
+++ b/libraries/shared/src/GLMHelpers.h
@@ -82,6 +82,8 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2);
+bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2);
+
glm::vec3 extractTranslation(const glm::mat4& matrix);
void setTranslation(glm::mat4& matrix, const glm::vec3& translation);
diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp
index 544df35b86..1c86f109c5 100644
--- a/libraries/shared/src/ShapeInfo.cpp
+++ b/libraries/shared/src/ShapeInfo.cpp
@@ -114,7 +114,7 @@ float ShapeInfo::computeVolume() const {
}
case SHAPE_TYPE_CAPSULE_Y: {
float radius = _halfExtents.x;
- volume = PI * radius * radius * (2.0f * _halfExtents.y + 4.0f * radius / 3.0f);
+ volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f);
break;
}
default:
@@ -124,6 +124,54 @@ float ShapeInfo::computeVolume() const {
return volume;
}
+bool ShapeInfo::contains(const glm::vec3& point) const {
+ switch(_type) {
+ case SHAPE_TYPE_SPHERE:
+ return glm::length(point) <= _halfExtents.x;
+ case SHAPE_TYPE_ELLIPSOID: {
+ glm::vec3 scaledPoint = glm::abs(point) / _halfExtents;
+ return glm::length(scaledPoint) <= 1.0f;
+ }
+ case SHAPE_TYPE_CYLINDER_X:
+ return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
+ case SHAPE_TYPE_CYLINDER_Y:
+ return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
+ case SHAPE_TYPE_CYLINDER_Z:
+ return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
+ case SHAPE_TYPE_CAPSULE_X: {
+ if (glm::abs(point.x) <= _halfExtents.x) {
+ return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
+ } else {
+ glm::vec3 absPoint = glm::abs(point) - _halfExtents.x;
+ return glm::length(absPoint) <= _halfExtents.z;
+ }
+ }
+ case SHAPE_TYPE_CAPSULE_Y: {
+ if (glm::abs(point.y) <= _halfExtents.y) {
+ return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
+ } else {
+ glm::vec3 absPoint = glm::abs(point) - _halfExtents.y;
+ return glm::length(absPoint) <= _halfExtents.x;
+ }
+ }
+ case SHAPE_TYPE_CAPSULE_Z: {
+ if (glm::abs(point.z) <= _halfExtents.z) {
+ return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
+ } else {
+ glm::vec3 absPoint = glm::abs(point) - _halfExtents.z;
+ return glm::length(absPoint) <= _halfExtents.y;
+ }
+ }
+ case SHAPE_TYPE_BOX:
+ default: {
+ glm::vec3 absPoint = glm::abs(point);
+ return absPoint.x <= _halfExtents.x
+ && absPoint.y <= _halfExtents.y
+ && absPoint.z <= _halfExtents.z;
+ }
+ }
+}
+
const DoubleHashKey& ShapeInfo::getHash() const {
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h
index 8770ef62c7..114d209788 100644
--- a/libraries/shared/src/ShapeInfo.h
+++ b/libraries/shared/src/ShapeInfo.h
@@ -57,6 +57,10 @@ public:
void appendToPoints (const QVector& newPoints) { _points << newPoints; }
float computeVolume() const;
+
+ /// Returns whether point is inside the shape
+ /// For compound shapes it will only return whether it is inside the bounding box
+ bool contains(const glm::vec3& point) const;
const DoubleHashKey& getHash() const;
diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp
index 705a50aa10..4cfadbccfc 100644
--- a/tests/octree/src/OctreeTests.cpp
+++ b/tests/octree/src/OctreeTests.cpp
@@ -74,7 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
props.setHasProperty(PROP_POSITION);
props.setHasProperty(PROP_RADIUS);
props.setHasProperty(PROP_MODEL_URL);
- props.setHasProperty(PROP_COLLISION_MODEL_URL);
+ props.setHasProperty(PROP_COMPOUND_SHAPE_URL);
props.setHasProperty(PROP_ROTATION);
QByteArray encoded = props.encode();