Merge branch 'master' of git://github.com/highfidelity/hifi into highlight

This commit is contained in:
Olivier Prat 2017-11-08 11:41:21 +01:00
commit f996435ac8
20 changed files with 194 additions and 52 deletions

View file

@ -175,7 +175,7 @@ bool EntityTreeSendThread::addAncestorsToExtraFlaggedEntities(const QUuid& filte
return parentWasNew || ancestorsWereNew; return parentWasNew || ancestorsWereNew;
} }
// since we didn't have a parent niether of our parents or ancestors could be new additions // since we didn't have a parent, neither of our parents or ancestors could be new additions
return false; return false;
} }
@ -204,7 +204,9 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil
return hasNewChild || hasNewDescendants; return hasNewChild || hasNewDescendants;
} }
void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) { void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset,
bool usesViewFrustum) {
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesViewFrustum); DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesViewFrustum);
// there are three types of traversal: // there are three types of traversal:
// //
@ -423,12 +425,19 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
uint64_t sendTime = usecTimestampNow(); uint64_t sendTime = usecTimestampNow();
auto nodeData = static_cast<OctreeQueryNode*>(params.nodeData); auto nodeData = static_cast<OctreeQueryNode*>(params.nodeData);
nodeData->stats.encodeStarted(); nodeData->stats.encodeStarted();
auto entityNode = _node.toStrongRef();
auto entityNodeData = static_cast<EntityNodeData*>(entityNode->getLinkedData());
while(!_sendQueue.empty()) { while(!_sendQueue.empty()) {
PrioritizedEntity queuedItem = _sendQueue.top(); PrioritizedEntity queuedItem = _sendQueue.top();
EntityItemPointer entity = queuedItem.getEntity(); EntityItemPointer entity = queuedItem.getEntity();
if (entity) { if (entity) {
// Only send entities that match the jsonFilters, but keep track of everything we've tried to send so we don't try to send it again // Only send entities that match the jsonFilters, but keep track of everything we've tried to send so we don't try to send it again
if (entity->matchesJSONFilters(jsonFilters)) { bool entityMatchesFilters = entity->matchesJSONFilters(jsonFilters);
if (entityMatchesFilters || entityNodeData->isEntityFlaggedAsExtra(entity->getID())) {
if (!jsonFilters.isEmpty() && entityMatchesFilters) {
// Record explicitly filtered-in entity so that extra entities can be flagged.
entityNodeData->insertSentFilteredEntity(entity->getID());
}
OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData); OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData);
if (appendEntityState != OctreeElement::COMPLETED) { if (appendEntityState != OctreeElement::COMPLETED) {

View file

@ -38,7 +38,8 @@ private:
bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum); void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset,
bool usesViewFrustum);
bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override; bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override;
void preDistributionProcessing() override; void preDistributionProcessing() override;

View file

@ -25,7 +25,6 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
_distanceScaleEnd(distanceScaleEnd), _distanceScaleEnd(distanceScaleEnd),
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps)) _rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps))
{ {
for (auto& state : _renderStates) { for (auto& state : _renderStates) {
if (!enabled || state.first != _currentRenderState) { if (!enabled || state.first != _currentRenderState) {
@ -119,23 +118,25 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
qApp->getOverlays().editOverlay(renderState.getStartID(), startProps); qApp->getOverlays().editOverlay(renderState.getStartID(), startProps);
} }
glm::vec3 endVec; glm::vec3 endVec;
if (((defaultState || !_lockEnd) && _objectLockEnd.first.isNull()) || type == IntersectionType::HUD) { if (((defaultState || !_lockEnd) && _lockEndObject.id.isNull()) || type == IntersectionType::HUD) {
endVec = pickRay.origin + pickRay.direction * distance; endVec = pickRay.origin + pickRay.direction * distance;
} else { } else {
if (!_objectLockEnd.first.isNull()) { if (!_lockEndObject.id.isNull()) {
glm::vec3 pos; glm::vec3 pos;
glm::quat rot; glm::quat rot;
glm::vec3 dim; glm::vec3 dim;
glm::vec3 registrationPoint; glm::vec3 registrationPoint;
if (_objectLockEnd.second) { if (_lockEndObject.isOverlay) {
pos = vec3FromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "position").value); pos = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "position").value);
rot = quatFromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "rotation").value); rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value);
dim = vec3FromVariant(qApp->getOverlays().getProperty(_objectLockEnd.first, "dimensions").value); dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value);
registrationPoint = glm::vec3(0.5f); registrationPoint = glm::vec3(0.5f);
} else { } else {
EntityItemProperties props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(_objectLockEnd.first); EntityItemProperties props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(_lockEndObject.id);
pos = props.getPosition(); glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition());
rot = props.getRotation(); glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat;
pos = extractTranslation(finalPosAndRotMat);
rot = glmExtractRotation(finalPosAndRotMat);
dim = props.getDimensions(); dim = props.getDimensions();
registrationPoint = props.getRegistrationPoint(); registrationPoint = props.getRegistrationPoint();
} }
@ -209,7 +210,7 @@ void LaserPointer::update() {
withReadLock([&] { withReadLock([&] {
RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID); RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID);
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_lockEndObject.id.isNull())) {
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false); updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
disableRenderState(_defaultRenderStates[_currentRenderState].second); disableRenderState(_defaultRenderStates[_currentRenderState].second);
@ -233,9 +234,11 @@ void LaserPointer::setLaserLength(const float laserLength) {
}); });
} }
void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) { void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay, const glm::mat4& offsetMat) {
withWriteLock([&] { withWriteLock([&] {
_objectLockEnd = std::pair<QUuid, bool>(objectID, isOverlay); _lockEndObject.id = objectID;
_lockEndObject.isOverlay = isOverlay;
_lockEndObject.offsetMat = offsetMat;
}); });
} }

View file

@ -21,6 +21,12 @@
class RayPickResult; class RayPickResult;
struct LockEndObject {
QUuid id { QUuid() };
bool isOverlay { false };
glm::mat4 offsetMat { glm::mat4() };
};
class RenderState { class RenderState {
public: public:
@ -74,7 +80,7 @@ public:
void setPrecisionPicking(const bool precisionPicking); void setPrecisionPicking(const bool precisionPicking);
void setLaserLength(const float laserLength); void setLaserLength(const float laserLength);
void setLockEndUUID(QUuid objectID, const bool isOverlay); void setLockEndUUID(QUuid objectID, const bool isOverlay, const glm::mat4& offsetMat = glm::mat4());
void setIgnoreItems(const QVector<QUuid>& ignoreItems) const; void setIgnoreItems(const QVector<QUuid>& ignoreItems) const;
void setIncludeItems(const QVector<QUuid>& includeItems) const; void setIncludeItems(const QVector<QUuid>& includeItems) const;
@ -91,7 +97,7 @@ private:
bool _centerEndY; bool _centerEndY;
bool _lockEnd; bool _lockEnd;
bool _distanceScaleEnd; bool _distanceScaleEnd;
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)}; LockEndObject _lockEndObject;
const QUuid _rayPickUID; const QUuid _rayPickUID;

View file

@ -113,9 +113,9 @@ void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>
} }
} }
void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat) const {
auto laserPointer = find(uid); auto laserPointer = find(uid);
if (laserPointer) { if (laserPointer) {
laserPointer->setLockEndUUID(objectID, isOverlay); laserPointer->setLockEndUUID(objectID, isOverlay, offsetMat);
} }
} }

View file

@ -39,7 +39,7 @@ public:
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const; void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignoreEntities) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const; void setIncludeItems(const QUuid& uid, const QVector<QUuid>& includeEntities) const;
void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const;
void update(); void update();

View file

@ -35,7 +35,7 @@ public slots:
Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const; Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const;
Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const; Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const;
Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); } Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay, offsetMat); }
private: private:
static RenderState buildRenderState(const QVariantMap& propMap); static RenderState buildRenderState(const QVariantMap& propMap);

View file

@ -152,6 +152,7 @@ void Rig::overrideRoleAnimation(const QString& role, const QString& url, float f
const float REFERENCE_FRAMES_PER_SECOND = 30.0f; const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND; float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
auto clipNode = std::make_shared<AnimClip>(role, url, firstFrame, lastFrame, timeScale, loop, false); auto clipNode = std::make_shared<AnimClip>(role, url, firstFrame, lastFrame, timeScale, loop, false);
_roleAnimStates[role] = { role, url, fps, loop, firstFrame, lastFrame };
AnimNode::Pointer parent = node->getParent(); AnimNode::Pointer parent = node->getParent();
parent->replaceChild(node, clipNode); parent->replaceChild(node, clipNode);
} else { } else {
@ -1638,6 +1639,11 @@ void Rig::initAnimGraph(const QUrl& url) {
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f }; _userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame); overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
} }
// restore the role animations we had before reset.
for (auto& roleAnimState : _roleAnimStates) {
auto roleState = roleAnimState.second;
overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame);
}
_animLoading = false; _animLoading = false;
emit onLoadComplete(); emit onLoadComplete();

View file

@ -335,8 +335,22 @@ protected:
float firstFrame; float firstFrame;
float lastFrame; float lastFrame;
}; };
struct RoleAnimState {
RoleAnimState() {}
RoleAnimState(const QString& roleId, const QString& urlIn, float fpsIn, bool loopIn, float firstFrameIn, float lastFrameIn) :
role(roleId), url(urlIn), fps(fpsIn), loop(loopIn), firstFrame(firstFrameIn), lastFrame(lastFrameIn) {}
QString role;
QString url;
float fps;
bool loop;
float firstFrame;
float lastFrame;
};
UserAnimState _userAnimState; UserAnimState _userAnimState;
std::map<QString, RoleAnimState> _roleAnimStates;
float _leftHandOverlayAlpha { 0.0f }; float _leftHandOverlayAlpha { 0.0f };
float _rightHandOverlayAlpha { 0.0f }; float _rightHandOverlayAlpha { 0.0f };

View file

@ -142,7 +142,8 @@ DiffTraversal::DiffTraversal() {
_path.reserve(MIN_PATH_DEPTH); _path.reserve(MIN_PATH_DEPTH);
} }
DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) { DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root,
int32_t lodLevelOffset, bool usesViewFrustum) {
assert(root); assert(root);
// there are three types of traversal: // there are three types of traversal:
// //

View file

@ -57,7 +57,8 @@ public:
DiffTraversal(); DiffTraversal();
Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum); Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset,
bool usesViewFrustum);
const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; } const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; }
const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; } const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; }

View file

@ -140,7 +140,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
// Mask out haze on the tablet // Mask out haze on the tablet
PrepareStencil::testNoAA(*state); PrepareStencil::testMask(*state);
gpu::Shader::BindingSet slotBindings; gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), HazeEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), HazeEffect_ParamsSlot));

View file

@ -116,9 +116,9 @@ void PrepareStencil::drawBackground(gpu::State& state) {
gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP)); gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP));
} }
// Pass if this area has NOT been marked as MASK // Pass if this area has NOT been marked as MASK or anything containing MASK
void PrepareStencil::testMask(gpu::State& state) { void PrepareStencil::testMask(gpu::State& state) {
state.setStencilTest(true, 0x00, gpu::State::StencilTest(STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, state.setStencilTest(true, 0x00, gpu::State::StencilTest(STENCIL_MASK, STENCIL_MASK, gpu::NOT_EQUAL,
gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
} }

View file

@ -49,8 +49,8 @@ public:
static void drawMask(gpu::State& state); static void drawMask(gpu::State& state);
static void drawBackground(gpu::State& state); static void drawBackground(gpu::State& state);
static void testNoAA(gpu::State& state);
static void testMask(gpu::State& state); static void testMask(gpu::State& state);
static void testNoAA(gpu::State& state);
static void testBackground(gpu::State& state); static void testBackground(gpu::State& state);
static void testShape(gpu::State& state); static void testShape(gpu::State& state);
static void testMaskDrawShape(gpu::State& state); static void testMaskDrawShape(gpu::State& state);

View file

@ -13,12 +13,13 @@
makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI, Xform, getEntityParents
*/ */
Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js"); Script.include("/~/system/libraries/controllers.js");
Script.include("/~/system/libraries/Xform.js");
(function() { (function() {
var PICK_WITH_HAND_RAY = true; var PICK_WITH_HAND_RAY = true;
@ -113,18 +114,71 @@ Script.include("/~/system/libraries/controllers.js");
]; ];
var MARGIN = 25; var MARGIN = 25;
function TargetObject(entityID, entityProps) {
this.entityID = entityID;
this.entityProps = entityProps;
this.targetEntityID = null;
this.targetEntityProps = null;
this.previousCollisionStatus = null;
this.madeDynamic = null;
this.makeDynamic = function() {
if (this.targetEntityID) {
var newProps = {
dynamic: true,
collisionless: true
};
this.previousCollisionStatus = this.targetEntityProps.collisionless;
Entities.editEntity(this.targetEntityID, newProps);
this.madeDynamic = true;
}
};
this.restoreTargetEntityOriginalProps = function() {
if (this.madeDynamic) {
var props = {};
props.dynamic = false;
props.collisionless = this.previousCollisionStatus;
var zeroVector = {x: 0, y: 0, z:0};
props.localVelocity = zeroVector;
props.localRotation = zeroVector;
Entities.editEntity(this.targetEntityID, props);
}
};
this.getTargetEntity = function() {
var parentPropsLength = this.parentProps.length;
if (parentPropsLength !== 0) {
var targetEntity = {
id: this.parentProps[parentPropsLength - 1].id,
props: this.parentProps[parentPropsLength - 1]};
this.targetEntityID = targetEntity.id;
this.targetEntityProps = targetEntity.props;
return targetEntity;
}
this.targetEntityID = this.entityID;
this.targetEntityProps = this.entityProps;
return {
id: this.entityID,
props: this.entityProps};
};
}
function FarActionGrabEntity(hand) { function FarActionGrabEntity(hand) {
this.hand = hand; this.hand = hand;
this.grabbedThingID = null; this.grabbedThingID = null;
this.targetObject = null;
this.actionID = null; // action this script created... this.actionID = null; // action this script created...
this.entityToLockOnto = null;
this.entityWithContextOverlay = false; this.entityWithContextOverlay = false;
this.contextOverlayTimer = false; this.contextOverlayTimer = false;
this.previousCollisionStatus = false; this.previousCollisionStatus = false;
this.locked = false;
this.reticleMinX = MARGIN; this.reticleMinX = MARGIN;
this.reticleMaxX; this.reticleMaxX;
this.reticleMinY = MARGIN; this.reticleMinY = MARGIN;
this.reticleMaxY; this.reticleMaxY;
this.madeDynamic = false;
var ACTION_TTL = 15; // seconds var ACTION_TTL = 15; // seconds
@ -158,9 +212,25 @@ Script.include("/~/system/libraries/controllers.js");
LaserPointers.enableLaserPointer(laserPointerID); LaserPointers.enableLaserPointer(laserPointerID);
LaserPointers.setRenderState(laserPointerID, mode); LaserPointers.setRenderState(laserPointerID, mode);
if (this.distanceHolding || this.distanceRotating) { if (this.distanceHolding || this.distanceRotating) {
LaserPointers.setLockEndUUID(laserPointerID, this.grabbedThingID, this.grabbedIsOverlay); if (!this.locked) {
// calculate offset
var targetProps = Entities.getEntityProperties(this.targetObject.entityID, [
"position",
"rotation"
]);
var zeroVector = { x: 0, y: 0, z:0, w: 0 };
var intersection = controllerData.rayPicks[this.hand].intersection;
var intersectionMat = new Xform(zeroVector, intersection);
var modelMat = new Xform(targetProps.rotation, targetProps.position);
var modelMatInv = modelMat.inv();
var xformMat = Xform.mul(modelMatInv, intersectionMat);
var offsetMat = Mat4.createFromRotAndTrans(xformMat.rot, xformMat.pos);
LaserPointers.setLockEndUUID(laserPointerID, this.targetObject.entityID, this.grabbedIsOverlay, offsetMat);
this.locked = true;
}
} else { } else {
LaserPointers.setLockEndUUID(laserPointerID, null, false); LaserPointers.setLockEndUUID(laserPointerID, null, false);
this.locked = false;
} }
}; };
@ -339,21 +409,15 @@ Script.include("/~/system/libraries/controllers.js");
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args); Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args);
if (this.targetObject) {
if (this.madeDynamic) { this.targetObject.restoreTargetEntityOriginalProps();
var props = {};
props.dynamic = false;
props.collisionless = this.previousCollisionStatus;
props.localVelocity = {x: 0, y: 0, z: 0};
props.localRotation = {x: 0, y: 0, z: 0};
Entities.editEntity(this.grabbedThingID, props);
this.madeDynamic = false;
} }
this.actionID = null; this.actionID = null;
this.grabbedThingID = null; this.grabbedThingID = null;
this.targetObject = null;
}; };
this.updateRecommendedArea = function() { this.updateRecommendedArea = function() {
var dims = Controller.getViewportDimensions(); var dims = Controller.getViewportDimensions();
this.reticleMaxX = dims.x - MARGIN; this.reticleMaxX = dims.x - MARGIN;
this.reticleMaxY = dims.y - MARGIN; this.reticleMaxY = dims.y - MARGIN;
@ -503,17 +567,18 @@ Script.include("/~/system/libraries/controllers.js");
"userData", "locked", "type" "userData", "locked", "type"
]); ]);
this.targetObject = new TargetObject(entityID, targetProps);
this.targetObject.parentProps = getEntityParents(targetProps);
if (entityID !== this.entityWithContextOverlay) { if (entityID !== this.entityWithContextOverlay) {
this.destroyContextOverlay(); this.destroyContextOverlay();
} }
var targetEntity = this.targetObject.getTargetEntity();
entityID = targetEntity.id;
targetProps = targetEntity.props;
if (entityIsGrabbable(targetProps)) { if (entityIsGrabbable(targetProps)) {
if (!entityIsDistanceGrabbable(targetProps)) { if (!entityIsDistanceGrabbable(targetProps)) {
targetProps.dynamic = true; this.targetObject.makeDynamic();
this.previousCollisionStatus = targetProps.collisionless;
targetProps.collisionless = true;
Entities.editEntity(entityID, targetProps);
this.madeDynamic = true;
} }
if (!this.distanceRotating) { if (!this.distanceRotating) {

View file

@ -315,6 +315,10 @@ Grabber.prototype.pressEvent = function(event) {
return; return;
} }
if (event.isAlt || event.isMeta) {
return;
}
if (Overlays.getOverlayAtPoint(Reticle.position) > 0) { if (Overlays.getOverlayAtPoint(Reticle.position) > 0) {
// the mouse is pointing at an overlay; don't look for entities underneath the overlay. // the mouse is pointing at an overlay; don't look for entities underneath the overlay.
return; return;

View file

@ -1333,7 +1333,7 @@ function sortSelectedEntities(selected) {
return sortedEntities; return sortedEntities;
} }
function recursiveDelete(entities, childrenList) { function recursiveDelete(entities, childrenList, deletedIDs) {
var entitiesLength = entities.length; var entitiesLength = entities.length;
for (var i = 0; i < entitiesLength; i++) { for (var i = 0; i < entitiesLength; i++) {
var entityID = entities[i]; var entityID = entities[i];
@ -1346,6 +1346,7 @@ function recursiveDelete(entities, childrenList) {
properties: initialProperties, properties: initialProperties,
children: grandchildrenList children: grandchildrenList
}); });
deletedIDs.push(entityID);
Entities.deleteEntity(entityID); Entities.deleteEntity(entityID);
} }
} }
@ -1413,6 +1414,8 @@ function parentSelectedEntities() {
} }
function deleteSelectedEntities() { function deleteSelectedEntities() {
if (SelectionManager.hasSelection()) { if (SelectionManager.hasSelection()) {
var deletedIDs = [];
selectedParticleEntityID = null; selectedParticleEntityID = null;
particleExplorerTool.destroyWebView(); particleExplorerTool.destroyWebView();
SelectionManager.saveProperties(); SelectionManager.saveProperties();
@ -1423,16 +1426,22 @@ function deleteSelectedEntities() {
var initialProperties = SelectionManager.savedProperties[entityID]; var initialProperties = SelectionManager.savedProperties[entityID];
var children = Entities.getChildrenIDs(entityID); var children = Entities.getChildrenIDs(entityID);
var childList = []; var childList = [];
recursiveDelete(children, childList); recursiveDelete(children, childList, deletedIDs);
savedProperties.push({ savedProperties.push({
entityID: entityID, entityID: entityID,
properties: initialProperties, properties: initialProperties,
children: childList children: childList
}); });
deletedIDs.push(entityID);
Entities.deleteEntity(entityID); Entities.deleteEntity(entityID);
} }
SelectionManager.clearSelections(); SelectionManager.clearSelections();
pushCommandForSelections([], savedProperties); pushCommandForSelections([], savedProperties);
entityListTool.webView.emitScriptEvent(JSON.stringify({
type: "deleted",
ids: deletedIDs
}));
} }
} }

View file

@ -286,7 +286,6 @@ function loaded() {
} }
elDelete.onclick = function() { elDelete.onclick = function() {
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
refreshEntities();
} }
document.addEventListener("keydown", function (keyDownEvent) { document.addEventListener("keydown", function (keyDownEvent) {
@ -362,6 +361,12 @@ function loaded() {
updateSelectedEntities(data.selectedIDs); updateSelectedEntities(data.selectedIDs);
resize(); resize();
} }
} else if (data.type === "deleted") {
for (i = 0, length = data.ids.length; i < length; i++) {
delete entities[data.ids[i]];
entityList.remove("id", data.ids[i]);
}
refreshFooter();
} }
}); });
setTimeout(refreshEntities, 1000); setTimeout(refreshEntities, 1000);

View file

@ -8,8 +8,7 @@
/* global entityIsCloneable:true, getGrabbableData:true, cloneEntity:true, propsAreCloneDynamic:true, Script, /* global entityIsCloneable:true, getGrabbableData:true, cloneEntity:true, propsAreCloneDynamic:true, Script,
propsAreCloneDynamic:true, Entities*/ propsAreCloneDynamic:true, Entities*/
Script.include("/~/system/controllers/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js");
// Object assign polyfill // Object assign polyfill
if (typeof Object.assign !== 'function') { if (typeof Object.assign !== 'function') {

View file

@ -35,12 +35,14 @@
propsArePhysical:true, propsArePhysical:true,
controllerDispatcherPluginsNeedSort:true, controllerDispatcherPluginsNeedSort:true,
projectOntoXYPlane:true, projectOntoXYPlane:true,
getChildrenProps:true,
projectOntoEntityXYPlane:true, projectOntoEntityXYPlane:true,
projectOntoOverlayXYPlane:true, projectOntoOverlayXYPlane:true,
entityHasActions:true, entityHasActions:true,
ensureDynamic:true, ensureDynamic:true,
findGroupParent:true, findGroupParent:true,
BUMPER_ON_VALUE:true, BUMPER_ON_VALUE:true,
getEntityParents:true,
findHandChildEntities:true, findHandChildEntities:true,
TEAR_AWAY_DISTANCE:true, TEAR_AWAY_DISTANCE:true,
TEAR_AWAY_COUNT:true, TEAR_AWAY_COUNT:true,
@ -306,6 +308,23 @@ findGroupParent = function (controllerData, targetProps) {
return targetProps; return targetProps;
}; };
getEntityParents = function(targetProps) {
var parentProperties = [];
while (targetProps.parentID &&
targetProps.parentID !== Uuid.NULL &&
Entities.getNestableType(targetProps.parentID) == "entity") {
var parentProps = Entities.getEntityProperties(targetProps.parentID, DISPATCHER_PROPERTIES);
if (!parentProps) {
break;
}
parentProps.id = targetProps.parentID;
targetProps = parentProps;
parentProperties.push(parentProps);
}
return parentProperties;
};
findHandChildEntities = function(hand) { findHandChildEntities = function(hand) {
// find children of avatar's hand joint // find children of avatar's hand joint