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

This commit is contained in:
samcake 2015-09-19 09:00:19 -07:00
commit c9cb768945
75 changed files with 1917 additions and 1414 deletions

View file

@ -18,7 +18,7 @@ Script.include("../libraries/utils.js");
// these tune time-averaging and "on" value for analog trigger
//
var TRIGGER_SMOOTH_RATIO = 0.7;
var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value
var TRIGGER_ON_VALUE = 0.2;
/////////////////////////////////////////////////////////////////
@ -26,7 +26,7 @@ var TRIGGER_ON_VALUE = 0.2;
// distant manipulation
//
var DISTANCE_HOLDING_RADIUS_FACTOR = 4; // multiplied by distance between hand and object
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
@ -37,14 +37,14 @@ var LINE_LENGTH = 500;
/////////////////////////////////////////////////////////////////
//
// close grabbing
// near grabbing
//
var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected
var CLOSE_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
var CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO = 0.9; // adjust time-averaging of held object's velocity
var CLOSE_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to 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
/////////////////////////////////////////////////////////////////
//
@ -65,10 +65,12 @@ var LIFETIME = 10;
// states for the state machine
var STATE_SEARCHING = 0;
var STATE_DISTANCE_HOLDING = 1;
var STATE_CLOSE_GRABBING = 2;
var STATE_CONTINUE_CLOSE_GRABBING = 3;
var STATE_RELEASE = 4;
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";
function controller(hand, triggerAction) {
this.hand = hand;
@ -86,7 +88,7 @@ function controller(hand, triggerAction) {
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; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing
this.state = 0;
this.pointer = null; // entity-id of line object
this.triggerValue = 0; // rolling average of trigger value
@ -98,11 +100,14 @@ function controller(hand, triggerAction) {
case STATE_DISTANCE_HOLDING:
this.distanceHolding();
break;
case STATE_CLOSE_GRABBING:
this.closeGrabbing();
case STATE_CONTINUE_DISTANCE_HOLDING:
this.continueDistanceHolding();
break;
case STATE_CONTINUE_CLOSE_GRABBING:
this.continueCloseGrabbing();
case STATE_NEAR_GRABBING:
this.nearGrabbing();
break;
case STATE_CONTINUE_NEAR_GRABBING:
this.continueNearGrabbing();
break;
case STATE_RELEASE:
this.release();
@ -175,9 +180,9 @@ function controller(hand, triggerAction) {
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
this.grabbedEntity = intersection.entityID;
if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) {
if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) {
// the hand is very close to the intersected object. go into close-grabbing mode.
this.state = STATE_CLOSE_GRABBING;
this.state = STATE_NEAR_GRABBING;
} else {
// the hand is far from the intersected object. go into distance-holding mode
this.state = STATE_DISTANCE_HOLDING;
@ -201,13 +206,49 @@ function controller(hand, triggerAction) {
if (this.grabbedEntity === null) {
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
} else {
this.state = STATE_CLOSE_GRABBING;
this.state = STATE_NEAR_GRABBING;
}
}
}
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"]);
// add the action and initialize some variables
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectRotation = grabbedProperties.rotation;
this.currentObjectTime = Date.now();
this.handPreviousPosition = handControllerPosition;
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;
}
if (this.actionID != null) {
this.state = STATE_CONTINUE_DISTANCE_HOLDING;
this.activateEntity(this.grabbedEntity);
Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab");
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
}
}
this.continueDistanceHolding = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
@ -216,53 +257,45 @@ function controller(hand, triggerAction) {
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);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
if (this.actionID === null) {
// first time here since trigger pulled -- add the action and initialize some variables
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectRotation = grabbedProperties.rotation;
this.handPreviousPosition = handControllerPosition;
this.handPreviousRotation = handRotation;
// 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);
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;
}
} else {
// 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);
var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition);
this.handPreviousPosition = handControllerPosition;
var superHandMoved = Vec3.multiply(handMoved, radius);
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved);
var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved);
var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters
var now = Date.now();
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
this.computeReleaseVelocity(deltaPosition, deltaTime, false);
// 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);
this.currentObjectPosition = newObjectPosition;
this.currentObjectTime = now;
Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
});
}
// 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
});
}
this.closeGrabbing = function() {
this.nearGrabbing = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
@ -270,7 +303,9 @@ function controller(hand, triggerAction) {
this.lineOff();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity);
this.activateEntity(this.grabbedEntity);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, "position");
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
@ -278,52 +313,69 @@ function controller(hand, triggerAction) {
var objectRotation = grabbedProperties.rotation;
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectTime = Date.now();
var offset = Vec3.subtract(this.currentObjectPosition, handPosition);
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: CLOSE_GRABBING_ACTION_TIMEFRAME,
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: offsetPosition,
relativeRotation: offsetRotation
});
if (this.actionID == NULL_ACTION_ID) {
this.actionID = null;
} else {
this.state = STATE_CONTINUE_CLOSE_GRABBING;
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.continueCloseGrabbing = function() {
this.continueNearGrabbing = function() {
if (!this.triggerSmoothedSqueezed()) {
this.state = STATE_RELEASE;
return;
}
// keep track of the measured velocity of the held object
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity);
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var now = Date.now();
var deltaPosition = Vec3.subtract(grabbedProperties.position, this.currentObjectPosition); // meters
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerPosition); // meters
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
this.computeReleaseVelocity(deltaPosition, deltaTime, true);
if (deltaTime > 0.0) {
this.currentHandControllerPosition = handControllerPosition;
this.currentObjectTime = now;
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
}
this.computeReleaseVelocity = function(deltaPosition, deltaTime, useMultiplier) {
if (deltaTime > 0.0 && !vec3equal(deltaPosition, ZERO_VEC)) {
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 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)),
Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO));
(1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)),
Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO));
}
if (useMultiplier) {
this.grabbedVelocity = Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER);
}
}
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectTime = now;
}
@ -332,11 +384,13 @@ function controller(hand, triggerAction) {
if (this.grabbedEntity != null && this.actionID != null) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
}
// 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: this.grabbedVelocity});
this.deactivateEntity(this.grabbedEntity);
this.grabbedVelocity = ZERO_VEC;
this.grabbedEntity = null;
@ -348,6 +402,22 @@ function controller(hand, triggerAction) {
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);
}
}

View file

@ -16,7 +16,7 @@ var PARTICLE_MAX_SIZE = 2.50;
var LIFETIME = 600;
var boxes = [];
var ids = Entities.findEntities({ x: 512, y: 512, z: 512 }, 50);
var ids = Entities.findEntities(MyAvatar.position, 50);
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
var properties = Entities.getEntityProperties(id);
@ -33,10 +33,10 @@ for (var x = 0; x < SIDE_SIZE; x++) {
var gray = Math.random() * 155;
var cube = Math.random() > 0.5;
var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray };
var position = { x: 512 + x * 0.2, y: 512 + y * 0.2, z: 512 + z * 0.2};
var position = Vec3.sum(MyAvatar.position, { x: x * 0.2, y: y * 0.2, z: z * 0.2});
var radius = Math.random() * 0.1;
boxes.push(Entities.addEntity({
type: cube ? "Box" : "Sphere",
type: cube ? "Box" : "Box",
name: "PerfTest",
position: position,
dimensions: { x: radius, y: radius, z: radius },

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...");
}
releaseGrab: 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);
@ -175,4 +178,4 @@ pointInExtents = function(point, minPoint, maxPoint) {
return (point.x >= minPoint.x && point.x <= maxPoint.x) &&
(point.y >= minPoint.y && point.y <= maxPoint.y) &&
(point.z >= minPoint.z && point.z <= maxPoint.z);
}
}

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

@ -39,9 +39,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableBoxEntityItem::render");
Q_ASSERT(getType() == EntityTypes::Box);
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
if (!_procedural) {
_procedural.reset(new Procedural(this->getUserData()));
@ -54,11 +51,15 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
}
gpu::Batch& batch = *args->_batch;
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
if (_procedural->ready()) {
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well
_procedural->prepare(batch, this->getDimensions());
DependencyManager::get<GeometryCache>()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor));
} else {
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor);
DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor);
}
RenderableDebugableEntityItem::render(this, args);

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),
@ -140,7 +140,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)
{
}
@ -423,105 +424,159 @@ 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);
// Boxes, Spheres, Light, Line, Model(??), Particle, PolyLine
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color);
// 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_VELOCITY, emitVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY_SPREAD, velocitySpread);
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);
}
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(emitVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(velocitySpread);
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);
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);
// Sitting properties support
if (!skipDefaults) {
@ -534,7 +589,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) {
@ -556,21 +611,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;
}
@ -709,6 +752,155 @@ 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_VELOCITY, EmitVelocity, emitVelocity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_VELOCITY_SPREAD, VelocitySpread, velocitySpread, glm::vec3);
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
@ -259,13 +262,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

@ -111,8 +111,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(); \
@ -122,8 +123,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); \
}
@ -131,12 +133,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;
@ -296,6 +305,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,
@ -190,6 +165,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,
@ -200,7 +176,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

@ -147,8 +147,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

@ -8,10 +8,10 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <string.h>
#include "Batch.h"
#include <string.h>
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
@ -302,4 +302,28 @@ void Batch::enableSkybox(bool enable) {
bool Batch::isSkyboxEnabled() const {
return _enableSkybox;
}
}
void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function) {
NamedBatchData& instance = _namedData[instanceName];
++instance._count;
instance._function = function;
}
BufferPointer Batch::getNamedBuffer(const std::string& instanceName, uint8_t index) {
NamedBatchData& instance = _namedData[instanceName];
if (instance._buffers.size() <= index) {
instance._buffers.resize(index + 1);
}
if (!instance._buffers[index]) {
instance._buffers[index].reset(new Buffer());
}
return instance._buffers[index];
}
void Batch::preExecute() {
for (auto& mapItem : _namedData) {
mapItem.second.process(*this);
}
_namedData.clear();
}

View file

@ -12,6 +12,8 @@
#define hifi_gpu_Batch_h
#include <vector>
#include <mutex>
#include <functional>
#include "Framebuffer.h"
#include "Pipeline.h"
@ -38,16 +40,42 @@ enum ReservedSlot {
TRANSFORM_CAMERA_SLOT = 7,
};
// The named batch data provides a mechanism for accumulating data into buffers over the course
// of many independent calls. For instance, two objects in the scene might both want to render
// a simple box, but are otherwise unaware of each other. The common code that they call to render
// the box can create buffers to store the rendering parameters for each box and register a function
// that will be called with the accumulated buffer data when the batch commands are finally
// executed against the backend
class Batch {
public:
typedef Stream::Slot Slot;
struct NamedBatchData {
using BufferPointers = std::vector<BufferPointer>;
using Function = std::function<void(gpu::Batch&, NamedBatchData&)>;
std::once_flag _once;
BufferPointers _buffers;
size_t _count{ 0 };
Function _function;
void process(Batch& batch) {
_function(batch, *this);
}
};
using NamedBatchDataMap = std::map<std::string, NamedBatchData>;
Batch();
explicit Batch(const Batch& batch);
~Batch();
void clear();
void preExecute();
// Batches may need to override the context level stereo settings
// if they're performing framebuffer copy operations, like the
// deferred lighting resolution mechanism
@ -67,6 +95,12 @@ public:
void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0);
void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0);
void setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function);
BufferPointer getNamedBuffer(const std::string& instanceName, uint8_t index = 0);
// Input Stage
// InputFormat
// InputBuffers
@ -291,6 +325,8 @@ public:
FramebufferCaches _framebuffers;
QueryCaches _queries;
NamedBatchDataMap _namedData;
bool _enableStereo{ true };
bool _enableSkybox{ false };

View file

@ -120,6 +120,18 @@ enum Dimension {
MAT4,
NUM_DIMENSIONS,
};
// Count (of scalars) in an Element for a given Dimension
static const int LOCATION_COUNT[NUM_DIMENSIONS] = {
1,
1,
1,
1,
1,
3,
4,
};
// Count (of scalars) in an Element for a given Dimension
static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
1,
@ -127,8 +139,8 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
3,
4,
4,
9,
16,
3,
4,
};
// Semantic of an Element
@ -184,6 +196,7 @@ public:
Dimension getDimension() const { return (Dimension)_dimension; }
uint8 getDimensionCount() const { return DIMENSION_COUNT[(Dimension)_dimension]; }
uint8 getLocationCount() const { return LOCATION_COUNT[(Dimension)_dimension]; }
Type getType() const { return (Type)_type; }
bool isNormalized() const { return (getType() >= NFLOAT); }

View file

@ -191,6 +191,9 @@ void GLBackend::renderPassDraw(Batch& batch) {
}
void GLBackend::render(Batch& batch) {
// Finalize the batch by moving all the instanced rendering into the command buffer
batch.preExecute();
_stereo._skybox = batch.isSkyboxEnabled();
// Allow the batch to override the rendering stereo settings
// for things like full framebuffer copy operations (deferred lighting passes)
@ -316,7 +319,19 @@ void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) {
}
void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
(void) CHECK_GL_ERROR();
updateInput();
updateTransform();
updatePipeline();
GLint numInstances = batch._params[paramOffset + 4]._uint;
GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 3]._uint];
uint32 numIndices = batch._params[paramOffset + 2]._uint;
uint32 startIndex = batch._params[paramOffset + 1]._uint;
uint32 startInstance = batch._params[paramOffset + 0]._uint;
GLenum glType = _elementTypeToGLType[_input._indexBufferType];
glDrawElementsInstanced(mode, numIndices, glType, nullptr, numInstances);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) {
@ -603,11 +618,16 @@ void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
DO_IT_NOW(_glColor4f, 4);
}
void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
// TODO Replace this with a proper sticky Input attribute buffer with frequency 0
glVertexAttrib4f( gpu::Stream::COLOR,
glm::vec4 newColor(
batch._params[paramOffset + 3]._float,
batch._params[paramOffset + 2]._float,
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 0]._float);
batch._params[paramOffset + 0]._float);
if (_input._colorAttribute != newColor) {
_input._colorAttribute = newColor;
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
}
(void) CHECK_GL_ERROR();
}

View file

@ -278,6 +278,8 @@ protected:
Offsets _bufferStrides;
std::vector<GLuint> _bufferVBOs;
glm::vec4 _colorAttribute{ 0.0f };
BufferPointer _indexBuffer;
Offset _indexBufferOffset;
Type _indexBufferType;

View file

@ -160,7 +160,10 @@ void GLBackend::updateInput() {
if (_input._format) {
for (auto& it : _input._format->getAttributes()) {
const Stream::Attribute& attrib = (it).second;
newActivation.set(attrib._slot);
uint8_t locationCount = attrib._element.getLocationCount();
for (int i = 0; i < locationCount; ++i) {
newActivation.set(attrib._slot + i);
}
}
}
@ -211,14 +214,19 @@ void GLBackend::updateInput() {
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
GLuint slot = attrib._slot;
GLuint count = attrib._element.getDimensionCount();
uint8_t locationCount = attrib._element.getLocationCount();
GLenum type = _elementTypeToGLType[attrib._element.getType()];
GLuint stride = strides[bufferNum];
GLenum perLocationStride = strides[bufferNum];
GLuint stride = perLocationStride * locationCount;
GLuint pointer = attrib._offset + offsets[bufferNum];
GLboolean isNormalized = attrib._element.isNormalized();
glVertexAttribPointer(slot, count, type, isNormalized, stride,
reinterpret_cast<GLvoid*>(pointer));
for (int j = 0; j < locationCount; ++j) {
glVertexAttribPointer(slot + j, count, type, isNormalized, stride,
reinterpret_cast<GLvoid*>(pointer + perLocationStride * j));
glVertexAttribDivisor(slot + j, attrib._frequency);
}
// TODO: Support properly the IAttrib version
(void) CHECK_GL_ERROR();

View file

@ -75,6 +75,11 @@ void makeBindings(GLBackend::GLShader* shader) {
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
}
loc = glGetAttribLocation(glprogram, "inInstanceTransform");
if (loc >= 0 && loc != gpu::Stream::INSTANCE_XFM) {
glBindAttribLocation(glprogram, gpu::Stream::INSTANCE_XFM, "inInstanceTransform");
}
// Link again to take into account the assigned attrib location
glLinkProgram(glprogram);

View file

@ -18,4 +18,5 @@ in vec4 inTangent;
in vec4 inSkinClusterIndex;
in vec4 inSkinClusterWeight;
in vec4 inTexCoord1;
in mat4 inInstanceTransform;
<@endif@>

View file

@ -139,6 +139,11 @@ public:
// \return the number of bytes copied
Size append(Size size, const Byte* data);
template <typename T>
Size append(const T& t) {
return append(sizeof(t), reinterpret_cast<const Byte*>(&t));
}
// Access the sysmem object.
const Sysmem& getSysmem() const { assert(_sysmem); return (*_sysmem); }
Sysmem& editSysmem() { assert(_sysmem); return (*_sysmem); }

View file

@ -35,11 +35,12 @@ public:
SKIN_CLUSTER_INDEX = 5,
SKIN_CLUSTER_WEIGHT = 6,
TEXCOORD1 = 7,
INSTANCE_XFM = 8,
INSTANCE_SCALE = 9,
INSTANCE_TRANSLATE = 10,
INSTANCE_SCALE = 8,
INSTANCE_TRANSLATE = 9,
INSTANCE_XFM = 10,
NUM_INPUT_SLOTS,
// Instance XFM is a mat4, and as such takes up 4 slots
NUM_INPUT_SLOTS = INSTANCE_XFM + 4,
};
typedef uint8 Slot;

View file

@ -53,6 +53,15 @@ TransformCamera getTransformCamera() {
}
<@endfunc@>
<@func transformInstancedModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@>
<!// Equivalent to the following but hoppefully a tad more accurate
//return camera._projection * camera._view * object._model * pos; !>
{ // transformModelToClipPos
vec4 _eyepos = (inInstanceTransform * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0);
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos;
}
<@endfunc@>
<@func $transformModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@>
<!// Equivalent to the following but hoppefully a tad more accurate
//return camera._projection * camera._view * object._model * pos; !>
@ -65,12 +74,31 @@ TransformCamera getTransformCamera() {
}
<@endfunc@>
<@func $transformInstancedModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@>
<!// Equivalent to the following but hoppefully a tad more accurate
//return camera._projection * camera._view * object._model * pos; !>
{ // transformModelToClipPos
vec4 _worldpos = (inInstanceTransform * <$modelPos$>);
<$eyePos$> = (<$cameraTransform$>._view * _worldpos);
vec4 _eyepos =(inInstanceTransform * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0);
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos;
// <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>);
}
<@endfunc@>
<@func transformModelToWorldPos(objectTransform, modelPos, worldPos)@>
{ // transformModelToWorldPos
<$worldPos$> = (<$objectTransform$>._model * <$modelPos$>);
}
<@endfunc@>
<@func transformInstancedModelToWorldPos(objectTransform, modelPos, worldPos)@>
{ // transformModelToWorldPos
<$worldPos$> = (inInstanceTransform * <$modelPos$>);
}
<@endfunc@>
<@func transformModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@>
{ // transformModelToEyeDir
vec3 mr0 = vec3(<$objectTransform$>._modelInverse[0].x, <$objectTransform$>._modelInverse[1].x, <$objectTransform$>._modelInverse[2].x);
@ -85,6 +113,21 @@ TransformCamera getTransformCamera() {
}
<@endfunc@>
<@func transformInstancedModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@>
{ // transformModelToEyeDir
mat4 modelInverse = inverse(inInstanceTransform);
vec3 mr0 = vec3(modelInverse[0].x, modelInverse[1].x, modelInverse[2].x);
vec3 mr1 = vec3(modelInverse[0].y, modelInverse[1].y, modelInverse[2].y);
vec3 mr2 = vec3(modelInverse[0].z, modelInverse[1].z, modelInverse[2].z);
vec3 mvc0 = vec3(dot(<$cameraTransform$>._viewInverse[0].xyz, mr0), dot(<$cameraTransform$>._viewInverse[0].xyz, mr1), dot(<$cameraTransform$>._viewInverse[0].xyz, mr2));
vec3 mvc1 = vec3(dot(<$cameraTransform$>._viewInverse[1].xyz, mr0), dot(<$cameraTransform$>._viewInverse[1].xyz, mr1), dot(<$cameraTransform$>._viewInverse[1].xyz, mr2));
vec3 mvc2 = vec3(dot(<$cameraTransform$>._viewInverse[2].xyz, mr0), dot(<$cameraTransform$>._viewInverse[2].xyz, mr1), dot(<$cameraTransform$>._viewInverse[2].xyz, mr2));
<$eyeDir$> = vec3(dot(mvc0, <$modelDir$>), dot(mvc1, <$modelDir$>), dot(mvc2, <$modelDir$>));
}
<@endfunc@>
<@func transformEyeToWorldDir(cameraTransform, eyeDir, worldDir)@>
{ // transformEyeToWorldDir
<$worldDir$> = vec3(<$cameraTransform$>._viewInverse * vec4(<$eyeDir$>.xyz, 0.0));

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; }

File diff suppressed because it is too large Load diff

View file

@ -37,15 +37,22 @@ public:
void init(AbstractViewStateInterface* viewState);
/// Sets up the state necessary to render static untextured geometry with the simple program.
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
bool emmisive = false, bool depthBias = false);
/// Sets up the state necessary to render static untextured geometry with the simple program.
void bindInstanceProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
bool emmisive = false, bool depthBias = false);
//// Renders a solid sphere with the simple program.
void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color);
//// Renders a wireframe sphere with the simple program.
void renderWireSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color);
//// Renders a solid cube using instancing. Transform should include scaling.
void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color);
//// Renders a solid cube with the simple program.
void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color);

View file

@ -691,28 +691,31 @@ void GeometryCache::renderVertices(gpu::Batch& batch, gpu::Primitive primitiveTy
}
}
void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) {
Vec2Pair colorKey(glm::vec2(color.x, color.y), glm::vec2(color.z, color.y));
const int FLOATS_PER_VERTEX = 3;
const int VERTICES_PER_FACE = 4;
const int NUMBER_OF_FACES = 6;
const int TRIANGLES_PER_FACE = 2;
const int VERTICES_PER_TRIANGLE = 3;
const int vertices = NUMBER_OF_FACES * VERTICES_PER_FACE;
const int indices = NUMBER_OF_FACES * TRIANGLES_PER_FACE * VERTICES_PER_TRIANGLE;
const int vertexPoints = vertices * FLOATS_PER_VERTEX;
const int VERTEX_STRIDE = sizeof(GLfloat) * FLOATS_PER_VERTEX * 2; // vertices and normals
const int NORMALS_OFFSET = sizeof(GLfloat) * FLOATS_PER_VERTEX;
static const int FLOATS_PER_VERTEX = 3;
static const int VERTICES_PER_TRIANGLE = 3;
static const int CUBE_NUMBER_OF_FACES = 6;
static const int CUBE_VERTICES_PER_FACE = 4;
static const int CUBE_TRIANGLES_PER_FACE = 2;
static const int CUBE_VERTICES = CUBE_NUMBER_OF_FACES * CUBE_VERTICES_PER_FACE;
static const int CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX;
static const int CUBE_INDICES = CUBE_NUMBER_OF_FACES * CUBE_TRIANGLES_PER_FACE * VERTICES_PER_TRIANGLE;
static const gpu::Element CUBE_POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element CUBE_NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element CUBE_COLOR_ELEMENT{ gpu::VEC4, gpu::NUINT8, gpu::RGBA };
static const gpu::Element INSTANCE_XFM_ELEMENT{ gpu::MAT4, gpu::FLOAT, gpu::XYZW };
gpu::BufferPointer GeometryCache::getCubeVertices(float size) {
if (!_solidCubeVertices.contains(size)) {
auto verticesBuffer = std::make_shared<gpu::Buffer>();
_solidCubeVertices[size] = verticesBuffer;
GLfloat* vertexData = new GLfloat[vertexPoints * 2]; // vertices and normals
GLfloat* vertexData = new GLfloat[CUBE_VERTEX_POINTS * 2]; // vertices and normals
GLfloat* vertex = vertexData;
float halfSize = size / 2.0f;
static GLfloat cannonicalVertices[vertexPoints] =
static GLfloat cannonicalVertices[CUBE_VERTEX_POINTS] =
{ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front)
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right)
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top)
@ -721,7 +724,7 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 }; // v4,v7,v6,v5 (back)
// normal array
static GLfloat cannonicalNormals[vertexPoints] =
static GLfloat cannonicalNormals[CUBE_VERTEX_POINTS] =
{ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front)
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right)
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top)
@ -733,7 +736,7 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve
GLfloat* cannonicalVertex = &cannonicalVertices[0];
GLfloat* cannonicalNormal = &cannonicalNormals[0];
for (int i = 0; i < vertices; i++) {
for (int i = 0; i < CUBE_VERTICES; i++) {
// vertices
*(vertex++) = halfSize * *cannonicalVertex++;
*(vertex++) = halfSize * *cannonicalVertex++;
@ -744,90 +747,121 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve
*(vertex++) = *cannonicalNormal++;
*(vertex++) = *cannonicalNormal++;
}
verticesBuffer->append(sizeof(GLfloat) * vertexPoints * 2, (gpu::Byte*) vertexData);
verticesBuffer->append(sizeof(GLfloat) * CUBE_VERTEX_POINTS * 2, (gpu::Byte*) vertexData);
}
return _solidCubeVertices[size];
}
gpu::BufferPointer GeometryCache::getSolidCubeIndices() {
if (!_solidCubeIndexBuffer) {
static GLubyte cannonicalIndices[indices] =
{ 0, 1, 2, 2, 3, 0, // front
static GLubyte cannonicalIndices[CUBE_INDICES] = { 0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // right
8, 9,10, 10,11, 8, // top
12,13,14, 14,15,12, // left
16,17,18, 18,19,16, // bottom
20,21,22, 22,23,20 }; // back
auto indexBuffer = std::make_shared<gpu::Buffer>();
_solidCubeIndexBuffer = indexBuffer;
_solidCubeIndexBuffer->append(sizeof(cannonicalIndices), (gpu::Byte*) cannonicalIndices);
}
return _solidCubeIndexBuffer;
}
void GeometryCache::setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer) {
static const int VERTEX_STRIDE = sizeof(GLfloat) * FLOATS_PER_VERTEX * 2; // vertices and normals
static const int NORMALS_OFFSET = sizeof(GLfloat) * FLOATS_PER_VERTEX;
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, CUBE_POSITION_ELEMENT);
gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, CUBE_NORMAL_ELEMENT);
batch.setInputBuffer(gpu::Stream::POSITION, verticesView);
batch.setInputBuffer(gpu::Stream::NORMAL, normalsView);
}
void GeometryCache::renderSolidCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) {
static gpu::Stream::FormatPointer streamFormat;
if (!streamFormat) {
streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, CUBE_POSITION_ELEMENT, 0);
streamFormat->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, CUBE_NORMAL_ELEMENT);
streamFormat->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, CUBE_COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
streamFormat->setAttribute(gpu::Stream::INSTANCE_XFM, gpu::Stream::INSTANCE_XFM, INSTANCE_XFM_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
}
batch.setInputFormat(streamFormat);
gpu::BufferView colorView(colorBuffer, CUBE_COLOR_ELEMENT);
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
gpu::BufferView instanceXfmView(transformBuffer, 0, transformBuffer->getSize(), INSTANCE_XFM_ELEMENT);
batch.setInputBuffer(gpu::Stream::INSTANCE_XFM, instanceXfmView);
gpu::BufferPointer verticesBuffer = getCubeVertices(1.0);
setupCubeVertices(batch, verticesBuffer);
batch.setIndexBuffer(gpu::UINT8, getSolidCubeIndices(), 0);
batch.drawIndexedInstanced(count, gpu::TRIANGLES, CUBE_INDICES);
}
void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) {
Vec2Pair colorKey(glm::vec2(color.x, color.y), glm::vec2(color.z, color.y));
if (!_solidCubeColors.contains(colorKey)) {
auto colorBuffer = std::make_shared<gpu::Buffer>();
_solidCubeColors[colorKey] = colorBuffer;
const int NUM_COLOR_SCALARS_PER_CUBE = 24;
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
((int(color.y * 255.0f) & 0xFF) << 8) |
((int(color.z * 255.0f) & 0xFF) << 16) |
((int(color.w * 255.0f) & 0xFF) << 24);
int colors[NUM_COLOR_SCALARS_PER_CUBE] = { compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor };
int colors[CUBE_VERTICES] = {
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor,
compactColor, compactColor, compactColor, compactColor
};
colorBuffer->append(sizeof(colors), (gpu::Byte*) colors);
}
gpu::BufferPointer verticesBuffer = _solidCubeVertices[size];
gpu::BufferPointer colorBuffer = _solidCubeColors[colorKey];
const int VERTICES_SLOT = 0;
const int NORMALS_SLOT = 1;
const int COLOR_SLOT = 2;
static gpu::Stream::FormatPointer streamFormat;
static gpu::Element positionElement, normalElement, colorElement;
if (!streamFormat) {
streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element;
normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element;
colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element;
streamFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, CUBE_POSITION_ELEMENT, 0);
streamFormat->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, CUBE_NORMAL_ELEMENT);
streamFormat->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, CUBE_COLOR_ELEMENT);
}
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, positionElement);
gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, normalElement);
gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
batch.setInputFormat(streamFormat);
batch.setInputBuffer(VERTICES_SLOT, verticesView);
batch.setInputBuffer(NORMALS_SLOT, normalsView);
batch.setInputBuffer(COLOR_SLOT, colorView);
batch.setIndexBuffer(gpu::UINT8, _solidCubeIndexBuffer, 0);
batch.drawIndexed(gpu::TRIANGLES, indices);
gpu::BufferView colorView(colorBuffer, CUBE_COLOR_ELEMENT);
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
gpu::BufferPointer verticesBuffer = getCubeVertices(size);
setupCubeVertices(batch, verticesBuffer);
batch.setIndexBuffer(gpu::UINT8, getSolidCubeIndices(), 0);
batch.drawIndexed(gpu::TRIANGLES, CUBE_INDICES);
}
void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) {
Vec2Pair colorKey(glm::vec2(color.x, color.y),glm::vec2(color.z, color.y));
const int FLOATS_PER_VERTEX = 3;
const int VERTICES_PER_EDGE = 2;
const int TOP_EDGES = 4;
const int BOTTOM_EDGES = 4;
const int SIDE_EDGES = 4;
const int vertices = 8;
const int indices = (TOP_EDGES + BOTTOM_EDGES + SIDE_EDGES) * VERTICES_PER_EDGE;
static const int WIRE_CUBE_VERTICES_PER_EDGE = 2;
static const int WIRE_CUBE_TOP_EDGES = 4;
static const int WIRE_CUBE_BOTTOM_EDGES = 4;
static const int WIRE_CUBE_SIDE_EDGES = 4;
static const int WIRE_CUBE_VERTICES = 8;
static const int WIRE_CUBE_INDICES = (WIRE_CUBE_TOP_EDGES + WIRE_CUBE_BOTTOM_EDGES + WIRE_CUBE_SIDE_EDGES) * WIRE_CUBE_VERTICES_PER_EDGE;
if (!_cubeVerticies.contains(size)) {
auto verticesBuffer = std::make_shared<gpu::Buffer>();
_cubeVerticies[size] = verticesBuffer;
int vertexPoints = vertices * FLOATS_PER_VERTEX;
GLfloat* vertexData = new GLfloat[vertexPoints]; // only vertices, no normals because we're a wire cube
static const int WIRE_CUBE_VERTEX_POINTS = WIRE_CUBE_VERTICES * FLOATS_PER_VERTEX;
GLfloat* vertexData = new GLfloat[WIRE_CUBE_VERTEX_POINTS]; // only vertices, no normals because we're a wire cube
GLfloat* vertex = vertexData;
float halfSize = size / 2.0f;
@ -836,15 +870,15 @@ void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec
1,-1, 1, 1,-1,-1, -1,-1,-1, -1,-1, 1 // v4, v5, v6, v7 (bottom)
};
for (int i = 0; i < vertexPoints; i++) {
for (int i = 0; i < WIRE_CUBE_VERTEX_POINTS; i++) {
vertex[i] = cannonicalVertices[i] * halfSize;
}
verticesBuffer->append(sizeof(GLfloat) * vertexPoints, (gpu::Byte*) vertexData); // I'm skeptical that this is right
verticesBuffer->append(sizeof(GLfloat) * WIRE_CUBE_VERTEX_POINTS, (gpu::Byte*) vertexData); // I'm skeptical that this is right
}
if (!_wireCubeIndexBuffer) {
static GLubyte cannonicalIndices[indices] = {
static GLubyte cannonicalIndices[WIRE_CUBE_INDICES] = {
0, 1, 1, 2, 2, 3, 3, 0, // (top)
4, 5, 5, 6, 6, 7, 7, 4, // (bottom)
0, 4, 1, 5, 2, 6, 3, 7, // (side edges)
@ -892,7 +926,7 @@ void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec
batch.setInputBuffer(VERTICES_SLOT, verticesView);
batch.setInputBuffer(COLOR_SLOT, colorView);
batch.setIndexBuffer(gpu::UINT8, _wireCubeIndexBuffer, 0);
batch.drawIndexed(gpu::LINES, indices);
batch.drawIndexed(gpu::LINES, WIRE_CUBE_INDICES);
}
void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id) {

View file

@ -136,6 +136,11 @@ public:
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra);
gpu::BufferPointer getCubeVertices(float size);
void setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer);
gpu::BufferPointer getSolidCubeIndices();
void renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec3& color, bool solid = true, int id = UNKNOWN_ID)
{ renderSphere(batch, radius, slices, stacks, glm::vec4(color, 1.0f), solid, id); }
@ -144,6 +149,7 @@ public:
void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color);
void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);
void renderSolidCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer);
void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color);
void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color);
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);

View file

@ -18,6 +18,7 @@
<$declareStandardTransform()$>
uniform bool Instanced = false;
// the interpolated normal
out vec3 _normal;
@ -33,6 +34,11 @@ void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
if (Instanced) {
<$transformInstancedModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformInstancedModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
} else {
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
}
}

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; }