Merge branch 'master' into 20681

Conflicts:
	libraries/entities/src/EntityItemProperties.cpp
This commit is contained in:
David Rowe 2015-09-18 16:44:04 -07:00
commit 812ab9b7c6
57 changed files with 990 additions and 765 deletions

View file

@ -10,72 +10,71 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../libraries/utils.js");
var RADIUS_FACTOR = 4;
var RIGHT_HAND_CLICK = Controller.findAction("RIGHT_HAND_CLICK");
var rightTriggerAction = RIGHT_HAND_CLICK;
/////////////////////////////////////////////////////////////////
//
// these tune time-averaging and "on" value for analog trigger
//
var TRIGGER_SMOOTH_RATIO = 0.0; // 0.0 disables smoothing of trigger value
var TRIGGER_ON_VALUE = 0.2;
/////////////////////////////////////////////////////////////////
//
// distant manipulation
//
var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
var NO_INTERSECT_COLOR = {red: 10, green: 10, blue: 255}; // line color when pick misses
var INTERSECT_COLOR = {red: 250, green: 10, blue: 10}; // line color when pick hits
var LINE_ENTITY_DIMENSIONS = {x: 1000, y: 1000, z: 1000};
var LINE_LENGTH = 500;
/////////////////////////////////////////////////////////////////
//
// near grabbing
//
var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
var NEAR_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
/////////////////////////////////////////////////////////////////
//
// other constants
//
var RIGHT_HAND = 1;
var LEFT_HAND = 0;
var ZERO_VEC = {x: 0, y: 0, z: 0};
var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}";
var MSEC_PER_SEC = 1000.0;
// these control how long an abandoned pointer line will hang around
var startTime = Date.now();
var LIFETIME = 10;
// states for the state machine
var STATE_SEARCHING = 0;
var STATE_DISTANCE_HOLDING = 1;
var STATE_CONTINUE_DISTANCE_HOLDING = 2;
var STATE_NEAR_GRABBING = 3;
var STATE_CONTINUE_NEAR_GRABBING = 4;
var STATE_RELEASE = 5;
var GRAB_USER_DATA_KEY = "grabKey";
var LEFT_HAND_CLICK = Controller.findAction("LEFT_HAND_CLICK");
var leftTriggerAction = LEFT_HAND_CLICK;
var LIFETIME = 10;
var EXTRA_TIME = 5;
var POINTER_CHECK_TIME = 5000;
var ZERO_VEC = {
x: 0,
y: 0,
z: 0
}
var LINE_LENGTH = 500;
var THICK_LINE_WIDTH = 7;
var THIN_LINE_WIDTH = 2;
var NO_INTERSECT_COLOR = {
red: 10,
green: 10,
blue: 255
};
var INTERSECT_COLOR = {
red: 250,
green: 10,
blue: 10
};
var GRAB_RADIUS = 0.3;
var GRAB_COLOR = {
red: 250,
green: 10,
blue: 250
};
var SHOW_LINE_THRESHOLD = 0.2;
var DISTANCE_HOLD_THRESHOLD = 0.8;
var right4Action = 18;
var left4Action = 17;
var RIGHT = 1;
var LEFT = 0;
var rightController = new controller(RIGHT, rightTriggerAction, right4Action, "right");
var leftController = new controller(LEFT, leftTriggerAction, left4Action, "left");
var startTime = Date.now();
//Need to wait before calling these methods for some reason...
Script.setTimeout(function() {
rightController.checkPointer();
leftController.checkPointer();
}, 100)
function controller(side, triggerAction, pullAction, hand) {
function controller(hand, triggerAction) {
this.hand = hand;
if (hand === "right") {
if (this.hand === RIGHT_HAND) {
this.getHandPosition = MyAvatar.getRightPalmPosition;
this.getHandRotation = MyAvatar.getRightPalmRotation;
} else {
@ -83,309 +82,345 @@ function controller(side, triggerAction, pullAction, hand) {
this.getHandRotation = MyAvatar.getLeftPalmRotation;
}
this.triggerAction = triggerAction;
this.pullAction = pullAction;
this.actionID = null;
this.distanceHolding = false;
this.closeGrabbing = false;
this.triggerValue = 0;
this.prevTriggerValue = 0;
this.palm = 2 * side;
this.tip = 2 * side + 1;
this.pointer = null;
}
this.palm = 2 * hand;
// this.tip = 2 * hand + 1; // unused, but I'm leaving this here for fear it will be needed
this.actionID = null; // action this script created...
this.grabbedEntity = null; // on this entity.
this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity
this.state = 0;
this.pointer = null; // entity-id of line object
this.triggerValue = 0; // rolling average of trigger value
controller.prototype.updateLine = function() {
if (this.pointer != null) {
if (Entities.getEntityProperties(this.pointer).id != this.pointer) {
this.pointer = null;
this.update = function() {
switch(this.state) {
case STATE_SEARCHING:
this.search();
break;
case STATE_DISTANCE_HOLDING:
this.distanceHolding();
break;
case STATE_CONTINUE_DISTANCE_HOLDING:
this.continueDistanceHolding();
break;
case STATE_NEAR_GRABBING:
this.nearGrabbing();
break;
case STATE_CONTINUE_NEAR_GRABBING:
this.continueNearGrabbing();
break;
case STATE_RELEASE:
this.release();
break;
}
}
if (this.pointer == null) {
this.lineCreationTime = Date.now();
this.pointer = Entities.addEntity({
type: "Line",
name: "pointer",
color: NO_INTERSECT_COLOR,
dimensions: {
x: 1000,
y: 1000,
z: 1000
},
visible: true,
lifetime: LIFETIME
});
}
var handPosition = this.getHandPosition();
var direction = Quat.getUp(this.getHandRotation());
//only check if we havent already grabbed an object
if (this.distanceHolding) {
Entities.editEntity(this.pointer, {
position: handPosition,
linePoints: [ ZERO_VEC, Vec3.subtract(Entities.getEntityProperties(this.grabbedEntity).position, handPosition) ],
lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME
});
return;
}
Entities.editEntity(this.pointer, {
position: handPosition,
linePoints: [ ZERO_VEC, Vec3.multiply(direction, LINE_LENGTH) ],
lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME
});
if (this.checkForIntersections(handPosition, direction)) {
Entities.editEntity(this.pointer, {
color: INTERSECT_COLOR,
});
} else {
Entities.editEntity(this.pointer, {
color: NO_INTERSECT_COLOR,
});
}
}
controller.prototype.checkPointer = function() {
var self = this;
Script.setTimeout(function() {
var props = Entities.getEntityProperties(self.pointer);
Entities.editEntity(self.pointer, {
lifetime: (Date.now() - startTime) / 1000.0 + LIFETIME
});
self.checkPointer();
}, POINTER_CHECK_TIME);
}
controller.prototype.checkForIntersections = function(origin, direction) {
var pickRay = {
origin: origin,
direction: direction
};
var intersection = Entities.findRayIntersection(pickRay, true);
if (intersection.intersects && intersection.properties.collisionsWillMove === 1) {
var handPosition = Controller.getSpatialControlPosition(this.palm);
this.distanceToEntity = Vec3.distance(handPosition, intersection.properties.position);
var intersectionDistance = Vec3.distance(handPosition, intersection.intersection);
if (intersectionDistance < 0.6) {
//We are grabbing an entity, so let it know we've grabbed it
this.grabbedEntity = intersection.entityID;
this.activateEntity(this.grabbedEntity);
this.hidePointer();
this.shouldDisplayLine = false;
this.grabEntity();
return true;
this.lineOn = function(closePoint, farPoint, color) {
// draw a line
if (this.pointer == null) {
this.pointer = Entities.addEntity({
type: "Line",
name: "pointer",
dimensions: LINE_ENTITY_DIMENSIONS,
visible: true,
position: closePoint,
linePoints: [ ZERO_VEC, farPoint ],
color: color,
lifetime: LIFETIME
});
} else {
Entities.editEntity(this.pointer, {
linePoints: [
ZERO_VEC,
Vec3.multiply(direction, this.distanceToEntity)
]
position: closePoint,
linePoints: [ ZERO_VEC, farPoint ],
color: color,
lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME
});
}
}
this.lineOff = function() {
if (this.pointer != null) {
Entities.deleteEntity(this.pointer);
}
this.pointer = null;
}
this.triggerSmoothedSqueezed = function() {
var triggerValue = Controller.getActionValue(this.triggerAction);
// smooth out trigger value
this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
(triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
return this.triggerValue > TRIGGER_ON_VALUE;
}
this.triggerSqueezed = function() {
var triggerValue = Controller.getActionValue(this.triggerAction);
return triggerValue > TRIGGER_ON_VALUE;
}
this.search = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
}
// the trigger is being pressed, do a ray test
var handPosition = this.getHandPosition();
var pickRay = {origin: handPosition, direction: Quat.getUp(this.getHandRotation())};
var intersection = Entities.findRayIntersection(pickRay, true);
if (intersection.intersects &&
intersection.properties.collisionsWillMove === 1 &&
intersection.properties.locked === 0) {
// the ray is intersecting something we can move.
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
this.grabbedEntity = intersection.entityID;
return true;
if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) {
// the hand is very close to the intersected object. go into close-grabbing mode.
this.state = STATE_NEAR_GRABBING;
} else {
// the hand is far from the intersected object. go into distance-holding mode
this.state = STATE_DISTANCE_HOLDING;
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
}
} else {
// forward ray test failed, try sphere test.
var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS);
var minDistance = GRAB_RADIUS;
var grabbedEntity = null;
for (var i = 0; i < nearbyEntities.length; i++) {
var props = Entities.getEntityProperties(nearbyEntities[i]);
var distance = Vec3.distance(props.position, handPosition);
if (distance < minDistance && props.name !== "pointer" &&
props.collisionsWillMove === 1 &&
props.locked === 0) {
this.grabbedEntity = nearbyEntities[i];
minDistance = distance;
}
}
if (this.grabbedEntity === null) {
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
} else {
this.state = STATE_NEAR_GRABBING;
}
}
}
return false;
}
controller.prototype.attemptMove = function() {
if (this.grabbedEntity || this.distanceHolding) {
var handPosition = Controller.getSpatialControlPosition(this.palm);
this.distanceHolding = function() {
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]);
this.distanceHolding = true;
if (this.actionID === null) {
this.currentObjectPosition = Entities.getEntityProperties(this.grabbedEntity).position;
this.currentObjectRotation = Entities.getEntityProperties(this.grabbedEntity).rotation;
// add the action and initialize some variables
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectRotation = grabbedProperties.rotation;
this.handPreviousPosition = handControllerPosition;
this.handPreviousRotation = handRotation;
this.handPreviousPosition = handPosition;
this.handPreviousRotation = handRotation;
this.actionID = Entities.addAction("spring", this.grabbedEntity, {
targetPosition: this.currentObjectPosition,
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: this.currentObjectRotation,
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
});
if (this.actionID == NULL_ACTION_ID) {
this.actionID = null;
}
this.actionID = Entities.addAction("spring", this.grabbedEntity, {
targetPosition: this.currentObjectPosition,
linearTimeScale: .1,
targetRotation: this.currentObjectRotation,
angularTimeScale: .1
});
} else {
var radius = Math.max(Vec3.distance(this.currentObjectPosition, handPosition) * RADIUS_FACTOR, 1.0);
if (this.actionID != null) {
this.state = STATE_CONTINUE_DISTANCE_HOLDING;
this.activateEntity(this.grabbedEntity);
Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab");
var handMoved = Vec3.subtract(handPosition, this.handPreviousPosition);
this.handPreviousPosition = handPosition;
var superHandMoved = Vec3.multiply(handMoved, radius);
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved);
// ---------------- this tracks hand rotation
// var handChange = Quat.multiply(handRotation, Quat.inverse(this.handPreviousRotation));
// this.handPreviousRotation = handRotation;
// this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
// ----------------
// ---------------- this doubles hand rotation
var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, 2.0),
Quat.inverse(this.handPreviousRotation));
this.handPreviousRotation = handRotation;
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
// ----------------
Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: this.currentObjectPosition, linearTimeScale: .1,
targetRotation: this.currentObjectRotation, angularTimeScale: .1
});
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
}
}
}
controller.prototype.showPointer = function() {
Entities.editEntity(this.pointer, {
visible: true
});
}
controller.prototype.hidePointer = function() {
Entities.editEntity(this.pointer, {
visible: false
});
}
controller.prototype.letGo = function() {
if (this.grabbedEntity && this.actionID) {
this.deactivateEntity(this.grabbedEntity);
Entities.deleteAction(this.grabbedEntity, this.actionID);
}
this.grabbedEntity = null;
this.actionID = null;
this.distanceHolding = false;
this.closeGrabbing = false;
}
controller.prototype.update = function() {
this.triggerValue = Controller.getActionValue(this.triggerAction);
if (this.triggerValue > SHOW_LINE_THRESHOLD && this.prevTriggerValue < SHOW_LINE_THRESHOLD) {
//First check if an object is within close range and then run the close grabbing logic
if (this.checkForInRangeObject()) {
this.grabEntity();
} else {
this.showPointer();
this.shouldDisplayLine = true;
this.continueDistanceHolding = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
}
} else if (this.triggerValue < SHOW_LINE_THRESHOLD && this.prevTriggerValue > SHOW_LINE_THRESHOLD) {
this.hidePointer();
this.letGo();
this.shouldDisplayLine = false;
var handPosition = this.getHandPosition();
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]);
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
// the action was set up on a previous call. update the targets.
var radius = Math.max(Vec3.distance(this.currentObjectPosition,
handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR,
DISTANCE_HOLDING_RADIUS_FACTOR);
var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition);
this.handPreviousPosition = handControllerPosition;
var superHandMoved = Vec3.multiply(handMoved, radius);
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved);
// this doubles hand rotation
var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation,
DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR),
Quat.inverse(this.handPreviousRotation));
this.handPreviousRotation = handRotation;
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab");
Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
});
}
if (this.shouldDisplayLine) {
this.updateLine();
}
if (this.triggerValue > DISTANCE_HOLD_THRESHOLD && !this.closeGrabbing) {
this.attemptMove();
}
this.prevTriggerValue = this.triggerValue;
}
controller.prototype.grabEntity = function() {
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
this.closeGrabbing = true;
//check if our entity has instructions on how to be grabbed, otherwise, just use default relative position and rotation
var userData = getEntityUserData(this.grabbedEntity);
var objectRotation = Entities.getEntityProperties(this.grabbedEntity).rotation;
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
var objectPosition = Entities.getEntityProperties(this.grabbedEntity).position;
var offset = Vec3.subtract(objectPosition, handPosition);
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
var relativePosition = offsetPosition;
var relativeRotation = offsetRotation;
if (userData.grabFrame) {
if (userData.grabFrame.relativePosition) {
relativePosition = userData.grabFrame.relativePosition;
this.nearGrabbing = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
}
if (userData.grabFrame.relativeRotation) {
relativeRotation = userData.grabFrame.relativeRotation;
}
}
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
hand: this.hand,
timeScale: 0.05,
relativePosition: relativePosition,
relativeRotation: relativeRotation
});
}
this.lineOff();
controller.prototype.checkForInRangeObject = function() {
var handPosition = Controller.getSpatialControlPosition(this.palm);
var entities = Entities.findEntities(handPosition, GRAB_RADIUS);
var minDistance = GRAB_RADIUS;
var grabbedEntity = null;
//Get nearby entities and assign nearest
for (var i = 0; i < entities.length; i++) {
var props = Entities.getEntityProperties(entities[i]);
var distance = Vec3.distance(props.position, handPosition);
if (distance < minDistance && props.name !== "pointer" && props.collisionsWillMove === 1) {
grabbedEntity = entities[i];
minDistance = distance;
}
}
if (grabbedEntity === null) {
return false;
} else {
//We are grabbing an entity, so let it know we've grabbed it
this.grabbedEntity = grabbedEntity;
this.activateEntity(this.grabbedEntity);
return true;
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, "position");
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
var objectRotation = grabbedProperties.rotation;
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
currentObjectPosition = grabbedProperties.position;
var offset = Vec3.subtract(currentObjectPosition, handPosition);
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
hand: this.hand == RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: offsetPosition,
relativeRotation: offsetRotation
});
if (this.actionID == NULL_ACTION_ID) {
this.actionID = null;
} else {
this.state = STATE_CONTINUE_NEAR_GRABBING;
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
}
this.currentHandControllerPosition = Controller.getSpatialControlPosition(this.palm);
this.currentObjectTime = Date.now();
}
this.continueNearGrabbing = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
}
// keep track of the measured velocity of the held object
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var now = Date.now();
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerPosition); // meters
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
if (deltaTime > 0.0 && !vec3equal(this.currentHandControllerPosition, handControllerPosition)) {
var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime);
// don't update grabbedVelocity if the trigger is off. the smoothing of the trigger
// value would otherwise give the held object time to slow down.
if (this.triggerSqueezed()) {
this.grabbedVelocity =
Vec3.sum(Vec3.multiply(this.grabbedVelocity,
(1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)),
Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO));
}
}
this.currentHandControllerPosition = handControllerPosition;
this.currentObjectTime = now;
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
}
this.release = function() {
this.lineOff();
if (this.grabbedEntity != null && this.actionID != null) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
}
// the action will tend to quickly bring an object's velocity to zero. now that
// the action is gone, set the objects velocity to something the holder might expect.
Entities.editEntity(this.grabbedEntity,
{velocity: Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER)}
);
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
this.deactivateEntity(this.grabbedEntity);
this.grabbedVelocity = ZERO_VEC;
this.grabbedEntity = null;
this.actionID = null;
this.state = STATE_SEARCHING;
}
this.cleanup = function() {
release();
}
this.activateEntity = function(entity) {
var data = {
activated: true,
avatarId: MyAvatar.sessionUUID
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
}
this.deactivateEntity = function(entity) {
var data = {
activated: false,
avatarId: null
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
}
}
controller.prototype.activateEntity = function(entity) {
var data = {
activated: true,
avatarId: MyAvatar.sessionUUID
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
}
controller.prototype.deactivateEntity = function(entity) {
var data = {
activated: false,
avatarId: null
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
}
var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK"));
var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK"));
controller.prototype.cleanup = function() {
Entities.deleteEntity(this.pointer);
if (this.grabbedEntity) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
}
}
function update() {
rightController.update();
leftController.update();
}
function cleanup() {
rightController.cleanup();
leftController.cleanup();
}
Script.scriptEnding.connect(cleanup);
Script.update.connect(update)

View file

@ -12,7 +12,6 @@
//
(function() {
Script.include("../libraries/utils.js");
var _this;
@ -24,39 +23,29 @@
DetectGrabbed.prototype = {
// update() will be called regulary, because we've hooked the update signal in our preload() function
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
// we will watch this for state changes and print out if we're being grabbed or released when it changes.
update: function() {
var GRAB_USER_DATA_KEY = "grabKey";
setRightHand: function () {
print("I am being held in a right hand... entity:" + this.entityID);
},
setLeftHand: function () {
print("I am being held in a left hand... entity:" + this.entityID);
},
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
var entityID = _this.entityID;
startDistantGrab: function () {
print("I am being distance held... entity:" + this.entityID);
},
continueDistantGrab: function () {
print("I continue to be distance held... entity:" + this.entityID);
},
// we want to assume that if there is no grab data, then we are not being grabbed
var defaultGrabData = { activated: false, avatarId: null };
startNearGrab: function () {
print("I was just grabbed... entity:" + this.entityID);
},
continueNearGrab: function () {
print("I am still being grabbed... entity:" + this.entityID);
},
// this handy function getEntityCustomData() is available in utils.js and it will return just the specific section
// of user data we asked for. If it's not available it returns our default data.
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData);
// if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface
if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) {
// remember we're being grabbed so we can detect being released
_this.beingGrabbed = true;
// print out that we're being grabbed
print("I'm being grabbed...");
} else if (_this.beingGrabbed) {
// if we are not being grabbed, and we previously were, then we were just released, remember that
// and print out a message
_this.beingGrabbed = false;
print("I'm was released...");
}
release: function () {
print("I was released... entity:" + this.entityID);
},
// preload() will be called when the entity has become visible (or known) to the interface
@ -65,14 +54,6 @@
// * connecting to the update signal so we can check our grabbed state
preload: function(entityID) {
this.entityID = entityID;
Script.update.connect(this.update);
},
// unload() will be called when our entity is no longer available. It may be because we were deleted,
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
// to the update signal
unload: function(entityID) {
Script.update.disconnect(this.update);
},
};

View file

@ -6,11 +6,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
vec3toStr = function (v, digits) {
vec3toStr = function(v, digits) {
if (!digits) { digits = 3; }
return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }";
}
vec3equal = function(v0, v1) {
return (v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z);
}
colorMix = function(colorA, colorB, mix) {
var result = {};
@ -60,7 +63,7 @@ setEntityUserData = function(id, data) {
// FIXME do non-destructive modification of the existing user data
getEntityUserData = function(id) {
var results = null;
var properties = Entities.getEntityProperties(id);
var properties = Entities.getEntityProperties(id, "userData");
if (properties.userData) {
try {
results = JSON.parse(properties.userData);

View file

@ -1063,7 +1063,7 @@ void Application::paintGL() {
auto lodManager = DependencyManager::get<LODManager>();
RenderArgs renderArgs(_gpuContext, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(),
RenderArgs renderArgs(_gpuContext, getEntities(), getViewFrustum(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
@ -3562,7 +3562,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
(RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP);
}
renderArgs->_debugFlags = renderDebugFlags;
_entities.render(renderArgs);
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges);
}
}
@ -3648,14 +3647,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems);
}
if (!selfAvatarOnly) {
// give external parties a change to hook in
{
PerformanceTimer perfTimer("inWorldInterface");
emit renderingInWorldInterface();
}
}
activeRenderingThread = nullptr;
}

View file

@ -347,9 +347,6 @@ signals:
/// Fired when we're simulating; allows external parties to hook in.
void simulating(float deltaTime);
/// Fired when we're rendering in-world interface elements; allows external parties to hook in.
void renderingInWorldInterface();
/// Fired when the import window is closed
void importDone();

View file

@ -22,8 +22,10 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
connect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
_downloading = false;
connect(Application::getInstance(), &Application::renderingInWorldInterface,
this, &GlobalServicesScriptingInterface::checkDownloadInfo);
QTimer* checkDownloadTimer = new QTimer(this);
connect(checkDownloadTimer, &QTimer::timeout, this, &GlobalServicesScriptingInterface::checkDownloadInfo);
const int CHECK_DOWNLOAD_INTERVAL = MSECS_PER_SECOND / 2;
checkDownloadTimer->start(CHECK_DOWNLOAD_INTERVAL);
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged,

View file

@ -153,6 +153,11 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
++constraintItr;
}
} else {
// clear the accumulators before we start the IK solver
for (auto& accumulatorPair: _accumulators) {
accumulatorPair.second.clear();
}
// compute absolute poses that correspond to relative target poses
AnimPoseVec absolutePoses;
computeAbsolutePoses(absolutePoses);
@ -165,8 +170,8 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
quint64 expiry = usecTimestampNow() + MAX_IK_TIME;
do {
largestError = 0.0f;
int lowestMovedIndex = _relativePoses.size();
for (auto& target: targets) {
int lowestMovedIndex = _relativePoses.size() - 1;
int tipIndex = target.index;
AnimPose targetPose = target.pose;
int rootIndex = target.rootIndex;
@ -226,7 +231,8 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
glm::inverse(absolutePoses[pivotIndex].rot);
}
}
_relativePoses[pivotIndex].rot = newRot;
// store the rotation change in the accumulator
_accumulators[pivotIndex].add(newRot);
}
// this joint has been changed so we check to see if it has the lowest index
if (pivotIndex < lowestMovedIndex) {
@ -243,36 +249,47 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
if (largestError < error) {
largestError = error;
}
if (lowestMovedIndex <= _maxTargetIndex && lowestMovedIndex < tipIndex) {
// only update the absolutePoses that matter: those between lowestMovedIndex and _maxTargetIndex
for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) {
int parentIndex = _skeleton->getParentIndex(i);
if (parentIndex != -1) {
absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i];
}
}
}
// finally set the relative rotation of the tip to agree with absolute target rotation
int parentIndex = _skeleton->getParentIndex(tipIndex);
if (parentIndex != -1) {
// compute tip's new parent-relative rotation
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot;
RotationConstraint* constraint = getConstraint(tipIndex);
if (constraint) {
constraint->apply(newRelativeRotation);
// TODO: ATM the final rotation target just fails but we need to provide
// feedback to the IK system so that it can adjust the bones up the skeleton
// to help this rotation target get met.
}
_relativePoses[tipIndex].rot = newRelativeRotation;
absolutePoses[tipIndex].rot = targetPose.rot;
}
}
++numLoops;
// harvest accumulated rotations and apply the average
for (auto& accumulatorPair: _accumulators) {
RotationAccumulator& accumulator = accumulatorPair.second;
if (accumulator.size() > 0) {
_relativePoses[accumulatorPair.first].rot = accumulator.getAverage();
accumulator.clear();
}
}
// only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex
for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) {
int parentIndex = _skeleton->getParentIndex(i);
if (parentIndex != -1) {
absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i];
}
}
} while (largestError > ACCEPTABLE_RELATIVE_ERROR && numLoops < MAX_IK_LOOPS && usecTimestampNow() < expiry);
// finally set the relative rotation of each tip to agree with absolute target rotation
for (auto& target: targets) {
int tipIndex = target.index;
int parentIndex = _skeleton->getParentIndex(tipIndex);
if (parentIndex != -1) {
AnimPose targetPose = target.pose;
// compute tip's new parent-relative rotation
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot;
RotationConstraint* constraint = getConstraint(tipIndex);
if (constraint) {
constraint->apply(newRelativeRotation);
// TODO: ATM the final rotation target just fails but we need to provide
// feedback to the IK system so that it can adjust the bones up the skeleton
// to help this rotation target get met.
}
_relativePoses[tipIndex].rot = newRelativeRotation;
absolutePoses[tipIndex].rot = targetPose.rot;
}
}
}
return _relativePoses;
}
@ -628,6 +645,7 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
_maxTargetIndex = 0;
_accumulators.clear();
if (skeleton) {
initConstraints();
} else {

View file

@ -12,8 +12,13 @@
#include <string>
#include <map>
#include <vector>
#include "AnimNode.h"
#include "RotationAccumulator.h"
class RotationConstraint;
class AnimInverseKinematics : public AnimNode {
@ -24,7 +29,6 @@ public:
void loadDefaultPoses(const AnimPoseVec& poses);
void loadPoses(const AnimPoseVec& poses);
const AnimPoseVec& getRelativePoses() const { return _relativePoses; }
void computeAbsolutePoses(AnimPoseVec& absolutePoses) const;
void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar);
@ -60,6 +64,7 @@ protected:
};
std::map<int, RotationConstraint*> _constraints;
std::map<int, RotationAccumulator> _accumulators;
std::vector<IKTargetVar> _targetVarVec;
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
AnimPoseVec _relativePoses; // current relative poses

View file

@ -0,0 +1,27 @@
//
// RotationAccumulator.h
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RotationAccumulator.h"
#include <glm/gtx/quaternion.hpp>
void RotationAccumulator::add(glm::quat rotation) {
// make sure both quaternions are on the same hyper-hemisphere before we add them linearly (lerp)
_rotationSum += copysignf(1.0f, glm::dot(_rotationSum, rotation)) * rotation;
++_numRotations;
}
glm::quat RotationAccumulator::getAverage() {
return (_numRotations > 0) ? glm::normalize(_rotationSum) : glm::quat();
}
void RotationAccumulator::clear() {
_rotationSum *= 0.0f;
_numRotations = 0;
}

View file

@ -0,0 +1,32 @@
//
// RotationAccumulator.h
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RotationAccumulator_h
#define hifi_RotationAccumulator_h
#include <glm/gtc/quaternion.hpp>
class RotationAccumulator {
public:
RotationAccumulator() : _rotationSum(0.0f, 0.0f, 0.0f, 0.0f), _numRotations(0) { }
int size() const { return _numRotations; }
void add(glm::quat rotation);
glm::quat getAverage();
void clear();
private:
glm::quat _rotationSum;
int _numRotations;
};
#endif // hifi_RotationAccumulator_h

View file

@ -52,9 +52,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
_lastMouseEventValid(false),
_viewState(viewState),
_scriptingServices(scriptingServices),
_displayElementChildProxies(false),
_displayModelBounds(false),
_displayModelElementProxy(false),
_dontDoPrecisionPicking(false)
{
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
@ -112,6 +110,7 @@ void EntityTreeRenderer::init() {
_scriptingServices->getControllerScriptingInterface());
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
_entitiesScriptEngine->runInThread();
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine);
}
// make sure our "last avatar position" is something other than our current position, so that on our
@ -151,6 +150,7 @@ void EntityTreeRenderer::update() {
}
}
deleteReleasedModels();
}
void EntityTreeRenderer::checkEnterLeaveEntities() {
@ -167,12 +167,41 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
_tree->withReadLock([&] {
std::static_pointer_cast<EntityTree>(_tree)->findEntities(avatarPosition, radius, foundEntities);
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
_bestZone = NULL; // NOTE: Is this what we want?
_bestZoneVolume = std::numeric_limits<float>::max();
// create a list of entities that actually contain the avatar's position
foreach(EntityItemPointer entity, foundEntities) {
if (entity->contains(avatarPosition)) {
entitiesContainingAvatar << entity->getEntityItemID();
// if this entity is a zone, use this time to determine the bestZone
if (entity->getType() == EntityTypes::Zone) {
float entityVolumeEstimate = entity->getVolumeEstimate();
if (entityVolumeEstimate < _bestZoneVolume) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
} else if (entityVolumeEstimate == _bestZoneVolume) {
if (!_bestZone) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
} else {
// in the case of the volume being equal, we will use the
// EntityItemID to deterministically pick one entity over the other
if (entity->getEntityItemID() < _bestZone->getEntityItemID()) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
}
}
}
}
}
}
applyZonePropertiesToScene(_bestZone);
});
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
@ -307,27 +336,6 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
}
}
void EntityTreeRenderer::render(RenderArgs* renderArgs) {
if (_tree && !_shuttingDown) {
renderArgs->_renderer = this;
_tree->withReadLock([&] {
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
_bestZone = NULL; // NOTE: Is this what we want?
_bestZoneVolume = std::numeric_limits<float>::max();
// FIX ME: right now the renderOperation does the following:
// 1) determining the best zone (not really rendering)
// 2) render the debug cell details
// we should clean this up
_tree->recurseTreeWithOperation(renderOperation, renderArgs);
applyZonePropertiesToScene(_bestZone);
});
}
deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup
}
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
const FBXGeometry* result = NULL;
@ -372,121 +380,6 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
return result;
}
void EntityTreeRenderer::renderElementProxy(EntityTreeElementPointer entityTreeElement, RenderArgs* args) {
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
Transform transform;
glm::vec3 elementCenter = entityTreeElement->getAACube().calcCenter();
float elementSize = entityTreeElement->getScale();
auto drawWireCube = [&](glm::vec3 offset, float size, glm::vec4 color) {
transform.setTranslation(elementCenter + offset);
batch.setModelTransform(transform);
deferredLighting->renderWireCube(batch, size, color);
};
drawWireCube(glm::vec3(), elementSize, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
if (_displayElementChildProxies) {
// draw the children
float halfSize = elementSize / 2.0f;
float quarterSize = elementSize / 4.0f;
drawWireCube(glm::vec3(-quarterSize, -quarterSize, -quarterSize), halfSize, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
drawWireCube(glm::vec3(quarterSize, -quarterSize, -quarterSize), halfSize, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
drawWireCube(glm::vec3(-quarterSize, quarterSize, -quarterSize), halfSize, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
drawWireCube(glm::vec3(-quarterSize, -quarterSize, quarterSize), halfSize, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
drawWireCube(glm::vec3(quarterSize, quarterSize, quarterSize), halfSize, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
drawWireCube(glm::vec3(-quarterSize, quarterSize, quarterSize), halfSize, glm::vec4(0.0f, 0.5f, 0.5f, 1.0f));
drawWireCube(glm::vec3(quarterSize, -quarterSize, quarterSize), halfSize, glm::vec4(0.5f, 0.0f, 0.0f, 1.0f));
drawWireCube(glm::vec3(quarterSize, quarterSize, -quarterSize), halfSize, glm::vec4(0.0f, 0.5f, 0.0f, 1.0f));
}
}
void EntityTreeRenderer::renderProxies(EntityItemPointer entity, RenderArgs* args) {
bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE;
if (!isShadowMode && _displayModelBounds) {
PerformanceTimer perfTimer("renderProxies");
AACube maxCube = entity->getMaximumAACube();
AACube minCube = entity->getMinimumAACube();
AABox entityBox = entity->getAABox();
glm::vec3 maxCenter = maxCube.calcCenter();
glm::vec3 minCenter = minCube.calcCenter();
glm::vec3 entityBoxCenter = entityBox.calcCenter();
glm::vec3 entityBoxScale = entityBox.getScale();
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
Transform transform;
// draw the max bounding cube
transform.setTranslation(maxCenter);
batch.setModelTransform(transform);
deferredLighting->renderWireCube(batch, maxCube.getScale(), glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
// draw the min bounding cube
transform.setTranslation(minCenter);
batch.setModelTransform(transform);
deferredLighting->renderWireCube(batch, minCube.getScale(), glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
// draw the entityBox bounding box
transform.setTranslation(entityBoxCenter);
transform.setScale(entityBoxScale);
batch.setModelTransform(transform);
deferredLighting->renderWireCube(batch, 1.0f, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
// Rotated bounding box
batch.setModelTransform(entity->getTransformToCenter());
deferredLighting->renderWireCube(batch, 1.0f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
}
}
void EntityTreeRenderer::renderElement(OctreeElementPointer element, RenderArgs* args) {
// actually render it here...
// we need to iterate the actual entityItems of the element
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE;
if (!isShadowMode && _displayModelElementProxy && entityTreeElement->size() > 0) {
renderElementProxy(entityTreeElement, args);
}
entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) {
if (entityItem->isVisible()) {
// NOTE: Zone Entities are a special case we handle here...
if (entityItem->getType() == EntityTypes::Zone) {
if (entityItem->contains(_viewState->getAvatarPosition())) {
float entityVolumeEstimate = entityItem->getVolumeEstimate();
if (entityVolumeEstimate < _bestZoneVolume) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entityItem);
} else if (entityVolumeEstimate == _bestZoneVolume) {
if (!_bestZone) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entityItem);
} else {
// in the case of the volume being equal, we will use the
// EntityItemID to deterministically pick one entity over the other
if (entityItem->getEntityItemID() < _bestZone->getEntityItemID()) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entityItem);
}
}
}
}
}
}
});
}
float EntityTreeRenderer::getSizeScale() const {
return _viewState->getSizeScale();
}

View file

@ -40,7 +40,6 @@ public:
virtual char getMyNodeType() const { return NodeType::EntityServer; }
virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; }
virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; }
virtual void renderElement(OctreeElementPointer element, RenderArgs* args);
virtual float getSizeScale() const;
virtual int getBoundaryLevelAdjust() const;
virtual void setTree(OctreePointer newTree);
@ -53,7 +52,6 @@ public:
void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode);
virtual void init();
virtual void render(RenderArgs* renderArgs) override;
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem);
virtual const Model* getModelForEntityItem(EntityItemPointer entityItem);
@ -114,9 +112,7 @@ public slots:
void updateEntityRenderStatus(bool shouldRenderEntities);
// optional slots that can be wired to menu items
void setDisplayElementChildProxies(bool value) { _displayElementChildProxies = value; }
void setDisplayModelBounds(bool value) { _displayModelBounds = value; }
void setDisplayModelElementProxy(bool value) { _displayModelElementProxy = value; }
void setDontDoPrecisionPicking(bool value) { _dontDoPrecisionPicking = value; }
protected:
@ -130,11 +126,9 @@ private:
void addEntityToScene(EntityItemPointer entity);
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
void renderElementProxy(EntityTreeElementPointer entityTreeElement, RenderArgs* args);
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
QList<Model*> _releasedModels;
void renderProxies(EntityItemPointer entity, RenderArgs* args);
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
bool precisionPicking);
@ -157,9 +151,7 @@ private:
MouseEvent _lastMouseEvent;
AbstractViewStateInterface* _viewState;
AbstractScriptingServicesInterface* _scriptingServices;
bool _displayElementChildProxies;
bool _displayModelBounds;
bool _displayModelElementProxy;
bool _dontDoPrecisionPicking;
bool _shuttingDown = false;

View file

@ -358,8 +358,8 @@ bool RenderableModelEntityItem::needsToCallUpdate() const {
return _needsInitialSimulation || ModelEntityItem::needsToCallUpdate();
}
EntityItemProperties RenderableModelEntityItem::getProperties() const {
EntityItemProperties properties = ModelEntityItem::getProperties(); // get the properties from our base class
EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties); // get the properties from our base class
if (_originalTexturesRead) {
properties.setTextureNames(_originalTextures);
}

View file

@ -35,7 +35,7 @@ public:
virtual ~RenderableModelEntityItem();
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,

View file

@ -32,14 +32,14 @@ AtmospherePropertyGroup::AtmospherePropertyGroup() {
_hasStars = true;
}
void AtmospherePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, Center, center);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, InnerRadius, innerRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, OuterRadius, outerRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, MieScattering, mieScattering);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, RayleighScattering, rayleighScattering);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, HasStars, hasStars);
void AtmospherePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_CENTER, Atmosphere, atmosphere, Center, center);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_INNER_RADIUS, Atmosphere, atmosphere, InnerRadius, innerRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_OUTER_RADIUS, Atmosphere, atmosphere, OuterRadius, outerRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_MIE_SCATTERING, Atmosphere, atmosphere, MieScattering, mieScattering);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, Atmosphere, atmosphere, RayleighScattering, rayleighScattering);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ATMOSPHERE_HAS_STARS, Atmosphere, atmosphere, HasStars, hasStars);
}
void AtmospherePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {

View file

@ -53,7 +53,7 @@ public:
virtual ~AtmospherePropertyGroup() {}
// EntityItemProperty related helpers
virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;

View file

@ -32,8 +32,8 @@ BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemP
setProperties(properties);
}
EntityItemProperties BoxEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
properties._color = getXColor();
properties._colorChanged = false;

View file

@ -23,7 +23,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -0,0 +1,25 @@
//
// EntitiesScriptEngineProvider.h
// libraries/entities/src
//
// Created by Brad Hefta-Gaub on Sept. 18, 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// TODO: How will we handle collision callbacks with Entities
//
#ifndef hifi_EntitiesScriptEngineProvider_h
#define hifi_EntitiesScriptEngineProvider_h
#include <QtCore/QString>
#include "EntityItemID.h"
class EntitiesScriptEngineProvider {
public:
virtual void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName) = 0;
};
#endif // hifi_EntitiesScriptEngineProvider_h

View file

@ -1019,8 +1019,10 @@ quint64 EntityItem::getExpiry() const {
return _created + (quint64)(_lifetime * (float)USECS_PER_SECOND);
}
EntityItemProperties EntityItem::getProperties() const {
EntityItemProperties properties;
EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EncodeBitstreamParams params; // unknown
EntityPropertyFlags propertyFlags = desiredProperties.isEmpty() ? getEntityProperties(params) : desiredProperties;
EntityItemProperties properties(propertyFlags);
properties._id = getID();
properties._idSet = true;
properties._created = _created;

View file

@ -131,7 +131,7 @@ public:
EntityItemID getEntityItemID() const { return EntityItemID(_id); }
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties);

View file

@ -36,7 +36,7 @@ StagePropertyGroup EntityItemProperties::_staticStage;
EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1);
EntityItemProperties::EntityItemProperties() :
EntityItemProperties::EntityItemProperties(EntityPropertyFlags desiredProperties) :
CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE),
CONSTRUCT_PROPERTY(position, 0.0f),
@ -147,7 +147,8 @@ _localRenderAlphaChanged(false),
_defaultSettings(true),
_naturalDimensions(1.0f, 1.0f, 1.0f),
_naturalPosition(0.0f, 0.0f, 0.0f)
_naturalPosition(0.0f, 0.0f, 0.0f),
_desiredProperties(desiredProperties)
{
}
@ -437,112 +438,164 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
EntityItemProperties defaultEntityProperties;
if (_idSet) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(id, _id.toString());
}
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
COPY_PROPERTY_TO_QSCRIPTVALUE(position);
COPY_PROPERTY_TO_QSCRIPTVALUE(dimensions);
if (!skipDefaults) {
COPY_PROPERTY_TO_QSCRIPTVALUE(naturalDimensions); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE(naturalPosition);
}
COPY_PROPERTY_TO_QSCRIPTVALUE(rotation);
COPY_PROPERTY_TO_QSCRIPTVALUE(velocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(gravity);
COPY_PROPERTY_TO_QSCRIPTVALUE(acceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(damping);
COPY_PROPERTY_TO_QSCRIPTVALUE(restitution);
COPY_PROPERTY_TO_QSCRIPTVALUE(friction);
COPY_PROPERTY_TO_QSCRIPTVALUE(density);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type));
auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec
created.setTimeSpec(Qt::OffsetFromUTC);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(created, created.toString(Qt::ISODate));
if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
}
auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec
created.setTimeSpec(Qt::OffsetFromUTC);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created.toString(Qt::ISODate));
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, position);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, dimensions);
if (!skipDefaults) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, naturalDimensions); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, naturalPosition);
}
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ROTATION, rotation);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY, velocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAVITY, gravity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION, acceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DAMPING, damping);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RESTITUTION, restitution);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FRICTION, friction);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFETIME, lifetime);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT, script);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_REGISTRATION_POINT, registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
COPY_PROPERTY_TO_QSCRIPTVALUE(scriptTimestamp);
COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
COPY_PROPERTY_TO_QSCRIPTVALUE(color);
COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(alpha);
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(animationSettings, getAnimationSettings());
COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions);
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove);
COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight);
COPY_PROPERTY_TO_QSCRIPTVALUE(intensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(exponent);
COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff);
COPY_PROPERTY_TO_QSCRIPTVALUE(locked);
COPY_PROPERTY_TO_QSCRIPTVALUE(textures);
COPY_PROPERTY_TO_QSCRIPTVALUE(userData);
//COPY_PROPERTY_TO_QSCRIPTVALUE(simulationOwner); // TODO: expose this for JSON saves?
COPY_PROPERTY_TO_QSCRIPTVALUE(text);
COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textColor, getTextColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundColor, getBackgroundColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(maxParticles);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifespan);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitRate);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitSpeed);
COPY_PROPERTY_TO_QSCRIPTVALUE(speedSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitOrientation);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitDimensions);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitRadiusStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(polarStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(polarFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(azimuthStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(azimuthFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
// Boxes, Spheres, Light, Line, Model(??), Particle, PolyLine
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightColor);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
COPY_PROPERTY_TO_QSCRIPTVALUE(lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(linePoints);
COPY_PROPERTY_TO_QSCRIPTVALUE(href);
COPY_PROPERTY_TO_QSCRIPTVALUE(description);
COPY_PROPERTY_TO_QSCRIPTVALUE(faceCamera);
COPY_PROPERTY_TO_QSCRIPTVALUE(actionData);
COPY_PROPERTY_TO_QSCRIPTVALUE(normals);
COPY_PROPERTY_TO_QSCRIPTVALUE(strokeWidths);
// Particles only
if (_type == EntityTypes::ParticleEffect) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_PARTICLES, maxParticles);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFESPAN, lifespan);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RATE, emitRate);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_SPEED, emitSpeed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPEED_SPREAD, speedSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ORIENTATION, emitOrientation);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_DIMENSIONS, emitDimensions);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RADIUS_START, emitRadiusStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POLAR_START, polarStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POLAR_FINISH, polarFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AZIMUTH_START, azimuthStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AZIMUTH_FINISH, azimuthFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ACCELERATION, emitAcceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION_SPREAD, accelerationSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_RADIUS, particleRadius);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_SPREAD, radiusSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_START, radiusStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_FINISH, radiusFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_SPREAD, colorSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_START, colorStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_FINISH, colorFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish);
}
// Models only
if (_type == EntityTypes::Model) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, animationURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures);
}
if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString());
}
// Models & Particles
if (_type == EntityTypes::Model || _type == EntityTypes::ParticleEffect) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, animationIsPlaying);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, animationFPS);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_SETTINGS, animationSettings, getAnimationSettings());
}
// Lights only
if (_type == EntityTypes::Light) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff);
}
// Text only
if (_type == EntityTypes::Text) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_COLOR, textColor, getTextColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_COLOR, backgroundColor, getBackgroundColor());
}
// Zones only
if (_type == EntityTypes::Zone) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_COLOR, keyLightColor);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BACKGROUND_MODE, backgroundMode, getBackgroundModeAsString());
_stage.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
_atmosphere.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
_skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
}
// Web only
if (_type == EntityTypes::Web) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl);
}
// PolyVoxel only
if (_type == EntityTypes::PolyVox) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_DATA, voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_TEXTURE_URL, xTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_TEXTURE_URL, yTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_TEXTURE_URL, zTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_N_NEIGHBOR_ID, xNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_P_NEIGHBOR_ID, xPNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID);
}
// Lines & PolyLines
if (_type == EntityTypes::Line || _type == EntityTypes::PolyLine) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths);
}
// Sitting properties support
if (!skipDefaults) {
@ -555,7 +608,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
sittingPoints.setProperty(i, sittingPoint);
}
sittingPoints.setProperty("length", _sittingPoints.size());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(sittingPoints, sittingPoints); // gettable, but not settable
}
if (!skipDefaults) {
@ -577,21 +630,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable
}
_stage.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
_atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
_skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE(xTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(zTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(xNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(yNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(zNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(xPNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(yPNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(zPNeighborID);
// FIXME - I don't think these properties are supported any more
//COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
//COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
return properties;
}
@ -737,6 +778,162 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object
}
QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) {
return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags);
QScriptValue result = engine->newObject();
return result;
}
void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) {
EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags);
}
QScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) {
QScriptValue result = engine->newObject();
return result;
}
static QHash<QString, EntityPropertyList> _propertyStringsToEnums;
void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) {
static std::once_flag initMap;
std::call_once(initMap, [](){
ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool);
ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_ROTATION, Rotation, rotation, glm::quat);
ADD_PROPERTY_TO_MAP(PROP_DENSITY, Density, density, float);
ADD_PROPERTY_TO_MAP(PROP_VELOCITY, Velocity, velocity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_GRAVITY, Gravity, gravity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_ACCELERATION, Acceleration, acceleration, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_DAMPING, Damping, damping, float);
ADD_PROPERTY_TO_MAP(PROP_RESTITUTION, Restitution, restitution, float);
ADD_PROPERTY_TO_MAP(PROP_FRICTION, Friction, friction, float);
ADD_PROPERTY_TO_MAP(PROP_LIFETIME, Lifetime, lifetime, float);
ADD_PROPERTY_TO_MAP(PROP_SCRIPT, Script, script, QString);
ADD_PROPERTY_TO_MAP(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64);
ADD_PROPERTY_TO_MAP(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
ADD_PROPERTY_TO_MAP(PROP_COLOR, Color, color, xColor);
ADD_PROPERTY_TO_MAP(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor);
ADD_PROPERTY_TO_MAP(PROP_COLOR_START, ColorStart, colorStart, xColor);
ADD_PROPERTY_TO_MAP(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor);
ADD_PROPERTY_TO_MAP(PROP_ALPHA, Alpha, alpha, float);
ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float);
ADD_PROPERTY_TO_MAP(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float);
ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString);
ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
ADD_PROPERTY_TO_MAP(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
ADD_PROPERTY_TO_MAP(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float);
ADD_PROPERTY_TO_MAP(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float);
ADD_PROPERTY_TO_MAP(PROP_ANIMATION_PLAYING, AnimationIsPlaying, animationIsPlaying, bool);
ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float);
ADD_PROPERTY_TO_MAP(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool);
ADD_PROPERTY_TO_MAP(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool);
ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool);
ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float);
ADD_PROPERTY_TO_MAP(PROP_EXPONENT, Exponent, exponent, float);
ADD_PROPERTY_TO_MAP(PROP_CUTOFF, Cutoff, cutoff, float);
ADD_PROPERTY_TO_MAP(PROP_LOCKED, Locked, locked, bool);
ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString);
ADD_PROPERTY_TO_MAP(PROP_ANIMATION_SETTINGS, AnimationSettings, animationSettings, QString);
ADD_PROPERTY_TO_MAP(PROP_USER_DATA, UserData, userData, QString);
ADD_PROPERTY_TO_MAP(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner);
ADD_PROPERTY_TO_MAP(PROP_TEXT, Text, text, QString);
ADD_PROPERTY_TO_MAP(PROP_LINE_HEIGHT, LineHeight, lineHeight, float);
ADD_PROPERTY_TO_MAP(PROP_TEXT_COLOR, TextColor, textColor, xColor);
ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor);
ADD_PROPERTY_TO_MAP(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType);
ADD_PROPERTY_TO_MAP(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32);
ADD_PROPERTY_TO_MAP(PROP_LIFESPAN, Lifespan, lifespan, float);
ADD_PROPERTY_TO_MAP(PROP_EMIT_RATE, EmitRate, emitRate, float);
ADD_PROPERTY_TO_MAP(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_SPEED_SPREAD, SpeedSpread, speedSpread, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_EMIT_ORIENTATION, EmitOrientation, emitOrientation, glm::quat);
ADD_PROPERTY_TO_MAP(PROP_EMIT_DIMENSIONS, EmitDimensions, emitDimensions, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_EMIT_RADIUS_START, EmitRadiusStart, emitRadiusStart, float);
ADD_PROPERTY_TO_MAP(PROP_POLAR_START, EmitPolarStart, polarStart, float);
ADD_PROPERTY_TO_MAP(PROP_POLAR_FINISH, EmitPolarFinish, polarFinish, float);
ADD_PROPERTY_TO_MAP(PROP_AZIMUTH_START, EmitAzimuthStart, azimuthStart, float);
ADD_PROPERTY_TO_MAP(PROP_AZIMUTH_FINISH, EmitAzimuthFinish, azimuthFinish, float);
ADD_PROPERTY_TO_MAP(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray);
ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t);
ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString);
ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_MODE, BackgroundMode, backgroundMode, BackgroundMode);
ADD_PROPERTY_TO_MAP(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString);
ADD_PROPERTY_TO_MAP(PROP_LINE_WIDTH, LineWidth, lineWidth, float);
ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector<glm::vec3>);
ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString);
ADD_PROPERTY_TO_MAP(PROP_DESCRIPTION, Description, description, QString);
ADD_PROPERTY_TO_MAP(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool);
ADD_PROPERTY_TO_MAP(PROP_ACTION_DATA, ActionData, actionData, QByteArray);
ADD_PROPERTY_TO_MAP(PROP_NORMALS, Normals, normals, QVector<glm::vec3>);
ADD_PROPERTY_TO_MAP(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>);
ADD_PROPERTY_TO_MAP(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
ADD_PROPERTY_TO_MAP(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString);
ADD_PROPERTY_TO_MAP(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString);
ADD_PROPERTY_TO_MAP(PROP_X_N_NEIGHBOR_ID, XNNeighborID, xNNeighborID, EntityItemID);
ADD_PROPERTY_TO_MAP(PROP_Y_N_NEIGHBOR_ID, YNNeighborID, yNNeighborID, EntityItemID);
ADD_PROPERTY_TO_MAP(PROP_Z_N_NEIGHBOR_ID, ZNNeighborID, zNNeighborID, EntityItemID);
ADD_PROPERTY_TO_MAP(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID);
ADD_PROPERTY_TO_MAP(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID);
ADD_PROPERTY_TO_MAP(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID);
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color);
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_CENTER, Atmosphere, atmosphere, Center, center);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_INNER_RADIUS, Atmosphere, atmosphere, InnerRadius, innerRadius);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_OUTER_RADIUS, Atmosphere, atmosphere, OuterRadius, outerRadius);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_MIE_SCATTERING, Atmosphere, atmosphere, MieScattering, mieScattering);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, Atmosphere, atmosphere, RayleighScattering, rayleighScattering);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_HAS_STARS, Atmosphere, atmosphere, HasStars, hasStars);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_SUN_MODEL_ENABLED, Stage, stage, SunModelEnabled, sunModelEnabled);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_LATITUDE, Stage, stage, Latitude, latitude);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_LONGITUDE, Stage, stage, Longitude, longitude);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_ALTITUDE, Stage, stage, Altitude, altitude);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_DAY, Stage, stage, Day, day);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_HOUR, Stage, stage, Hour, hour);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_AUTOMATIC_HOURDAY, Stage, stage, AutomaticHourDay, automaticHourDay);
// FIXME - these are not yet handled
//ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64);
});
if (object.isString()) {
if (_propertyStringsToEnums.contains(object.toString())) {
flags << _propertyStringsToEnums[object.toString()];
}
} else if (object.isArray()) {
quint32 length = object.property("length").toInt32();
for (quint32 i = 0; i < length; i++) {
QString propertyName = object.property(i).toString();
if (_propertyStringsToEnums.contains(propertyName)) {
flags << _propertyStringsToEnums[propertyName];
}
}
}
}
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the
// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar
// to how we handle this in the Octree streaming case.

View file

@ -58,7 +58,7 @@ class EntityItemProperties {
friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class PolyLineEntityItem; // TODO: consider removing this friend relationship and use public methods
public:
EntityItemProperties();
EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags());
virtual ~EntityItemProperties();
EntityTypes::EntityType getType() const { return _type; }
@ -67,6 +67,9 @@ public:
virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly);
static QScriptValue entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags);
static void entityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags);
// editing related features supported by all entities
quint64 getLastEdited() const { return _lastEdited; }
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
@ -266,13 +269,19 @@ private:
QStringList _textureNames;
glm::vec3 _naturalDimensions;
glm::vec3 _naturalPosition;
EntityPropertyFlags _desiredProperties; // if set will narrow scopes of copy/to/from to just these properties
};
Q_DECLARE_METATYPE(EntityItemProperties);
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue& object, EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue& object, EntityItemProperties& properties);
Q_DECLARE_METATYPE(EntityPropertyFlags);
QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags);
void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags);
// define these inline here so the macros work

View file

@ -119,8 +119,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); }
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \
if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \
(!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
QScriptValue groupProperties = properties.property(#g); \
if (!groupProperties.isValid()) { \
groupProperties = engine->newObject(); \
@ -130,8 +131,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v)
properties.setProperty(#g, groupProperties); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
#define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \
if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
(!skipDefaults || defaultEntityProperties._##P != _##P)) { \
QScriptValue V = convertScriptValue(engine, _##P); \
properties.setProperty(#P, V); \
}
@ -139,12 +141,19 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v)
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \
properties.setProperty(#P, G);
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \
if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
(!skipDefaults || defaultEntityProperties._##P != _##P)) { \
QScriptValue V = convertScriptValue(engine, G); \
properties.setProperty(#P, V); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
QScriptValue V = convertScriptValue(engine, G); \
properties.setProperty(#P, V); \
}
typedef glm::vec3 glmVec3;
typedef glm::quat glmQuat;
typedef QVector<glm::vec3> qVectorVec3;
@ -304,6 +313,12 @@ inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid
T _##n; \
static T _static##N;
#define ADD_PROPERTY_TO_MAP(P, N, n, T) \
_propertyStringsToEnums[#n] = P;
#define ADD_GROUP_PROPERTY_TO_MAP(P, G, g, N, n) \
_propertyStringsToEnums[#g "." #n] = P;
#define DEFINE_PROPERTY(P, N, n, T) \
public: \
T get##N() const { return _##n; } \

View file

@ -12,33 +12,8 @@
#ifndef hifi_EntityPropertyFlags_h
#define hifi_EntityPropertyFlags_h
/*
#include <stdint.h>
#include <glm/glm.hpp>
#include <glm/gtx/extented_min_max.hpp>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>
#include <QVector>
#include <QString>
#include <AACube.h>
#include <FBXReader.h> // for SittingPoint
*/
#include <PropertyFlags.h>
/*
#include <OctreeConstants.h>
#include <ShapeInfo.h>
#include "AtmospherePropertyGroup.h"
#include "EntityItemID.h"
#include "EntityItemPropertiesMacros.h"
#include "EntityTypes.h"
*/
enum EntityPropertyList {
PROP_PAGED_PROPERTY,
PROP_CUSTOM_PROPERTIES_INCLUDED,
@ -197,6 +172,7 @@ enum EntityPropertyList {
PROP_STAGE_ALTITUDE = PROP_SPECULAR_COLOR_UNUSED,
PROP_STAGE_DAY = PROP_LINEAR_ATTENUATION_UNUSED,
PROP_STAGE_HOUR = PROP_QUADRATIC_ATTENUATION_UNUSED,
PROP_STAGE_AUTOMATIC_HOURDAY = PROP_ANIMATION_FRAME_INDEX,
PROP_ATMOSPHERE_CENTER = PROP_MAX_PARTICLES,
PROP_ATMOSPHERE_INNER_RADIUS = PROP_LIFESPAN,
PROP_ATMOSPHERE_OUTER_RADIUS = PROP_EMIT_RATE,
@ -207,7 +183,6 @@ enum EntityPropertyList {
PROP_BACKGROUND_MODE = PROP_MODEL_URL,
PROP_SKYBOX_COLOR = PROP_ANIMATION_URL,
PROP_SKYBOX_URL = PROP_ANIMATION_FPS,
PROP_STAGE_AUTOMATIC_HOURDAY = PROP_ANIMATION_FRAME_INDEX,
// Aliases/Piggyback properties for Web. These properties intentionally reuse the enum values for
// other properties which will never overlap with each other.

View file

@ -11,6 +11,7 @@
#include "EntityScriptingInterface.h"
#include "EntityItemID.h"
#include <VariantMapToScriptValue.h>
#include "EntitiesLogging.h"
@ -100,12 +101,17 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
}
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {
EntityPropertyFlags noSpecificProperties;
return getEntityProperties(identity, noSpecificProperties);
}
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {
EntityItemProperties results;
if (_entityTree) {
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));
if (entity) {
results = entity->getProperties();
results = entity->getProperties(desiredProperties);
// 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
@ -211,6 +217,14 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
}
}
void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method) {
if (_entitiesScriptEngine) {
EntityItemID entityID{ id };
_entitiesScriptEngine->callEntityScriptMethod(entityID, method);
}
}
QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
EntityItemID result;
if (_entityTree) {

View file

@ -20,18 +20,19 @@
#include <Octree.h>
#include <OctreeScriptingInterface.h>
#include <RegisteredMetaTypes.h>
#include "PolyVoxEntityItem.h"
#include "LineEntityItem.h"
#include "PolyLineEntityItem.h"
#include "EntityTree.h"
#include "EntityEditPacketSender.h"
#include "EntitiesScriptEngineProvider.h"
class EntityTree;
class MouseEvent;
class RayToEntityIntersectionResult {
public:
RayToEntityIntersectionResult();
@ -63,6 +64,7 @@ public:
void setEntityTree(EntityTreePointer modelTree);
EntityTreePointer getEntityTree() { return _entityTree; }
void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine) { _entitiesScriptEngine = engine; }
public slots:
@ -78,6 +80,7 @@ public slots:
/// gets the current model properties for a specific model
/// this function will not find return results in script engine contexts which don't have access to models
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID);
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties);
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
/// successful edit, if the input entityID is for an unknown model this function will have no effect
@ -86,6 +89,11 @@ public slots:
/// deletes a model
Q_INVOKABLE void deleteEntity(QUuid entityID);
/// Allows a script to call a method on an entity's script. The method will execute in the entity script
/// engine. If the entity does not have an entity script or the method does not exist, this call will have
/// no effect.
Q_INVOKABLE void callEntityMethod(QUuid entityID, const QString& method);
/// finds the closest model to the center point, within the radius
/// will return a EntityItemID.isKnownID = false if no models are in the radius
/// this function will not find any models in script engine contexts which don't have access to models
@ -180,6 +188,7 @@ private:
bool precisionPicking);
EntityTreePointer _entityTree;
EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr;
};
#endif // hifi_EntityScriptingInterface_h

View file

@ -56,8 +56,8 @@ void LightEntityItem::setDimensions(const glm::vec3& value) {
}
EntityItemProperties LightEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);

View file

@ -26,7 +26,7 @@ public:
virtual void setDimensions(const glm::vec3& value);
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;

View file

@ -43,9 +43,9 @@ LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityIte
}
EntityItemProperties LineEntityItem::getProperties() const {
EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
properties._color = getXColor();

View file

@ -22,8 +22,8 @@ class LineEntityItem : public EntityItem {
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -43,8 +43,8 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI
_color[0] = _color[1] = _color[2] = 0;
}
EntityItemProperties ModelEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);

View file

@ -25,7 +25,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -163,8 +163,8 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() {
}
EntityItemProperties ParticleEffectEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);

View file

@ -25,7 +25,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of this entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;

View file

@ -45,9 +45,9 @@ _strokeWidths(QVector<float>(0.0f))
setProperties(properties);
}
EntityItemProperties PolyLineEntityItem::getProperties() const {
EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
QWriteLocker lock(&_quadReadWriteLock);
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
properties._color = getXColor();

View file

@ -23,7 +23,7 @@ class PolyLineEntityItem : public EntityItem {
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -104,8 +104,8 @@ const glm::vec3& PolyVoxEntityItem::getVoxelVolumeSize() const {
}
EntityItemProperties PolyVoxEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties PolyVoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle);

View file

@ -23,7 +23,7 @@ class PolyVoxEntityItem : public EntityItem {
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -55,7 +55,7 @@ public:
virtual ~PropertyGroup() {}
// EntityItemProperty related helpers
virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0;
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) = 0;
virtual void debugDump() const { }

View file

@ -20,9 +20,9 @@ SkyboxPropertyGroup::SkyboxPropertyGroup() {
_url = QString();
}
void SkyboxPropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, Color, color);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, URL, url);
void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_SKYBOX_URL, Skybox, skybox, URL, url);
}
void SkyboxPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {

View file

@ -33,7 +33,7 @@ public:
virtual ~SkyboxPropertyGroup() {}
// EntityItemProperty related helpers
virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;

View file

@ -37,8 +37,8 @@ SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const Entit
_volumeMultiplier *= PI / 6.0f;
}
EntityItemProperties SphereEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties SphereEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
properties.setColor(getXColor());
return properties;
}

View file

@ -23,7 +23,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;

View file

@ -36,14 +36,14 @@ StagePropertyGroup::StagePropertyGroup() {
_automaticHourDay = false;
}
void StagePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, SunModelEnabled, sunModelEnabled);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Latitude, latitude);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Longitude, longitude);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Altitude, altitude);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Day, day);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, Hour, hour);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Stage, stage, AutomaticHourDay, automaticHourDay);
void StagePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_SUN_MODEL_ENABLED, Stage, stage, SunModelEnabled, sunModelEnabled);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_LATITUDE, Stage, stage, Latitude, latitude);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_LONGITUDE, Stage, stage, Longitude, longitude);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_ALTITUDE, Stage, stage, Altitude, altitude);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_DAY, Stage, stage, Day, day);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_HOUR, Stage, stage, Hour, hour);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_STAGE_AUTOMATIC_HOURDAY, Stage, stage, AutomaticHourDay, automaticHourDay);
}
void StagePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {

View file

@ -33,7 +33,7 @@ public:
virtual ~StagePropertyGroup() {}
// EntityItemProperty related helpers
virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;

View file

@ -47,8 +47,8 @@ void TextEntityItem::setDimensions(const glm::vec3& value) {
EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH));
}
EntityItemProperties TextEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties TextEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight);

View file

@ -27,7 +27,7 @@ public:
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -40,8 +40,8 @@ void WebEntityItem::setDimensions(const glm::vec3& value) {
EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH));
}
EntityItemProperties WebEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties WebEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl);
return properties;
}

View file

@ -26,7 +26,7 @@ public:
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -73,8 +73,8 @@ EnvironmentData ZoneEntityItem::getEnvironmentData() const {
return result;
}
EntityItemProperties ZoneEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightColor, getKeyLightColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightIntensity, getKeyLightIntensity);

View file

@ -27,7 +27,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time

View file

@ -42,7 +42,7 @@ const unsigned int GRIP_BUTTON = 1U << 2;
const unsigned int TRACKPAD_BUTTON = 1U << 3;
const unsigned int TRIGGER_BUTTON = 1U << 4;
const float CONTROLLER_LENGTH_OFFSET = 0.175f;
const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
const QString ViveControllerManager::NAME = "OpenVR";

View file

@ -38,7 +38,7 @@ public:
virtual char getMyNodeType() const = 0;
virtual PacketType getMyQueryMessageType() const = 0;
virtual PacketType getExpectedPacketType() const = 0;
virtual void renderElement(OctreeElementPointer element, RenderArgs* args) = 0;
virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { }
virtual float getSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; }
virtual int getBoundaryLevelAdjust() const { return 0; }

View file

@ -280,6 +280,7 @@ void ScriptEngine::init() {
_controllerScriptingInterface->registerControllerTypes(this);
}
qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue);
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);

View file

@ -25,6 +25,7 @@
#include <AvatarHashMap.h>
#include <LimitedNodeList.h>
#include <EntityItemID.h>
#include <EntitiesScriptEngineProvider.h>
#include "AbstractControllerScriptingInterface.h"
#include "ArrayBufferClass.h"
@ -46,7 +47,7 @@ public:
QScriptValue scriptObject;
};
class ScriptEngine : public QScriptEngine, public ScriptUser {
class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider {
Q_OBJECT
public:
ScriptEngine(const QString& scriptContents = NO_SCRIPT,

View file

@ -45,6 +45,7 @@ public:
_maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false), _encodedLength(0) { decode(fromEncoded); }
void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped = false; _encodedLength = 0; }
bool isEmpty() const { return _maxFlag == INT_MIN && _minFlag == INT_MAX && _trailingFlipped == false && _encodedLength == 0; }
Enum firstFlag() const { return (Enum)_minFlag; }
Enum lastFlag() const { return (Enum)_maxFlag; }