mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge pull request #3402 from ZappoMan/stretchableEntities
New Entities Features
This commit is contained in:
commit
3fbe183196
34 changed files with 1545 additions and 923 deletions
|
@ -878,10 +878,10 @@ void OctreeServer::setupDatagramProcessingThread() {
|
|||
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
||||
// setup a QThread with us as parent that will house the AudioMixerDatagramProcessor
|
||||
// setup a QThread with us as parent that will house the OctreeServerDatagramProcessor
|
||||
_datagramProcessingThread = new QThread(this);
|
||||
|
||||
// create an AudioMixerDatagramProcessor and move it to that thread
|
||||
// create an OctreeServerDatagramProcessor and move it to that thread
|
||||
OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread());
|
||||
datagramProcessor->moveToThread(_datagramProcessingThread);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ function vInterpolate(a, b, fraction) {
|
|||
|
||||
var startTimeInSeconds = new Date().getTime() / 1000;
|
||||
|
||||
var NATURAL_SIZE_OF_BUTTERFLY = { x: 9.512, y: 4.427, z: 1.169 };
|
||||
var lifeTime = 600; // lifetime of the butterflies in seconds
|
||||
var range = 1.0; // Over what distance in meters do you want the flock to fly around
|
||||
var frame = 0;
|
||||
|
@ -78,7 +79,13 @@ function addButterfly() {
|
|||
var color = { red: 100, green: 100, blue: 100 };
|
||||
var size = 0;
|
||||
|
||||
var minSize = 0.06;
|
||||
var randomSize = 0.2;
|
||||
var maxSize = minSize + randomSize;
|
||||
|
||||
size = 0.06 + Math.random() * 0.2;
|
||||
|
||||
var dimensions = Vec3.multiply(NATURAL_SIZE_OF_BUTTERFLY, (size / maxSize));
|
||||
|
||||
flockPosition = Vec3.sum(MyAvatar.position,Vec3.sum(
|
||||
Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_ABOVE_ME),
|
||||
|
@ -91,7 +98,7 @@ function addButterfly() {
|
|||
velocity: { x: 0, y: 0.0, z: 0 },
|
||||
gravity: { x: 0, y: 1.0, z: 0 },
|
||||
damping: 0.1,
|
||||
radius : size,
|
||||
dimensions: dimensions,
|
||||
color: color,
|
||||
rotation: rotation,
|
||||
animationURL: "http://business.ozblog.me/objects/butterfly/newButterfly2.fbx",
|
||||
|
@ -203,7 +210,8 @@ function updateButterflies(deltaTime) {
|
|||
|
||||
|
||||
// If we are near the target, we should get a new target
|
||||
if (Vec3.length(Vec3.subtract(properties.position, butterflies[i].targetPosition)) < (properties.radius / 1.0)) {
|
||||
var halfLargestDimension = Vec3.length(properties.dimensions) / 2.0;
|
||||
if (Vec3.length(Vec3.subtract(properties.position, butterflies[i].targetPosition)) < (halfLargestDimension)) {
|
||||
butterflies[i].moving = false;
|
||||
}
|
||||
|
||||
|
@ -214,7 +222,7 @@ function updateButterflies(deltaTime) {
|
|||
}
|
||||
|
||||
// Use a cosine wave offset to make it look like its flapping.
|
||||
var offset = Math.cos(nowTimeInSeconds * BUTTERFLY_FLAP_SPEED) * (properties.radius);
|
||||
var offset = Math.cos(nowTimeInSeconds * BUTTERFLY_FLAP_SPEED) * (halfLargestDimension);
|
||||
properties.position.y = properties.position.y + (offset - butterflies[i].previousFlapOffset);
|
||||
// Change position relative to previous offset.
|
||||
butterflies[i].previousFlapOffset = offset;
|
||||
|
|
|
@ -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,8 +1311,9 @@ 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 {
|
||||
print("Can't create box: Box would be out of bounds.");
|
||||
|
@ -1327,7 +1328,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 +1805,7 @@ function controller(wichSide) {
|
|||
this.modelURL = "";
|
||||
this.oldModelRotation;
|
||||
this.oldModelPosition;
|
||||
this.oldModelRadius;
|
||||
this.oldModelHalfDiagonal;
|
||||
|
||||
this.positionAtGrab;
|
||||
this.rotationAtGrab;
|
||||
|
@ -1864,7 +1865,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 +1874,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 +1898,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 +1917,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 +1971,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 +2023,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 +2104,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 +2197,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 +2320,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();
|
||||
|
@ -2379,7 +2395,7 @@ function Tooltip() {
|
|||
this.x = 285;
|
||||
this.y = 115;
|
||||
this.width = 500;
|
||||
this.height = 145;
|
||||
this.height = 180; // 145;
|
||||
this.margin = 5;
|
||||
this.decimals = 3;
|
||||
|
||||
|
@ -2407,7 +2423,14 @@ 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 += "Dimensions: " + properties.dimensions.x.toFixed(this.decimals) + ", "
|
||||
+ properties.dimensions.y.toFixed(this.decimals) + ", "
|
||||
+ properties.dimensions.z.toFixed(this.decimals) + "\n";
|
||||
|
||||
text += "Natural Dimensions: " + properties.naturalDimensions.x.toFixed(this.decimals) + ", "
|
||||
+ properties.naturalDimensions.y.toFixed(this.decimals) + ", "
|
||||
+ properties.naturalDimensions.z.toFixed(this.decimals) + "\n";
|
||||
|
||||
text += "ID: " + properties.id + "\n"
|
||||
if (properties.type == "Model") {
|
||||
text += "Model URL: " + properties.modelURL + "\n"
|
||||
|
@ -2426,6 +2449,7 @@ function Tooltip() {
|
|||
text += "Lifetime: " + properties.lifetime + "\n"
|
||||
}
|
||||
text += "Age: " + properties.ageAsText + "\n"
|
||||
text += "Script: " + properties.script + "\n"
|
||||
|
||||
|
||||
Overlays.editOverlay(this.textOverlay, { text: text });
|
||||
|
@ -2477,7 +2501,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 +2522,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 +2533,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 +2577,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 +2604,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 +2634,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;
|
||||
}
|
||||
|
@ -2753,6 +2787,13 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|||
|
||||
setupModelMenus();
|
||||
|
||||
var propertiesForEditedEntity;
|
||||
var editEntityFormArray;
|
||||
var editModelID = -1;
|
||||
var dimensionX;
|
||||
var dimensionY;
|
||||
var dimensionZ;
|
||||
|
||||
function handeMenuEvent(menuItem) {
|
||||
print("menuItemEvent() in JS... menuItem=" + menuItem);
|
||||
if (menuItem == "Delete") {
|
||||
|
@ -2781,7 +2822,7 @@ function handeMenuEvent(menuItem) {
|
|||
print(" Delete Entity.... not holding...");
|
||||
}
|
||||
} else if (menuItem == "Edit Properties...") {
|
||||
var editModelID = -1;
|
||||
editModelID = -1;
|
||||
if (leftController.grabbing) {
|
||||
print(" Edit Properties.... leftController.entityID="+ leftController.entityID);
|
||||
editModelID = leftController.entityID;
|
||||
|
@ -2797,79 +2838,111 @@ function handeMenuEvent(menuItem) {
|
|||
if (editModelID != -1) {
|
||||
print(" Edit Properties.... about to edit properties...");
|
||||
|
||||
var properties = Entities.getEntityProperties(editModelID);
|
||||
propertiesForEditedEntity = Entities.getEntityProperties(editModelID);
|
||||
var properties = propertiesForEditedEntity;
|
||||
|
||||
var array = new Array();
|
||||
var index = 0;
|
||||
var decimals = 3;
|
||||
if (properties.type == "Model") {
|
||||
array.push({ label: "Model URL:", value: properties.modelURL });
|
||||
index++;
|
||||
array.push({ label: "Animation URL:", value: properties.animationURL });
|
||||
index++;
|
||||
array.push({ label: "Animation is playing:", value: properties.animationIsPlaying });
|
||||
index++;
|
||||
array.push({ label: "Animation FPS:", value: properties.animationFPS });
|
||||
index++;
|
||||
array.push({ label: "Animation Frame:", value: properties.animationFrameIndex });
|
||||
index++;
|
||||
}
|
||||
array.push({ label: "Position:", type: "header" });
|
||||
index++;
|
||||
array.push({ label: "X:", value: properties.position.x.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Y:", value: properties.position.y.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Z:", value: properties.position.z.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Registration X:", value: properties.registrationPoint.x.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Registration Y:", value: properties.registrationPoint.y.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Registration Z:", value: properties.registrationPoint.z.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Rotation:", type: "header" });
|
||||
index++;
|
||||
var angles = Quat.safeEulerAngles(properties.rotation);
|
||||
array.push({ label: "Pitch:", value: angles.x.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Roll:", value: angles.z.toFixed(decimals) });
|
||||
array.push({ label: "Scale:", value: 2 * properties.radius.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Velocity X:", value: properties.velocity.x.toFixed(decimals) });
|
||||
array.push({ label: "Velocity Y:", value: properties.velocity.y.toFixed(decimals) });
|
||||
array.push({ label: "Velocity Z:", value: properties.velocity.z.toFixed(decimals) });
|
||||
array.push({ label: "Damping:", value: properties.damping.toFixed(decimals) });
|
||||
array.push({ label: "Dimensions:", type: "header" });
|
||||
index++;
|
||||
array.push({ label: "Width:", value: properties.dimensions.x.toFixed(decimals) });
|
||||
dimensionX = index;
|
||||
index++;
|
||||
array.push({ label: "Height:", value: properties.dimensions.y.toFixed(decimals) });
|
||||
dimensionY = index;
|
||||
index++;
|
||||
array.push({ label: "Depth:", value: properties.dimensions.z.toFixed(decimals) });
|
||||
dimensionZ = index;
|
||||
index++;
|
||||
array.push({ label: "", type: "inlineButton", buttonLabel: "Reset to Natural Dimensions", name: "resetDimensions" });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Velocity:", type: "header" });
|
||||
index++;
|
||||
array.push({ label: "Linear X:", value: properties.velocity.x.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Linear Y:", value: properties.velocity.y.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Linear Z:", value: properties.velocity.z.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Linear Damping:", value: properties.damping.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Angular Pitch:", value: properties.angularVelocity.x.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Angular Yaw:", value: properties.angularVelocity.y.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Angular Roll:", value: properties.angularVelocity.z.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Angular Damping:", value: properties.angularDamping.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Gravity X:", value: properties.gravity.x.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Gravity Y:", value: properties.gravity.y.toFixed(decimals) });
|
||||
index++;
|
||||
array.push({ label: "Gravity Z:", value: properties.gravity.z.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Visible:", value: properties.visible });
|
||||
index++;
|
||||
|
||||
if (properties.type == "Box" || properties.type == "Sphere") {
|
||||
array.push({ label: "Color:", type: "header" });
|
||||
index++;
|
||||
array.push({ label: "Red:", value: properties.color.red });
|
||||
index++;
|
||||
array.push({ label: "Green:", value: properties.color.green });
|
||||
index++;
|
||||
array.push({ label: "Blue:", value: properties.color.blue });
|
||||
index++;
|
||||
}
|
||||
array.push({ button: "Cancel" });
|
||||
|
||||
if (Window.form("Edit Properties", array)) {
|
||||
var index = 0;
|
||||
if (properties.type == "Model") {
|
||||
properties.modelURL = array[index++].value;
|
||||
properties.animationURL = array[index++].value;
|
||||
properties.animationIsPlaying = array[index++].value;
|
||||
properties.animationFPS = array[index++].value;
|
||||
properties.animationFrameIndex = array[index++].value;
|
||||
}
|
||||
properties.position.x = array[index++].value;
|
||||
properties.position.y = array[index++].value;
|
||||
properties.position.z = array[index++].value;
|
||||
angles.x = array[index++].value;
|
||||
angles.y = array[index++].value;
|
||||
angles.z = array[index++].value;
|
||||
properties.rotation = Quat.fromVec3Degrees(angles);
|
||||
properties.radius = array[index++].value / 2;
|
||||
index++;
|
||||
|
||||
properties.velocity.x = array[index++].value;
|
||||
properties.velocity.y = array[index++].value;
|
||||
properties.velocity.z = array[index++].value;
|
||||
properties.damping = array[index++].value;
|
||||
properties.gravity.x = array[index++].value;
|
||||
properties.gravity.y = array[index++].value;
|
||||
properties.gravity.z = array[index++].value;
|
||||
properties.lifetime = array[index++].value; // give ourselves that many more seconds
|
||||
|
||||
if (properties.type == "Box" || properties.type == "Sphere") {
|
||||
properties.color.red = array[index++].value;
|
||||
properties.color.green = array[index++].value;
|
||||
properties.color.blue = array[index++].value;
|
||||
}
|
||||
Entities.editEntity(editModelID, properties);
|
||||
}
|
||||
modelSelected = false;
|
||||
editEntityFormArray = array;
|
||||
Window.nonBlockingForm("Edit Properties", array);
|
||||
}
|
||||
} else if (menuItem == "Paste Models") {
|
||||
modelImporter.paste();
|
||||
|
@ -2930,3 +3003,76 @@ Controller.keyReleaseEvent.connect(function (event) {
|
|||
handeMenuEvent("Delete");
|
||||
}
|
||||
});
|
||||
|
||||
Window.inlineButtonClicked.connect(function (name) {
|
||||
if (name == "resetDimensions") {
|
||||
var decimals = 3;
|
||||
Window.reloadNonBlockingForm([
|
||||
{ value: propertiesForEditedEntity.naturalDimensions.x.toFixed(decimals), oldIndex: dimensionX },
|
||||
{ value: propertiesForEditedEntity.naturalDimensions.y.toFixed(decimals), oldIndex: dimensionY },
|
||||
{ value: propertiesForEditedEntity.naturalDimensions.z.toFixed(decimals), oldIndex: dimensionZ }
|
||||
]);
|
||||
}
|
||||
});
|
||||
Window.nonBlockingFormClosed.connect(function() {
|
||||
array = editEntityFormArray;
|
||||
if (Window.getNonBlockingFormResult(array)) {
|
||||
var properties = propertiesForEditedEntity;
|
||||
var index = 0;
|
||||
if (properties.type == "Model") {
|
||||
properties.modelURL = array[index++].value;
|
||||
properties.animationURL = array[index++].value;
|
||||
properties.animationIsPlaying = array[index++].value;
|
||||
properties.animationFPS = array[index++].value;
|
||||
properties.animationFrameIndex = array[index++].value;
|
||||
}
|
||||
index++; // skip header
|
||||
properties.position.x = array[index++].value;
|
||||
properties.position.y = array[index++].value;
|
||||
properties.position.z = array[index++].value;
|
||||
properties.registrationPoint.x = array[index++].value;
|
||||
properties.registrationPoint.y = array[index++].value;
|
||||
properties.registrationPoint.z = array[index++].value;
|
||||
|
||||
index++; // skip header
|
||||
var angles = Quat.safeEulerAngles(properties.rotation);
|
||||
angles.x = array[index++].value;
|
||||
angles.y = array[index++].value;
|
||||
angles.z = array[index++].value;
|
||||
properties.rotation = Quat.fromVec3Degrees(angles);
|
||||
|
||||
index++; // skip header
|
||||
properties.dimensions.x = array[index++].value;
|
||||
properties.dimensions.y = array[index++].value;
|
||||
properties.dimensions.z = array[index++].value;
|
||||
index++; // skip reset button
|
||||
|
||||
index++; // skip header
|
||||
properties.velocity.x = array[index++].value;
|
||||
properties.velocity.y = array[index++].value;
|
||||
properties.velocity.z = array[index++].value;
|
||||
properties.damping = array[index++].value;
|
||||
|
||||
properties.angularVelocity.x = array[index++].value;
|
||||
properties.angularVelocity.y = array[index++].value;
|
||||
properties.angularVelocity.z = array[index++].value;
|
||||
properties.angularDamping = array[index++].value;
|
||||
|
||||
properties.gravity.x = array[index++].value;
|
||||
properties.gravity.y = array[index++].value;
|
||||
properties.gravity.z = array[index++].value;
|
||||
properties.lifetime = array[index++].value;
|
||||
properties.visible = array[index++].value;
|
||||
|
||||
if (properties.type == "Box" || properties.type == "Sphere") {
|
||||
index++; // skip header
|
||||
properties.color.red = array[index++].value;
|
||||
properties.color.green = array[index++].value;
|
||||
properties.color.blue = array[index++].value;
|
||||
}
|
||||
Entities.editEntity(editModelID, properties);
|
||||
}
|
||||
modelSelected = false;
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -192,7 +192,71 @@ bool EntityTreeRenderer::shouldRenderEntity(float largestDimension, float distan
|
|||
return (distanceToCamera <= visibleDistanceAtScale);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* args) {
|
||||
bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE;
|
||||
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
|
||||
if (!isShadowMode && displayModelBounds) {
|
||||
PerformanceTimer perfTimer("renderProxies");
|
||||
|
||||
AACube maxCube = entity->getMaximumAACube();
|
||||
AACube minCube = entity->getMinimumAACube();
|
||||
AABox entityBox = entity->getAABox();
|
||||
|
||||
maxCube.scale((float)TREE_SCALE);
|
||||
minCube.scale((float)TREE_SCALE);
|
||||
entityBox.scale((float)TREE_SCALE);
|
||||
|
||||
glm::vec3 maxCenter = maxCube.calcCenter();
|
||||
glm::vec3 minCenter = minCube.calcCenter();
|
||||
glm::vec3 entityBoxCenter = entityBox.calcCenter();
|
||||
glm::vec3 entityBoxScale = entityBox.getScale();
|
||||
|
||||
// draw the max bounding cube
|
||||
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(maxCenter.x, maxCenter.y, maxCenter.z);
|
||||
glutWireCube(maxCube.getScale());
|
||||
glPopMatrix();
|
||||
|
||||
// draw the min bounding cube
|
||||
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(minCenter.x, minCenter.y, minCenter.z);
|
||||
glutWireCube(minCube.getScale());
|
||||
glPopMatrix();
|
||||
|
||||
// draw the entityBox bounding box
|
||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(entityBoxCenter.x, entityBoxCenter.y, entityBoxCenter.z);
|
||||
glScalef(entityBoxScale.x, entityBoxScale.y, entityBoxScale.z);
|
||||
glutWireCube(1.0f);
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
|
||||
glm::vec3 center = entity->getCenter() * (float)TREE_SCALE;
|
||||
glm::vec3 dimensions = entity->getDimensions() * (float)TREE_SCALE;
|
||||
glm::quat rotation = entity->getRotation();
|
||||
|
||||
glColor4f(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
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);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
glutWireCube(1.0f);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
||||
bool wantDebug = false;
|
||||
|
||||
args->_elementsTouched++;
|
||||
// actually render it here...
|
||||
// we need to iterate the actual entityItems of the element
|
||||
|
@ -214,26 +278,48 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
|
||||
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
||||
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
|
||||
// when they are outside of the view frustum...
|
||||
float distance = distanceToCamera(entityCube.calcCenter(), *args->_viewFrustum);
|
||||
if (shouldRenderEntity(entityCube.getLargestDimension(), distance) &&
|
||||
args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) {
|
||||
if (entityItem->isVisible()) {
|
||||
// render entityItem
|
||||
AABox entityBox = entityItem->getAABox();
|
||||
|
||||
Glower* glower = NULL;
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
glower = new Glower(entityItem->getGlowLevel());
|
||||
entityBox.scale(TREE_SCALE);
|
||||
|
||||
// TODO: some entity types (like lights) might want to be rendered even
|
||||
// when they are outside of the view frustum...
|
||||
float distance = distanceToCamera(entityBox.calcCenter(), *args->_viewFrustum);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "------- renderElement() ----------";
|
||||
qDebug() << " type:" << EntityTypes::getEntityTypeName(entityItem->getType());
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
ModelEntityItem* modelEntity = static_cast<ModelEntityItem*>(entityItem);
|
||||
qDebug() << " url:" << modelEntity->getModelURL();
|
||||
}
|
||||
qDebug() << " entityBox:" << entityBox;
|
||||
qDebug() << " dimensions:" << entityItem->getDimensionsInMeters() << "in meters";
|
||||
qDebug() << " largestDimension:" << entityBox.getLargestDimension() << "in meters";
|
||||
qDebug() << " shouldRender:" << shouldRenderEntity(entityBox.getLargestDimension(), distance);
|
||||
qDebug() << " in frustum:" << (args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE);
|
||||
}
|
||||
entityItem->render(args);
|
||||
if (glower) {
|
||||
delete glower;
|
||||
|
||||
if (shouldRenderEntity(entityBox.getLargestDimension(), distance) &&
|
||||
args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE) {
|
||||
|
||||
|
||||
renderProxies(entityItem, args);
|
||||
|
||||
Glower* glower = NULL;
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
glower = new Glower(entityItem->getGlowLevel());
|
||||
}
|
||||
entityItem->render(args);
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ private:
|
|||
|
||||
float distanceToCamera(const glm::vec3& center, const ViewFrustum& viewFrustum) const;
|
||||
bool shouldRenderEntity(float largestDimension, float distanceToCamera) const;
|
||||
void renderProxies(const EntityItem* entity, RenderArgs* args);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -32,11 +32,12 @@ EntityItem* RenderableBoxEntityItem::factory(const EntityItemID& entityID, const
|
|||
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 position = getPositionInMeters();
|
||||
glm::vec3 center = getCenter() * (float)TREE_SCALE;
|
||||
glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
|
||||
const bool useGlutCube = true;
|
||||
|
||||
if (useGlutCube) {
|
||||
|
@ -45,10 +46,14 @@ 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);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
glutSolidCube(1.0f);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
} else {
|
||||
|
||||
static GLfloat vertices[] = { 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front)
|
||||
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right)
|
||||
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top)
|
||||
|
@ -79,20 +84,19 @@ 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();
|
||||
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);
|
||||
|
||||
// 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);
|
||||
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
// we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1
|
||||
glScalef(halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
|
||||
|
|
|
@ -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,8 +98,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
|
||||
glm::quat rotation = getRotation();
|
||||
if (needsSimulation() && _model->isActive()) {
|
||||
_model->setScaleToFit(true, radius * 2.0f);
|
||||
_model->setSnapModelToCenter(true);
|
||||
_model->setScaleToFit(true, dimensions);
|
||||
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||
_model->setRotation(rotation);
|
||||
_model->setTranslation(position);
|
||||
|
||||
|
@ -128,52 +128,6 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
glutWireCube(size);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE;
|
||||
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
|
||||
|
||||
if (!isShadowMode && displayModelBounds) {
|
||||
PerformanceTimer perfTimer("displayModelBounds");
|
||||
|
||||
glm::vec3 unRotatedMinimum = _model->getUnscaledMeshExtents().minimum;
|
||||
glm::vec3 unRotatedMaximum = _model->getUnscaledMeshExtents().maximum;
|
||||
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
||||
|
||||
float width = unRotatedExtents.x;
|
||||
float height = unRotatedExtents.y;
|
||||
float depth = unRotatedExtents.z;
|
||||
|
||||
Extents rotatedExtents = _model->getUnscaledMeshExtents();
|
||||
rotatedExtents.rotate(rotation);
|
||||
|
||||
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
|
||||
|
||||
const glm::vec3& modelScale = _model->getScale();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
|
||||
// draw the orignal bounding cube
|
||||
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
glutWireCube(size);
|
||||
|
||||
// draw the rotated bounding cube
|
||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
|
||||
glutWireCube(1.0);
|
||||
glPopMatrix();
|
||||
|
||||
// draw the model relative bounding box
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
glutWireCube(1.0);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
} else {
|
||||
// if we couldn't get a model, then just draw a cube
|
||||
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
|
||||
|
|
|
@ -31,12 +31,24 @@ EntityItem* RenderableSphereEntityItem::factory(const EntityItemID& entityID, co
|
|||
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 position = getPositionInMeters();
|
||||
glm::vec3 center = getCenterInMeters();
|
||||
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);
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
glutSolidSphere(0.5f, 15, 15);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
};
|
||||
|
|
|
@ -54,10 +54,10 @@ 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),
|
||||
_snapModelToRegistrationPoint(false),
|
||||
_snappedToRegistrationPoint(false),
|
||||
_showTrueJointTransforms(true),
|
||||
_lodDistance(0.0f),
|
||||
_pupilDilation(0.0f),
|
||||
|
@ -157,8 +157,8 @@ void Model::setOffset(const glm::vec3& offset) {
|
|||
_offset = offset;
|
||||
|
||||
// if someone manually sets our offset, then we are no longer snapped to center
|
||||
_snapModelToCenter = false;
|
||||
_snappedToCenter = false;
|
||||
_snapModelToRegistrationPoint = false;
|
||||
_snappedToRegistrationPoint = false;
|
||||
}
|
||||
|
||||
void Model::initProgram(ProgramObject& program, Model::Locations& locations,
|
||||
|
@ -882,50 +882,57 @@ 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;
|
||||
}
|
||||
|
||||
void Model::setSnapModelToCenter(bool snapModelToCenter) {
|
||||
if (_snapModelToCenter != snapModelToCenter) {
|
||||
_snapModelToCenter = snapModelToCenter;
|
||||
_snappedToCenter = false; // force re-centering
|
||||
void Model::setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint) {
|
||||
glm::vec3 clampedRegistrationPoint = glm::clamp(registrationPoint, 0.0f, 1.0f);
|
||||
if (_snapModelToRegistrationPoint != snapModelToRegistrationPoint || _registrationPoint != clampedRegistrationPoint) {
|
||||
_snapModelToRegistrationPoint = snapModelToRegistrationPoint;
|
||||
_registrationPoint = clampedRegistrationPoint;
|
||||
_snappedToRegistrationPoint = false; // force re-centering
|
||||
}
|
||||
}
|
||||
|
||||
void Model::snapToCenter() {
|
||||
void Model::snapToRegistrationPoint() {
|
||||
Extents modelMeshExtents = getUnscaledMeshExtents();
|
||||
glm::vec3 halfDimensions = (modelMeshExtents.maximum - modelMeshExtents.minimum) * 0.5f;
|
||||
glm::vec3 offset = -modelMeshExtents.minimum - halfDimensions;
|
||||
glm::vec3 dimensions = (modelMeshExtents.maximum - modelMeshExtents.minimum);
|
||||
glm::vec3 offset = -modelMeshExtents.minimum - (dimensions * _registrationPoint);
|
||||
_offset = offset;
|
||||
_snappedToCenter = true;
|
||||
_snappedToRegistrationPoint = true;
|
||||
}
|
||||
|
||||
void Model::simulate(float deltaTime, bool fullUpdate) {
|
||||
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit) || (_snapModelToCenter && !_snappedToCenter);
|
||||
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|
||||
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
|
||||
|
||||
if (isActive() && fullUpdate) {
|
||||
// check for scale to fit
|
||||
if (_scaleToFit && !_scaledToFit) {
|
||||
scaleToFit();
|
||||
}
|
||||
if (_snapModelToCenter && !_snappedToCenter) {
|
||||
snapToCenter();
|
||||
if (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint) {
|
||||
snapToRegistrationPoint();
|
||||
}
|
||||
simulateInternal(deltaTime);
|
||||
}
|
||||
|
|
|
@ -52,10 +52,18 @@ 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; }
|
||||
void setSnapModelToCenter(bool snapModelToCenter) {
|
||||
setSnapModelToRegistrationPoint(snapModelToCenter, glm::vec3(0.5f,0.5f,0.5f));
|
||||
};
|
||||
bool getSnapModelToCenter() {
|
||||
return _snapModelToRegistrationPoint && _registrationPoint == glm::vec3(0.5f,0.5f,0.5f);
|
||||
}
|
||||
|
||||
void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint);
|
||||
bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; }
|
||||
|
||||
void setScale(const glm::vec3& scale);
|
||||
const glm::vec3& getScale() const { return _scale; }
|
||||
|
@ -181,11 +189,13 @@ 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
|
||||
bool _snappedToCenter; /// are we currently snapped to center
|
||||
bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space
|
||||
bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point
|
||||
glm::vec3 _registrationPoint; /// the point in model space our center is snapped to
|
||||
|
||||
bool _showTrueJointTransforms;
|
||||
|
||||
QVector<LocalLight> _localLights;
|
||||
|
@ -206,7 +216,7 @@ protected:
|
|||
|
||||
void setScaleInternal(const glm::vec3& scale);
|
||||
void scaleToFit();
|
||||
void snapToCenter();
|
||||
void snapToRegistrationPoint();
|
||||
|
||||
void simulateInternal(float deltaTime);
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
|||
{
|
||||
// caller must have verified existence of newEntity
|
||||
assert(_newEntity);
|
||||
|
||||
_newEntityBox = _newEntity->getAACube().clamp(0.0f, 1.0f);
|
||||
_newEntityBox = _newEntity->getMaximumAACube().clamp(0.0f, 1.0f);
|
||||
}
|
||||
|
||||
bool AddEntityOperator::preRecursion(OctreeElement* element) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -27,14 +27,21 @@ const float EntityItem::IMMORTAL = -1.0f; /// special lifetime which means the e
|
|||
const float EntityItem::DEFAULT_GLOW_LEVEL = 0.0f;
|
||||
const float EntityItem::DEFAULT_MASS = 1.0f;
|
||||
const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL;
|
||||
const float EntityItem::DEFAULT_DAMPING = 0.99f;
|
||||
const float EntityItem::DEFAULT_DAMPING = 0.5f;
|
||||
const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0);
|
||||
const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 10000.0f) / (float)TREE_SCALE; // really small
|
||||
const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second
|
||||
const glm::vec3 EntityItem::DEFAULT_VELOCITY = EntityItem::NO_VELOCITY;
|
||||
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);
|
||||
const glm::vec3 EntityItem::DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center
|
||||
const glm::vec3 EntityItem::NO_ANGULAR_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
const glm::vec3 EntityItem::DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY;
|
||||
const float EntityItem::DEFAULT_ANGULAR_DAMPING = 0.5f;
|
||||
const bool EntityItem::DEFAULT_VISIBLE = true;
|
||||
|
||||
void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
||||
_id = entityItemID.id;
|
||||
|
@ -50,8 +57,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;
|
||||
|
@ -59,6 +66,20 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
|||
_gravity = DEFAULT_GRAVITY;
|
||||
_damping = DEFAULT_DAMPING;
|
||||
_lifetime = DEFAULT_LIFETIME;
|
||||
_registrationPoint = DEFAULT_REGISTRATION_POINT;
|
||||
_angularVelocity = DEFAULT_ANGULAR_VELOCITY;
|
||||
_angularDamping = DEFAULT_ANGULAR_DAMPING;
|
||||
_visible = DEFAULT_VISIBLE;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -76,7 +97,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 +105,10 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
|
|||
requestedProperties += PROP_DAMPING;
|
||||
requestedProperties += PROP_LIFETIME;
|
||||
requestedProperties += PROP_SCRIPT;
|
||||
requestedProperties += PROP_REGISTRATION_POINT;
|
||||
requestedProperties += PROP_ANGULAR_VELOCITY;
|
||||
requestedProperties += PROP_ANGULAR_DAMPING;
|
||||
requestedProperties += PROP_VISIBLE;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -178,10 +203,14 @@ 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
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " APPEND_ENTITY_PROPERTY() PROP_DIMENSIONS:" << getDimensions();
|
||||
}
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, getMass());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity());
|
||||
|
@ -189,6 +218,10 @@ 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());
|
||||
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, getAngularDamping());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible());
|
||||
|
||||
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
|
||||
requestedProperties,
|
||||
|
@ -408,9 +441,36 @@ 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) {
|
||||
setRadius(fromBuffer);
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " readEntityDataFromBuffer() OLD FORMAT... found PROP_RADIUS";
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, _dimensions);
|
||||
if (wantDebug) {
|
||||
qDebug() << " readEntityDataFromBuffer() NEW FORMAT... look for PROP_DIMENSIONS";
|
||||
}
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " readEntityDataFromBuffer() _dimensions:" << getDimensionsInMeters() << " in meters";
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY_QUAT(PROP_ROTATION, _rotation);
|
||||
READ_ENTITY_PROPERTY(PROP_MASS, float, _mass);
|
||||
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, _velocity);
|
||||
|
@ -418,6 +478,15 @@ 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);
|
||||
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint);
|
||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, _angularVelocity);
|
||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping);
|
||||
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint;
|
||||
qDebug() << " readEntityDataFromBuffer() _visible:" << _visible;
|
||||
}
|
||||
|
||||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
||||
|
||||
|
@ -429,7 +498,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,9 +522,14 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: we probably want to change this to make "down" be the direction of the entity's gravity vector
|
||||
// for now, this is always true DOWN even if entity has non-down gravity.
|
||||
// TODO: the old code had "&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON" --- what was I thinking?
|
||||
bool EntityItem::isRestingOnSurface() const {
|
||||
return _position.y <= _radius
|
||||
&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON
|
||||
glm::vec3 downwardVelocity = glm::vec3(0.0f, _velocity.y, 0.0f);
|
||||
|
||||
return _position.y <= getDistanceToBottomOfEntity()
|
||||
&& (glm::length(downwardVelocity) <= EPSILON_VELOCITY_LENGTH)
|
||||
&& _gravity.y < 0.0f;
|
||||
}
|
||||
|
||||
|
@ -466,9 +540,39 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
|
||||
if (wantDebug) {
|
||||
qDebug() << "********** EntityItem::update()";
|
||||
qDebug() << " entity ID=" << getEntityItemID();
|
||||
qDebug() << " updateTime=" << updateTime;
|
||||
qDebug() << " _lastUpdated=" << _lastUpdated;
|
||||
qDebug() << " timeElapsed=" << timeElapsed;
|
||||
qDebug() << " hasVelocity=" << hasVelocity();
|
||||
qDebug() << " hasGravity=" << hasGravity();
|
||||
qDebug() << " isRestingOnSurface=" << isRestingOnSurface();
|
||||
qDebug() << " hasAngularVelocity=" << hasAngularVelocity();
|
||||
qDebug() << " getAngularVelocity=" << getAngularVelocity();
|
||||
qDebug() << " isMortal=" << isMortal();
|
||||
qDebug() << " getAge()=" << getAge();
|
||||
qDebug() << " getLifetime()=" << getLifetime();
|
||||
|
||||
|
||||
if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) {
|
||||
qDebug() << " MOVING...=";
|
||||
qDebug() << " hasVelocity=" << hasVelocity();
|
||||
qDebug() << " hasGravity=" << hasGravity();
|
||||
qDebug() << " isRestingOnSurface=" << isRestingOnSurface();
|
||||
qDebug() << " hasAngularVelocity=" << hasAngularVelocity();
|
||||
qDebug() << " getAngularVelocity=" << getAngularVelocity();
|
||||
}
|
||||
if (hasAngularVelocity()) {
|
||||
qDebug() << " CHANGING...=";
|
||||
qDebug() << " hasAngularVelocity=" << hasAngularVelocity();
|
||||
qDebug() << " getAngularVelocity=" << getAngularVelocity();
|
||||
}
|
||||
if (isMortal()) {
|
||||
qDebug() << " MORTAL...=";
|
||||
qDebug() << " isMortal=" << isMortal();
|
||||
qDebug() << " getAge()=" << getAge();
|
||||
qDebug() << " getLifetime()=" << getLifetime();
|
||||
}
|
||||
}
|
||||
|
||||
_lastUpdated = updateTime;
|
||||
|
@ -477,22 +581,54 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
qDebug() << "********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated;
|
||||
}
|
||||
|
||||
if (hasAngularVelocity()) {
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 angularVelocity = glm::radians(getAngularVelocity());
|
||||
float angularSpeed = glm::length(angularVelocity);
|
||||
|
||||
if (angularSpeed < EPSILON_VELOCITY_LENGTH) {
|
||||
setAngularVelocity(NO_ANGULAR_VELOCITY);
|
||||
} else {
|
||||
float angle = timeElapsed * angularSpeed;
|
||||
glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity));
|
||||
rotation = dQ * rotation;
|
||||
setRotation(rotation);
|
||||
|
||||
// handle damping for angular velocity
|
||||
if (getAngularDamping() > 0.0f) {
|
||||
glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping();
|
||||
glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed);
|
||||
setAngularVelocity(newAngularVelocity);
|
||||
if (wantDebug) {
|
||||
qDebug() << " getDamping():" << getDamping();
|
||||
qDebug() << " dampingResistance:" << dampingResistance;
|
||||
qDebug() << " newAngularVelocity:" << newAngularVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasVelocity() || hasGravity()) {
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 velocity = getVelocity();
|
||||
glm::vec3 newPosition = position + (velocity * timeElapsed);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "EntityItem::update()....";
|
||||
qDebug() << " timeElapsed:" << timeElapsed;
|
||||
qDebug() << " old AACube:" << getAACube();
|
||||
qDebug() << " old AACube:" << getMaximumAACube();
|
||||
qDebug() << " old position:" << position;
|
||||
qDebug() << " old velocity:" << velocity;
|
||||
qDebug() << " old getAABox:" << getAABox();
|
||||
qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters";
|
||||
qDebug() << " newPosition:" << newPosition;
|
||||
qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position);
|
||||
}
|
||||
|
||||
position += velocity * timeElapsed;
|
||||
position = newPosition;
|
||||
|
||||
// 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 +636,7 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
velocity = NO_VELOCITY;
|
||||
}
|
||||
|
||||
position.y = _radius;
|
||||
position.y = getDistanceToBottomOfEntity();
|
||||
}
|
||||
|
||||
// handle gravity....
|
||||
|
@ -512,10 +648,10 @@ 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
|
||||
// handle damping for velocity
|
||||
glm::vec3 dampingResistance = velocity * getDamping();
|
||||
if (wantDebug) {
|
||||
qDebug() << " getDamping():" << getDamping();
|
||||
|
@ -526,21 +662,23 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
|
||||
if (wantDebug) {
|
||||
qDebug() << " velocity AFTER dampingResistance:" << velocity;
|
||||
qDebug() << " glm::length(velocity):" << glm::length(velocity);
|
||||
qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH;
|
||||
}
|
||||
|
||||
// round velocity to zero if it's close enough...
|
||||
if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = NO_VELOCITY;
|
||||
}
|
||||
|
||||
setPosition(position);
|
||||
setVelocity(velocity);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " new position:" << position;
|
||||
qDebug() << " new velocity:" << velocity;
|
||||
}
|
||||
setPosition(position);
|
||||
setVelocity(velocity);
|
||||
if (wantDebug) {
|
||||
qDebug() << " new AACube:" << getAACube();
|
||||
qDebug() << " new AACube:" << getMaximumAACube();
|
||||
qDebug() << " old getAABox:" << getAABox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -549,6 +687,9 @@ EntityItem::SimulationState EntityItem::getSimulationState() const {
|
|||
if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) {
|
||||
return EntityItem::Moving;
|
||||
}
|
||||
if (hasAngularVelocity()) {
|
||||
return EntityItem::Changing;
|
||||
}
|
||||
if (isMortal()) {
|
||||
return EntityItem::Mortal;
|
||||
}
|
||||
|
@ -566,33 +707,26 @@ void EntityItem::copyChangedProperties(const EntityItem& other) {
|
|||
|
||||
EntityItemProperties EntityItem::getProperties() const {
|
||||
EntityItemProperties properties;
|
||||
|
||||
properties._id = getID();
|
||||
properties._idSet = true;
|
||||
properties._created = _created;
|
||||
|
||||
properties._type = getType();
|
||||
|
||||
properties._position = getPosition() * (float) TREE_SCALE;
|
||||
properties._radius = getRadius() * (float) TREE_SCALE;
|
||||
properties._rotation = getRotation();
|
||||
|
||||
properties._mass = getMass();
|
||||
properties._velocity = getVelocity() * (float) TREE_SCALE;
|
||||
properties._gravity = getGravity() * (float) TREE_SCALE;
|
||||
properties._damping = getDamping();
|
||||
properties._lifetime = getLifetime();
|
||||
properties._script = getScript();
|
||||
|
||||
properties._positionChanged = false;
|
||||
properties._radiusChanged = false;
|
||||
properties._rotationChanged = false;
|
||||
properties._massChanged = false;
|
||||
properties._velocityChanged = false;
|
||||
properties._gravityChanged = false;
|
||||
properties._dampingChanged = false;
|
||||
properties._lifetimeChanged = false;
|
||||
properties._scriptChanged = false;
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPositionInMeters);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensionsInMeters); // NOTE: radius is obsolete
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(mass, getMass);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getVelocityInMeters);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravityInMeters);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getAngularVelocity);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible);
|
||||
|
||||
properties._defaultSettings = false;
|
||||
|
||||
|
@ -610,55 +744,21 @@ 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, setVelocityInMeters);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravityInMeters);
|
||||
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(angularVelocity, setAngularVelocity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
|
||||
|
||||
if (somethingChanged) {
|
||||
somethingChangedNotification(); // notify derived classes that something has changed
|
||||
|
@ -675,3 +775,127 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
|
|||
return somethingChanged;
|
||||
}
|
||||
|
||||
|
||||
// TODO: is this really correct? how do we use size, does it need to handle rotation?
|
||||
float EntityItem::getSize() const {
|
||||
return glm::length(_dimensions);
|
||||
}
|
||||
|
||||
float EntityItem::getDistanceToBottomOfEntity() const {
|
||||
glm::vec3 minimumPoint = getAABox().getMinimumPoint();
|
||||
return getPosition().y - minimumPoint.y;
|
||||
}
|
||||
|
||||
// TODO: doesn't this need to handle rotation?
|
||||
glm::vec3 EntityItem::getCenter() const {
|
||||
return _position + (_dimensions * (glm::vec3(0.5f,0.5f,0.5f) - _registrationPoint));
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
/// This accounts for the registration point (upon which rotation occurs around).
|
||||
///
|
||||
AACube EntityItem::getMaximumAACube() const {
|
||||
// * we know that the position is the center of rotation
|
||||
glm::vec3 centerOfRotation = _position; // also where _registration point is
|
||||
|
||||
// * we know that the registration point is the center of rotation
|
||||
// * we can calculate the length of the furthest extent from the registration point
|
||||
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
|
||||
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
|
||||
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
|
||||
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
|
||||
|
||||
// * we know that if you rotate in any direction you would create a sphere
|
||||
// that has a radius of the length of furthest extent from registration point
|
||||
float radius = glm::length(furthestExtentFromRegistration);
|
||||
|
||||
// * we know that the minimum bounding cube of this maximum possible sphere is
|
||||
// (center - radius) to (center + radius)
|
||||
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
|
||||
|
||||
AACube boundingCube(minimumCorner, radius * 2.0f);
|
||||
return boundingCube;
|
||||
}
|
||||
|
||||
/// The minimum bounding cube for the entity accounting for it's rotation.
|
||||
/// This accounts for the registration point (upon which rotation occurs around).
|
||||
///
|
||||
AACube EntityItem::getMinimumAACube() const {
|
||||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
||||
// shift the extents to be relative to the position/registration point
|
||||
rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position);
|
||||
|
||||
// the cube that best encompasses extents is...
|
||||
AABox box(rotatedExtentsRelativeToRegistrationPoint);
|
||||
glm::vec3 centerOfBox = box.calcCenter();
|
||||
float longestSide = box.getLargestDimension();
|
||||
float halfLongestSide = longestSide / 2.0f;
|
||||
glm::vec3 cornerOfCube = centerOfBox - glm::vec3(halfLongestSide, halfLongestSide, halfLongestSide);
|
||||
|
||||
|
||||
// old implementation... not correct!!!
|
||||
return AACube(cornerOfCube, longestSide);
|
||||
}
|
||||
|
||||
AABox EntityItem::getAABox() const {
|
||||
|
||||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
||||
// shift the extents to be relative to the position/registration point
|
||||
rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position);
|
||||
|
||||
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
qDebug() << "EntityItem::setRadius()...";
|
||||
qDebug() << " radius:" << value;
|
||||
qDebug() << " diameter:" << diameter;
|
||||
qDebug() << " maxDimension:" << maxDimension;
|
||||
qDebug() << " _dimensions:" << _dimensions;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() { }
|
||||
|
||||
|
@ -119,11 +121,27 @@ public:
|
|||
// attributes applicable to all entity types
|
||||
EntityTypes::EntityType getType() const { return _type; }
|
||||
const glm::vec3& getPosition() const { return _position; } /// get position in domain scale units (0.0 - 1.0)
|
||||
glm::vec3 getPositionInMeters() const { return _position * (float) TREE_SCALE; } /// get position in meters
|
||||
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)
|
||||
glm::vec3 getCenter() const; /// calculates center of the entity in domain scale units (0.0 - 1.0)
|
||||
glm::vec3 getCenterInMeters() const { return getCenter() * (float) TREE_SCALE; }
|
||||
|
||||
static const glm::vec3 DEFAULT_DIMENSIONS;
|
||||
const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0)
|
||||
glm::vec3 getDimensionsInMeters() const { return _dimensions * (float) TREE_SCALE; } /// get dimensions in meters
|
||||
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; }
|
||||
|
||||
|
@ -138,15 +156,19 @@ public:
|
|||
static const glm::vec3 DEFAULT_VELOCITY;
|
||||
static const glm::vec3 NO_VELOCITY;
|
||||
static const float EPSILON_VELOCITY_LENGTH;
|
||||
const glm::vec3& getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
const glm::vec3 getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters
|
||||
bool hasVelocity() const { return _velocity != NO_VELOCITY; }
|
||||
|
||||
static const glm::vec3 DEFAULT_GRAVITY;
|
||||
static const glm::vec3 REGULAR_GRAVITY;
|
||||
static const glm::vec3 NO_GRAVITY;
|
||||
const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared
|
||||
glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared
|
||||
void setGravityInMeters(const glm::vec3& value) { _gravity = value / (float) TREE_SCALE; } /// gravity in meters
|
||||
bool hasGravity() const { return _gravity != NO_GRAVITY; }
|
||||
|
||||
// TODO: this should eventually be updated to support resting on collisions with other surfaces
|
||||
|
@ -173,14 +195,38 @@ 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); }
|
||||
AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0)
|
||||
float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0)
|
||||
AACube getMaximumAACube() const;
|
||||
AACube getMinimumAACube() const;
|
||||
AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
|
||||
|
||||
static const QString DEFAULT_SCRIPT;
|
||||
const QString& getScript() const { return _script; }
|
||||
void setScript(const QString& value) { _script = value; }
|
||||
|
||||
static const glm::vec3 DEFAULT_REGISTRATION_POINT;
|
||||
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity
|
||||
void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = glm::clamp(value, 0.0f, 1.0f); } /// registration point as ratio of entity
|
||||
|
||||
static const glm::vec3 NO_ANGULAR_VELOCITY;
|
||||
static const glm::vec3 DEFAULT_ANGULAR_VELOCITY;
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; }
|
||||
bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; }
|
||||
|
||||
static const float DEFAULT_ANGULAR_DAMPING;
|
||||
float getAngularDamping() const { return _angularDamping; }
|
||||
void setAngularDamping(float value) { _angularDamping = value; }
|
||||
|
||||
static const bool DEFAULT_VISIBLE;
|
||||
bool getVisible() const { return _visible; }
|
||||
void setVisible(bool value) { _visible = value; }
|
||||
bool isVisible() const { return _visible; }
|
||||
bool isInvisible() const { return !_visible; }
|
||||
|
||||
// TODO: We need to get rid of these users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
@ -196,7 +242,7 @@ protected:
|
|||
quint64 _created;
|
||||
|
||||
glm::vec3 _position;
|
||||
float _radius;
|
||||
glm::vec3 _dimensions;
|
||||
glm::quat _rotation;
|
||||
float _glowLevel;
|
||||
float _mass;
|
||||
|
@ -205,6 +251,17 @@ protected:
|
|||
float _damping;
|
||||
float _lifetime;
|
||||
QString _script;
|
||||
glm::vec3 _registrationPoint;
|
||||
glm::vec3 _angularVelocity;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
|
||||
// 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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "ModelEntityItem.h"
|
||||
|
||||
EntityItemProperties::EntityItemProperties() :
|
||||
|
||||
|
@ -28,17 +29,21 @@ 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),
|
||||
_damping(EntityItem::DEFAULT_DAMPING),
|
||||
_lifetime(EntityItem::DEFAULT_LIFETIME),
|
||||
_script(EntityItem::DEFAULT_SCRIPT),
|
||||
_registrationPoint(EntityItem::DEFAULT_REGISTRATION_POINT),
|
||||
_angularVelocity(EntityItem::DEFAULT_ANGULAR_VELOCITY),
|
||||
_angularDamping(EntityItem::DEFAULT_ANGULAR_DAMPING),
|
||||
_visible(EntityItem::DEFAULT_VISIBLE),
|
||||
|
||||
_positionChanged(false),
|
||||
_radiusChanged(false),
|
||||
_dimensionsChanged(false),
|
||||
_rotationChanged(false),
|
||||
_massChanged(false),
|
||||
_velocityChanged(false),
|
||||
|
@ -46,15 +51,20 @@ EntityItemProperties::EntityItemProperties() :
|
|||
_dampingChanged(false),
|
||||
_lifetimeChanged(false),
|
||||
_scriptChanged(false),
|
||||
_registrationPointChanged(false),
|
||||
_angularVelocityChanged(false),
|
||||
_angularDampingChanged(false),
|
||||
_visibleChanged(false),
|
||||
|
||||
_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),
|
||||
|
||||
_naturalDimensions(1.0f, 1.0f, 1.0f),
|
||||
_colorChanged(false),
|
||||
_modelURLChanged(false),
|
||||
_animationURLChanged(false),
|
||||
|
@ -73,7 +83,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,65 +92,26 @@ void EntityItemProperties::debugDump() const {
|
|||
|
||||
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||
EntityPropertyFlags changedProperties;
|
||||
if (_radiusChanged) {
|
||||
changedProperties += PROP_RADIUS;
|
||||
}
|
||||
|
||||
if (_positionChanged) {
|
||||
changedProperties += PROP_POSITION;
|
||||
}
|
||||
|
||||
if (_rotationChanged) {
|
||||
changedProperties += PROP_ROTATION;
|
||||
}
|
||||
|
||||
if (_massChanged) {
|
||||
changedProperties += PROP_MASS;
|
||||
}
|
||||
|
||||
if (_velocityChanged) {
|
||||
changedProperties += PROP_VELOCITY;
|
||||
}
|
||||
|
||||
if (_gravityChanged) {
|
||||
changedProperties += PROP_GRAVITY;
|
||||
}
|
||||
|
||||
if (_dampingChanged) {
|
||||
changedProperties += PROP_DAMPING;
|
||||
}
|
||||
|
||||
if (_lifetimeChanged) {
|
||||
changedProperties += PROP_LIFETIME;
|
||||
}
|
||||
|
||||
if (_scriptChanged) {
|
||||
changedProperties += PROP_SCRIPT;
|
||||
}
|
||||
|
||||
if (_colorChanged) {
|
||||
changedProperties += PROP_COLOR;
|
||||
}
|
||||
|
||||
if (_modelURLChanged) {
|
||||
changedProperties += PROP_MODEL_URL;
|
||||
}
|
||||
|
||||
if (_animationURLChanged) {
|
||||
changedProperties += PROP_ANIMATION_URL;
|
||||
}
|
||||
|
||||
if (_animationIsPlayingChanged) {
|
||||
changedProperties += PROP_ANIMATION_PLAYING;
|
||||
}
|
||||
|
||||
if (_animationFrameIndexChanged) {
|
||||
changedProperties += PROP_ANIMATION_FRAME_INDEX;
|
||||
}
|
||||
|
||||
if (_animationFPSChanged) {
|
||||
changedProperties += PROP_ANIMATION_FPS;
|
||||
}
|
||||
|
||||
CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions);
|
||||
CHECK_PROPERTY_CHANGE(PROP_POSITION, position);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ROTATION, rotation);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MASS, mass);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VELOCITY, velocity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping);
|
||||
CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime);
|
||||
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FPS, animationFPS);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible);
|
||||
CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping);
|
||||
|
||||
return changedProperties;
|
||||
}
|
||||
|
@ -149,38 +120,35 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
QScriptValue properties = engine->newObject();
|
||||
|
||||
if (_idSet) {
|
||||
properties.setProperty("id", _id.toString());
|
||||
bool isKnownID = (_id != UNKNOWN_ENTITY_ID);
|
||||
properties.setProperty("isKnownID", isKnownID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(isKnownID, (_id != UNKNOWN_ENTITY_ID));
|
||||
} else {
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(isKnownID, false);
|
||||
}
|
||||
|
||||
properties.setProperty("type", EntityTypes::getEntityTypeName(_type));
|
||||
|
||||
QScriptValue position = vec3toScriptValue(engine, _position);
|
||||
properties.setProperty("position", position);
|
||||
properties.setProperty("radius", _radius);
|
||||
QScriptValue rotation = quatToScriptValue(engine, _rotation);
|
||||
properties.setProperty("rotation", rotation);
|
||||
properties.setProperty("mass", _mass);
|
||||
QScriptValue velocity = vec3toScriptValue(engine, _velocity);
|
||||
properties.setProperty("velocity", velocity);
|
||||
QScriptValue gravity = vec3toScriptValue(engine, _gravity);
|
||||
properties.setProperty("gravity", gravity);
|
||||
properties.setProperty("damping", _damping);
|
||||
properties.setProperty("lifetime", _lifetime);
|
||||
properties.setProperty("age", getAge()); // gettable, but not settable
|
||||
properties.setProperty("ageAsText", formatSecondsElapsed(getAge())); // gettable, but not settable
|
||||
properties.setProperty("script", _script);
|
||||
|
||||
QScriptValue color = xColorToScriptValue(engine, _color);
|
||||
properties.setProperty("color", color);
|
||||
properties.setProperty("modelURL", _modelURL);
|
||||
|
||||
properties.setProperty("animationURL", _animationURL);
|
||||
properties.setProperty("animationIsPlaying", _animationIsPlaying);
|
||||
properties.setProperty("animationFrameIndex", _animationFrameIndex);
|
||||
properties.setProperty("animationFPS", _animationFPS);
|
||||
properties.setProperty("glowLevel", _glowLevel);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(position);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(dimensions);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(naturalDimensions); // gettable, but not settable
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_QUAT(rotation);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(velocity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(gravity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(damping);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(age, getAge()); // gettable, but not settable
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(registrationPoint);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(angularVelocity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
|
||||
|
||||
// Sitting properties support
|
||||
QScriptValue sittingPoints = engine->newObject();
|
||||
|
@ -192,217 +160,39 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
sittingPoints.setProperty(i, sittingPoint);
|
||||
}
|
||||
sittingPoints.setProperty("length", _sittingPoints.size());
|
||||
properties.setProperty("sittingPoints", sittingPoints);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
||||
|
||||
|
||||
QScriptValue typeScriptValue = object.property("type");
|
||||
if (typeScriptValue.isValid()) {
|
||||
QString typeName;
|
||||
typeName = typeScriptValue.toVariant().toString();
|
||||
_type = EntityTypes::getEntityTypeFromName(typeName);
|
||||
setType(typeScriptValue.toVariant().toString());
|
||||
}
|
||||
|
||||
QScriptValue position = object.property("position");
|
||||
if (position.isValid()) {
|
||||
QScriptValue x = position.property("x");
|
||||
QScriptValue y = position.property("y");
|
||||
QScriptValue z = position.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
newPosition.x = x.toVariant().toFloat();
|
||||
newPosition.y = y.toVariant().toFloat();
|
||||
newPosition.z = z.toVariant().toFloat();
|
||||
if (_defaultSettings || newPosition != _position) {
|
||||
setPosition(newPosition); // gives us automatic clamping
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue radius = object.property("radius");
|
||||
if (radius.isValid()) {
|
||||
float newRadius;
|
||||
newRadius = radius.toVariant().toFloat();
|
||||
if (_defaultSettings || newRadius != _radius) {
|
||||
_radius = newRadius;
|
||||
_radiusChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue rotation = object.property("rotation");
|
||||
if (rotation.isValid()) {
|
||||
QScriptValue x = rotation.property("x");
|
||||
QScriptValue y = rotation.property("y");
|
||||
QScriptValue z = rotation.property("z");
|
||||
QScriptValue w = rotation.property("w");
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||
glm::quat newRotation;
|
||||
newRotation.x = x.toVariant().toFloat();
|
||||
newRotation.y = y.toVariant().toFloat();
|
||||
newRotation.z = z.toVariant().toFloat();
|
||||
newRotation.w = w.toVariant().toFloat();
|
||||
if (_defaultSettings || newRotation != _rotation) {
|
||||
_rotation = newRotation;
|
||||
_rotationChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue mass = object.property("mass");
|
||||
if (mass.isValid()) {
|
||||
float newValue;
|
||||
newValue = mass.toVariant().toFloat();
|
||||
if (_defaultSettings || newValue != _mass) {
|
||||
_mass = newValue;
|
||||
_massChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue velocity = object.property("velocity");
|
||||
if (velocity.isValid()) {
|
||||
QScriptValue x = velocity.property("x");
|
||||
QScriptValue y = velocity.property("y");
|
||||
QScriptValue z = velocity.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newValue;
|
||||
newValue.x = x.toVariant().toFloat();
|
||||
newValue.y = y.toVariant().toFloat();
|
||||
newValue.z = z.toVariant().toFloat();
|
||||
if (_defaultSettings || newValue != _velocity) {
|
||||
_velocity = newValue;
|
||||
_velocityChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue gravity = object.property("gravity");
|
||||
if (gravity.isValid()) {
|
||||
QScriptValue x = gravity.property("x");
|
||||
QScriptValue y = gravity.property("y");
|
||||
QScriptValue z = gravity.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newValue;
|
||||
newValue.x = x.toVariant().toFloat();
|
||||
newValue.y = y.toVariant().toFloat();
|
||||
newValue.z = z.toVariant().toFloat();
|
||||
if (_defaultSettings || newValue != _gravity) {
|
||||
_gravity = newValue;
|
||||
_gravityChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue damping = object.property("damping");
|
||||
if (damping.isValid()) {
|
||||
float newValue;
|
||||
newValue = damping.toVariant().toFloat();
|
||||
if (_defaultSettings || newValue != _damping) {
|
||||
_damping = newValue;
|
||||
_dampingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue lifetime = object.property("lifetime");
|
||||
if (lifetime.isValid()) {
|
||||
float newValue;
|
||||
newValue = lifetime.toVariant().toFloat();
|
||||
if (_defaultSettings || newValue != _lifetime) {
|
||||
_lifetime = newValue;
|
||||
_lifetimeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue script = object.property("script");
|
||||
if (script.isValid()) {
|
||||
QString newValue;
|
||||
newValue = script.toVariant().toString();
|
||||
if (_defaultSettings || newValue != _script) {
|
||||
_script = newValue;
|
||||
_scriptChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue color = object.property("color");
|
||||
if (color.isValid()) {
|
||||
QScriptValue red = color.property("red");
|
||||
QScriptValue green = color.property("green");
|
||||
QScriptValue blue = color.property("blue");
|
||||
if (red.isValid() && green.isValid() && blue.isValid()) {
|
||||
xColor newColor;
|
||||
newColor.red = red.toVariant().toInt();
|
||||
newColor.green = green.toVariant().toInt();
|
||||
newColor.blue = blue.toVariant().toInt();
|
||||
if (_defaultSettings || (newColor.red != _color.red ||
|
||||
newColor.green != _color.green ||
|
||||
newColor.blue != _color.blue)) {
|
||||
_color = newColor;
|
||||
_colorChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue modelURL = object.property("modelURL");
|
||||
if (modelURL.isValid()) {
|
||||
QString newModelURL;
|
||||
newModelURL = modelURL.toVariant().toString();
|
||||
if (_defaultSettings || newModelURL != _modelURL) {
|
||||
_modelURL = newModelURL;
|
||||
_modelURLChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue animationURL = object.property("animationURL");
|
||||
if (animationURL.isValid()) {
|
||||
QString newAnimationURL;
|
||||
newAnimationURL = animationURL.toVariant().toString();
|
||||
if (_defaultSettings || newAnimationURL != _animationURL) {
|
||||
_animationURL = newAnimationURL;
|
||||
_animationURLChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue animationIsPlaying = object.property("animationIsPlaying");
|
||||
if (animationIsPlaying.isValid()) {
|
||||
bool newIsAnimationPlaying;
|
||||
newIsAnimationPlaying = animationIsPlaying.toVariant().toBool();
|
||||
if (_defaultSettings || newIsAnimationPlaying != _animationIsPlaying) {
|
||||
_animationIsPlaying = newIsAnimationPlaying;
|
||||
_animationIsPlayingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue animationFrameIndex = object.property("animationFrameIndex");
|
||||
if (animationFrameIndex.isValid()) {
|
||||
float newFrameIndex;
|
||||
newFrameIndex = animationFrameIndex.toVariant().toFloat();
|
||||
if (_defaultSettings || newFrameIndex != _animationFrameIndex) {
|
||||
_animationFrameIndex = newFrameIndex;
|
||||
_animationFrameIndexChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue animationFPS = object.property("animationFPS");
|
||||
if (animationFPS.isValid()) {
|
||||
float newFPS;
|
||||
newFPS = animationFPS.toVariant().toFloat();
|
||||
if (_defaultSettings || newFPS != _animationFPS) {
|
||||
_animationFPS = newFPS;
|
||||
_animationFPSChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue glowLevel = object.property("glowLevel");
|
||||
if (glowLevel.isValid()) {
|
||||
float newGlowLevel;
|
||||
newGlowLevel = glowLevel.toVariant().toFloat();
|
||||
if (_defaultSettings || newGlowLevel != _glowLevel) {
|
||||
_glowLevel = newGlowLevel;
|
||||
_glowLevelChanged = true;
|
||||
}
|
||||
}
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(position, setPosition);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(dimensions, setDimensions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_QUAT(rotation, setRotation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(mass, setMass);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(velocity, setVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(gravity, setGravity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(damping, setDamping);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lifetime, setLifetime);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(script, setScript);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(registrationPoint, setRegistrationPoint);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(angularVelocity, setAngularVelocity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(angularDamping, setAngularDamping);
|
||||
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(animationURL, setAnimationURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel);
|
||||
|
||||
_lastEdited = usecTimestampNow();
|
||||
}
|
||||
|
@ -432,7 +222,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
|
||||
|
||||
|
@ -532,23 +321,26 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
// These items would go here once supported....
|
||||
// PROP_PAGED_PROPERTY,
|
||||
// PROP_CUSTOM_PROPERTIES_INCLUDED,
|
||||
// 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());
|
||||
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, properties.getGravity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, properties.getDamping());
|
||||
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, properties.getLifetime());
|
||||
//APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, properties.getScript()); // not supported by edit messages
|
||||
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, properties.getScript());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, properties.getColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
|
||||
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());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, properties.getAnimationIsPlaying());
|
||||
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, properties.getRegistrationPoint());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, properties.getAngularVelocity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, properties.getAngularDamping());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible());
|
||||
}
|
||||
if (propertyCount > 0) {
|
||||
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
||||
|
@ -727,20 +519,24 @@ 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);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRAVITY, glm::vec3, setGravity);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DAMPING, float, setDamping);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime);
|
||||
//READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); // not yet supported by edit messages...
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_SCRIPT,setScript);
|
||||
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_COLOR, setColor);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
|
||||
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);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
@ -774,10 +570,8 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
void EntityItemProperties::markAllChanged() {
|
||||
_positionChanged = true;
|
||||
_radiusChanged = true;
|
||||
_rotationChanged = true;
|
||||
_massChanged = true;
|
||||
_velocityChanged = true;
|
||||
|
@ -785,7 +579,10 @@ void EntityItemProperties::markAllChanged() {
|
|||
_dampingChanged = true;
|
||||
_lifetimeChanged = true;
|
||||
_scriptChanged = true;
|
||||
|
||||
_registrationPointChanged = true;
|
||||
_angularVelocityChanged = true;
|
||||
_angularDampingChanged = true;
|
||||
_visibleChanged = true;
|
||||
_colorChanged = true;
|
||||
_modelURLChanged = true;
|
||||
_animationURLChanged = true;
|
||||
|
@ -793,5 +590,36 @@ void EntityItemProperties::markAllChanged() {
|
|||
_animationFrameIndexChanged = true;
|
||||
_animationFPSChanged = true;
|
||||
_glowLevelChanged = true;
|
||||
|
||||
}
|
||||
|
||||
AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const {
|
||||
AACube maxCube = getMaximumAACubeInMeters();
|
||||
maxCube.scale(1 / (float)TREE_SCALE);
|
||||
return maxCube;
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
/// This accounts for the registration point (upon which rotation occurs around).
|
||||
///
|
||||
AACube EntityItemProperties::getMaximumAACubeInMeters() const {
|
||||
// * we know that the position is the center of rotation
|
||||
glm::vec3 centerOfRotation = _position; // also where _registration point is
|
||||
|
||||
// * we know that the registration point is the center of rotation
|
||||
// * we can calculate the length of the furthest extent from the registration point
|
||||
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
|
||||
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
|
||||
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
|
||||
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
|
||||
|
||||
// * we know that if you rotate in any direction you would create a sphere
|
||||
// that has a radius of the length of furthest extent from registration point
|
||||
float radius = glm::length(furthestExtentFromRegistration);
|
||||
|
||||
// * we know that the minimum bounding cube of this maximum possible sphere is
|
||||
// (center - radius) to (center + radius)
|
||||
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
|
||||
float diameter = radius * 2.0f;
|
||||
|
||||
return AACube(minimumCorner, diameter);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/extented_min_max.hpp>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -28,20 +29,9 @@
|
|||
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
#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 {
|
||||
PROP_PAGED_PROPERTY,
|
||||
|
@ -50,7 +40,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 +58,24 @@ 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_ANGULAR_VELOCITY,
|
||||
PROP_ANGULAR_DAMPING,
|
||||
|
||||
PROP_LAST_ITEM = PROP_ANGULAR_DAMPING
|
||||
};
|
||||
|
||||
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,31 +95,27 @@ 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); }
|
||||
AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units
|
||||
|
||||
glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; }
|
||||
glm::vec3 getMaximumPointTreeUnits() const { return getMaximumPointMeters() / (float)TREE_SCALE; }
|
||||
/// AACube in domain scale units (0.0 - 1.0)
|
||||
AACube getAACubeTreeUnits() const {
|
||||
return AACube(getMinimumPointMeters() / (float)TREE_SCALE, getMaxDimension() / (float)TREE_SCALE);
|
||||
}
|
||||
AACube getMaximumAACubeInTreeUnits() const;
|
||||
AACube getMaximumAACubeInMeters() const;
|
||||
|
||||
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 +143,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...
|
||||
|
@ -162,6 +157,7 @@ public:
|
|||
bool getAnimationIsPlaying() const { return _animationIsPlaying; }
|
||||
float getAnimationFPS() const { return _animationFPS; }
|
||||
float getGlowLevel() const { return _glowLevel; }
|
||||
const QString& getScript() const { return _script; }
|
||||
|
||||
// model related properties
|
||||
void setColor(const xColor& value) { _color = value; _colorChanged = true; }
|
||||
|
@ -171,6 +167,7 @@ public:
|
|||
void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; _animationIsPlayingChanged = true; }
|
||||
void setAnimationFPS(float value) { _animationFPS = value; _animationFPSChanged = true; }
|
||||
void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; }
|
||||
void setScript(const QString& value) { _script = value; _scriptChanged = true; }
|
||||
|
||||
|
||||
static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
||||
|
@ -184,7 +181,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 +188,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; }
|
||||
|
@ -203,6 +201,24 @@ public:
|
|||
void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; }
|
||||
void markAllChanged();
|
||||
|
||||
QVector<SittingPoint> getSittingPoints() const { return _sittingPoints; }
|
||||
void setSittingPoints(QVector<SittingPoint> sittingPoints) { _sittingPoints = sittingPoints; }
|
||||
|
||||
const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; }
|
||||
void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; }
|
||||
|
||||
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; }
|
||||
void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; _registrationPointChanged = true; }
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; _angularVelocityChanged = true; }
|
||||
|
||||
float getAngularDamping() const { return _angularDamping; }
|
||||
void setAngularDamping(float value) { _angularDamping = value; _angularDampingChanged = true; }
|
||||
|
||||
bool getVisible() const { return _visible; }
|
||||
void setVisible(bool value) { _visible = value; _visibleChanged = true; }
|
||||
|
||||
private:
|
||||
void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; }
|
||||
|
||||
|
@ -212,8 +228,11 @@ private:
|
|||
quint64 _created;
|
||||
|
||||
EntityTypes::EntityType _type;
|
||||
|
||||
void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); }
|
||||
|
||||
glm::vec3 _position;
|
||||
float _radius;
|
||||
glm::vec3 _dimensions;
|
||||
glm::quat _rotation;
|
||||
float _mass;
|
||||
glm::vec3 _velocity;
|
||||
|
@ -221,9 +240,13 @@ private:
|
|||
float _damping;
|
||||
float _lifetime;
|
||||
QString _script;
|
||||
glm::vec3 _registrationPoint;
|
||||
glm::vec3 _angularVelocity;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
|
||||
bool _positionChanged;
|
||||
bool _radiusChanged;
|
||||
bool _dimensionsChanged;
|
||||
bool _rotationChanged;
|
||||
bool _massChanged;
|
||||
bool _velocityChanged;
|
||||
|
@ -231,6 +254,10 @@ private:
|
|||
bool _dampingChanged;
|
||||
bool _lifetimeChanged;
|
||||
bool _scriptChanged;
|
||||
bool _registrationPointChanged;
|
||||
bool _angularVelocityChanged;
|
||||
bool _angularDampingChanged;
|
||||
bool _visibleChanged;
|
||||
|
||||
// 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...
|
||||
|
@ -242,6 +269,7 @@ private:
|
|||
float _animationFPS;
|
||||
float _glowLevel;
|
||||
QVector<SittingPoint> _sittingPoints;
|
||||
glm::vec3 _naturalDimensions;
|
||||
|
||||
bool _colorChanged;
|
||||
bool _modelURLChanged;
|
||||
|
@ -257,107 +285,4 @@ Q_DECLARE_METATYPE(EntityItemProperties);
|
|||
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
|
||||
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties);
|
||||
|
||||
#define APPEND_ENTITY_PROPERTY(P,O,V) \
|
||||
if (requestedProperties.getHasProperty(P)) { \
|
||||
LevelDetails propertyLevel = packetData->startLevel(); \
|
||||
successPropertyFits = packetData->O(V); \
|
||||
if (successPropertyFits) { \
|
||||
propertyFlags |= P; \
|
||||
propertiesDidntFit -= P; \
|
||||
propertyCount++; \
|
||||
packetData->endLevel(propertyLevel); \
|
||||
} else { \
|
||||
packetData->discardLevel(propertyLevel); \
|
||||
appendState = OctreeElement::PARTIAL; \
|
||||
} \
|
||||
} else { \
|
||||
propertiesDidntFit -= P; \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY(P,T,M) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
T fromBuffer; \
|
||||
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
|
||||
dataAt += sizeof(fromBuffer); \
|
||||
bytesRead += sizeof(fromBuffer); \
|
||||
if (overwriteLocalData) { \
|
||||
M = fromBuffer; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_QUAT(P,M) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
glm::quat fromBuffer; \
|
||||
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
|
||||
dataAt += bytes; \
|
||||
bytesRead += bytes; \
|
||||
if (overwriteLocalData) { \
|
||||
M = fromBuffer; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_STRING(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
uint16_t length; \
|
||||
memcpy(&length, dataAt, sizeof(length)); \
|
||||
dataAt += sizeof(length); \
|
||||
bytesRead += sizeof(length); \
|
||||
QString value((const char*)dataAt); \
|
||||
dataAt += length; \
|
||||
bytesRead += length; \
|
||||
if (overwriteLocalData) { \
|
||||
O(value); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_COLOR(P,M) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
if (overwriteLocalData) { \
|
||||
memcpy(M, dataAt, sizeof(M)); \
|
||||
} \
|
||||
dataAt += sizeof(rgbColor); \
|
||||
bytesRead += sizeof(rgbColor); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
T fromBuffer; \
|
||||
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
|
||||
dataAt += sizeof(fromBuffer); \
|
||||
processedBytes += sizeof(fromBuffer); \
|
||||
properties.O(fromBuffer); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
glm::quat fromBuffer; \
|
||||
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
|
||||
dataAt += bytes; \
|
||||
processedBytes += bytes; \
|
||||
properties.O(fromBuffer); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
uint16_t length; \
|
||||
memcpy(&length, dataAt, sizeof(length)); \
|
||||
dataAt += sizeof(length); \
|
||||
processedBytes += sizeof(length); \
|
||||
QString value((const char*)dataAt); \
|
||||
dataAt += length; \
|
||||
processedBytes += length; \
|
||||
properties.O(value); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
xColor color; \
|
||||
memcpy(&color, dataAt, sizeof(color)); \
|
||||
dataAt += sizeof(color); \
|
||||
processedBytes += sizeof(color); \
|
||||
properties.O(color); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // hifi_EntityItemProperties_h
|
||||
|
|
241
libraries/entities/src/EntityItemPropertiesMacros.h
Normal file
241
libraries/entities/src/EntityItemPropertiesMacros.h
Normal file
|
@ -0,0 +1,241 @@
|
|||
//
|
||||
// EntityItemPropertiesMacros.h
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/10/14.
|
||||
// Copyright 2014 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_EntityItemPropertiesMacros_h
|
||||
#define hifi_EntityItemPropertiesMacros_h
|
||||
|
||||
#define APPEND_ENTITY_PROPERTY(P,O,V) \
|
||||
if (requestedProperties.getHasProperty(P)) { \
|
||||
LevelDetails propertyLevel = packetData->startLevel(); \
|
||||
successPropertyFits = packetData->O(V); \
|
||||
if (successPropertyFits) { \
|
||||
propertyFlags |= P; \
|
||||
propertiesDidntFit -= P; \
|
||||
propertyCount++; \
|
||||
packetData->endLevel(propertyLevel); \
|
||||
} else { \
|
||||
packetData->discardLevel(propertyLevel); \
|
||||
appendState = OctreeElement::PARTIAL; \
|
||||
} \
|
||||
} else { \
|
||||
propertiesDidntFit -= P; \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY(P,T,M) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
T fromBuffer; \
|
||||
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
|
||||
dataAt += sizeof(fromBuffer); \
|
||||
bytesRead += sizeof(fromBuffer); \
|
||||
if (overwriteLocalData) { \
|
||||
M = fromBuffer; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_QUAT(P,M) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
glm::quat fromBuffer; \
|
||||
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
|
||||
dataAt += bytes; \
|
||||
bytesRead += bytes; \
|
||||
if (overwriteLocalData) { \
|
||||
M = fromBuffer; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_STRING(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
uint16_t length; \
|
||||
memcpy(&length, dataAt, sizeof(length)); \
|
||||
dataAt += sizeof(length); \
|
||||
bytesRead += sizeof(length); \
|
||||
QString value((const char*)dataAt); \
|
||||
dataAt += length; \
|
||||
bytesRead += length; \
|
||||
if (overwriteLocalData) { \
|
||||
O(value); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_COLOR(P,M) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
if (overwriteLocalData) { \
|
||||
memcpy(M, dataAt, sizeof(M)); \
|
||||
} \
|
||||
dataAt += sizeof(rgbColor); \
|
||||
bytesRead += sizeof(rgbColor); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
T fromBuffer; \
|
||||
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
|
||||
dataAt += sizeof(fromBuffer); \
|
||||
processedBytes += sizeof(fromBuffer); \
|
||||
properties.O(fromBuffer); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
glm::quat fromBuffer; \
|
||||
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
|
||||
dataAt += bytes; \
|
||||
processedBytes += bytes; \
|
||||
properties.O(fromBuffer); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
uint16_t length; \
|
||||
memcpy(&length, dataAt, sizeof(length)); \
|
||||
dataAt += sizeof(length); \
|
||||
processedBytes += sizeof(length); \
|
||||
QString value((const char*)dataAt); \
|
||||
dataAt += length; \
|
||||
processedBytes += length; \
|
||||
properties.O(value); \
|
||||
}
|
||||
|
||||
#define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \
|
||||
if (propertyFlags.getHasProperty(P)) { \
|
||||
xColor color; \
|
||||
memcpy(&color, dataAt, sizeof(color)); \
|
||||
dataAt += sizeof(color); \
|
||||
processedBytes += sizeof(color); \
|
||||
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; \
|
||||
}
|
||||
|
||||
#define COPY_ENTITY_PROPERTY_TO_PROPERTIES(M,G) \
|
||||
properties._##M = G(); \
|
||||
properties._##M##Changed = false;
|
||||
|
||||
#define CHECK_PROPERTY_CHANGE(P,M) \
|
||||
if (_##M##Changed) { \
|
||||
changedProperties += P; \
|
||||
}
|
||||
|
||||
|
||||
#define COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(P) \
|
||||
QScriptValue P = vec3toScriptValue(engine, _##P); \
|
||||
properties.setProperty(#P, P);
|
||||
|
||||
#define COPY_PROPERTY_TO_QSCRIPTVALUE_QUAT(P) \
|
||||
QScriptValue P = quatToScriptValue(engine, _##P); \
|
||||
properties.setProperty(#P, P);
|
||||
|
||||
#define COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(P) \
|
||||
QScriptValue P = xColorToScriptValue(engine, _##P); \
|
||||
properties.setProperty(#P, P);
|
||||
|
||||
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \
|
||||
properties.setProperty(#P, G);
|
||||
|
||||
#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \
|
||||
properties.setProperty(#P, _##P);
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
float newValue = P.toVariant().toFloat(); \
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
bool newValue = P.toVariant().toBool(); \
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(P, S)\
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
QString newValue = P.toVariant().toString();\
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
QScriptValue x = P.property("x"); \
|
||||
QScriptValue y = P.property("y"); \
|
||||
QScriptValue z = P.property("z"); \
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {\
|
||||
glm::vec3 newValue; \
|
||||
newValue.x = x.toVariant().toFloat(); \
|
||||
newValue.y = y.toVariant().toFloat(); \
|
||||
newValue.z = z.toVariant().toFloat(); \
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_QUAT(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
QScriptValue x = P.property("x"); \
|
||||
QScriptValue y = P.property("y"); \
|
||||
QScriptValue z = P.property("z"); \
|
||||
QScriptValue w = P.property("w"); \
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { \
|
||||
glm::quat newValue; \
|
||||
newValue.x = x.toVariant().toFloat(); \
|
||||
newValue.y = y.toVariant().toFloat(); \
|
||||
newValue.z = z.toVariant().toFloat(); \
|
||||
newValue.w = w.toVariant().toFloat(); \
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
QScriptValue r = P.property("red"); \
|
||||
QScriptValue g = P.property("green"); \
|
||||
QScriptValue b = P.property("blue"); \
|
||||
if (r.isValid() && g.isValid() && b.isValid()) {\
|
||||
xColor newColor; \
|
||||
newColor.red = r.toVariant().toInt(); \
|
||||
newColor.green = g.toVariant().toInt(); \
|
||||
newColor.blue = b.toVariant().toInt(); \
|
||||
if (_defaultSettings || \
|
||||
(newColor.red != _color.red || \
|
||||
newColor.green != _color.green || \
|
||||
newColor.blue != _color.blue)) { \
|
||||
S(newColor); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // hifi_EntityItemPropertiesMacros_h
|
|
@ -31,9 +31,6 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
|
|||
|
||||
EntityItemID id(NEW_ENTITY, creatorTokenID, false );
|
||||
|
||||
// queue the packet
|
||||
queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties);
|
||||
|
||||
// If we have a local entity tree set, then also update it.
|
||||
if (_entityTree) {
|
||||
_entityTree->lockForWrite();
|
||||
|
@ -41,6 +38,9 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
|
|||
_entityTree->unlock();
|
||||
}
|
||||
|
||||
// queue the packet
|
||||
queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -68,18 +68,20 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID
|
|||
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(identity));
|
||||
|
||||
if (entity) {
|
||||
|
||||
// TODO: improve sitting points in the future, for now we've included the old model behavior for entity
|
||||
// types that are models
|
||||
results = entity->getProperties();
|
||||
|
||||
// TODO: improve sitting points and naturalDimensions in the future,
|
||||
// for now we've included the old sitting points model behavior for entity types that are models
|
||||
// we've also added this hack for setting natural dimensions of models
|
||||
if (entity->getType() == EntityTypes::Model) {
|
||||
ModelEntityItem* model = dynamic_cast<ModelEntityItem*>(entity);
|
||||
const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity);
|
||||
if (geometry) {
|
||||
model->setSittingPoints(geometry->sittingPoints);
|
||||
results.setSittingPoints(geometry->sittingPoints);
|
||||
Extents meshExtents = geometry->getUnscaledMeshExtents();
|
||||
results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
|
||||
}
|
||||
}
|
||||
|
||||
results = entity->getProperties();
|
||||
|
||||
} else {
|
||||
results.setIsUnknownID();
|
||||
}
|
||||
|
@ -95,13 +97,10 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E
|
|||
// if the entity is unknown, attempt to look it up
|
||||
if (!entityID.isKnownID) {
|
||||
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
|
||||
}
|
||||
|
||||
// if at this point, we know the id, send the update to the entity server
|
||||
if (actualID.id != UNKNOWN_ENTITY_ID) {
|
||||
entityID.id = actualID.id;
|
||||
entityID.isKnownID = true;
|
||||
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
||||
if (actualID.id != UNKNOWN_ENTITY_ID) {
|
||||
entityID.id = actualID.id;
|
||||
entityID.isKnownID = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a local entity tree set, then also update it. We can do this even if we don't know
|
||||
|
@ -111,6 +110,12 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E
|
|||
_entityTree->updateEntity(entityID, properties);
|
||||
_entityTree->unlock();
|
||||
}
|
||||
|
||||
// if at this point, we know the id, send the update to the entity server
|
||||
if (entityID.isKnownID) {
|
||||
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
||||
}
|
||||
|
||||
return entityID;
|
||||
}
|
||||
|
||||
|
@ -121,13 +126,10 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
|
|||
// if the entity is unknown, attempt to look it up
|
||||
if (!entityID.isKnownID) {
|
||||
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
|
||||
}
|
||||
|
||||
// if at this point, we know the id, send the update to the entity server
|
||||
if (actualID.id != UNKNOWN_ENTITY_ID) {
|
||||
entityID.id = actualID.id;
|
||||
entityID.isKnownID = true;
|
||||
getEntityPacketSender()->queueEraseEntityMessage(entityID);
|
||||
if (actualID.id != UNKNOWN_ENTITY_ID) {
|
||||
entityID.id = actualID.id;
|
||||
entityID.isKnownID = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a local entity tree set, then also update it.
|
||||
|
@ -136,6 +138,11 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
|
|||
_entityTree->deleteEntity(entityID);
|
||||
_entityTree->unlock();
|
||||
}
|
||||
|
||||
// if at this point, we know the id, send the update to the entity server
|
||||
if (entityID.isKnownID) {
|
||||
getEntityPacketSender()->queueEraseEntityMessage(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
EntityItemID EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
|
||||
|
|
|
@ -652,13 +652,14 @@ void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesT
|
|||
entitiesToDelete << thisEntity->getEntityItemID();
|
||||
entitiesBecomingStatic << thisEntity;
|
||||
} else {
|
||||
AACube oldCube = thisEntity->getAACube();
|
||||
AACube oldCube = thisEntity->getMaximumAACube();
|
||||
thisEntity->update(now);
|
||||
AACube newCube = thisEntity->getAACube();
|
||||
AACube newCube = thisEntity->getMaximumAACube();
|
||||
|
||||
// check to see if this movement has sent the entity outside of the domain.
|
||||
AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f);
|
||||
if (!domainBounds.touches(newCube)) {
|
||||
qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds.";
|
||||
entitiesToDelete << thisEntity->getEntityItemID();
|
||||
entitiesBecomingStatic << thisEntity;
|
||||
} else {
|
||||
|
|
|
@ -122,6 +122,9 @@ public:
|
|||
const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem) {
|
||||
return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL;
|
||||
}
|
||||
const Model* getModelForEntityItem(const EntityItem* entityItem) {
|
||||
return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL;
|
||||
}
|
||||
|
||||
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/;
|
||||
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||
|
|
|
@ -296,7 +296,12 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
}
|
||||
|
||||
if (includeThisEntity && params.viewFrustum) {
|
||||
AACube entityCube = entity->getAACube();
|
||||
|
||||
// we want to use the maximum possible box for this, so that we don't have to worry about the nuance of
|
||||
// simulation changing what's visible. consider the case where the entity contains an angular velocity
|
||||
// the entity may not be in view and then in view a frame later, let the client side handle it's view
|
||||
// frustum culling on rendering.
|
||||
AACube entityCube = entity->getMaximumAACube();
|
||||
entityCube.scale(TREE_SCALE);
|
||||
if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
|
||||
includeThisEntity = false; // out of view, don't include it
|
||||
|
@ -405,19 +410,19 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
}
|
||||
|
||||
bool EntityTreeElement::containsEntityBounds(const EntityItem* entity) const {
|
||||
return containsBounds(entity->getMinimumPoint(), entity->getMaximumPoint());
|
||||
return containsBounds(entity->getMaximumAACube());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::bestFitEntityBounds(const EntityItem* entity) const {
|
||||
return bestFitBounds(entity->getMinimumPoint(), entity->getMaximumPoint());
|
||||
return bestFitBounds(entity->getMaximumAACube());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::containsBounds(const EntityItemProperties& properties) const {
|
||||
return containsBounds(properties.getMinimumPointTreeUnits(), properties.getMaximumPointTreeUnits());
|
||||
return containsBounds(properties.getMaximumAACubeInTreeUnits());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) const {
|
||||
return bestFitBounds(properties.getMinimumPointTreeUnits(), properties.getMaximumPointTreeUnits());
|
||||
return bestFitBounds(properties.getMaximumAACubeInTreeUnits());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::containsBounds(const AACube& bounds) const {
|
||||
|
@ -477,76 +482,37 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
|||
while(entityItr != entityEnd) {
|
||||
EntityItem* entity = (*entityItr);
|
||||
|
||||
AACube entityCube = entity->getAACube();
|
||||
AABox entityBox = entity->getAABox();
|
||||
float localDistance;
|
||||
BoxFace localFace;
|
||||
|
||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||
if (entityCube.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||
const FBXGeometry* fbxGeometry = _myTree->getGeometryForEntity(entity);
|
||||
if (fbxGeometry && fbxGeometry->meshExtents.isValid()) {
|
||||
Extents extents = fbxGeometry->meshExtents;
|
||||
if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||
|
||||
// NOTE: If the entity has a bad mesh, then extents will be 0,0,0 & 0,0,0
|
||||
if (extents.minimum == extents.maximum && extents.minimum == glm::vec3(0,0,0)) {
|
||||
extents.maximum = glm::vec3(1.0f,1.0f,1.0f); // in this case we will simulate the unit cube
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
|
||||
glm::mat4 translation = glm::translate(entity->getPosition());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
glm::vec3 registrationPoint = entity->getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint);
|
||||
|
||||
AABox entityFrameBox(corner, dimensions);
|
||||
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
||||
|
||||
// we can use the AABox's ray intersection by mapping our origin and direction into the entity frame
|
||||
// and testing intersection there.
|
||||
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) {
|
||||
if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
*intersectedObject = (void*)entity;
|
||||
somethingIntersected = true;
|
||||
}
|
||||
|
||||
// NOTE: these extents are entity space, so we need to scale and center them accordingly
|
||||
// size is our "target size in world space"
|
||||
// we need to set our entity scale so that the extents of the mesh, fit in a cube that size...
|
||||
float maxDimension = glm::distance(extents.maximum, extents.minimum);
|
||||
float scale = entity->getSize() / maxDimension;
|
||||
|
||||
glm::vec3 halfDimensions = (extents.maximum - extents.minimum) * 0.5f;
|
||||
glm::vec3 offset = -extents.minimum - halfDimensions;
|
||||
|
||||
extents.minimum += offset;
|
||||
extents.maximum += offset;
|
||||
|
||||
extents.minimum *= scale;
|
||||
extents.maximum *= scale;
|
||||
|
||||
Extents rotatedExtents = extents;
|
||||
|
||||
rotatedExtents.rotate(entity->getRotation());
|
||||
|
||||
rotatedExtents.minimum += entity->getPosition();
|
||||
rotatedExtents.maximum += entity->getPosition();
|
||||
|
||||
|
||||
AABox rotatedExtentsBox(rotatedExtents.minimum, (rotatedExtents.maximum - rotatedExtents.minimum));
|
||||
|
||||
// if it's in our AABOX for our rotated extents, then check to see if it's in our non-AABox
|
||||
if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
|
||||
glm::mat4 translation = glm::translate(entity->getPosition());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
AABox entityFrameBox(extents.minimum, (extents.maximum - extents.minimum));
|
||||
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
||||
|
||||
// we can use the AABox's ray intersection by mapping our origin and direction into the entity frame
|
||||
// and testing intersection there.
|
||||
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) {
|
||||
if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
*intersectedObject = (void*)entity;
|
||||
somethingIntersected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
*intersectedObject = (void*)entity;
|
||||
somethingIntersected = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,6 +521,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 +572,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 +584,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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -40,7 +47,6 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
|||
properties._animationIsPlaying = getAnimationIsPlaying();
|
||||
properties._animationFrameIndex = getAnimationFrameIndex();
|
||||
properties._animationFPS = getAnimationFPS();
|
||||
properties._sittingPoints = getSittingPoints(); // sitting support
|
||||
properties._colorChanged = false;
|
||||
properties._modelURLChanged = false;
|
||||
properties._animationURLChanged = false;
|
||||
|
@ -55,40 +61,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 +148,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 +374,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();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,10 +54,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(); }
|
||||
|
||||
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; }
|
||||
|
||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||
void setColor(const xColor& value) {
|
||||
|
@ -69,10 +72,14 @@ 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; }
|
||||
|
||||
void mapJoints(const QStringList& modelJointNames);
|
||||
QVector<glm::quat> getAnimationFrame();
|
||||
|
@ -92,7 +99,6 @@ protected:
|
|||
|
||||
rgbColor _color;
|
||||
QString _modelURL;
|
||||
QVector<SittingPoint> _sittingPoints;
|
||||
|
||||
quint64 _lastAnimated;
|
||||
QString _animationURL;
|
||||
|
|
|
@ -20,21 +20,53 @@ MovingEntitiesOperator::MovingEntitiesOperator(EntityTree* tree) :
|
|||
_changeTime(usecTimestampNow()),
|
||||
_foundOldCount(0),
|
||||
_foundNewCount(0),
|
||||
_lookingCount(0)
|
||||
_lookingCount(0),
|
||||
_wantDebug(false)
|
||||
{
|
||||
}
|
||||
|
||||
MovingEntitiesOperator::~MovingEntitiesOperator() {
|
||||
if (_wantDebug) {
|
||||
bool stopExecution = false;
|
||||
qDebug() << "MovingEntitiesOperator::~MovingEntitiesOperator() -----------------------------";
|
||||
qDebug() << " _lookingCount:" << _lookingCount;
|
||||
qDebug() << " _foundOldCount:" << _foundOldCount;
|
||||
qDebug() << " _foundNewCount:" << _foundNewCount;
|
||||
if (_foundOldCount < _lookingCount) {
|
||||
qDebug() << " FAILURE: **** _foundOldCount < _lookingCount ******";
|
||||
stopExecution = true;
|
||||
}
|
||||
if (_foundNewCount < _lookingCount) {
|
||||
qDebug() << " FAILURE: **** _foundNewCount < _lookingCount ******";
|
||||
stopExecution = true;
|
||||
}
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
if(stopExecution) {
|
||||
debug();
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube) {
|
||||
EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID());
|
||||
AABox newBox = newCube.clamp(0.0f, 1.0f);
|
||||
AABox newCubeClamped = newCube.clamp(0.0f, 1.0f);
|
||||
AABox oldCubeClamped = oldCube.clamp(0.0f, 1.0f);
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
||||
qDebug() << " oldCube:" << oldCube;
|
||||
qDebug() << " newCube:" << newCube;
|
||||
qDebug() << " oldCubeClamped:" << oldCubeClamped;
|
||||
qDebug() << " newCubeClamped:" << newCubeClamped;
|
||||
qDebug() << " oldContainingElement:" << oldContainingElement->getAACube();
|
||||
qDebug() << " oldContainingElement->bestFitBounds(newCubeClamped):" << oldContainingElement->bestFitBounds(newCubeClamped);
|
||||
}
|
||||
|
||||
// If the original containing element is the best fit for the requested newCube locations then
|
||||
// we don't actually need to add the entity for moving and we can short circuit all this work
|
||||
if (!oldContainingElement->bestFitBounds(newBox)) {
|
||||
if (!oldContainingElement->bestFitBounds(newCubeClamped)) {
|
||||
// check our tree, to determine if this entity is known
|
||||
EntityToMoveDetails details;
|
||||
details.oldContainingElement = oldContainingElement;
|
||||
|
@ -44,9 +76,29 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACub
|
|||
details.newFound = false;
|
||||
details.oldCube = oldCube;
|
||||
details.newCube = newCube;
|
||||
details.newBox = newBox;
|
||||
details.oldCubeClamped = oldCubeClamped;
|
||||
details.newCubeClamped = newCubeClamped;
|
||||
_entitiesToMove << details;
|
||||
_lookingCount++;
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||
qDebug() << " details.oldCube:" << details.oldCube;
|
||||
qDebug() << " details.newCube:" << details.newCube;
|
||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||
qDebug() << " _lookingCount:" << _lookingCount;
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
} else {
|
||||
if (_wantDebug) {
|
||||
qDebug() << " oldContainingElement->bestFitBounds(newCubeClamped) IS BEST FIT... NOTHING TO DO";
|
||||
}
|
||||
}
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,11 +110,29 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) {
|
|||
// check the bounds
|
||||
if (_entitiesToMove.size() > 0) {
|
||||
AACube elementCube = element->getAACube();
|
||||
int detailIndex = 0;
|
||||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
||||
if (elementCube.contains(details.oldCube) || elementCube.contains(details.newCube)) {
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::shouldRecurseSubTree() details["<< detailIndex <<"]-----------------------------";
|
||||
qDebug() << " element:" << element->getAACube();
|
||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||
qDebug() << " details.oldCube:" << details.oldCube;
|
||||
qDebug() << " details.newCube:" << details.newCube;
|
||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||
qDebug() << " elementCube.contains(details.oldCube)" << elementCube.contains(details.oldCube);
|
||||
qDebug() << " elementCube.contains(details.newCube)" << elementCube.contains(details.newCube);
|
||||
qDebug() << " elementCube.contains(details.oldCubeClamped)" << elementCube.contains(details.oldCubeClamped);
|
||||
qDebug() << " elementCube.contains(details.newCubeClamped)" << elementCube.contains(details.newCubeClamped);
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
|
||||
if (elementCube.contains(details.oldCubeClamped) || elementCube.contains(details.newCubeClamped)) {
|
||||
containsEntity = true;
|
||||
break; // if it contains at least one, we're good to go
|
||||
}
|
||||
detailIndex++;
|
||||
}
|
||||
}
|
||||
return containsEntity;
|
||||
|
@ -87,13 +157,36 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
|
|||
if (keepSearching && shouldRecurseSubTree(element)) {
|
||||
|
||||
// check against each of our search entities
|
||||
int detailIndex = 0;
|
||||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::preRecursion() details["<< detailIndex <<"]-----------------------------";
|
||||
qDebug() << " entityTreeElement:" << entityTreeElement->getAACube();
|
||||
qDebug() << " entityTreeElement->bestFitBounds(details.newCube):" << entityTreeElement->bestFitBounds(details.newCube);
|
||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||
qDebug() << " entityTreeElement:" << entityTreeElement;
|
||||
qDebug() << " details.oldCube:" << details.oldCube;
|
||||
qDebug() << " details.newCube:" << details.newCube;
|
||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||
qDebug() << " _lookingCount:" << _lookingCount;
|
||||
qDebug() << " _foundOldCount:" << _foundOldCount;
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
|
||||
|
||||
// If this is one of the old elements we're looking for, then ask it to remove the old entity
|
||||
if (!details.oldFound && entityTreeElement == details.oldContainingElement) {
|
||||
entityTreeElement->removeEntityItem(details.entity);
|
||||
_foundOldCount++;
|
||||
//details.oldFound = true; // TODO: would be nice to add this optimization
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::preRecursion() -----------------------------";
|
||||
qDebug() << " FOUND OLD - REMOVING";
|
||||
qDebug() << " entityTreeElement == details.oldContainingElement";
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
}
|
||||
|
||||
// If this element is the best fit for the new bounds of this entity then add the entity to the element
|
||||
|
@ -103,7 +196,14 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
|
|||
_tree->setContainingElement(entityItemID, entityTreeElement);
|
||||
_foundNewCount++;
|
||||
//details.newFound = true; // TODO: would be nice to add this optimization
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::preRecursion() -----------------------------";
|
||||
qDebug() << " FOUND NEW - ADDING";
|
||||
qDebug() << " entityTreeElement->bestFitBounds(details.newCube)";
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
}
|
||||
detailIndex++;
|
||||
}
|
||||
// if we haven't found all of our search for entities, then keep looking
|
||||
keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount);
|
||||
|
@ -163,9 +263,9 @@ OctreeElement* MovingEntitiesOperator::possiblyCreateChildAt(OctreeElement* elem
|
|||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
||||
|
||||
// if the scale of our desired cube is smaller than our children, then consider making a child
|
||||
if (details.newBox.getLargestDimension() <= childElementScale) {
|
||||
if (details.newCubeClamped.getLargestDimension() <= childElementScale) {
|
||||
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newBox);
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newCubeClamped);
|
||||
|
||||
// If the childIndex we were asked if we wanted to create contains this newCube,
|
||||
// then we will create this branch and continue. We can exit this loop immediately
|
||||
|
|
|
@ -17,7 +17,8 @@ public:
|
|||
EntityItem* entity;
|
||||
AACube oldCube;
|
||||
AACube newCube;
|
||||
AABox newBox;
|
||||
AABox oldCubeClamped;
|
||||
AABox newCubeClamped;
|
||||
EntityTreeElement* oldContainingElement;
|
||||
AACube oldContainingElementCube;
|
||||
bool oldFound;
|
||||
|
@ -50,6 +51,8 @@ private:
|
|||
int _foundNewCount;
|
||||
int _lookingCount;
|
||||
bool shouldRecurseSubTree(OctreeElement* element);
|
||||
|
||||
bool _wantDebug;
|
||||
};
|
||||
|
||||
#endif // hifi_MovingEntitiesOperator_h
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -31,23 +31,27 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
|
|||
_dontMove(false), // assume we'll be moving
|
||||
_changeTime(usecTimestampNow()),
|
||||
_oldEntityCube(),
|
||||
_newEntityCube()
|
||||
_newEntityCube(),
|
||||
_wantDebug(false)
|
||||
{
|
||||
// caller must have verified existence of containingElement and oldEntity
|
||||
assert(_containingElement && _existingEntity);
|
||||
|
||||
_oldEntityCube = _existingEntity->getAACube();
|
||||
// Here we have a choice to make, do we want to "tight fit" the actual minimum for the
|
||||
// entity into the the element, or do we want to use the entities "relaxed" bounds
|
||||
// which can handle all potential rotations?
|
||||
// the getMaximumAACube is the relaxed form.
|
||||
_oldEntityCube = _existingEntity->getMaximumAACube();
|
||||
_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);
|
||||
}
|
||||
|
@ -72,11 +76,24 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
|
|||
_newEntityCube = _oldEntityCube;
|
||||
_dontMove = true;
|
||||
} else {
|
||||
_newEntityCube = _properties.getAACubeTreeUnits();
|
||||
_newEntityCube = _properties.getMaximumAACubeInTreeUnits();
|
||||
_removeOld = true; // our properties are going to move us, so remember this for later processing
|
||||
}
|
||||
|
||||
_newEntityBox = _newEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds
|
||||
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "UpdateEntityOperator::UpdateEntityOperator() -----------------------------";
|
||||
qDebug() << " _entityItemID:" << _entityItemID;
|
||||
qDebug() << " _containingElementCube:" << _containingElementCube;
|
||||
qDebug() << " _oldEntityCube:" << _oldEntityCube;
|
||||
qDebug() << " _oldEntityBox:" << _oldEntityBox;
|
||||
qDebug() << " _newEntityCube:" << _newEntityCube;
|
||||
qDebug() << " _newEntityBox:" << _newEntityBox;
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ private:
|
|||
|
||||
bool subTreeContainsOldEntity(OctreeElement* element);
|
||||
bool subTreeContainsNewEntity(OctreeElement* element);
|
||||
|
||||
bool _wantDebug;
|
||||
};
|
||||
|
||||
#endif // hifi_UpdateEntityOperator_h
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -392,6 +392,41 @@ ViewFrustum::location ViewFrustum::cubeInFrustum(const AACube& cube) const {
|
|||
return regularResult;
|
||||
}
|
||||
|
||||
ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const {
|
||||
|
||||
ViewFrustum::location regularResult = INSIDE;
|
||||
ViewFrustum::location keyholeResult = OUTSIDE;
|
||||
|
||||
// If we have a keyholeRadius, check that first, since it's cheaper
|
||||
if (_keyholeRadius >= 0.0f) {
|
||||
keyholeResult = boxInKeyhole(box);
|
||||
}
|
||||
if (keyholeResult == INSIDE) {
|
||||
return keyholeResult;
|
||||
}
|
||||
|
||||
// TODO: These calculations are expensive, taking up 80% of our time in this function.
|
||||
// This appears to be expensive because we have to test the distance to each plane.
|
||||
// One suggested optimization is to first check against the approximated cone. We might
|
||||
// also be able to test against the cone to the bounding sphere of the box.
|
||||
for(int i=0; i < 6; i++) {
|
||||
const glm::vec3& normal = _planes[i].getNormal();
|
||||
const glm::vec3& boxVertexP = box.getVertexP(normal);
|
||||
float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP);
|
||||
|
||||
const glm::vec3& boxVertexN = box.getVertexN(normal);
|
||||
float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN);
|
||||
|
||||
if (planeToBoxVertexPDistance < 0) {
|
||||
// This is outside the regular frustum, so just return the value from checking the keyhole
|
||||
return keyholeResult;
|
||||
} else if (planeToBoxVertexNDistance < 0) {
|
||||
regularResult = INTERSECT;
|
||||
}
|
||||
}
|
||||
return regularResult;
|
||||
}
|
||||
|
||||
bool testMatches(glm::quat lhs, glm::quat rhs, float epsilon = EPSILON) {
|
||||
return (fabs(lhs.x - rhs.x) <= epsilon && fabs(lhs.y - rhs.y) <= epsilon && fabs(lhs.z - rhs.z) <= epsilon
|
||||
&& fabs(lhs.w - rhs.w) <= epsilon);
|
||||
|
|
|
@ -35,6 +35,10 @@ public:
|
|||
/// \return whether or not the extents are empty
|
||||
bool isEmpty() const { return minimum == maximum; }
|
||||
bool isValid() const { return !((minimum == glm::vec3(FLT_MAX)) && (maximum == glm::vec3(-FLT_MAX))); }
|
||||
|
||||
/// \param vec3 for delta amount to shift the extents by
|
||||
/// \return true if point is within current limits
|
||||
void shiftBy(const glm::vec3& delta) { minimum += delta; maximum += delta; }
|
||||
|
||||
/// rotate the extents around orign by rotation
|
||||
void rotate(const glm::quat& rotation);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue