first cut at replacing radius with dimensions

This commit is contained in:
ZappoMan 2014-09-09 13:33:05 -07:00
parent 31fc5bb4f7
commit b78b8ccbb0
21 changed files with 392 additions and 246 deletions

View file

@ -40,7 +40,7 @@ var LEFT = 0;
var RIGHT = 1;
var SPAWN_DISTANCE = 1;
var DEFAULT_RADIUS = 0.10;
var DEFAULT_DIMENSION = 0.20;
var modelURLs = [
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX",
@ -1220,7 +1220,7 @@ var toolBar = (function () {
Entities.addEntity({
type: "Model",
position: position,
radius: DEFAULT_RADIUS,
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
modelURL: url
});
print("Model added: " + url);
@ -1311,7 +1311,7 @@ var toolBar = (function () {
Entities.addEntity({
type: "Box",
position: position,
radius: DEFAULT_RADIUS,
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
color: { red: 255, green: 0, blue: 0 }
});
} else {
@ -1327,7 +1327,7 @@ var toolBar = (function () {
Entities.addEntity({
type: "Sphere",
position: position,
radius: DEFAULT_RADIUS,
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
color: { red: 255, green: 0, blue: 0 }
});
} else {
@ -1804,7 +1804,7 @@ function controller(wichSide) {
this.modelURL = "";
this.oldModelRotation;
this.oldModelPosition;
this.oldModelRadius;
this.oldModelHalfDiagonal;
this.positionAtGrab;
this.rotationAtGrab;
@ -1864,7 +1864,7 @@ function controller(wichSide) {
this.oldModelPosition = properties.position;
this.oldModelRotation = properties.rotation;
this.oldModelRadius = properties.radius;
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
this.positionAtGrab = this.palmPosition;
this.rotationAtGrab = this.rotation;
@ -1873,7 +1873,7 @@ function controller(wichSide) {
this.jointsIntersectingFromStart = [];
for (var i = 0; i < jointList.length; i++) {
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
if (distance < this.oldModelRadius) {
if (distance < this.oldModelHalfDiagonal) {
this.jointsIntersectingFromStart.push(i);
}
}
@ -1897,10 +1897,10 @@ function controller(wichSide) {
if (closestJointIndex != -1) {
print("closestJoint: " + jointList[closestJointIndex]);
print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")");
print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")");
}
if (closestJointDistance < this.oldModelRadius) {
if (closestJointDistance < this.oldModelHalfDiagonal) {
if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 ||
(leftController.grabbing && rightController.grabbing &&
@ -1916,7 +1916,7 @@ function controller(wichSide) {
var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation);
MyAvatar.attach(this.modelURL, jointList[closestJointIndex],
attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius,
attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal,
true, false);
Entities.deleteEntity(this.entityID);
}
@ -1970,11 +1970,12 @@ function controller(wichSide) {
var z = Vec3.dot(Vec3.subtract(P, A), this.right);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
if (0 < x && angularSize > MIN_ANGULAR_SIZE) {
if (angularSize > MAX_ANGULAR_SIZE) {
print("Angular size too big: " + 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14);
print("Angular size too big: " + angularSize);
return { valid: false };
}
@ -2021,7 +2022,10 @@ function controller(wichSide) {
origin: this.palmPosition,
direction: this.front
});
var angularSize = 2 * Math.atan(intersection.properties.radius / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14;
var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14;
if (intersection.accurate && intersection.entityID.isKnownID && angularSize > MIN_ANGULAR_SIZE && angularSize < MAX_ANGULAR_SIZE) {
this.glowedIntersectingModel = intersection.entityID;
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 });
@ -2099,7 +2103,7 @@ function controller(wichSide) {
var indicesToRemove = [];
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
if (distance >= this.oldModelRadius) {
if (distance >= this.oldModelHalfDiagonal) {
indicesToRemove.push(this.jointsIntersectingFromStart[i]);
}
@ -2192,7 +2196,12 @@ function controller(wichSide) {
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)),
rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName),
attachments[attachmentIndex].rotation),
radius: attachments[attachmentIndex].scale / 2.0,
// TODO: how do we know the correct dimensions for detachment???
dimensions: { x: attachments[attachmentIndex].scale / 2.0,
y: attachments[attachmentIndex].scale / 2.0,
z: attachments[attachmentIndex].scale / 2.0 },
modelURL: attachments[attachmentIndex].modelURL
};
@ -2310,15 +2319,21 @@ function moveEntities() {
Entities.editEntity(leftController.entityID, {
position: newPosition,
rotation: rotation,
radius: leftController.oldModelRadius * ratio
// TODO: how do we know the correct dimensions for detachment???
//radius: leftController.oldModelHalfDiagonal * ratio
dimensions: { x: leftController.oldModelHalfDiagonal * ratio,
y: leftController.oldModelHalfDiagonal * ratio,
z: leftController.oldModelHalfDiagonal * ratio }
});
leftController.oldModelPosition = newPosition;
leftController.oldModelRotation = rotation;
leftController.oldModelRadius *= ratio;
leftController.oldModelHalfDiagonal *= ratio;
rightController.oldModelPosition = newPosition;
rightController.oldModelRotation = rotation;
rightController.oldModelRadius *= ratio;
rightController.oldModelHalfDiagonal *= ratio;
return;
}
leftController.moveEntity();
@ -2407,7 +2422,9 @@ function Tooltip() {
text += "Pitch: " + angles.x.toFixed(this.decimals) + "\n"
text += "Yaw: " + angles.y.toFixed(this.decimals) + "\n"
text += "Roll: " + angles.z.toFixed(this.decimals) + "\n"
text += "Scale: " + 2 * properties.radius.toFixed(this.decimals) + "\n"
text += "Width: " + properties.dimensions.x.toFixed(this.decimals) + "\n"
text += "Height: " + properties.dimensions.y.toFixed(this.decimals) + "\n"
text += "Depth: " + properties.dimensions.z.toFixed(this.decimals) + "\n"
text += "ID: " + properties.id + "\n"
if (properties.type == "Model") {
text += "Model URL: " + properties.modelURL + "\n"
@ -2477,7 +2494,9 @@ function mousePressEvent(event) {
if (isLocked(properties)) {
print("Model locked " + properties.id);
} else {
print("Checking properties: " + properties.id + " " + properties.isKnownID);
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
@ -2496,8 +2515,9 @@ function mousePressEvent(event) {
var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
if (0 < x && angularSize > MIN_ANGULAR_SIZE) {
if (angularSize < MAX_ANGULAR_SIZE) {
entitySelected = true;
@ -2506,13 +2526,13 @@ function mousePressEvent(event) {
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
} else {
print("Angular size too big: " + 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14);
print("Angular size too big: " + angularSize);
}
}
}
}
if (entitySelected) {
selectedEntityProperties.oldRadius = selectedEntityProperties.radius;
selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions;
selectedEntityProperties.oldPosition = {
x: selectedEntityProperties.position.x,
y: selectedEntityProperties.position.y,
@ -2550,8 +2570,12 @@ function mouseMoveEvent(event) {
glowedEntityID.id = -1;
glowedEntityID.isKnownID = false;
}
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(entityIntersection.properties.radius / Vec3.distance(Camera.getPosition(), entityIntersection.properties.position)) * 180 / 3.14;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
entityIntersection.properties.position)) * 180 / 3.14;
if (entityIntersection.entityID.isKnownID && angularSize > MIN_ANGULAR_SIZE && angularSize < MAX_ANGULAR_SIZE) {
Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 });
glowedEntityID = entityIntersection.entityID;
@ -2573,7 +2597,7 @@ function mouseMoveEvent(event) {
}
pickRay = Camera.computePickRay(event.x, event.y);
if (wasShifted != event.isShifted || modifier != oldModifier) {
selectedEntityProperties.oldRadius = selectedEntityProperties.radius;
selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions;
selectedEntityProperties.oldPosition = {
x: selectedEntityProperties.position.x,
@ -2603,9 +2627,12 @@ function mouseMoveEvent(event) {
return;
case 1:
// Let's Scale
selectedEntityProperties.radius = (selectedEntityProperties.oldRadius *
selectedEntityProperties.dimensions = Vec3.multiply(selectedEntityProperties.dimensions,
(1.0 + (mouseLastPosition.y - event.y) / SCALE_FACTOR));
if (selectedEntityProperties.radius < 0.01) {
var halfDiagonal = Vec3.length(selectedEntityProperties.dimensions) / 2.0;
if (halfDiagonal < 0.01) {
print("Scale too small ... bailling.");
return;
}
@ -2815,7 +2842,10 @@ function handeMenuEvent(menuItem) {
array.push({ label: "Pitch:", value: angles.x.toFixed(decimals) });
array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) });
array.push({ label: "Roll:", value: angles.z.toFixed(decimals) });
array.push({ label: "Scale:", value: 2 * properties.radius.toFixed(decimals) });
array.push({ label: "Width:", value: properties.dimensions.x.toFixed(decimals) });
array.push({ label: "Height:", value: properties.dimensions.y.toFixed(decimals) });
array.push({ label: "Depth:", value: properties.dimensions.z.toFixed(decimals) });
array.push({ label: "Velocity X:", value: properties.velocity.x.toFixed(decimals) });
array.push({ label: "Velocity Y:", value: properties.velocity.y.toFixed(decimals) });
@ -2851,7 +2881,10 @@ function handeMenuEvent(menuItem) {
angles.y = array[index++].value;
angles.z = array[index++].value;
properties.rotation = Quat.fromVec3Degrees(angles);
properties.radius = array[index++].value / 2;
properties.dimensions.x = array[index++].value;
properties.dimensions.y = array[index++].value;
properties.dimensions.z = array[index++].value;
properties.velocity.x = array[index++].value;
properties.velocity.y = array[index++].value;

View file

@ -33,7 +33,7 @@ ModelReferential::ModelReferential(Referential* referential, EntityTree* tree, A
const EntityItem* item = _tree->findEntityByID(_entityID);
if (item != NULL) {
_refScale = item->getRadius();
_refScale = item->getLargestDimension();
_refRotation = item->getRotation();
_refPosition = item->getPosition() * (float)TREE_SCALE;
update();
@ -52,7 +52,7 @@ ModelReferential::ModelReferential(const QUuid& entityID, EntityTree* tree, Avat
return;
}
_refScale = item->getRadius();
_refScale = item->getLargestDimension();
_refRotation = item->getRotation();
_refPosition = item->getPosition() * (float)TREE_SCALE;
@ -69,8 +69,8 @@ void ModelReferential::update() {
}
bool somethingChanged = false;
if (item->getRadius() != _refScale) {
_refScale = item->getRadius();
if (item->getLargestDimension() != _refScale) {
_refScale = item->getLargestDimension();
_avatar->setTargetScale(_refScale * _scale, true);
somethingChanged = true;
}
@ -109,7 +109,7 @@ JointReferential::JointReferential(Referential* referential, EntityTree* tree, A
const EntityItem* item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
_refScale = item->getRadius();
_refScale = item->getLargestDimension();
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
}
@ -129,7 +129,7 @@ JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, E
return;
}
_refScale = item->getRadius();
_refScale = item->getLargestDimension();
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
@ -147,8 +147,8 @@ void JointReferential::update() {
}
bool somethingChanged = false;
if (item->getRadius() != _refScale) {
_refScale = item->getRadius();
if (item->getLargestDimension() != _refScale) {
_refScale = item->getLargestDimension();
_avatar->setTargetScale(_refScale * _scale, true);
somethingChanged = true;
}

View file

@ -216,6 +216,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
EntityItem* entityItem = entityItems[i];
// render entityItem
AACube entityCube = entityItem->getAACube();
entityCube.scale(TREE_SCALE);
// TODO: some entity types (like lights) might want to be rendered even

View file

@ -33,7 +33,8 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableBoxEntityItem::render");
assert(getType() == EntityTypes::Box);
glm::vec3 position = getPosition() * (float)TREE_SCALE;
float size = getSize() * (float)TREE_SCALE;
glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
glm::vec3 halfDimensions = dimensions / 2.0f;
glm::quat rotation = getRotation();
@ -45,7 +46,8 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glutSolidCube(size);
glScalef(dimensions.x, dimensions.y, dimensions.z);
glutSolidCube(1.0f);
glPopMatrix();
} else {
@ -79,8 +81,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
glNormalPointer(GL_FLOAT, 0, normals);
glVertexPointer(3, GL_FLOAT, 0, vertices);
//glEnable(GL_BLEND);
glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]);
glPushMatrix();
@ -89,9 +89,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
// we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1
float halfSize = size/2.0f;
glScalef(halfSize, halfSize, halfSize);
glScalef(halfDimensions.x, halfDimensions.y, halfDimensions.z);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
glPopMatrix();

View file

@ -65,8 +65,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
bool drawAsModel = hasModel();
glm::vec3 position = getPosition() * (float)TREE_SCALE;
float radius = getRadius() * (float)TREE_SCALE;
float size = getSize() * (float)TREE_SCALE;
glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
if (drawAsModel) {
glPushMatrix();
@ -98,7 +98,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
glm::quat rotation = getRotation();
if (needsSimulation() && _model->isActive()) {
_model->setScaleToFit(true, radius * 2.0f);
_model->setScaleToFit(true, dimensions);
_model->setSnapModelToCenter(true);
_model->setRotation(rotation);
_model->setTranslation(position);

View file

@ -32,11 +32,15 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableSphereEntityItem::render");
assert(getType() == EntityTypes::Sphere);
glm::vec3 position = getPosition() * (float)TREE_SCALE;
float radius = getRadius() * (float)TREE_SCALE;
glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
glm::quat rotation = getRotation();
glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glScalef(dimensions.x, dimensions.y, dimensions.z);
glutSolidSphere(0.5f, 15, 15);
glPopMatrix();
};

View file

@ -54,7 +54,7 @@ Model::Model(QObject* parent) :
QObject(parent),
_scale(1.0f, 1.0f, 1.0f),
_scaleToFit(false),
_scaleToFitLargestDimension(0.0f),
_scaleToFitDimensions(0.0f),
_scaledToFit(false),
_snapModelToCenter(false),
_snappedToCenter(false),
@ -882,23 +882,26 @@ void Blender::run() {
Q_ARG(const QVector<glm::vec3>&, vertices), Q_ARG(const QVector<glm::vec3>&, normals));
}
void Model::setScaleToFit(bool scaleToFit, float largestDimension) {
if (_scaleToFit != scaleToFit || _scaleToFitLargestDimension != largestDimension) {
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) {
if (_scaleToFit != scaleToFit || _scaleToFitDimensions != dimensions) {
_scaleToFit = scaleToFit;
_scaleToFitLargestDimension = largestDimension;
_scaleToFitDimensions = dimensions;
_scaledToFit = false; // force rescaling
}
}
void Model::setScaleToFit(bool scaleToFit, float largestDimension) {
setScaleToFit(scaleToFit, glm::vec3(largestDimension, largestDimension, largestDimension));
}
void Model::scaleToFit() {
Extents modelMeshExtents = getUnscaledMeshExtents();
// size is our "target size in world space"
// we need to set our model scale so that the extents of the mesh, fit in a cube that size...
float maxDimension = glm::distance(modelMeshExtents.maximum, modelMeshExtents.minimum);
float maxScale = _scaleToFitLargestDimension / maxDimension;
glm::vec3 scale(maxScale, maxScale, maxScale);
setScaleInternal(scale);
glm::vec3 meshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum;
glm::vec3 rescaleDimensions = _scaleToFitDimensions / meshDimensions;
setScaleInternal(rescaleDimensions);
_scaledToFit = true;
}

View file

@ -52,7 +52,8 @@ public:
void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f);
bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled
bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit
bool getScaleToFitDimension() const { return _scaleToFitLargestDimension; } /// the dimension model is scaled to
const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to
void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions);
void setSnapModelToCenter(bool snapModelToCenter);
bool getSnapModelToCenter() { return _snapModelToCenter; }
@ -181,7 +182,7 @@ protected:
glm::vec3 _offset;
bool _scaleToFit; /// If you set scaleToFit, we will calculate scale based on MeshExtents
float _scaleToFitLargestDimension; /// this is the dimension that scale to fit will use
glm::vec3 _scaleToFitDimensions; /// this is the dimensions that scale to fit will use
bool _scaledToFit; /// have we scaled to fit
bool _snapModelToCenter; /// is the model's offset automatically adjusted to center around 0,0,0 in model space

View file

@ -20,13 +20,15 @@
EntityItem* BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new BoxEntityItem(entityID, properties);
EntityItem* result = new BoxEntityItem(entityID, properties);
return result;
}
BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties)
{
EntityItem(entityItemID)
{
_type = EntityTypes::Box;
_created = properties.getCreated();
setProperties(properties, true);
}
@ -44,18 +46,9 @@ EntityItemProperties BoxEntityItem::getProperties() const {
bool BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
bool somethingChanged = false;
somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties._colorChanged || forceCopy) {
setColor(properties._color);
somethingChanged = true;
}
if (properties._glowLevelChanged || forceCopy) {
setGlowLevel(properties._glowLevel);
somethingChanged = true;
}
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
if (somethingChanged) {
bool wantDebug = false;

View file

@ -35,6 +35,9 @@ const glm::vec3 EntityItem::NO_GRAVITY = glm::vec3(0, 0, 0);
const glm::vec3 EntityItem::REGULAR_GRAVITY = glm::vec3(0, (-9.8f / TREE_SCALE), 0);
const glm::vec3 EntityItem::DEFAULT_GRAVITY = EntityItem::NO_GRAVITY;
const QString EntityItem::DEFAULT_SCRIPT = QString("");
const glm::quat EntityItem::DEFAULT_ROTATION;
const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f);
void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_id = entityItemID.id;
@ -50,8 +53,8 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_created = 0; // TODO: when do we actually want to make this "now"
_position = glm::vec3(0,0,0);
_radius = 0;
_rotation = ENTITY_DEFAULT_ROTATION;
_rotation = DEFAULT_ROTATION;
_dimensions = DEFAULT_DIMENSIONS;
_glowLevel = DEFAULT_GLOW_LEVEL;
_mass = DEFAULT_MASS;
@ -61,6 +64,16 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_lifetime = DEFAULT_LIFETIME;
}
EntityItem::EntityItem(const EntityItemID& entityItemID) {
_type = EntityTypes::Unknown;
_lastEdited = 0;
_lastEditedFromRemote = 0;
_lastEditedFromRemoteInRemoteTime = 0;
_lastUpdated = 0;
_created = 0;
initFromEntityItemID(entityItemID);
}
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) {
_type = EntityTypes::Unknown;
_lastEdited = 0;
@ -76,7 +89,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_POSITION;
requestedProperties += PROP_RADIUS;
requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete
requestedProperties += PROP_ROTATION;
requestedProperties += PROP_MASS;
requestedProperties += PROP_VELOCITY;
@ -84,6 +97,9 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_DAMPING;
requestedProperties += PROP_LIFETIME;
requestedProperties += PROP_SCRIPT;
// TODO: add PROP_REGISTRATION_POINT,
// TODO: add PROP_ROTATIONAL_VELOCITY,
// TODO: add PROP_VISIBLE,
return requestedProperties;
}
@ -178,10 +194,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
// These items would go here once supported....
// PROP_PAGED_PROPERTY,
// PROP_CUSTOM_PROPERTIES_INCLUDED,
// PROP_VISIBLE,
APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, getPosition());
APPEND_ENTITY_PROPERTY(PROP_RADIUS, appendValue, getRadius());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation());
APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, getMass());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity());
@ -189,6 +204,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript());
// TODO: add PROP_REGISTRATION_POINT,
// TODO: add PROP_ROTATIONAL_VELOCITY,
// TODO: add PROP_VISIBLE,
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
@ -408,9 +426,23 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
bytesRead += propertyFlags.getEncodedLength();
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, _position);
READ_ENTITY_PROPERTY(PROP_RADIUS, float, _radius);
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
float fromBuffer;
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer));
dataAt += sizeof(fromBuffer);
bytesRead += sizeof(fromBuffer);
if (overwriteLocalData) {
setRadiusInMeters(fromBuffer);
}
}
} else {
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, _dimensions);
}
READ_ENTITY_PROPERTY_QUAT(PROP_ROTATION, _rotation);
READ_ENTITY_PROPERTY(PROP_MASS, float, _mass);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, _velocity);
@ -418,6 +450,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime);
READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript);
// TODO: add PROP_REGISTRATION_POINT,
// TODO: add PROP_ROTATIONAL_VELOCITY,
// TODO: add PROP_VISIBLE,
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
@ -429,7 +464,7 @@ void EntityItem::debugDump() const {
qDebug() << "EntityItem id:" << getEntityItemID();
qDebug(" edited ago:%f", getEditedAgo());
qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z);
qDebug(" radius:%f", getRadius());
qDebug() << " dimensions:" << _dimensions;
}
// adjust any internal timestamps to fix clock skew for this server
@ -453,8 +488,14 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
}
}
float EntityItem::getDistanceToBottomOfEntity() const {
// TODO: change this to support registration point
return _dimensions.y / 2.0f;
}
bool EntityItem::isRestingOnSurface() const {
return _position.y <= _radius
// TODO: change this to support registration point
return _position.y <= getDistanceToBottomOfEntity()
&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON
&& _gravity.y < 0.0f;
}
@ -491,8 +532,8 @@ void EntityItem::update(const quint64& updateTime) {
position += velocity * timeElapsed;
// handle bounces off the ground... We bounce at the height of our radius...
if (position.y <= _radius) {
// handle bounces off the ground... We bounce at the distance to the bottom of our entity
if (position.y <= getDistanceToBottomOfEntity()) {
velocity = velocity * glm::vec3(1,-1,1);
// if we've slowed considerably, then just stop moving
@ -500,7 +541,7 @@ void EntityItem::update(const quint64& updateTime) {
velocity = NO_VELOCITY;
}
position.y = _radius;
position.y = getDistanceToBottomOfEntity();
}
// handle gravity....
@ -512,7 +553,7 @@ void EntityItem::update(const quint64& updateTime) {
// "ground" plane of the domain, but for now it
if (hasGravity() && isRestingOnSurface()) {
velocity.y = 0.0f;
position.y = _radius;
position.y = getDistanceToBottomOfEntity();
}
// handle damping
@ -574,7 +615,7 @@ EntityItemProperties EntityItem::getProperties() const {
properties._type = getType();
properties._position = getPosition() * (float) TREE_SCALE;
properties._radius = getRadius() * (float) TREE_SCALE;
properties.setDimensions(getDimensions() * (float) TREE_SCALE);
properties._rotation = getRotation();
properties._mass = getMass();
@ -585,7 +626,6 @@ EntityItemProperties EntityItem::getProperties() const {
properties._script = getScript();
properties._positionChanged = false;
properties._radiusChanged = false;
properties._rotationChanged = false;
properties._massChanged = false;
properties._velocityChanged = false;
@ -610,55 +650,19 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
_created = properties.getCreated();
}
}
if (properties._positionChanged || forceCopy) {
// clamp positions to the domain to prevent someone from moving an entity out of the domain
setPosition(glm::clamp(properties._position / (float) TREE_SCALE, 0.0f, 1.0f));
somethingChanged = true;
}
if (properties._radiusChanged || forceCopy) {
setRadius(properties._radius / (float) TREE_SCALE);
somethingChanged = true;
}
if (properties._rotationChanged || forceCopy) {
setRotation(properties._rotation);
somethingChanged = true;
}
if (properties._massChanged || forceCopy) {
setMass(properties._mass);
somethingChanged = true;
}
if (properties._velocityChanged || forceCopy) {
setVelocity(properties._velocity / (float) TREE_SCALE);
somethingChanged = true;
}
if (properties._massChanged || forceCopy) {
setMass(properties._mass);
somethingChanged = true;
}
if (properties._gravityChanged || forceCopy) {
setGravity(properties._gravity / (float) TREE_SCALE);
somethingChanged = true;
}
if (properties._dampingChanged || forceCopy) {
setDamping(properties._damping);
somethingChanged = true;
}
if (properties._lifetimeChanged || forceCopy) {
setLifetime(properties._lifetime);
somethingChanged = true;
}
if (properties._scriptChanged || forceCopy) {
setScript(properties._script);
somethingChanged = true;
}
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPositionInMeters);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
//SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint);
//SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotationalVelocity, setRotationalVelocity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
if (somethingChanged) {
somethingChangedNotification(); // notify derived classes that something has changed
@ -675,3 +679,50 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
return somethingChanged;
}
float EntityItem::getSize() const {
return glm::length(_dimensions);
}
// TODO: Add support for registration point
glm::vec3 EntityItem::getMinimumPoint() const {
// This assumes the registration point is in the center, we need to update this when we really support
// registration point
return _position - (_dimensions / 2.0f);
}
// TODO: Add support for registration point
glm::vec3 EntityItem::getMaximumPoint() const {
// This assumes the registration point is in the center, we need to update this when we really support
// registration point
return _position + (_dimensions / 2.0f);
}
// 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)
// ... radius = cornerToCornerLength / 2.0f
// ... radius * 2.0f = cornerToCornerLength
// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2)
// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2)
// ... radius * 2.0f = sqrt(3 x maxDimension ^ 2)
// ... (radius * 2.0f) ^2 = 3 x maxDimension ^ 2
// ... ((radius * 2.0f) ^2) / 3 = maxDimension ^ 2
// ... sqrt(((radius * 2.0f) ^2) / 3) = maxDimension
// ... sqrt((diameter ^2) / 3) = maxDimension
//
void EntityItem::setRadius(float value) {
float diameter = value * 2.0f;
float maxDimension = sqrt((diameter * diameter) / 3.0f);
_dimensions = glm::vec3(maxDimension, maxDimension, maxDimension);
}
// TODO: get rid of all users of this function...
// ... radius = cornerToCornerLength / 2.0f
// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2)
// ... radius = sqrt(3 x maxDimension ^ 2) / 2.0f;
float EntityItem::getRadius() const {
float length = glm::length(_dimensions);
float radius = length / 2.0f;
return radius;
}

View file

@ -25,6 +25,7 @@
#include "EntityItemProperties.h"
#include "EntityTypes.h"
class EntityTreeElement;
class EntityTreeElementExtraEncodeData;
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
@ -39,6 +40,7 @@ class EntityItem {
public:
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
EntityItem(const EntityItemID& entityItemID);
EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~EntityItem() { }
@ -120,10 +122,21 @@ public:
EntityTypes::EntityType getType() const { return _type; }
const glm::vec3& getPosition() const { return _position; } /// get position in domain scale units (0.0 - 1.0)
void setPosition(const glm::vec3& value) { _position = value; } /// set position in domain scale units (0.0 - 1.0)
void setPositionInMeters(const glm::vec3& value) /// set position in meter units (0.0 - TREE_SCALE)
{ setPosition(glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f)); }
float getRadius() const { return _radius; } /// get radius in domain scale units (0.0 - 1.0)
void setRadius(float value) { _radius = value; } /// set radius in domain scale units (0.0 - 1.0)
static const glm::vec3 DEFAULT_DIMENSIONS;
const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0)
float getDistanceToBottomOfEntity() const; /// get the distance from the position of the entity to its "bottom" in y axis
float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
void setDimensions(const glm::vec3& value) { _dimensions = value; }
/// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately
void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); }
static const glm::quat DEFAULT_ROTATION;
const glm::quat& getRotation() const { return _rotation; }
void setRotation(const glm::quat& rotation) { _rotation = rotation; }
@ -173,9 +186,9 @@ public:
bool lifetimeHasExpired() const;
// position, size, and bounds related helpers
float getSize() const { return _radius * 2.0f; } /// get maximum dimension in domain scale units (0.0 - 1.0)
glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); }
glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); }
float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0)
glm::vec3 getMinimumPoint() const;
glm::vec3 getMaximumPoint() const;
AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0)
static const QString DEFAULT_SCRIPT;
@ -196,7 +209,7 @@ protected:
quint64 _created;
glm::vec3 _position;
float _radius;
glm::vec3 _dimensions;
glm::quat _rotation;
float _glowLevel;
float _mass;
@ -205,6 +218,24 @@ protected:
float _damping;
float _lifetime;
QString _script;
// NOTE: Radius support is obsolete, but these private helper functions are available for this class to
// parse old data streams
/// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis
void setRadius(float value);
/// set radius in meter units (0.0 - TREE_SCALE), this will also reset dimensions to be equal for each axis
void setRadiusInMeters(float value) {
float valueInTreeUnits = value / (float) TREE_SCALE;
setRadius(valueInTreeUnits);
}
private:
// TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends
// so they can be the only ones accessing this method.
friend EntityTreeElement;
float getRadius() const;
};

View file

@ -18,6 +18,7 @@
#include "EntityItem.h"
#include "EntityItemProperties.h"
#include "ModelEntityItem.h"
EntityItemProperties::EntityItemProperties() :
@ -28,8 +29,8 @@ EntityItemProperties::EntityItemProperties() :
_type(EntityTypes::Unknown),
_position(0),
_radius(ENTITY_DEFAULT_RADIUS),
_rotation(ENTITY_DEFAULT_ROTATION),
_dimensions(EntityItem::DEFAULT_DIMENSIONS),
_rotation(EntityItem::DEFAULT_ROTATION),
_mass(EntityItem::DEFAULT_MASS),
_velocity(EntityItem::DEFAULT_VELOCITY),
_gravity(EntityItem::DEFAULT_GRAVITY),
@ -38,7 +39,7 @@ EntityItemProperties::EntityItemProperties() :
_script(EntityItem::DEFAULT_SCRIPT),
_positionChanged(false),
_radiusChanged(false),
_dimensionsChanged(false),
_rotationChanged(false),
_massChanged(false),
_velocityChanged(false),
@ -50,9 +51,9 @@ EntityItemProperties::EntityItemProperties() :
_color(),
_modelURL(""),
_animationURL(""),
_animationIsPlaying(false),
_animationFrameIndex(0.0),
_animationFPS(ENTITY_DEFAULT_ANIMATION_FPS),
_animationIsPlaying(ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING),
_animationFrameIndex(ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
_animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS),
_glowLevel(0.0f),
_colorChanged(false),
@ -73,7 +74,7 @@ void EntityItemProperties::debugDump() const {
qDebug() << " _id=" << _id;
qDebug() << " _idSet=" << _idSet;
qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z;
qDebug() << " _radius=" << _radius;
qDebug() << " _dimensions=" << getDimensions();
qDebug() << " _modelURL=" << _modelURL;
qDebug() << " changed properties...";
EntityPropertyFlags props = getChangedProperties();
@ -82,8 +83,8 @@ void EntityItemProperties::debugDump() const {
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
EntityPropertyFlags changedProperties;
if (_radiusChanged) {
changedProperties += PROP_RADIUS;
if (_dimensionsChanged) {
changedProperties += PROP_DIMENSIONS;
}
if (_positionChanged) {
@ -158,7 +159,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
QScriptValue position = vec3toScriptValue(engine, _position);
properties.setProperty("position", position);
properties.setProperty("radius", _radius);
QScriptValue dimensions = vec3toScriptValue(engine, _dimensions);
properties.setProperty("dimensions", dimensions);
QScriptValue rotation = quatToScriptValue(engine, _rotation);
properties.setProperty("rotation", rotation);
properties.setProperty("mass", _mass);
@ -198,7 +200,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
}
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
QScriptValue typeScriptValue = object.property("type");
if (typeScriptValue.isValid()) {
QString typeName;
@ -222,13 +223,19 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
}
}
QScriptValue radius = object.property("radius");
if (radius.isValid()) {
float newRadius;
newRadius = radius.toVariant().toFloat();
if (_defaultSettings || newRadius != _radius) {
_radius = newRadius;
_radiusChanged = true;
QScriptValue dimensions = object.property("dimensions");
if (dimensions.isValid()) {
QScriptValue x = dimensions.property("x");
QScriptValue y = dimensions.property("y");
QScriptValue z = dimensions.property("z");
if (x.isValid() && y.isValid() && z.isValid()) {
glm::vec3 newDimensions;
newDimensions.x = x.toVariant().toFloat();
newDimensions.y = y.toVariant().toFloat();
newDimensions.z = z.toVariant().toFloat();
if (_defaultSettings || newDimensions != getDimensions()) {
setDimensions(newDimensions);
}
}
}
@ -403,7 +410,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
_glowLevelChanged = true;
}
}
_lastEdited = usecTimestampNow();
}
@ -432,7 +438,6 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
//
bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too.
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
@ -535,7 +540,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
// PROP_VISIBLE,
APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, properties.getPosition());
APPEND_ENTITY_PROPERTY(PROP_RADIUS, appendValue, properties.getRadius());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, properties.getRotation());
APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, properties.getMass());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, properties.getVelocity());
@ -727,7 +732,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
processedBytes += propertyFlags.getEncodedLength();
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS, float, setRadius);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete
READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(PROP_ROTATION, setRotation);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MASS, float, setMass);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity);
@ -741,6 +746,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
// TODO: add PROP_REGISTRATION_POINT,
// TODO: add PROP_ROTATIONAL_VELOCITY,
// TODO: add PROP_VISIBLE,
return valid;
}
@ -777,7 +785,6 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt
void EntityItemProperties::markAllChanged() {
_positionChanged = true;
_radiusChanged = true;
_rotationChanged = true;
_massChanged = true;
_velocityChanged = true;
@ -795,3 +802,18 @@ void EntityItemProperties::markAllChanged() {
_glowLevelChanged = true;
}
// TODO: Add support for registration point
glm::vec3 EntityItemProperties::getMinimumPointMeters() const {
// This assumes the registration point is in the center, we need to update this when we really support
// registration point
return _position - (_dimensions / 2.0f);
}
// TODO: Add support for registration point
glm::vec3 EntityItemProperties::getMaximumPointMeters() const {
// This assumes the registration point is in the center, we need to update this when we really support
// registration point
return _position + (_dimensions / 2.0f);
}

View file

@ -15,6 +15,7 @@
#include <stdint.h>
#include <glm/glm.hpp>
#include <glm/gtx/extented_min_max.hpp>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>
@ -31,16 +32,6 @@
#include "EntityTypes.h"
// TODO: should these be static members of EntityItem or EntityItemProperties?
const float ENTITY_DEFAULT_RADIUS = 0.1f / TREE_SCALE;
const float ENTITY_MINIMUM_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
const QString ENTITY_DEFAULT_MODEL_URL("");
const glm::quat ENTITY_DEFAULT_ROTATION;
const QString ENTITY_DEFAULT_ANIMATION_URL("");
const float ENTITY_DEFAULT_ANIMATION_FPS = 30.0f;
const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1);
const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2);
// PropertyFlags support
enum EntityPropertyList {
@ -50,7 +41,8 @@ enum EntityPropertyList {
// these properties are supported by the EntityItem base class
PROP_VISIBLE,
PROP_POSITION,
PROP_RADIUS,
PROP_RADIUS, // NOTE: PROP_RADIUS is obsolete and only included in old format streams
PROP_DIMENSIONS = PROP_RADIUS,
PROP_ROTATION,
PROP_MASS,
PROP_VELOCITY,
@ -67,16 +59,23 @@ enum EntityPropertyList {
PROP_ANIMATION_FRAME_INDEX,
PROP_ANIMATION_PLAYING,
PROP_LAST_ITEM = PROP_ANIMATION_PLAYING
// these properties are supported by the EntityItem base class
PROP_REGISTRATION_POINT,
PROP_ROTATIONAL_VELOCITY,
PROP_LAST_ITEM = PROP_ROTATIONAL_VELOCITY
};
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1);
const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2);
/// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an
/// entity and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete
/// set of entity item properties via JavaScript hashes/QScriptValues
/// all units for position, radius, etc are in meter units
/// all units for position, dimensions, etc are in meter units
class EntityItemProperties {
friend class EntityItem; // TODO: consider removing this friend relationship and use public methods
friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods
@ -96,8 +95,8 @@ public:
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
glm::vec3 getMinimumPointMeters() const { return _position - glm::vec3(_radius, _radius, _radius); }
glm::vec3 getMaximumPointMeters() const { return _position + glm::vec3(_radius, _radius, _radius); }
glm::vec3 getMinimumPointMeters() const;
glm::vec3 getMaximumPointMeters() const;
AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units
glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; }
@ -109,18 +108,22 @@ public:
void debugDump() const;
// properties of all entities
EntityTypes::EntityType getType() const { return _type; }
const glm::vec3& getPosition() const { return _position; }
float getRadius() const { return _radius; }
float getMaxDimension() const { return _radius * 2.0f; }
glm::vec3 getDimensions() const { return glm::vec3(_radius, _radius, _radius) * 2.0f; }
const glm::quat& getRotation() const { return _rotation; }
void setType(EntityTypes::EntityType type) { _type = type; }
const glm::vec3& getPosition() const { return _position; }
/// set position in meter units, will be clamped to domain bounds
void setPosition(const glm::vec3& value) { _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; }
void setRadius(float value) { _radius = value; _radiusChanged = true; }
const glm::vec3& getDimensions() const { return _dimensions; }
void setDimensions(const glm::vec3& value) { _dimensions = value; _dimensionsChanged = true; }
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
const glm::quat& getRotation() const { return _rotation; }
void setRotation(const glm::quat& rotation) { _rotation = rotation; _rotationChanged = true; }
float getMass() const { return _mass; }
@ -148,9 +151,9 @@ public:
// NOTE: how do we handle _defaultSettings???
bool containsBoundsProperties() const { return (_positionChanged || _radiusChanged); }
bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); }
bool containsPositionChange() const { return _positionChanged; }
bool containsRadiusChange() const { return _radiusChanged; }
bool containsDimensionsChange() const { return _dimensionsChanged; }
// TODO: this need to be more generic. for now, we're going to have the properties class support these as
// named getter/setters, but we want to move them to generic types...
@ -184,7 +187,6 @@ public:
EntityItemID& entityID, EntityItemProperties& properties);
bool positionChanged() const { return _positionChanged; }
bool radiusChanged() const { return _radiusChanged; }
bool rotationChanged() const { return _rotationChanged; }
bool massChanged() const { return _massChanged; }
bool velocityChanged() const { return _velocityChanged; }
@ -192,6 +194,8 @@ public:
bool dampingChanged() const { return _dampingChanged; }
bool lifetimeChanged() const { return _lifetimeChanged; }
bool scriptChanged() const { return _scriptChanged; }
bool dimensionsChanged() const { return _dimensionsChanged; }
bool registrationPointChanged() const { return _registrationPointChanged; }
bool colorChanged() const { return _colorChanged; }
bool modelURLChanged() const { return _modelURLChanged; }
bool animationURLChanged() const { return _animationURLChanged; }
@ -213,7 +217,7 @@ private:
EntityTypes::EntityType _type;
glm::vec3 _position;
float _radius;
glm::vec3 _dimensions;
glm::quat _rotation;
float _mass;
glm::vec3 _velocity;
@ -221,9 +225,10 @@ private:
float _damping;
float _lifetime;
QString _script;
glm::vec3 _registrationPoint;
bool _positionChanged;
bool _radiusChanged;
bool _dimensionsChanged;
bool _rotationChanged;
bool _massChanged;
bool _velocityChanged;
@ -231,6 +236,7 @@ private:
bool _dampingChanged;
bool _lifetimeChanged;
bool _scriptChanged;
bool _registrationPointChanged;
// TODO: this need to be more generic. for now, we're going to have the properties class support these as
// named getter/setters, but we want to move them to generic types...
@ -358,6 +364,17 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
properties.O(color); \
}
#define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \
if (properties._##P##Changed || forceCopy) { \
M(properties._##P); \
somethingChanged = true; \
}
#define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \
if (properties.C() || forceCopy) { \
S(properties.G()); \
somethingChanged = true; \
}
#endif // hifi_EntityItemProperties_h

View file

@ -555,6 +555,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
return somethingIntersected;
}
// TODO: change this to use better bounding shape for entity than sphere
bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
QList<EntityItem*>::iterator entityItr = _entityItems->begin();
@ -605,6 +606,7 @@ const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const
return closestEntity;
}
// TODO: change this to use better bounding shape for entity than sphere
void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector<const EntityItem*>& foundEntities) const {
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
@ -616,6 +618,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
}
}
// TODO: change this to use better bounding shape for entity than sphere
void EntityTreeElement::getEntities(const AACube& box, QVector<EntityItem*>& foundEntities) {
QList<EntityItem*>::iterator entityItr = _entityItems->begin();
QList<EntityItem*>::iterator entityEnd = _entityItems->end();

View file

@ -17,6 +17,13 @@
#include "ModelEntityItem.h"
const QString ModelEntityItem::DEFAULT_MODEL_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;
const float ModelEntityItem::DEFAULT_ANIMATION_FPS = 30.0f;
EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new ModelEntityItem(entityID, properties);
}
@ -55,40 +62,13 @@ EntityItemProperties ModelEntityItem::getProperties() const {
bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
bool somethingChanged = false;
somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties._colorChanged || forceCopy) {
setColor(properties._color);
somethingChanged = true;
}
if (properties._modelURLChanged || forceCopy) {
setModelURL(properties._modelURL);
somethingChanged = true;
}
if (properties._animationURLChanged || forceCopy) {
setAnimationURL(properties._animationURL);
somethingChanged = true;
}
if (properties._animationIsPlayingChanged || forceCopy) {
setAnimationIsPlaying(properties._animationIsPlaying);
somethingChanged = true;
}
if (properties._animationFrameIndexChanged || forceCopy) {
setAnimationFrameIndex(properties._animationFrameIndex);
somethingChanged = true;
}
if (properties._animationFPSChanged || forceCopy) {
setAnimationFPS(properties._animationFPS);
somethingChanged = true;
}
if (properties._glowLevelChanged || forceCopy) {
setGlowLevel(properties._glowLevel);
somethingChanged = true;
}
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS);
if (somethingChanged) {
bool wantDebug = false;
@ -169,9 +149,11 @@ int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* dat
<< "old ID=" << oldID << "new ID=" << _id;
// radius
memcpy(&_radius, dataAt, sizeof(_radius));
dataAt += sizeof(_radius);
bytesRead += sizeof(_radius);
float radius;
memcpy(&radius, dataAt, sizeof(radius));
dataAt += sizeof(radius);
bytesRead += sizeof(radius);
setRadius(radius);
// position
memcpy(&_position, dataAt, sizeof(_position));
@ -393,7 +375,7 @@ void ModelEntityItem::debugDump() const {
qDebug() << "ModelEntityItem id:" << getEntityItemID();
qDebug() << " edited ago:" << getEditedAgo();
qDebug() << " position:" << getPosition() * (float)TREE_SCALE;
qDebug() << " radius:" << getRadius() * (float)TREE_SCALE;
qDebug() << " dimensions:" << getDimensions() * (float)TREE_SCALE;
qDebug() << " model URL:" << getModelURL();
}

View file

@ -54,8 +54,12 @@ 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(); }
static const QString DEFAULT_MODEL_URL;
const QString& getModelURL() const { return _modelURL; }
bool hasAnimation() const { return !_animationURL.isEmpty(); }
static const QString DEFAULT_ANIMATION_URL;
const QString& getAnimationURL() const { return _animationURL; }
QVector<SittingPoint> getSittingPoints() const { return _sittingPoints; }
@ -69,8 +73,13 @@ public:
// model related properties
void setModelURL(const QString& url) { _modelURL = url; }
void setAnimationURL(const QString& url) { _animationURL = url; }
static const float DEFAULT_ANIMATION_FRAME_INDEX;
void setAnimationFrameIndex(float value) { _animationFrameIndex = value; }
static const bool DEFAULT_ANIMATION_IS_PLAYING;
void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; }
static const float DEFAULT_ANIMATION_FPS;
void setAnimationFPS(float value) { _animationFPS = value; }
void setSittingPoints(QVector<SittingPoint> sittingPoints) { _sittingPoints = sittingPoints; }

View file

@ -43,15 +43,7 @@ EntityItemProperties SphereEntityItem::getProperties() const {
bool SphereEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties.colorChanged() || forceCopy) {
setColor(properties.getColor());
somethingChanged = true;
}
if (properties.glowLevelChanged() || forceCopy) {
setGlowLevel(properties.getGlowLevel());
somethingChanged = true;
}
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
if (somethingChanged) {
bool wantDebug = false;

View file

@ -39,15 +39,14 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
_oldEntityCube = _existingEntity->getAACube();
_oldEntityBox = _oldEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds
// If the new properties has position OR radius changes, but not both, we need to
// If the new properties has position OR dimension changes, but not both, we need to
// get the old property value and set it in our properties in order for our bounds
// calculations to work.
if (_properties.containsPositionChange() && !_properties.containsRadiusChange()) {
float oldRadiusInMeters = _existingEntity->getRadius() * (float)TREE_SCALE;
_properties.setRadius(oldRadiusInMeters);
if (_properties.containsPositionChange() && !_properties.containsDimensionsChange()) {
glm::vec3 oldDimensionsInMeters = _existingEntity->getDimensions() * (float)TREE_SCALE;
_properties.setDimensions(oldDimensionsInMeters);
}
if (!_properties.containsPositionChange() && _properties.containsRadiusChange()) {
if (!_properties.containsPositionChange() && _properties.containsDimensionsChange()) {
glm::vec3 oldPositionInMeters = _existingEntity->getPosition() * (float)TREE_SCALE;
_properties.setPosition(oldPositionInMeters);
}

View file

@ -75,8 +75,11 @@ PacketVersion versionForPacketType(PacketType type) {
return 1;
case PacketTypeParticleErase:
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData:
return VERSION_ENTITIES_SUPPORT_SPLIT_MTU;
return VERSION_ENTITIES_SUPPORT_DIMENSIONS;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:

View file

@ -117,6 +117,7 @@ const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1;
const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2;
const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3;
const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU;
const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1;
#endif // hifi_PacketHeaders_h

View file

@ -45,7 +45,7 @@ void EntityTests::entityTreeTests(bool verbose) {
entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs
EntityItemProperties properties;
float oneMeter = 1.0f;
float halfMeter = oneMeter / 2.0f;
//float halfMeter = oneMeter / 2.0f;
float halfOfDomain = TREE_SCALE * 0.5f;
glm::vec3 positionNearOriginInMeters(oneMeter, oneMeter, oneMeter); // when using properties, these are in meter not tree units
glm::vec3 positionAtCenterInMeters(halfOfDomain, halfOfDomain, halfOfDomain);
@ -60,7 +60,8 @@ void EntityTests::entityTreeTests(bool verbose) {
}
properties.setPosition(positionAtCenterInMeters);
properties.setRadius(halfMeter);
// TODO: Fix these unit tests.
//properties.setRadius(halfMeter);
//properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx");
tree.addEntity(entityID, properties);
@ -265,8 +266,10 @@ void EntityTests::entityTreeTests(bool verbose) {
glm::vec3 randomPositionInTreeUnits = randomPositionInMeters / (float)TREE_SCALE;
properties.setPosition(randomPositionInMeters);
properties.setRadius(halfMeter);
//properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx");
// TODO: fix these unit tests
//properties.setRadius(halfMeter);
//properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx");
if (extraVerbose) {
qDebug() << "iteration:" << i