Merge branch 'master' into feature/grab-script-polish-part-deux

This commit is contained in:
Anthony J. Thibault 2016-07-14 15:57:41 -07:00
commit 31f1d69c43
14 changed files with 176 additions and 44 deletions

View file

@ -16,6 +16,7 @@ macro(install_beside_console)
install( install(
TARGETS ${TARGET_NAME} TARGETS ${TARGET_NAME}
RUNTIME DESTINATION ${COMPONENT_INSTALL_DIR} RUNTIME DESTINATION ${COMPONENT_INSTALL_DIR}
LIBRARY DESTINATION ${CONSOLE_PLUGIN_INSTALL_DIR}
COMPONENT ${SERVER_COMPONENT} COMPONENT ${SERVER_COMPONENT}
) )
else () else ()

View file

@ -69,6 +69,8 @@ macro(SET_PACKAGING_PARAMETERS)
set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents")
set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app") set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app")
set(COMPONENT_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/MacOS") set(COMPONENT_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/MacOS")
set(CONSOLE_PLUGIN_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/PlugIns")
set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app") set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app")
set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns") set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns")

View file

@ -13,7 +13,7 @@ macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
if (APPLE) if (APPLE)
set(CLIENT_PLUGIN_PATH "${INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns") set(CLIENT_PLUGIN_PATH "${INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns")
set(SERVER_PLUGIN_PATH "Components.app/Contents/PlugIns") set(SERVER_PLUGIN_PATH "plugins")
else() else()
set(CLIENT_PLUGIN_PATH "plugins") set(CLIENT_PLUGIN_PATH "plugins")
set(SERVER_PLUGIN_PATH "plugins") set(SERVER_PLUGIN_PATH "plugins")

View file

@ -17,11 +17,14 @@
#include "CharacterController.h" #include "CharacterController.h"
const uint16_t AvatarActionHold::holdVersion = 1; const uint16_t AvatarActionHold::holdVersion = 1;
const int AvatarActionHold::velocitySmoothFrames = 6;
AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) : AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectActionSpring(id, ownerEntity) ObjectActionSpring(id, ownerEntity)
{ {
_type = ACTION_TYPE_HOLD; _type = ACTION_TYPE_HOLD;
_measuredLinearVelocities.resize(AvatarActionHold::velocitySmoothFrames);
#if WANT_DEBUG #if WANT_DEBUG
qDebug() << "AvatarActionHold::AvatarActionHold"; qDebug() << "AvatarActionHold::AvatarActionHold";
#endif #endif
@ -204,8 +207,38 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
} }
withWriteLock([&]{ withWriteLock([&]{
if (_previousSet) {
glm::vec3 oneFrameVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
_measuredLinearVelocities[_measuredLinearVelocitiesIndex++] = oneFrameVelocity;
if (_measuredLinearVelocitiesIndex >= AvatarActionHold::velocitySmoothFrames) {
_measuredLinearVelocitiesIndex = 0;
}
}
glm::vec3 measuredLinearVelocity;
for (int i = 0; i < AvatarActionHold::velocitySmoothFrames; i++) {
// there is a bit of lag between when someone releases the trigger and when the software reacts to
// the release. we calculate the velocity from previous frames but we don't include several
// of the most recent.
//
// if _measuredLinearVelocitiesIndex is
// 0 -- ignore i of 3 4 5
// 1 -- ignore i of 4 5 0
// 2 -- ignore i of 5 0 1
// 3 -- ignore i of 0 1 2
// 4 -- ignore i of 1 2 3
// 5 -- ignore i of 2 3 4
if ((i + 1) % 6 == _measuredLinearVelocitiesIndex ||
(i + 2) % 6 == _measuredLinearVelocitiesIndex ||
(i + 3) % 6 == _measuredLinearVelocitiesIndex) {
continue;
}
measuredLinearVelocity += _measuredLinearVelocities[i];
}
measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames - 3); // 3 because of the 3 we skipped, above
if (_kinematicSetVelocity) { if (_kinematicSetVelocity) {
rigidBody->setLinearVelocity(glmToBullet(_linearVelocityTarget)); rigidBody->setLinearVelocity(glmToBullet(measuredLinearVelocity));
rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget)); rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget));
} }

View file

@ -64,6 +64,10 @@ private:
glm::vec3 _palmOffsetFromRigidBody; glm::vec3 _palmOffsetFromRigidBody;
// leaving this here for future refernece. // leaving this here for future refernece.
// glm::quat _palmRotationFromRigidBody; // glm::quat _palmRotationFromRigidBody;
static const int velocitySmoothFrames;
QVector<glm::vec3> _measuredLinearVelocities;
int _measuredLinearVelocitiesIndex { 0 };
}; };
#endif // hifi_AvatarActionHold_h #endif // hifi_AvatarActionHold_h

View file

@ -17,7 +17,7 @@
class Base3DOverlay : public Overlay { class Base3DOverlay : public Overlay {
Q_OBJECT Q_OBJECT
public: public:
Base3DOverlay(); Base3DOverlay();
Base3DOverlay(const Base3DOverlay* base3DOverlay); Base3DOverlay(const Base3DOverlay* base3DOverlay);
@ -27,10 +27,10 @@ public:
const glm::vec3& getPosition() const { return _transform.getTranslation(); } const glm::vec3& getPosition() const { return _transform.getTranslation(); }
const glm::quat& getRotation() const { return _transform.getRotation(); } const glm::quat& getRotation() const { return _transform.getRotation(); }
const glm::vec3& getScale() const { return _transform.getScale(); } const glm::vec3& getScale() const { return _transform.getScale(); }
// TODO: consider implementing registration points in this class // TODO: consider implementing registration points in this class
const glm::vec3& getCenter() const { return getPosition(); } const glm::vec3& getCenter() const { return getPosition(); }
float getLineWidth() const { return _lineWidth; } float getLineWidth() const { return _lineWidth; }
bool getIsSolid() const { return _isSolid; } bool getIsSolid() const { return _isSolid; }
bool getIsDashedLine() const { return _isDashedLine; } bool getIsDashedLine() const { return _isDashedLine; }
@ -43,7 +43,7 @@ public:
void setRotation(const glm::quat& value) { _transform.setRotation(value); } void setRotation(const glm::quat& value) { _transform.setRotation(value); }
void setScale(float value) { _transform.setScale(value); } void setScale(float value) { _transform.setScale(value); }
void setScale(const glm::vec3& value) { _transform.setScale(value); } void setScale(const glm::vec3& value) { _transform.setScale(value); }
void setLineWidth(float lineWidth) { _lineWidth = lineWidth; } void setLineWidth(float lineWidth) { _lineWidth = lineWidth; }
void setIsSolid(bool isSolid) { _isSolid = isSolid; } void setIsSolid(bool isSolid) { _isSolid = isSolid; }
void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; } void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; }
@ -55,22 +55,22 @@ public:
void setProperties(const QVariantMap& properties) override; void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override; QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal); BoxFace& face, glm::vec3& surfaceNormal);
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) { float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) {
return findRayIntersection(origin, direction, distance, face, surfaceNormal); return findRayIntersection(origin, direction, distance, face, surfaceNormal);
} }
protected: protected:
Transform _transform; Transform _transform;
float _lineWidth; float _lineWidth;
bool _isSolid; bool _isSolid;
bool _isDashedLine; bool _isDashedLine;
bool _ignoreRayIntersection; bool _ignoreRayIntersection;
bool _drawInFront; bool _drawInFront;
}; };
#endif // hifi_Base3DOverlay_h #endif // hifi_Base3DOverlay_h

View file

@ -19,8 +19,7 @@ QString const ModelOverlay::TYPE = "model";
ModelOverlay::ModelOverlay() ModelOverlay::ModelOverlay()
: _model(std::make_shared<Model>(std::make_shared<Rig>())), : _model(std::make_shared<Model>(std::make_shared<Rig>())),
_modelTextures(QVariantMap()), _modelTextures(QVariantMap())
_updateModel(false)
{ {
_model->init(); _model->init();
_isLoaded = false; _isLoaded = false;
@ -44,7 +43,11 @@ void ModelOverlay::update(float deltatime) {
if (_updateModel) { if (_updateModel) {
_updateModel = false; _updateModel = false;
_model->setSnapModelToCenter(true); _model->setSnapModelToCenter(true);
_model->setScaleToFit(true, getDimensions()); if (_scaleToFit) {
_model->setScaleToFit(true, getScale() * getDimensions());
} else {
_model->setScale(getScale());
}
_model->setRotation(getRotation()); _model->setRotation(getRotation());
_model->setTranslation(getPosition()); _model->setTranslation(getPosition());
_model->setURL(_url); _model->setURL(_url);
@ -84,16 +87,31 @@ void ModelOverlay::render(RenderArgs* args) {
} }
void ModelOverlay::setProperties(const QVariantMap& properties) { void ModelOverlay::setProperties(const QVariantMap& properties) {
auto position = getPosition(); auto origPosition = getPosition();
auto rotation = getRotation(); auto origRotation = getRotation();
auto origDimensions = getDimensions();
auto origScale = getScale();
Volume3DOverlay::setProperties(properties); Base3DOverlay::setProperties(properties);
if (position != getPosition() || rotation != getRotation()) { auto scale = properties["scale"];
_updateModel = true; if (scale.isValid()) {
setScale(vec3FromVariant(scale));
} }
_updateModel = true; auto dimensions = properties["dimensions"];
if (dimensions.isValid()) {
_scaleToFit = true;
setDimensions(vec3FromVariant(dimensions));
} else if (scale.isValid()) {
// if "scale" property is set but "dimentions" is not.
// do NOT scale to fit.
_scaleToFit = false;
}
if (origPosition != getPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getScale()) {
_updateModel = true;
}
auto urlValue = properties["url"]; auto urlValue = properties["url"];
if (urlValue.isValid() && urlValue.canConvert<QString>()) { if (urlValue.isValid() && urlValue.canConvert<QString>()) {
@ -101,15 +119,15 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
_updateModel = true; _updateModel = true;
_isLoaded = false; _isLoaded = false;
} }
auto texturesValue = properties["textures"]; auto texturesValue = properties["textures"];
if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) { if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) {
QVariantMap textureMap = texturesValue.toMap(); QVariantMap textureMap = texturesValue.toMap();
foreach(const QString& key, textureMap.keys()) { foreach(const QString& key, textureMap.keys()) {
QUrl newTextureURL = textureMap[key].toUrl(); QUrl newTextureURL = textureMap[key].toUrl();
qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL;
QMetaObject::invokeMethod(_model.get(), "setTextureWithNameToURL", Qt::AutoConnection, QMetaObject::invokeMethod(_model.get(), "setTextureWithNameToURL", Qt::AutoConnection,
Q_ARG(const QString&, key), Q_ARG(const QString&, key),
Q_ARG(const QUrl&, newTextureURL)); Q_ARG(const QUrl&, newTextureURL));
@ -123,8 +141,11 @@ QVariant ModelOverlay::getProperty(const QString& property) {
if (property == "url") { if (property == "url") {
return _url.toString(); return _url.toString();
} }
if (property == "dimensions" || property == "scale" || property == "size") { if (property == "dimensions" || property == "size") {
return vec3toVariant(_model->getScaleToFitDimensions()); return vec3toVariant(getDimensions());
}
if (property == "scale") {
return vec3toVariant(getScale());
} }
if (property == "textures") { if (property == "textures") {
if (_modelTextures.size() > 0) { if (_modelTextures.size() > 0) {
@ -143,14 +164,14 @@ QVariant ModelOverlay::getProperty(const QString& property) {
bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal) { float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
QString subMeshNameTemp; QString subMeshNameTemp;
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, subMeshNameTemp); return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, subMeshNameTemp);
} }
bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) { float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) {
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo); return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo);
} }

View file

@ -43,9 +43,10 @@ private:
ModelPointer _model; ModelPointer _model;
QVariantMap _modelTextures; QVariantMap _modelTextures;
QUrl _url; QUrl _url;
bool _updateModel; bool _updateModel = { false };
bool _scaleToFit = { false };
}; };
#endif // hifi_ModelOverlay_h #endif // hifi_ModelOverlay_h

View file

@ -22,7 +22,7 @@ AABox Volume3DOverlay::getBounds() const {
auto extents = Extents{_localBoundingBox}; auto extents = Extents{_localBoundingBox};
extents.rotate(getRotation()); extents.rotate(getRotation());
extents.shiftBy(getPosition()); extents.shiftBy(getPosition());
return AABox(extents); return AABox(extents);
} }
@ -31,7 +31,7 @@ void Volume3DOverlay::setProperties(const QVariantMap& properties) {
auto dimensions = properties["dimensions"]; auto dimensions = properties["dimensions"];
// if "dimensions" property was not there, check to see if they included aliases: scale // if "dimensions" property was not there, check to see if they included aliases: scale, size
if (!dimensions.isValid()) { if (!dimensions.isValid()) {
dimensions = properties["scale"]; dimensions = properties["scale"];
if (!dimensions.isValid()) { if (!dimensions.isValid()) {
@ -57,7 +57,7 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
// extents is the entity relative, scaled, centered extents of the entity // extents is the entity relative, scaled, centered extents of the entity
glm::mat4 worldToEntityMatrix; glm::mat4 worldToEntityMatrix;
_transform.getInverseMatrix(worldToEntityMatrix); _transform.getInverseMatrix(worldToEntityMatrix);
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); glm::vec3 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));

View file

@ -15,13 +15,13 @@
class Volume3DOverlay : public Base3DOverlay { class Volume3DOverlay : public Base3DOverlay {
Q_OBJECT Q_OBJECT
public: public:
Volume3DOverlay() {} Volume3DOverlay() {}
Volume3DOverlay(const Volume3DOverlay* volume3DOverlay); Volume3DOverlay(const Volume3DOverlay* volume3DOverlay);
virtual AABox getBounds() const override; virtual AABox getBounds() const override;
const glm::vec3& getDimensions() const { return _localBoundingBox.getDimensions(); } const glm::vec3& getDimensions() const { return _localBoundingBox.getDimensions(); }
void setDimensions(float value) { _localBoundingBox.setBox(glm::vec3(-value / 2.0f), value); } void setDimensions(float value) { _localBoundingBox.setBox(glm::vec3(-value / 2.0f), value); }
void setDimensions(const glm::vec3& value) { _localBoundingBox.setBox(-value / 2.0f, value); } void setDimensions(const glm::vec3& value) { _localBoundingBox.setBox(-value / 2.0f, value); }
@ -29,13 +29,13 @@ public:
void setProperties(const QVariantMap& properties) override; void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override; QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal) override; BoxFace& face, glm::vec3& surfaceNormal) override;
protected: protected:
// Centered local bounding box // Centered local bounding box
AABox _localBoundingBox{ vec3(0.0f), 1.0f }; AABox _localBoundingBox{ vec3(0.0f), 1.0f };
}; };
#endif // hifi_Volume3DOverlay_h #endif // hifi_Volume3DOverlay_h

View file

@ -954,7 +954,6 @@ void AudioClient::processReceivedSamples(const QByteArray& decodedBuffer, QByteA
if (hasReverb) { if (hasReverb) {
assert(_outputFormat.channelCount() == 2); assert(_outputFormat.channelCount() == 2);
updateReverbOptions(); updateReverbOptions();
qDebug() << "handling reverb";
_listenerReverb.render(outputSamples, outputSamples, numDeviceOutputSamples/2); _listenerReverb.render(outputSamples, outputSamples, numDeviceOutputSamples/2);
} }
} }

View file

@ -15,5 +15,6 @@ if (WIN32 OR APPLE)
add_dependency_external_projects(HiFiAudioCodec) add_dependency_external_projects(HiFiAudioCodec)
target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS}) target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES}) target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES})
install_beside_console()
endif() endif()

View file

@ -9,3 +9,5 @@
set(TARGET_NAME pcmCodec) set(TARGET_NAME pcmCodec)
setup_hifi_client_server_plugin() setup_hifi_client_server_plugin()
link_hifi_libraries(shared plugins) link_hifi_libraries(shared plugins)
install_beside_console()

View file

@ -13,7 +13,7 @@
/* global setEntityCustomData, getEntityCustomData, vec3toStr, flatten, Xform */ /* global setEntityCustomData, getEntityCustomData, vec3toStr, flatten, Xform */
Script.include("/~/system/libraries/utils.js"); Script.include("/~/system/libraries/utils.js");
Script.include("../libraries/Xform.js"); Script.include("/~/system/libraries/Xform.js");
// //
// add lines where the hand ray picking is happening // add lines where the hand ray picking is happening
@ -33,6 +33,8 @@ var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
var TRIGGER_OFF_VALUE = 0.15; var TRIGGER_OFF_VALUE = 0.15;
var COLLIDE_WITH_AV_AFTER_RELEASE_DELAY = 0.25; // seconds
var BUMPER_ON_VALUE = 0.5; var BUMPER_ON_VALUE = 0.5;
var THUMB_ON_VALUE = 0.5; var THUMB_ON_VALUE = 0.5;
@ -173,6 +175,10 @@ var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC; var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC; var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
var delayedDeactivateFunc;
var delayedDeactivateTimeout;
var delayedDeactivateEntityID;
var CONTROLLER_STATE_MACHINE = {}; var CONTROLLER_STATE_MACHINE = {};
CONTROLLER_STATE_MACHINE[STATE_OFF] = { CONTROLLER_STATE_MACHINE[STATE_OFF] = {
@ -300,6 +306,17 @@ function storeAttachPointForHotspotInSettings(hotspot, hand, offsetPosition, off
setAttachPointSettings(attachPointSettings); setAttachPointSettings(attachPointSettings);
} }
function removeMyAvatarFromCollidesWith(origCollidesWith) {
var collidesWithSplit = origCollidesWith.split(",");
// remove myAvatar from the array
for (var i = collidesWithSplit.length - 1; i >= 0; i--) {
if (collidesWithSplit[i] === "myAvatar") {
collidesWithSplit.splice(i, 1);
}
}
return collidesWithSplit.join();
}
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here, // If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode. // and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true; var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
@ -2205,6 +2222,17 @@ function MyController(hand) {
} }
this.entityActivated = true; this.entityActivated = true;
if (delayedDeactivateTimeout && delayedDeactivateEntityID == entityID) {
// we have a timeout waiting to set collisions with myAvatar back on (so that when something
// is thrown it doesn't collide with the avatar's capsule the moment it's released). We've
// regrabbed the entity before the timeout fired, so cancel the timeout, run the function now
// and adjust the grabbedProperties. This will make the saved set of properties (the ones that
// get re-instated after all the grabs have been released) be correct.
Script.clearTimeout(delayedDeactivateTimeout);
delayedDeactivateTimeout = null;
grabbedProperties["collidesWith"] = delayedDeactivateFunc();
}
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
var now = Date.now(); var now = Date.now();
@ -2272,7 +2300,27 @@ function MyController(hand) {
}); });
}; };
this.deactivateEntity = function (entityID, noVelocity) { this.delayedDeactivateEntity = function (entityID, collidesWith) {
// If, before the grab started, the held entity collided with myAvatar, we do the deactivation in
// two parts. Most of it is done in deactivateEntity(), but the final collidesWith and refcount
// are delayed a bit. This keeps thrown things from colliding with the avatar's capsule so often.
// The refcount is handled in this delayed fashion so things don't get confused if someone else
// grabs the entity before the timeout fires.
Entities.editEntity(entityID, { collidesWith: collidesWith });
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1;
if (data["refCount"] < 1) {
data = null;
}
} else {
data = null;
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
this.deactivateEntity = function (entityID, noVelocity, delayed) {
var deactiveProps; var deactiveProps;
if (!this.entityActivated) { if (!this.entityActivated) {
@ -2281,18 +2329,37 @@ function MyController(hand) {
this.entityActivated = false; this.entityActivated = false;
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
var doDelayedDeactivate = false;
if (data && data["refCount"]) { if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1; data["refCount"] = data["refCount"] - 1;
if (data["refCount"] < 1) { if (data["refCount"] < 1) {
deactiveProps = { deactiveProps = {
gravity: data["gravity"], gravity: data["gravity"],
collidesWith: data["collidesWith"], // don't set collidesWith myAvatar back right away, because thrown things tend to bounce off the
// avatar's capsule.
collidesWith: removeMyAvatarFromCollidesWith(data["collidesWith"]),
collisionless: data["collisionless"], collisionless: data["collisionless"],
dynamic: data["dynamic"], dynamic: data["dynamic"],
parentID: data["parentID"], parentID: data["parentID"],
parentJointIndex: data["parentJointIndex"] parentJointIndex: data["parentJointIndex"]
}; };
doDelayedDeactivate = (data["collidesWith"].indexOf("myAvatar") >= 0);
if (doDelayedDeactivate) {
var delayedCollidesWith = data["collidesWith"];
var delayedEntityID = entityID;
delayedDeactivateFunc = function () {
// set collidesWith back to original value a bit later than the rest
delayedDeactivateTimeout = null;
_this.delayedDeactivateEntity(delayedEntityID, delayedCollidesWith);
return delayedCollidesWith;
}
delayedDeactivateTimeout =
Script.setTimeout(delayedDeactivateFunc, COLLIDE_WITH_AV_AFTER_RELEASE_DELAY * MSECS_PER_SEC);
delayedDeactivateEntityID = entityID;
}
// things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If // things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If
// it looks like the dropped thing should fall, give it a little velocity. // it looks like the dropped thing should fall, give it a little velocity.
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]); var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]);
@ -2335,7 +2402,6 @@ function MyController(hand) {
// angularVelocity: this.currentAngularVelocity // angularVelocity: this.currentAngularVelocity
}); });
} }
data = null; data = null;
} else if (this.shouldResetParentOnRelease) { } else if (this.shouldResetParentOnRelease) {
// we parent-grabbed this from another parent grab. try to put it back where we found it. // we parent-grabbed this from another parent grab. try to put it back where we found it.
@ -2354,7 +2420,9 @@ function MyController(hand) {
} else { } else {
data = null; data = null;
} }
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); if (!doDelayedDeactivate) {
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
}
}; };
this.getOtherHandController = function () { this.getOtherHandController = function () {