Merge pull request #13890 from sethalves/grab-properties-1

move grab pseudo-properties (userData) into first-class EntityItemProperties
This commit is contained in:
Brad Hefta-Gaub 2018-10-17 13:29:20 -07:00 committed by GitHub
commit 0e0542ec6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 1527 additions and 738 deletions

View file

@ -75,8 +75,11 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints, bool hasGrabJoints)
totalSize += numJoints * sizeof(SixByteTrans); // Translations
size_t NUM_FAUX_JOINT = 2;
size_t num_grab_joints = (hasGrabJoints ? 2 : 0);
totalSize += (NUM_FAUX_JOINT + num_grab_joints) * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints
totalSize += NUM_FAUX_JOINT * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints
if (hasGrabJoints) {
totalSize += sizeof(AvatarDataPacket::FarGrabJoints);
}
return totalSize;
}
@ -690,7 +693,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (hasGrabJoints) {
// the far-grab joints may range further than 3 meters, so we can't use packFloatVec3ToSignedTwoByteFixed etc
auto startSection = destinationBuffer;
auto data = reinterpret_cast<AvatarDataPacket::FarGrabJoints*>(destinationBuffer);
glm::vec3 leftFarGrabPosition = extractTranslation(leftFarGrabMatrix);
glm::quat leftFarGrabRotation = extractRotation(leftFarGrabMatrix);
glm::vec3 rightFarGrabPosition = extractTranslation(rightFarGrabMatrix);
@ -698,28 +701,17 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
glm::vec3 mouseFarGrabPosition = extractTranslation(mouseFarGrabMatrix);
glm::quat mouseFarGrabRotation = extractRotation(mouseFarGrabMatrix);
AVATAR_MEMCPY(leftFarGrabPosition);
// Can't do block copy as struct order is x, y, z, w.
data->leftFarGrabRotation[0] = leftFarGrabRotation.w;
data->leftFarGrabRotation[1] = leftFarGrabRotation.x;
data->leftFarGrabRotation[2] = leftFarGrabRotation.y;
data->leftFarGrabRotation[3] = leftFarGrabRotation.z;
destinationBuffer += sizeof(data->leftFarGrabPosition);
AVATAR_MEMCPY(rightFarGrabPosition);
data->rightFarGrabRotation[0] = rightFarGrabRotation.w;
data->rightFarGrabRotation[1] = rightFarGrabRotation.x;
data->rightFarGrabRotation[2] = rightFarGrabRotation.y;
data->rightFarGrabRotation[3] = rightFarGrabRotation.z;
destinationBuffer += sizeof(data->rightFarGrabRotation);
AVATAR_MEMCPY(mouseFarGrabPosition);
data->mouseFarGrabRotation[0] = mouseFarGrabRotation.w;
data->mouseFarGrabRotation[1] = mouseFarGrabRotation.x;
data->mouseFarGrabRotation[2] = mouseFarGrabRotation.y;
data->mouseFarGrabRotation[3] = mouseFarGrabRotation.z;
destinationBuffer += sizeof(data->mouseFarGrabRotation);
AvatarDataPacket::FarGrabJoints farGrabJoints = {
{ leftFarGrabPosition.x, leftFarGrabPosition.y, leftFarGrabPosition.z },
{ leftFarGrabRotation.w, leftFarGrabRotation.x, leftFarGrabRotation.y, leftFarGrabRotation.z },
{ rightFarGrabPosition.x, rightFarGrabPosition.y, rightFarGrabPosition.z },
{ rightFarGrabRotation.w, rightFarGrabRotation.x, rightFarGrabRotation.y, rightFarGrabRotation.z },
{ mouseFarGrabPosition.x, mouseFarGrabPosition.y, mouseFarGrabPosition.z },
{ mouseFarGrabRotation.w, mouseFarGrabRotation.x, mouseFarGrabRotation.y, mouseFarGrabRotation.z }
};
memcpy(destinationBuffer, &farGrabJoints, sizeof(farGrabJoints));
destinationBuffer += sizeof(AvatarDataPacket::FarGrabJoints);
int numBytes = destinationBuffer - startSection;
if (outboundDataRateOut) {
@ -1250,25 +1242,37 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
auto startSection = sourceBuffer;
PACKET_READ_CHECK(FarGrabJoints, sizeof(AvatarDataPacket::FarGrabJoints));
auto data = reinterpret_cast<const AvatarDataPacket::FarGrabJoints*>(sourceBuffer);
glm::vec3 leftFarGrabPosition = glm::vec3(data->leftFarGrabPosition[0], data->leftFarGrabPosition[1],
data->leftFarGrabPosition[2]);
glm::quat leftFarGrabRotation = glm::quat(data->leftFarGrabRotation[0], data->leftFarGrabRotation[1],
data->leftFarGrabRotation[2], data->leftFarGrabRotation[3]);
glm::vec3 rightFarGrabPosition = glm::vec3(data->rightFarGrabPosition[0], data->rightFarGrabPosition[1],
data->rightFarGrabPosition[2]);
glm::quat rightFarGrabRotation = glm::quat(data->rightFarGrabRotation[0], data->rightFarGrabRotation[1],
data->rightFarGrabRotation[2], data->rightFarGrabRotation[3]);
glm::vec3 mouseFarGrabPosition = glm::vec3(data->mouseFarGrabPosition[0], data->mouseFarGrabPosition[1],
data->mouseFarGrabPosition[2]);
glm::quat mouseFarGrabRotation = glm::quat(data->mouseFarGrabRotation[0], data->mouseFarGrabRotation[1],
data->mouseFarGrabRotation[2], data->mouseFarGrabRotation[3]);
AvatarDataPacket::FarGrabJoints farGrabJoints;
memcpy(&farGrabJoints, sourceBuffer, sizeof(farGrabJoints)); // to avoid misaligned floats
glm::vec3 leftFarGrabPosition = glm::vec3(farGrabJoints.leftFarGrabPosition[0],
farGrabJoints.leftFarGrabPosition[1],
farGrabJoints.leftFarGrabPosition[2]);
glm::quat leftFarGrabRotation = glm::quat(farGrabJoints.leftFarGrabRotation[0],
farGrabJoints.leftFarGrabRotation[1],
farGrabJoints.leftFarGrabRotation[2],
farGrabJoints.leftFarGrabRotation[3]);
glm::vec3 rightFarGrabPosition = glm::vec3(farGrabJoints.rightFarGrabPosition[0],
farGrabJoints.rightFarGrabPosition[1],
farGrabJoints.rightFarGrabPosition[2]);
glm::quat rightFarGrabRotation = glm::quat(farGrabJoints.rightFarGrabRotation[0],
farGrabJoints.rightFarGrabRotation[1],
farGrabJoints.rightFarGrabRotation[2],
farGrabJoints.rightFarGrabRotation[3]);
glm::vec3 mouseFarGrabPosition = glm::vec3(farGrabJoints.mouseFarGrabPosition[0],
farGrabJoints.mouseFarGrabPosition[1],
farGrabJoints.mouseFarGrabPosition[2]);
glm::quat mouseFarGrabRotation = glm::quat(farGrabJoints.mouseFarGrabRotation[0],
farGrabJoints.mouseFarGrabRotation[1],
farGrabJoints.mouseFarGrabRotation[2],
farGrabJoints.mouseFarGrabRotation[3]);
_farGrabLeftMatrixCache.set(createMatFromQuatAndPos(leftFarGrabRotation, leftFarGrabPosition));
_farGrabRightMatrixCache.set(createMatFromQuatAndPos(rightFarGrabRotation, rightFarGrabPosition));
_farGrabMouseMatrixCache.set(createMatFromQuatAndPos(mouseFarGrabRotation, mouseFarGrabPosition));
sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
sourceBuffer += sizeof(AvatarDataPacket::FarGrabJoints);
int numBytesRead = sourceBuffer - startSection;
_farGrabJointRate.increment(numBytesRead);
_farGrabJointUpdateRate.increment();

View file

@ -131,6 +131,10 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_CLONE_AVATAR_ENTITY;
requestedProperties += PROP_CLONE_ORIGIN_ID;
withReadLock([&] {
requestedProperties += _grabProperties.getEntityProperties(params);
});
return requestedProperties;
}
@ -168,6 +172,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
EntityPropertyFlags requestedProperties = getEntityProperties(params);
requestedProperties -= PROP_CLIENT_ONLY;
requestedProperties -= PROP_OWNING_AVATAR_ID;
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
// then our entityTreeElementExtraEncodeData should include data about which properties we need to append.
if (entityTreeElementExtraEncodeData && entityTreeElementExtraEncodeData->entities.contains(getEntityItemID())) {
@ -300,7 +307,12 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, getCloneLimit());
APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, getCloneDynamic());
APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, getCloneAvatarEntity());
APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID());
APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID());
withReadLock([&] {
_grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
});
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
@ -892,7 +904,15 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_CLONE_LIMIT, float, setCloneLimit);
READ_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, bool, setCloneDynamic);
READ_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity);
READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID);
READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID);
withWriteLock([&] {
int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData,
somethingChanged);
bytesRead += bytesFromGrab;
dataAt += bytesFromGrab;
});
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, somethingChanged);
@ -1329,6 +1349,10 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneAvatarEntity, getCloneAvatarEntity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneOriginID, getCloneOriginID);
withReadLock([&] {
_grabProperties.getProperties(properties);
});
properties._defaultSettings = false;
return properties;
@ -1465,6 +1489,11 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneAvatarEntity, setCloneAvatarEntity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneOriginID, setCloneOriginID);
withWriteLock([&] {
bool grabPropertiesChanged = _grabProperties.setProperties(properties);
somethingChanged |= grabPropertiesChanged;
});
if (updateQueryAACube()) {
somethingChanged = true;
}

View file

@ -35,6 +35,7 @@
#include "SimulationOwner.h"
#include "SimulationFlags.h"
#include "EntityDynamicInterface.h"
#include "GrabPropertyGroup.h"
#include "graphics/Material.h"
@ -533,6 +534,8 @@ public:
void setCloneIDs(const QVector<QUuid>& cloneIDs);
void setVisuallyReady(bool visuallyReady) { _visuallyReady = visuallyReady; }
const GrabPropertyGroup& getGrabProperties() const { return _grabProperties; }
signals:
void requestRenderUpdate();
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
@ -711,6 +714,8 @@ protected:
QUuid _cloneOriginID;
QVector<QUuid> _cloneIDs;
GrabPropertyGroup _grabProperties;
private:
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;

View file

@ -40,6 +40,7 @@ HazePropertyGroup EntityItemProperties::_staticHaze;
BloomPropertyGroup EntityItemProperties::_staticBloom;
KeyLightPropertyGroup EntityItemProperties::_staticKeyLight;
AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight;
GrabPropertyGroup EntityItemProperties::_staticGrab;
EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1);
@ -86,6 +87,7 @@ void EntityItemProperties::debugDump() const {
getKeyLight().debugDump();
getAmbientLight().debugDump();
getBloom().debugDump();
getGrab().debugDump();
qCDebug(entities) << " changed properties...";
EntityPropertyFlags props = getChangedProperties();
@ -471,6 +473,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
changedProperties += _skybox.getChangedProperties();
changedProperties += _haze.getChangedProperties();
changedProperties += _bloom.getChangedProperties();
changedProperties += _grab.getChangedProperties();
return changedProperties;
}
@ -628,6 +631,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* avatar entities: their <code>clientOnly</code> property will be set to <code>true</code>.
* @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from.
*
* @property {Entities.Grab} grab - The grab-related properties.
*
* @property {string} itemName="" - Certifiable name of the Marketplace item.
* @property {string} itemDescription="" - Certifiable description of the Marketplace item.
* @property {string} itemCategories="" - Certifiable category of the Marketplace item.
@ -1530,6 +1535,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_ORIGIN_ID, cloneOriginID);
_grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
// Rendering info
if (!skipDefaults && !strictSemantics &&
(!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::RenderInfo))) {
@ -1700,7 +1707,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeColors, qVectorVec3, setStrokeColors);
COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths,qVectorFloat, setStrokeWidths);
COPY_PROPERTY_FROM_QSCRIPTVALUE(isUVModeStretch, bool, setIsUVModeStretch);
if (!honorReadOnly) {
// this is used by the json reader to set things that we don't want javascript to able to affect.
@ -1718,6 +1725,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
_skybox.copyFromScriptValue(object, _defaultSettings);
_haze.copyFromScriptValue(object, _defaultSettings);
_bloom.copyFromScriptValue(object, _defaultSettings);
_grab.copyFromScriptValue(object, _defaultSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
@ -1883,6 +1891,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
_skybox.merge(other._skybox);
_haze.merge(other._haze);
_bloom.merge(other._bloom);
_grab.merge(other._grab);
COPY_PROPERTY_IF_CHANGED(xTextureURL);
COPY_PROPERTY_IF_CHANGED(yTextureURL);
@ -2172,6 +2181,26 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool);
ADD_PROPERTY_TO_MAP(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_FOLLOWS_CONTROLLER, Grab, grab, GrabFollowsController, grabFollowsController);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_TRIGGERABLE, Grab, grab, Triggerable, triggerable);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE, Grab, grab, Equippable, equippable);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, Grab, grab,
EquippableLeftPosition, equippableLeftPosition);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab,
EquippableLeftRotation, equippableLeftRotation);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, Grab, grab,
EquippableRightPosition, equippableRightPosition);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab,
EquippableRightRotation, equippableRightRotation);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, Grab, grab,
EquippableIndicatorURL, equippableIndicatorURL);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, Grab, grab,
EquippableIndicatorScale, equippableIndicatorScale);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab,
EquippableIndicatorOffset, equippableIndicatorOffset);
// FIXME - these are not yet handled
//ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64);
@ -2501,6 +2530,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, properties.getCloneLimit());
APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, properties.getCloneDynamic());
APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, properties.getCloneAvatarEntity());
_staticGrab.setProperties(properties);
_staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
}
if (propertyCount > 0) {
@ -2794,7 +2827,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FILTER_URL, QString, setFilterURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode);
properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
@ -2881,6 +2914,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_DYNAMIC, bool, setCloneDynamic);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity);
properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
return valid;
}
@ -3120,6 +3155,7 @@ void EntityItemProperties::markAllChanged() {
_skybox.markAllChanged();
_haze.markAllChanged();
_bloom.markAllChanged();
_grab.markAllChanged();
_sourceUrlChanged = true;
_voxelVolumeSizeChanged = true;
@ -3654,6 +3690,7 @@ QList<QString> EntityItemProperties::listChangedProperties() {
getSkybox().listChangedProperties(out);
getHaze().listChangedProperties(out);
getBloom().listChangedProperties(out);
getGrab().listChangedProperties(out);
return out;
}

View file

@ -292,6 +292,8 @@ public:
DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY);
DEFINE_PROPERTY_REF(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID);
DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup);
static QString getComponentModeString(uint32_t mode);
static QString getComponentModeAsString(uint32_t mode);

View file

@ -0,0 +1,207 @@
#include "EntityPropertyFlags.h"
QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) {
QString result = "[ ";
result = f.getHasProperty(PROP_PAGED_PROPERTY) ? result + "pagedProperty " : result;
result = f.getHasProperty(PROP_CUSTOM_PROPERTIES_INCLUDED) ? result + "customPropertiesIncluded " : result;
result = f.getHasProperty(PROP_VISIBLE) ? result + "visible " : result;
result = f.getHasProperty(PROP_CAN_CAST_SHADOW) ? result + "canCastShadow " : result;
result = f.getHasProperty(PROP_POSITION) ? result + "position " : result;
result = f.getHasProperty(PROP_DIMENSIONS) ? result + "dimensions " : result;
result = f.getHasProperty(PROP_ROTATION) ? result + "rotation " : result;
result = f.getHasProperty(PROP_DENSITY) ? result + "density " : result;
result = f.getHasProperty(PROP_VELOCITY) ? result + "velocity " : result;
result = f.getHasProperty(PROP_GRAVITY) ? result + "gravity " : result;
result = f.getHasProperty(PROP_DAMPING) ? result + "damping " : result;
result = f.getHasProperty(PROP_LIFETIME) ? result + "lifetime " : result;
result = f.getHasProperty(PROP_SCRIPT) ? result + "script " : result;
result = f.getHasProperty(PROP_COLOR) ? result + "color " : result;
result = f.getHasProperty(PROP_MODEL_URL) ? result + "modelUrl " : result;
result = f.getHasProperty(PROP_ANIMATION_URL) ? result + "animationUrl " : result;
result = f.getHasProperty(PROP_ANIMATION_FPS) ? result + "animationFps " : result;
result = f.getHasProperty(PROP_ANIMATION_FRAME_INDEX) ? result + "animationFrameIndex " : result;
result = f.getHasProperty(PROP_ANIMATION_PLAYING) ? result + "animationPlaying " : result;
result = f.getHasProperty(PROP_ANIMATION_ALLOW_TRANSLATION) ? result + "animationAllowTranslation " : result;
result = f.getHasProperty(PROP_RELAY_PARENT_JOINTS) ? result + "relayParentJoints " : result;
result = f.getHasProperty(PROP_REGISTRATION_POINT) ? result + "registrationPoint " : result;
result = f.getHasProperty(PROP_ANGULAR_VELOCITY) ? result + "angularVelocity " : result;
result = f.getHasProperty(PROP_ANGULAR_DAMPING) ? result + "angularDamping " : result;
result = f.getHasProperty(PROP_COLLISIONLESS) ? result + "collisionless " : result;
result = f.getHasProperty(PROP_DYNAMIC) ? result + "dynamic " : result;
result = f.getHasProperty(PROP_IS_SPOTLIGHT) ? result + "isSpotlight " : result;
result = f.getHasProperty(PROP_DIFFUSE_COLOR) ? result + "diffuseColor " : result;
result = f.getHasProperty(PROP_AMBIENT_COLOR_UNUSED) ? result + "ambientColorUnused " : result;
result = f.getHasProperty(PROP_SPECULAR_COLOR_UNUSED) ? result + "specularColorUnused " : result;
result = f.getHasProperty(PROP_INTENSITY) ? result + "intensity " : result;
result = f.getHasProperty(PROP_LINEAR_ATTENUATION_UNUSED) ? result + "linearAttenuationUnused " : result;
result = f.getHasProperty(PROP_QUADRATIC_ATTENUATION_UNUSED) ? result + "quadraticAttenuationUnused " : result;
result = f.getHasProperty(PROP_EXPONENT) ? result + "exponent " : result;
result = f.getHasProperty(PROP_CUTOFF) ? result + "cutoff " : result;
result = f.getHasProperty(PROP_LOCKED) ? result + "locked " : result;
result = f.getHasProperty(PROP_TEXTURES) ? result + "textures " : result;
result = f.getHasProperty(PROP_ANIMATION_SETTINGS_UNUSED) ? result + "animationSettingsUnused " : result;
result = f.getHasProperty(PROP_USER_DATA) ? result + "userData " : result;
result = f.getHasProperty(PROP_SHAPE_TYPE) ? result + "shapeType " : result;
result = f.getHasProperty(PROP_MAX_PARTICLES) ? result + "maxParticles " : result;
result = f.getHasProperty(PROP_LIFESPAN) ? result + "lifespan " : result;
result = f.getHasProperty(PROP_EMIT_RATE) ? result + "emitRate " : result;
result = f.getHasProperty(PROP_EMIT_SPEED) ? result + "emitSpeed " : result;
result = f.getHasProperty(PROP_EMIT_STRENGTH) ? result + "emitStrength " : result;
result = f.getHasProperty(PROP_EMIT_ACCELERATION) ? result + "emitAcceleration " : result;
result = f.getHasProperty(PROP_PARTICLE_RADIUS) ? result + "particleRadius " : result;
result = f.getHasProperty(PROP_COMPOUND_SHAPE_URL) ? result + "compoundShapeUrl " : result;
result = f.getHasProperty(PROP_MARKETPLACE_ID) ? result + "marketplaceID " : result;
result = f.getHasProperty(PROP_ACCELERATION) ? result + "acceleration " : result;
result = f.getHasProperty(PROP_SIMULATION_OWNER) ? result + "simulationOwner " : result;
result = f.getHasProperty(PROP_NAME) ? result + "name " : result;
result = f.getHasProperty(PROP_COLLISION_SOUND_URL) ? result + "collisionSoundUrl " : result;
result = f.getHasProperty(PROP_RESTITUTION) ? result + "restitution " : result;
result = f.getHasProperty(PROP_FRICTION) ? result + "friction " : result;
result = f.getHasProperty(PROP_VOXEL_VOLUME_SIZE) ? result + "voxelVolumeSize " : result;
result = f.getHasProperty(PROP_VOXEL_DATA) ? result + "voxelData " : result;
result = f.getHasProperty(PROP_VOXEL_SURFACE_STYLE) ? result + "voxelSurfaceStyle " : result;
result = f.getHasProperty(PROP_LINE_WIDTH) ? result + "lineWidth " : result;
result = f.getHasProperty(PROP_LINE_POINTS) ? result + "linePoints " : result;
result = f.getHasProperty(PROP_HREF) ? result + "href " : result;
result = f.getHasProperty(PROP_DESCRIPTION) ? result + "description " : result;
result = f.getHasProperty(PROP_FACE_CAMERA) ? result + "faceCamera " : result;
result = f.getHasProperty(PROP_SCRIPT_TIMESTAMP) ? result + "scriptTimestamp " : result;
result = f.getHasProperty(PROP_ACTION_DATA) ? result + "actionData " : result;
result = f.getHasProperty(PROP_X_TEXTURE_URL) ? result + "xTextureUrl " : result;
result = f.getHasProperty(PROP_Y_TEXTURE_URL) ? result + "yTextureUrl " : result;
result = f.getHasProperty(PROP_Z_TEXTURE_URL) ? result + "zTextureUrl " : result;
result = f.getHasProperty(PROP_NORMALS) ? result + "normals " : result;
result = f.getHasProperty(PROP_STROKE_COLORS) ? result + "strokeColors " : result;
result = f.getHasProperty(PROP_STROKE_WIDTHS) ? result + "strokeWidths " : result;
result = f.getHasProperty(PROP_IS_UV_MODE_STRETCH) ? result + "isUvModeStretch " : result;
result = f.getHasProperty(PROP_SPEED_SPREAD) ? result + "speedSpread " : result;
result = f.getHasProperty(PROP_ACCELERATION_SPREAD) ? result + "accelerationSpread " : result;
result = f.getHasProperty(PROP_X_N_NEIGHBOR_ID) ? result + "xNNeighborID " : result;
result = f.getHasProperty(PROP_Y_N_NEIGHBOR_ID) ? result + "yNNeighborID " : result;
result = f.getHasProperty(PROP_Z_N_NEIGHBOR_ID) ? result + "zNNeighborID " : result;
result = f.getHasProperty(PROP_X_P_NEIGHBOR_ID) ? result + "xPNeighborID " : result;
result = f.getHasProperty(PROP_Y_P_NEIGHBOR_ID) ? result + "yPNeighborID " : result;
result = f.getHasProperty(PROP_Z_P_NEIGHBOR_ID) ? result + "zPNeighborID " : result;
result = f.getHasProperty(PROP_RADIUS_SPREAD) ? result + "radiusSpread " : result;
result = f.getHasProperty(PROP_RADIUS_START) ? result + "radiusStart " : result;
result = f.getHasProperty(PROP_RADIUS_FINISH) ? result + "radiusFinish " : result;
result = f.getHasProperty(PROP_ALPHA) ? result + "alpha " : result;
result = f.getHasProperty(PROP_COLOR_SPREAD) ? result + "colorSpread " : result;
result = f.getHasProperty(PROP_COLOR_START) ? result + "colorStart " : result;
result = f.getHasProperty(PROP_COLOR_FINISH) ? result + "colorFinish " : result;
result = f.getHasProperty(PROP_ALPHA_SPREAD) ? result + "alphaSpread " : result;
result = f.getHasProperty(PROP_ALPHA_START) ? result + "alphaStart " : result;
result = f.getHasProperty(PROP_ALPHA_FINISH) ? result + "alphaFinish " : result;
result = f.getHasProperty(PROP_EMIT_ORIENTATION) ? result + "emitOrientation " : result;
result = f.getHasProperty(PROP_EMIT_DIMENSIONS) ? result + "emitDimensions " : result;
result = f.getHasProperty(PROP_EMIT_RADIUS_START) ? result + "emitRadiusStart " : result;
result = f.getHasProperty(PROP_POLAR_START) ? result + "polarStart " : result;
result = f.getHasProperty(PROP_POLAR_FINISH) ? result + "polarFinish " : result;
result = f.getHasProperty(PROP_AZIMUTH_START) ? result + "azimuthStart " : result;
result = f.getHasProperty(PROP_AZIMUTH_FINISH) ? result + "azimuthFinish " : result;
result = f.getHasProperty(PROP_ANIMATION_LOOP) ? result + "animationLoop " : result;
result = f.getHasProperty(PROP_ANIMATION_FIRST_FRAME) ? result + "animationFirstFrame " : result;
result = f.getHasProperty(PROP_ANIMATION_LAST_FRAME) ? result + "animationLastFrame " : result;
result = f.getHasProperty(PROP_ANIMATION_HOLD) ? result + "animationHold " : result;
result = f.getHasProperty(PROP_ANIMATION_START_AUTOMATICALLY) ? result + "animationStartAutomatically " : result;
result = f.getHasProperty(PROP_EMITTER_SHOULD_TRAIL) ? result + "emitterShouldTrail " : result;
result = f.getHasProperty(PROP_PARENT_ID) ? result + "parentID " : result;
result = f.getHasProperty(PROP_PARENT_JOINT_INDEX) ? result + "parentJointIndex " : result;
result = f.getHasProperty(PROP_LOCAL_POSITION) ? result + "localPosition " : result;
result = f.getHasProperty(PROP_LOCAL_ROTATION) ? result + "localRotation " : result;
result = f.getHasProperty(PROP_QUERY_AA_CUBE) ? result + "queryAaCube " : result;
result = f.getHasProperty(PROP_JOINT_ROTATIONS_SET) ? result + "jointRotationsSet " : result;
result = f.getHasProperty(PROP_JOINT_ROTATIONS) ? result + "jointRotations " : result;
result = f.getHasProperty(PROP_JOINT_TRANSLATIONS_SET) ? result + "jointTranslationsSet " : result;
result = f.getHasProperty(PROP_JOINT_TRANSLATIONS) ? result + "jointTranslations " : result;
result = f.getHasProperty(PROP_COLLISION_MASK) ? result + "collisionMask " : result;
result = f.getHasProperty(PROP_FALLOFF_RADIUS) ? result + "falloffRadius " : result;
result = f.getHasProperty(PROP_FLYING_ALLOWED) ? result + "flyingAllowed " : result;
result = f.getHasProperty(PROP_GHOSTING_ALLOWED) ? result + "ghostingAllowed " : result;
result = f.getHasProperty(PROP_CLIENT_ONLY) ? result + "clientOnly " : result;
result = f.getHasProperty(PROP_OWNING_AVATAR_ID) ? result + "owningAvatarID " : result;
result = f.getHasProperty(PROP_SHAPE) ? result + "shape " : result;
result = f.getHasProperty(PROP_DPI) ? result + "dpi " : result;
result = f.getHasProperty(PROP_LOCAL_VELOCITY) ? result + "localVelocity " : result;
result = f.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) ? result + "localAngularVelocity " : result;
result = f.getHasProperty(PROP_LAST_EDITED_BY) ? result + "lastEditedBy " : result;
result = f.getHasProperty(PROP_SERVER_SCRIPTS) ? result + "serverScripts " : result;
result = f.getHasProperty(PROP_FILTER_URL) ? result + "filterUrl " : result;
result = f.getHasProperty(PROP_ITEM_NAME) ? result + "itemName " : result;
result = f.getHasProperty(PROP_ITEM_DESCRIPTION) ? result + "itemDescription " : result;
result = f.getHasProperty(PROP_ITEM_CATEGORIES) ? result + "itemCategories " : result;
result = f.getHasProperty(PROP_ITEM_ARTIST) ? result + "itemArtist " : result;
result = f.getHasProperty(PROP_ITEM_LICENSE) ? result + "itemLicense " : result;
result = f.getHasProperty(PROP_LIMITED_RUN) ? result + "limitedRun " : result;
result = f.getHasProperty(PROP_EDITION_NUMBER) ? result + "editionNumber " : result;
result = f.getHasProperty(PROP_ENTITY_INSTANCE_NUMBER) ? result + "entityInstanceNumber " : result;
result = f.getHasProperty(PROP_CERTIFICATE_ID) ? result + "certificateID " : result;
result = f.getHasProperty(PROP_STATIC_CERTIFICATE_VERSION) ? result + "staticCertificateVersion " : result;
result = f.getHasProperty(PROP_CLONEABLE) ? result + "cloneable " : result;
result = f.getHasProperty(PROP_CLONE_LIFETIME) ? result + "cloneLifetime " : result;
result = f.getHasProperty(PROP_CLONE_LIMIT) ? result + "cloneLimit " : result;
result = f.getHasProperty(PROP_CLONE_DYNAMIC) ? result + "cloneDynamic " : result;
result = f.getHasProperty(PROP_CLONE_AVATAR_ENTITY) ? result + "cloneAvatarEntity " : result;
result = f.getHasProperty(PROP_CLONE_ORIGIN_ID) ? result + "cloneOriginID " : result;
result = f.getHasProperty(PROP_HAZE_MODE) ? result + "hazeMode " : result;
result = f.getHasProperty(PROP_KEYLIGHT_COLOR) ? result + "keylightColor " : result;
result = f.getHasProperty(PROP_KEYLIGHT_INTENSITY) ? result + "keylightIntensity " : result;
result = f.getHasProperty(PROP_KEYLIGHT_DIRECTION) ? result + "keylightDirection " : result;
result = f.getHasProperty(PROP_KEYLIGHT_CAST_SHADOW) ? result + "keylightCastShadow " : result;
result = f.getHasProperty(PROP_HAZE_RANGE) ? result + "hazeRange " : result;
result = f.getHasProperty(PROP_HAZE_COLOR) ? result + "hazeColor " : result;
result = f.getHasProperty(PROP_HAZE_GLARE_COLOR) ? result + "hazeGlareColor " : result;
result = f.getHasProperty(PROP_HAZE_ENABLE_GLARE) ? result + "hazeEnableGlare " : result;
result = f.getHasProperty(PROP_HAZE_GLARE_ANGLE) ? result + "hazeGlareAngle " : result;
result = f.getHasProperty(PROP_HAZE_ALTITUDE_EFFECT) ? result + "hazeAltitudeEffect " : result;
result = f.getHasProperty(PROP_HAZE_CEILING) ? result + "hazeCeiling " : result;
result = f.getHasProperty(PROP_HAZE_BASE_REF) ? result + "hazeBaseRef " : result;
result = f.getHasProperty(PROP_HAZE_BACKGROUND_BLEND) ? result + "hazeBackgroundBlend " : result;
result = f.getHasProperty(PROP_HAZE_ATTENUATE_KEYLIGHT) ? result + "hazeAttenuateKeylight " : result;
result = f.getHasProperty(PROP_HAZE_KEYLIGHT_RANGE) ? result + "hazeKeylightRange " : result;
result = f.getHasProperty(PROP_HAZE_KEYLIGHT_ALTITUDE) ? result + "hazeKeylightAltitude " : result;
result = f.getHasProperty(PROP_KEY_LIGHT_MODE) ? result + "keyLightMode " : result;
result = f.getHasProperty(PROP_AMBIENT_LIGHT_MODE) ? result + "ambientLightMode " : result;
result = f.getHasProperty(PROP_SKYBOX_MODE) ? result + "skyboxMode " : result;
result = f.getHasProperty(PROP_LOCAL_DIMENSIONS) ? result + "localDimensions " : result;
result = f.getHasProperty(PROP_MATERIAL_URL) ? result + "materialUrl " : result;
result = f.getHasProperty(PROP_MATERIAL_MAPPING_MODE) ? result + "materialMappingMode " : result;
result = f.getHasProperty(PROP_MATERIAL_PRIORITY) ? result + "materialPriority " : result;
result = f.getHasProperty(PROP_PARENT_MATERIAL_NAME) ? result + "parentMaterialName " : result;
result = f.getHasProperty(PROP_MATERIAL_MAPPING_POS) ? result + "materialMappingPos " : result;
result = f.getHasProperty(PROP_MATERIAL_MAPPING_SCALE) ? result + "materialMappingScale " : result;
result = f.getHasProperty(PROP_MATERIAL_MAPPING_ROT) ? result + "materialMappingRot " : result;
result = f.getHasProperty(PROP_MATERIAL_DATA) ? result + "materialData " : result;
result = f.getHasProperty(PROP_VISIBLE_IN_SECONDARY_CAMERA) ? result + "visibleInSecondaryCamera " : result;
result = f.getHasProperty(PROP_PARTICLE_SPIN) ? result + "particleSpin " : result;
result = f.getHasProperty(PROP_SPIN_START) ? result + "spinStart " : result;
result = f.getHasProperty(PROP_SPIN_FINISH) ? result + "spinFinish " : result;
result = f.getHasProperty(PROP_SPIN_SPREAD) ? result + "spinSpread " : result;
result = f.getHasProperty(PROP_PARTICLE_ROTATE_WITH_ENTITY) ? result + "particleRotateWithEntity " : result;
result = f.getHasProperty(PROP_BLOOM_INTENSITY) ? result + "bloomIntensity " : result;
result = f.getHasProperty(PROP_BLOOM_THRESHOLD) ? result + "bloomThreshold " : result;
result = f.getHasProperty(PROP_BLOOM_SIZE) ? result + "bloomSize " : result;
result = f.getHasProperty(PROP_GRAB_GRABBABLE) ? result + "grab.Grabbable " : result;
result = f.getHasProperty(PROP_GRAB_KINEMATIC) ? result + "grab.Kinematic " : result;
result = f.getHasProperty(PROP_GRAB_FOLLOWS_CONTROLLER) ? result + "grab.FollowsController " : result;
result = f.getHasProperty(PROP_GRAB_TRIGGERABLE) ? result + "grab.Triggerable " : result;
result = f.getHasProperty(PROP_GRAB_EQUIPPABLE) ? result + "grab.Equippable " : result;
result =
f.getHasProperty(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET) ? result + "grab.LeftEquippablePositionOffset " : result;
result =
f.getHasProperty(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET) ? result + "grab.LeftEquippableRotationOffset " : result;
result =
f.getHasProperty(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET) ? result + "grab.RightEquippablePositionOffset " : result;
result =
f.getHasProperty(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET) ? result + "grab.RightEquippableRotationOffset " : result;
result = f.getHasProperty(PROP_GRAB_EQUIPPABLE_INDICATOR_URL) ? result + "grab.EquippableIndicatorURL " : result;
result = f.getHasProperty(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE) ? result + "grab.EquippableIndicatorScale " : result;
result = f.getHasProperty(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET) ? result + "grab.EquippableIndicatorOffset " : result;
result += "]";
dbg.nospace() << result;
return dbg;
}

View file

@ -262,6 +262,19 @@ enum EntityPropertyList {
PROP_BLOOM_THRESHOLD,
PROP_BLOOM_SIZE,
PROP_GRAB_GRABBABLE,
PROP_GRAB_KINEMATIC,
PROP_GRAB_FOLLOWS_CONTROLLER,
PROP_GRAB_TRIGGERABLE,
PROP_GRAB_EQUIPPABLE,
PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET,
PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET,
PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET,
PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET,
PROP_GRAB_EQUIPPABLE_INDICATOR_URL,
PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE,
PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,
@ -304,5 +317,10 @@ typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
// one greater than the last item property due to the enum's auto-incrementing.
extern EntityPropertyList PROP_LAST_ITEM;
QString EntityPropertyFlagsToString(EntityPropertyFlags propertiesFlags);
QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f);
#endif // hifi_EntityPropertyFlags_h

View file

@ -668,7 +668,7 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) {
void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) {
EntityItemPointer entity = findEntityByEntityItemID(entityID);
if (entity) {
// remove clone ID from it's clone origin's clone ID list if clone origin exists
// remove clone ID from its clone origin's clone ID list if clone origin exists
const QUuid& cloneOriginID = entity->getCloneOriginID();
if (!cloneOriginID.isNull()) {
EntityItemPointer cloneOrigin = findEntityByID(cloneOriginID);
@ -2558,7 +2558,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
if (needsConversion && (properties.getType() == EntityTypes::EntityType::Zone)) {
// The legacy version had no keylight mode - this is set to on
properties.setKeyLightMode(COMPONENT_MODE_ENABLED);
// The ambient URL has been moved from "keyLight" to "ambientLight"
if (entityMap.contains("keyLight")) {
QVariantMap keyLightObject = entityMap["keyLight"].toMap();
@ -2629,6 +2629,108 @@ bool EntityTree::readFromMap(QVariantMap& map) {
}
}
// convert old grab-related userData to new grab properties
if (contentVersion < (int)EntityVersion::GrabProperties) {
QJsonObject userData = QJsonDocument::fromJson(properties.getUserData().toUtf8()).object();
QJsonObject grabbableKey = userData["grabbableKey"].toObject();
QJsonValue wantsTrigger = grabbableKey["wantsTrigger"];
GrabPropertyGroup& grabProperties = properties.getGrab();
if (wantsTrigger.isBool()) {
grabProperties.setTriggerable(wantsTrigger.toBool());
}
QJsonValue triggerable = grabbableKey["triggerable"];
if (triggerable.isBool()) {
grabProperties.setTriggerable(triggerable.toBool());
}
QJsonValue grabbable = grabbableKey["grabbable"];
if (grabbable.isBool()) {
grabProperties.setGrabbable(grabbable.toBool());
}
QJsonValue ignoreIK = grabbableKey["ignoreIK"];
if (ignoreIK.isBool()) {
grabProperties.setGrabFollowsController(ignoreIK.toBool());
}
QJsonValue kinematic = grabbableKey["kinematic"];
if (kinematic.isBool()) {
grabProperties.setGrabKinematic(kinematic.toBool());
}
if (grabbableKey["spatialKey"].isObject()) {
QJsonObject spatialKey = grabbableKey["spatialKey"].toObject();
grabProperties.setEquippable(true);
if (spatialKey["leftRelativePosition"].isObject()) {
grabProperties.setEquippableLeftPosition(qMapToVec3(spatialKey["leftRelativePosition"].toVariant()));
}
if (spatialKey["rightRelativePosition"].isObject()) {
grabProperties.setEquippableRightPosition(qMapToVec3(spatialKey["rightRelativePosition"].toVariant()));
}
if (spatialKey["relativeRotation"].isObject()) {
grabProperties.setEquippableLeftRotation(qMapToQuat(spatialKey["relativeRotation"].toVariant()));
grabProperties.setEquippableRightRotation(qMapToQuat(spatialKey["relativeRotation"].toVariant()));
}
}
QJsonObject wearable = userData["wearable"].toObject();
QJsonObject joints = wearable["joints"].toObject();
if (joints["LeftHand"].isArray()) {
QJsonArray leftHand = joints["LeftHand"].toArray();
if (leftHand.size() == 2) {
grabProperties.setEquippable(true);
grabProperties.setEquippableLeftPosition(qMapToVec3(leftHand[0].toVariant()));
grabProperties.setEquippableLeftRotation(qMapToQuat(leftHand[1].toVariant()));
}
}
if (joints["RightHand"].isArray()) {
QJsonArray rightHand = joints["RightHand"].toArray();
if (rightHand.size() == 2) {
grabProperties.setEquippable(true);
grabProperties.setEquippableRightPosition(qMapToVec3(rightHand[0].toVariant()));
grabProperties.setEquippableRightRotation(qMapToQuat(rightHand[1].toVariant()));
}
}
if (userData["equipHotspots"].isArray()) {
QJsonArray equipHotspots = userData["equipHotspots"].toArray();
if (equipHotspots.size() > 0) {
// just take the first one
QJsonObject firstHotSpot = equipHotspots[0].toObject();
QJsonObject joints = firstHotSpot["joints"].toObject();
if (joints["LeftHand"].isArray()) {
QJsonArray leftHand = joints["LeftHand"].toArray();
if (leftHand.size() == 2) {
grabProperties.setEquippable(true);
grabProperties.setEquippableLeftPosition(qMapToVec3(leftHand[0].toVariant()));
grabProperties.setEquippableLeftRotation(qMapToQuat(leftHand[1].toVariant()));
}
}
if (joints["RightHand"].isArray()) {
QJsonArray rightHand = joints["RightHand"].toArray();
if (rightHand.size() == 2) {
grabProperties.setEquippable(true);
grabProperties.setEquippableRightPosition(qMapToVec3(rightHand[0].toVariant()));
grabProperties.setEquippableRightRotation(qMapToQuat(rightHand[1].toVariant()));
}
}
QJsonValue indicatorURL = firstHotSpot["modelURL"];
if (indicatorURL.isString()) {
grabProperties.setEquippableIndicatorURL(indicatorURL.toString());
}
QJsonValue indicatorScale = firstHotSpot["modelScale"];
if (indicatorScale.isDouble()) {
grabProperties.setEquippableIndicatorScale(glm::vec3((float)indicatorScale.toDouble()));
} else if (indicatorScale.isObject()) {
grabProperties.setEquippableIndicatorScale(qMapToVec3(indicatorScale.toVariant()));
}
QJsonValue indicatorOffset = firstHotSpot["position"];
if (indicatorOffset.isObject()) {
grabProperties.setEquippableIndicatorOffset(qMapToVec3(indicatorOffset.toVariant()));
}
}
}
}
// Zero out the spread values that were fixed in version ParticleEntityFix so they behave the same as before
if (contentVersion < (int)EntityVersion::ParticleEntityFix) {
properties.setRadiusSpread(0.0f);

View file

@ -0,0 +1,303 @@
//
// GrabPropertyGroup.h
// libraries/entities/src
//
// Created by Seth Alves on 2018-8-8.
// Copyright 2018 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 "GrabPropertyGroup.h"
#include <OctreePacketData.h>
#include "EntityItemProperties.h"
#include "EntityItemPropertiesMacros.h"
void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties,
QScriptEngine* engine, bool skipDefaults,
EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_FOLLOWS_CONTROLLER, Grab, grab, GrabFollowsController, grabFollowsController);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_TRIGGERABLE, Grab, grab, Triggerable, triggerable);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE, Grab, grab, Equippable, equippable);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, Grab, grab,
EquippableLeftPosition, equippableLeftPosition);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab,
EquippableLeftRotation, equippableLeftRotation);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, Grab, grab,
EquippableRightPosition, equippableRightPosition);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab,
EquippableRightRotation, equippableRightRotation);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, Grab, grab,
EquippableIndicatorURL, equippableIndicatorURL);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, Grab, grab,
EquippableIndicatorScale, equippableIndicatorScale);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab,
EquippableIndicatorOffset, equippableIndicatorOffset);
}
void GrabPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabbable, bool, setGrabbable);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabKinematic, bool, setGrabKinematic);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabFollowsController, bool, setGrabFollowsController);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, triggerable, bool, setTriggerable);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippable, bool, setEquippable);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableLeftPosition, vec3, setEquippableLeftPosition);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableLeftRotation, quat, setEquippableLeftRotation);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableRightPosition, vec3, setEquippableRightPosition);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableRightRotation, quat, setEquippableRightRotation);
}
void GrabPropertyGroup::merge(const GrabPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(grabbable);
COPY_PROPERTY_IF_CHANGED(grabKinematic);
COPY_PROPERTY_IF_CHANGED(grabFollowsController);
COPY_PROPERTY_IF_CHANGED(triggerable);
COPY_PROPERTY_IF_CHANGED(equippable);
COPY_PROPERTY_IF_CHANGED(equippableLeftPosition);
COPY_PROPERTY_IF_CHANGED(equippableLeftRotation);
COPY_PROPERTY_IF_CHANGED(equippableRightPosition);
COPY_PROPERTY_IF_CHANGED(equippableRightRotation);
}
void GrabPropertyGroup::debugDump() const {
qCDebug(entities) << " GrabPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " _grabbable:" << _grabbable;
qCDebug(entities) << " _grabKinematic:" << _grabKinematic;
qCDebug(entities) << " _grabFollowsController:" << _grabFollowsController;
qCDebug(entities) << " _triggerable:" << _triggerable;
qCDebug(entities) << " _equippable:" << _equippable;
qCDebug(entities) << " _equippableLeftPosition:" << _equippableLeftPosition;
qCDebug(entities) << " _equippableLeftRotation:" << _equippableLeftRotation;
qCDebug(entities) << " _equippableRightPosition:" << _equippableRightPosition;
qCDebug(entities) << " _equippableRightRotation:" << _equippableRightRotation;
}
void GrabPropertyGroup::listChangedProperties(QList<QString>& out) {
if (grabbableChanged()) {
out << "grab-grabbable";
}
if (grabKinematicChanged()) {
out << "grab-grabKinematic";
}
if (grabFollowsControllerChanged()) {
out << "grab-followsController";
}
if (triggerableChanged()) {
out << "grab-triggerable";
}
if (equippableChanged()) {
out << "grab-equippable";
}
if (equippableLeftPositionChanged()) {
out << "grab-equippableLeftPosition";
}
if (equippableLeftRotationChanged()) {
out << "grab-equippableLeftRotation";
}
if (equippableRightPositionChanged()) {
out << "grab-equippableRightPosition";
}
if (equippableRightRotationChanged()) {
out << "grab-equippableRightRotation";
}
}
bool GrabPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, getGrabbable());
APPEND_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, getGrabKinematic());
APPEND_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, getGrabFollowsController());
APPEND_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, getTriggerable());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, getEquippable());
APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, getEquippableLeftPosition());
APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, getEquippableLeftRotation());
APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, getEquippableRightPosition());
APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, getEquippableRightRotation());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, getEquippableIndicatorURL());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, getEquippableIndicatorScale());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, getEquippableIndicatorOffset());
return true;
}
bool GrabPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0;
bool overwriteLocalData = true;
bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, bool, setGrabbable);
READ_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, bool, setGrabKinematic);
READ_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, bool, setGrabFollowsController);
READ_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, bool, setTriggerable);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, bool, setEquippable);
READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableLeftPosition);
READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableLeftRotation);
READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableRightPosition);
READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableRightRotation);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, QString, setEquippableIndicatorURL);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, glm::vec3, setEquippableIndicatorScale);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, glm::vec3, setEquippableIndicatorOffset);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_GRABBABLE, Grabbable);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_KINEMATIC, GrabKinematic);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_FOLLOWS_CONTROLLER, GrabFollowsController);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_TRIGGERABLE, Triggerable);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE, Equippable);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, EquippableLeftPosition);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, EquippableLeftRotation);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, EquippableRightPosition);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, EquippableRightRotation);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, EquippableIndicatorURL);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, EquippableIndicatorScale);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, EquippableIndicatorOffset);
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}
void GrabPropertyGroup::markAllChanged() {
_grabbableChanged = true;
_grabKinematicChanged = true;
_grabFollowsControllerChanged = true;
_triggerableChanged = true;
_equippableChanged = true;
_equippableLeftPositionChanged = true;
_equippableLeftRotationChanged = true;
_equippableRightPositionChanged = true;
_equippableRightRotationChanged = true;
}
EntityPropertyFlags GrabPropertyGroup::getChangedProperties() const {
EntityPropertyFlags changedProperties;
CHECK_PROPERTY_CHANGE(PROP_GRAB_GRABBABLE, grabbable);
CHECK_PROPERTY_CHANGE(PROP_GRAB_KINEMATIC, grabKinematic);
CHECK_PROPERTY_CHANGE(PROP_GRAB_FOLLOWS_CONTROLLER, grabFollowsController);
CHECK_PROPERTY_CHANGE(PROP_GRAB_TRIGGERABLE, triggerable);
CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE, equippable);
CHECK_PROPERTY_CHANGE(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, equippableLeftPosition);
CHECK_PROPERTY_CHANGE(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, equippableLeftRotation);
CHECK_PROPERTY_CHANGE(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, equippableRightPosition);
CHECK_PROPERTY_CHANGE(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, equippableRightRotation);
CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, equippableIndicatorURL);
CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, equippableIndicatorScale);
CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, equippableIndicatorOffset);
return changedProperties;
}
void GrabPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Grabbable, getGrabbable);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabKinematic, getGrabKinematic);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabFollowsController, getGrabFollowsController);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Triggerable, getTriggerable);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Equippable, getEquippable);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableLeftPosition, getEquippableLeftPosition);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableLeftRotation, getEquippableLeftRotation);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableRightPosition, getEquippableRightPosition);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableRightRotation, getEquippableRightRotation);
}
bool GrabPropertyGroup::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Grabbable, grabbable, setGrabbable);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabKinematic, grabKinematic, setGrabKinematic);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabFollowsController, grabFollowsController, setGrabFollowsController);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Triggerable, triggerable, setTriggerable);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Equippable, equippable, setEquippable);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableLeftPosition, equippableLeftPosition, setEquippableLeftPosition);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableLeftRotation, equippableLeftRotation, setEquippableLeftRotation);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableRightPosition, equippableRightPosition,
setEquippableRightPosition);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableRightRotation, equippableRightRotation,
setEquippableRightRotation);
return somethingChanged;
}
EntityPropertyFlags GrabPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_GRAB_GRABBABLE;
requestedProperties += PROP_GRAB_KINEMATIC;
requestedProperties += PROP_GRAB_FOLLOWS_CONTROLLER;
requestedProperties += PROP_GRAB_TRIGGERABLE;
requestedProperties += PROP_GRAB_EQUIPPABLE;
requestedProperties += PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET;
requestedProperties += PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET;
requestedProperties += PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET;
requestedProperties += PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET;
requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_URL;
requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE;
requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET;
return requestedProperties;
}
void GrabPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, getGrabbable());
APPEND_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, getGrabKinematic());
APPEND_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, getGrabFollowsController());
APPEND_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, getTriggerable());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, getEquippable());
APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, getEquippableLeftPosition());
APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, getEquippableLeftRotation());
APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, getEquippableRightPosition());
APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, getEquippableRightRotation());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, getEquippableIndicatorURL());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, getEquippableIndicatorScale());
APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, getEquippableIndicatorOffset());
}
int GrabPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, bool, setGrabbable);
READ_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, bool, setGrabKinematic);
READ_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, bool, setGrabFollowsController);
READ_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, bool, setTriggerable);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, bool, setEquippable);
READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableLeftPosition);
READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableLeftRotation);
READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableRightPosition);
READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableRightRotation);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, QString, setEquippableIndicatorURL);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, glm::vec3, setEquippableIndicatorScale);
READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, glm::vec3, setEquippableIndicatorOffset);
return bytesRead;
}

View file

@ -0,0 +1,141 @@
//
// GrabPropertyGroup.h
// libraries/entities/src
//
// Created by Seth Alves on 2018-8-8.
// Copyright 2018 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_GrabPropertyGroup_h
#define hifi_GrabPropertyGroup_h
#include <stdint.h>
#include <glm/glm.hpp>
#include <QtScript/QScriptEngine>
#include "PropertyGroup.h"
#include "EntityItemPropertiesMacros.h"
class EntityItemProperties;
class EncodeBitstreamParams;
class OctreePacketData;
class ReadBitstreamToTreeParams;
static const bool INITIAL_GRABBABLE { true };
static const bool INITIAL_KINEMATIC { true };
static const bool INITIAL_FOLLOWS_CONTROLLER { true };
static const bool INITIAL_TRIGGERABLE { false };
static const bool INITIAL_EQUIPPABLE { false };
static const glm::vec3 INITIAL_LEFT_EQUIPPABLE_POSITION { glm::vec3(0.0f) };
static const glm::quat INITIAL_LEFT_EQUIPPABLE_ROTATION { glm::quat() };
static const glm::vec3 INITIAL_RIGHT_EQUIPPABLE_POSITION { glm::vec3(0.0f) };
static const glm::quat INITIAL_RIGHT_EQUIPPABLE_ROTATION { glm::quat() };
static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_SCALE { glm::vec3(1.0f) };
static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) };
/**jsdoc
* Grab is defined by the following properties.
* @typedef {object} Entities.Grab
*
* @property {boolean} grabbable=true - If <code>true</code> the entity can be grabbed.
* @property {boolean} grabKinematic=true - If <code>true</code> the entity is updated in a kinematic manner.
* If <code>false</code> it will be grabbed using a tractor action. A kinematic grab will make the item appear more
* tightly held, but will cause it to behave poorly when interacting with dynamic entities.
* @property {boolean} grabFollowsController=true - If <code>true</code> the entity will follow the motions of the
* hand-controller even if the avatar's hand can't get to the implied position. This should be <code>true</code>
* for tools, pens, etc and false for things meant to decorate the hand.
*
* @property {boolean} triggerable=false - If <code>true</code> the entity will receive calls to trigger
* {@link Controller|Controller entity methods}.
*
* @property {boolean} equippable=true - If <code>true</code> the entity can be equipped.
* @property {Vec3} equippableLeftPosition=0,0,0 - Positional offset from the left hand, when equipped.
* @property {Quat} equippableLeftRotation=0,0,0,1 - Rotational offset from the left hand, when equipped.
* @property {Vec3} equippableRightPosition=0,0,0 - Positional offset from the right hand, when equipped.
* @property {Quat} equippableRightRotation=0,0,0,1 - Rotational offset from the right hand, when equipped.
*
* @property {string} equippableIndicatorURL="" - If non-empty, this model will be used to indicate that an
* entity is equippable, rather than the default.
* @property {Vec3} equippableIndicatorScale=1,1,1 - If equippableIndicatorURL is non-empty, this controls the
scale of the displayed overlay.
* @property {Vec3} equippableIndicatorOffset=0,0,0 - If equippableIndicatorURL is non-empty, this controls the
relative offset of the displayed overlay from the equippable entity.
*/
class GrabPropertyGroup : public PropertyGroup {
public:
// EntityItemProperty related helpers
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties,
QScriptEngine* engine, bool skipDefaults,
EntityItemProperties& defaultEntityProperties) const override;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override;
void merge(const GrabPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
// grab properties
DEFINE_PROPERTY(PROP_GRAB_GRABBABLE, Grabbable, grabbable, bool, INITIAL_GRABBABLE);
DEFINE_PROPERTY(PROP_GRAB_KINEMATIC, GrabKinematic, grabKinematic, bool, INITIAL_KINEMATIC);
DEFINE_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, GrabFollowsController, grabFollowsController, bool,
INITIAL_FOLLOWS_CONTROLLER);
DEFINE_PROPERTY(PROP_GRAB_TRIGGERABLE, Triggerable, triggerable, bool, INITIAL_TRIGGERABLE);
DEFINE_PROPERTY(PROP_GRAB_EQUIPPABLE, Equippable, equippable, bool, INITIAL_EQUIPPABLE);
DEFINE_PROPERTY_REF(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, EquippableLeftPosition, equippableLeftPosition,
glm::vec3, INITIAL_LEFT_EQUIPPABLE_POSITION);
DEFINE_PROPERTY_REF(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, EquippableLeftRotation, equippableLeftRotation,
glm::quat, INITIAL_LEFT_EQUIPPABLE_ROTATION);
DEFINE_PROPERTY_REF(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, EquippableRightPosition, equippableRightPosition,
glm::vec3, INITIAL_RIGHT_EQUIPPABLE_POSITION);
DEFINE_PROPERTY_REF(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, EquippableRightRotation, equippableRightRotation,
glm::quat, INITIAL_RIGHT_EQUIPPABLE_ROTATION);
DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, EquippableIndicatorURL, equippableIndicatorURL, QString, "");
DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, EquippableIndicatorScale, equippableIndicatorScale,
glm::vec3, INITIAL_EQUIPPABLE_INDICATOR_SCALE);
DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, EquippableIndicatorOffset, equippableIndicatorOffset,
glm::vec3, INITIAL_EQUIPPABLE_INDICATOR_OFFSET);
};
#endif // hifi_GrabPropertyGroup_h

View file

@ -33,14 +33,14 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::BloomEffect);
return static_cast<PacketVersion>(EntityVersion::GrabProperties);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity:
case PacketType::AvatarData:
case PacketType::BulkAvatarData:
case PacketType::KillAvatar:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::MigrateAvatarEntitiesToTraits);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FarGrabJointsRedux);
case PacketType::MessagesData:
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
// ICE packets

View file

@ -242,7 +242,8 @@ enum class EntityVersion : PacketVersion {
YieldSimulationOwnership,
ParticleEntityFix,
ParticleSpin,
BloomEffect
BloomEffect,
GrabProperties
};
enum class EntityScriptCallMethodVersion : PacketVersion {
@ -293,7 +294,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
ProceduralFaceMovementFlagsAndBlendshapes,
FarGrabJoints,
MigrateSkeletonURLToTraits,
MigrateAvatarEntitiesToTraits
MigrateAvatarEntitiesToTraits,
FarGrabJointsRedux
};
enum class DomainConnectRequestVersion : PacketVersion {

View file

@ -198,17 +198,17 @@ const unsigned char* OctreePacketData::getFinalizedData() {
int OctreePacketData::getFinalizedSize() {
if (!_enableCompression) {
return _bytesInUse;
return _bytesInUse;
}
if (_dirty) {
if (_debug) {
qCDebug(octree, "getFinalizedSize() _compressedBytes=%d _bytesInUse=%d",_compressedBytes, _bytesInUse);
}
compressContent();
compressContent();
}
return _compressedBytes;
return _compressedBytes;
}
@ -604,6 +604,9 @@ bool OctreePacketData::compressContent() {
memcpy(_compressed, compressedData.constData(), _compressedBytes);
_dirty = false;
success = true;
} else {
qCWarning(octree) << "OctreePacketData::compressContent -- compressedData.size >= MAX_OCTREE_PACKET_DATA_SIZE";
assert(false);
}
return success;
}
@ -623,11 +626,16 @@ void OctreePacketData::loadFinalizedContent(const unsigned char* data, int lengt
memcpy(compressedData.data(), data, _compressedBytes);
QByteArray uncompressedData = qUncompress(compressedData);
if (uncompressedData.size() <= _bytesAvailable) {
_bytesInUse = uncompressedData.size();
_bytesAvailable -= uncompressedData.size();
memcpy(_uncompressed, uncompressedData.constData(), _bytesInUse);
if (uncompressedData.size() > _bytesAvailable) {
int moreNeeded = uncompressedData.size() - _bytesAvailable;
_uncompressedByteArray.resize(_uncompressedByteArray.size() + moreNeeded);
_uncompressed = (unsigned char*)_uncompressedByteArray.data();
_bytesAvailable += moreNeeded;
}
_bytesInUse = uncompressedData.size();
_bytesAvailable -= uncompressedData.size();
memcpy(_uncompressed, uncompressedData.constData(), _bytesInUse);
} else {
memcpy(_uncompressed, data, length);
memcpy(_compressed, data, length);

View file

@ -10,7 +10,7 @@ var uuid = Entities.addEntity({
maxVolume: 0.1,
range: 25,
disabled: true,
grabbableKey: { wantsTrigger: true },
grab: { triggerable: true }
}),
lifetime: 600,
});

View file

@ -1,7 +1,7 @@
"use strict";
/* jslint bitwise: true */
/* global Script, Entities, MyAvatar, Vec3, Quat, Mat4 */
/* global Script, Entities, MyAvatar, Vec3, Quat, Mat4, Overlays */
(function() { // BEGIN LOCAL_SCOPE
@ -19,7 +19,7 @@
var sectionCenterB = 0;
var sectionCenterSign = 0;
var yFlip = 0;
var objects = [];
var overlays = [];
@ -35,41 +35,41 @@
createPropsCube(index, false, false, true, true);
createPropsModel(index, false, false, true, true);
createSign(index, "Clone Dynamic Entity");
};
}
function createCloneEntity(index) {
createPropsCube(index, false, false, true, false);
createPropsModel(index, false, false, true, false);
createSign(index, "Clone Non-Dynamic Entity");
};
}
function createNearGrabOverlay(index) {
createPropsCubeOverlay(index, false, false, true, true);
createPropsModelOverlay(index, false, false, true, true);
createSign(index, "Near Grab Overlay");
};
}
function createNearGrabEntity(index) {
createPropsCube(index, false, false, false, false);
createPropsModel(index, false, false, false, false);
createSign(index, "Near Grab Entity");
};
}
function createFarGrabEntity(index) {
createPropsCube(index, true, false, false, false);
createPropsModel(index, true, false, false, false);
createSign(index, "Far Grab Entity");
};
}
function createPropsModel(i, dynamic, collisionless, clone, cloneDynamic) {
var propsModel = {
name: "controller-tests model object " + i,
type: "Model",
modelURL: "http://headache.hungry.com/~seth/hifi/controller-tests/color-cube.obj",
position: sectionCenterA,
rotation: sectionRotation,
gravity: (dynamic && !collisionless) ? { x: 0, y: -1, z: 0 } : { x: 0, y: 0, z: 0 },
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
userData: JSON.stringify({
@ -270,8 +270,8 @@
Entities.deleteEntity(nearbyID);
}
for (var i = 0; i < overlays.length; i++) {
var overlayID = overlays[i];
for (var j = 0; j < overlays.length; j++) {
var overlayID = overlays[j];
Overlays.deleteOverlay(overlayID);
}
});

View file

@ -329,36 +329,18 @@ function isGrabbable(entityID) {
return false;
}
var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'userData']);
var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'grab.grabbable']);
if (properties.clientOnly) {
var userData;
try {
userData = JSON.parse(properties.userData);
} catch (e) {
userData = {};
}
return userData.grabbableKey && userData.grabbableKey.grabbable;
return properties.grab.grabbable;
}
return false;
}
function setGrabbable(entityID, grabbable) {
var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'userData']);
var properties = Entities.getEntityProperties(entityID, ['clientOnly']);
if (properties.clientOnly) {
var userData;
try {
userData = JSON.parse(properties.userData);
} catch (e) {
userData = {};
}
if (userData.grabbableKey === undefined) {
userData.grabbableKey = {};
}
userData.grabbableKey.grabbable = grabbable;
Entities.editEntity(entityID, {userData: JSON.stringify(userData)});
Entities.editEntity(entityID, { grab: { grabbable: grabbable }});
}
}

View file

@ -10,9 +10,8 @@
/* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation,
controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true,
LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES,
getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, COLORS_GRAB_SEARCHING_HALF_SQUEEZE
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, TRIGGER_ON_VALUE, PointerManager, print
getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers,
PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers,
PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE
*/
@ -34,6 +33,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
var PROFILE = false;
var DEBUG = false;
var SHOW_GRAB_SPHERE = false;
if (typeof Test !== "undefined") {
PROFILE = true;
@ -51,6 +52,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
this.tabletID = null;
this.blacklist = [];
this.pointerManager = new PointerManager();
this.grabSphereOverlays = [null, null];
// a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are
// not set to false (not in use), a module cannot start. When a module is using a slot, that module's name
@ -251,7 +253,28 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
for (h = LEFT_HAND; h <= RIGHT_HAND; h++) {
if (controllerLocations[h].valid) {
var controllerPosition = controllerLocations[h].position;
var nearbyEntityIDs = Entities.findEntities(controllerPosition, NEAR_MAX_RADIUS * sensorScaleFactor);
var findRadius = NEAR_MAX_RADIUS * sensorScaleFactor;
if (SHOW_GRAB_SPHERE) {
if (this.grabSphereOverlays[h]) {
Overlays.editOverlay(this.grabSphereOverlays[h], { position: controllerLocations[h].position });
} else {
var grabSphereSize = findRadius * 2;
this.grabSphereOverlays[h] = Overlays.addOverlay("sphere", {
position: controllerLocations[h].position,
dimensions: { x: grabSphereSize, y: grabSphereSize, z: grabSphereSize },
color: { red: 30, green: 30, blue: 255 },
alpha: 0.3,
solid: true,
visible: true,
// lineWidth: 2.0,
drawInFront: false,
grabbable: false
});
}
}
var nearbyEntityIDs = Entities.findEntities(controllerPosition, findRadius);
for (var j = 0; j < nearbyEntityIDs.length; j++) {
var entityID = nearbyEntityIDs[j];
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);

View file

@ -7,7 +7,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* globals createControllerDisplay:true deleteControllerDisplay:true */
/* globals createControllerDisplay:true, deleteControllerDisplay:true, Controller, Overlays, Vec3, MyAvatar, Quat */
function clamp(value, min, max) {
if (value < min) {
@ -188,7 +188,7 @@ createControllerDisplay = function(config) {
for (var partName in controller.parts) {
var part = controller.parts[partName];
var localPosition = Vec3.subtract(part.naturalPosition, controller.naturalPosition);
var localRotation = { x: 0, y: 0, z: 0, w: 1 }
var localRotation = { x: 0, y: 0, z: 0, w: 1 };
controllerDisplay.parts[partName] = controller.parts[partName];
@ -203,7 +203,7 @@ createControllerDisplay = function(config) {
if (part.defaultTextureLayer) {
var textures = {};
textures[part.textureName] = part.textureLayers[part.defaultTextureLayer].defaultTextureURL;
properties['textures'] = textures;
properties.textures = textures;
}
var overlayID = Overlays.addOverlay("model", properties);

View file

@ -7,8 +7,9 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* globals ControllerDisplayManager:true createControllerDisplay deleteControllerDisplay
VIVE_CONTROLLER_CONFIGURATION_LEFT VIVE_CONTROLLER_CONFIGURATION_RIGHT */
/* globals ControllerDisplayManager:true, createControllerDisplay, deleteControllerDisplay,
VIVE_CONTROLLER_CONFIGURATION_LEFT, VIVE_CONTROLLER_CONFIGURATION_RIGHT, Script, HMD, Controller,
MyAvatar, Overlays, TOUCH_CONTROLLER_CONFIGURATION_LEFT, TOUCH_CONTROLLER_CONFIGURATION_RIGHT, Messages */
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
(function () {
@ -93,7 +94,7 @@ ControllerDisplayManager = function() {
if (controllerRight) {
controllerRight.resize(sensorScaleFactor);
}
};
}
var handleMessages = function(channel, message, sender) {
var i, data, name, visible;

View file

@ -58,18 +58,16 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
if (channel === 'Hifi-Hand-Disabler') {
if (message === 'left') {
leftDisableModules.disableModules = true;
}
if (message === 'right') {
} else if (message === 'right') {
rightDisableModules.disableModules = true;
}
if (message === 'both' || message === 'none') {
if (message === 'both') {
leftDisableModules.disableModules = true;
rightDisableModules.disableModules = true;
} else if (message === 'none') {
leftDisableModules.disableModules = false;
rightDisableModules.disableModules = false;
}
} else if (message === 'both') {
leftDisableModules.disableModules = true;
rightDisableModules.disableModules = true;
} else if (message === 'none') {
leftDisableModules.disableModules = false;
rightDisableModules.disableModules = false;
} else {
print("disableOtherModule -- unknown command: " + message);
}
}
}

View file

@ -6,11 +6,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera,
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print,
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther,
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode
cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode, getGrabbableData
*/
Script.include("/~/system/libraries/Xform.js");
@ -66,12 +66,16 @@ EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) {
overlays: []
};
var diameter = hotspot.radius * 2;
var dimensions = hotspot.radius * 2 * EQUIP_SPHERE_SCALE_FACTOR;
if (hotspot.indicatorURL) {
dimensions = hotspot.indicatorScale;
}
// override default sphere with a user specified model, if it exists.
overlayInfoSet.overlays.push(Overlays.addOverlay("model", {
name: "hotspot overlay",
url: hotspot.modelURL ? hotspot.modelURL : DEFAULT_SPHERE_MODEL_URL,
url: hotspot.indicatorURL ? hotspot.indicatorURL : DEFAULT_SPHERE_MODEL_URL,
position: hotspot.worldPosition,
rotation: {
x: 0,
@ -79,8 +83,7 @@ EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) {
z: 0,
w: 1
},
dimensions: diameter * EQUIP_SPHERE_SCALE_FACTOR,
scale: hotspot.modelScale,
dimensions: dimensions,
ignoreRayIntersection: true
}));
overlayInfoSet.type = "model";
@ -137,8 +140,13 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
var position = entityXform.xformPoint(overlayInfoSet.localPosition);
var dimensions;
if (overlayInfoSet.type === "sphere") {
dimensions = (overlayInfoSet.hotspot.radius / 2) * overlayInfoSet.currentSize * EQUIP_SPHERE_SCALE_FACTOR;
if (overlayInfoSet.hotspot.indicatorURL) {
var ratio = overlayInfoSet.currentSize / overlayInfoSet.targetSize;
dimensions = {
x: overlayInfoSet.hotspot.dimensions.x * ratio,
y: overlayInfoSet.hotspot.dimensions.y * ratio,
z: overlayInfoSet.hotspot.dimensions.z * ratio
};
} else {
dimensions = (overlayInfoSet.hotspot.radius / 2) * overlayInfoSet.currentSize;
}
@ -158,12 +166,21 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
};
var alreadyWarned = {};
function warnAboutUserData(props) {
if (alreadyWarned[props.id]) {
return;
}
print("Warning -- overriding grab properties with userData for " + props.id + " / " + props.name);
alreadyWarned[props.id] = true;
}
(function() {
var ATTACH_POINT_SETTINGS = "io.highfidelity.attachPoints";
var EQUIP_RADIUS = 1.0; // radius used for palm vs equip-hotspot for equipping.
var HAPTIC_PULSE_STRENGTH = 1.0;
var HAPTIC_PULSE_DURATION = 13.0;
var HAPTIC_TEXTURE_STRENGTH = 0.1;
@ -176,36 +193,86 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
var TRIGGER_OFF_VALUE = 0.1;
var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab
var BUMPER_ON_VALUE = 0.5;
var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}";
var UNEQUIP_KEY = "u";
function getWearableData(props) {
var wearable = {};
try {
if (!props.userDataParsed) {
props.userDataParsed = JSON.parse(props.userData);
}
if (props.grab.equippable) {
// if equippable is true, we know this was already converted from the old userData style to properties
return {
joints: {
LeftHand: [ props.grab.equippableLeftPosition, props.grab.equippableLeftRotation ],
RightHand: [ props.grab.equippableRightPosition, props.grab.equippableRightRotation ]
},
indicatorURL: props.grab.equippableIndicatorURL,
indicatorScale: props.grab.equippableIndicatorScale,
indicatorOffset: props.grab.equippableIndicatorOffset
};
} else {
// check for old userData equippability. The JSON reader will convert userData to properties
// in EntityTree.cpp, but this won't catch things created from scripts or some items in
// the market. Eventually we'll remove this section.
try {
if (!props.userDataParsed) {
props.userDataParsed = JSON.parse(props.userData);
}
var userDataParsed = props.userDataParsed;
wearable = props.userDataParsed.wearable ? props.userDataParsed.wearable : {};
} catch (err) {
// don't want to spam the logs
}
return wearable;
}
function getEquipHotspotsData(props) {
var equipHotspots = [];
try {
if (!props.userDataParsed) {
props.userDataParsed = JSON.parse(props.userData);
}
// userData: { wearable: { joints: { LeftHand: {...}, RightHand: {...} } } }
if (userDataParsed.wearable && userDataParsed.wearable.joints) {
warnAboutUserData(props);
userDataParsed.wearable.indicatorURL = "";
userDataParsed.wearable.indicatorScale = { x: 1, y: 1, z: 1 };
userDataParsed.wearable.indicatorOffset = { x: 0, y: 0, z: 0 };
return userDataParsed.wearable;
}
equipHotspots = props.userDataParsed.equipHotspots ? props.userDataParsed.equipHotspots : [];
} catch (err) {
// don't want to spam the logs
// userData: { equipHotspots: { joints: { LeftHand: {...}, RightHand: {...} } } }
// https://highfidelity.atlassian.net/wiki/spaces/HOME/pages/51085337/Authoring+Equippable+Entities
if (userDataParsed.equipHotspots &&
userDataParsed.equipHotspots.length > 0 &&
userDataParsed.equipHotspots[0].joints) {
warnAboutUserData(props);
var hotSpot = userDataParsed.equipHotspots[0];
var indicatorScale = { x: hotSpot.radius, y: hotSpot.radius, z: hotSpot.radius };
if (hotSpot.modelURL && hotSpot.modelURL !== "") {
indicatorScale = hotSpot.modelScale;
}
return {
joints: hotSpot.joints,
indicatorURL: hotSpot.modelURL,
indicatorScale: indicatorScale,
indicatorOffset: hotSpot.position,
};
}
// userData:{grabbableKey:{spatialKey:{leftRelativePosition:{...},rightRelativePosition:{...}}}}
if (userDataParsed.grabbableKey &&
userDataParsed.grabbableKey.spatialKey) {
warnAboutUserData(props);
var joints = {};
joints.LeftHand = [ { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 } ];
joints.RightHand = [ { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 } ];
if (userDataParsed.grabbableKey.spatialKey.leftRelativePosition) {
joints.LeftHand = [userDataParsed.grabbableKey.spatialKey.leftRelativePosition,
userDataParsed.grabbableKey.spatialKey.relativeRotation];
}
if (userDataParsed.grabbableKey.spatialKey.rightRelativePosition) {
joints.RightHand = [userDataParsed.grabbableKey.spatialKey.rightRelativePosition,
userDataParsed.grabbableKey.spatialKey.relativeRotation];
}
return { joints: joints };
}
} catch (err) {
// don't spam logs
}
return null;
}
return equipHotspots;
}
function getAttachPointSettings() {
@ -275,7 +342,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.handHasBeenRightsideUp = false;
this.parameters = makeDispatcherModuleParameters(
300,
115,
this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip"] : ["leftHand", "leftHandEquip"],
[],
100);
@ -299,51 +366,29 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
// * radius {number} radius of equip hotspot
// * joints {Object} keys are joint names values are arrays of two elements:
// offset position {Vec3} and offset rotation {Quat}, both are in the coordinate system of the joint.
// * modelURL {string} url for model to use instead of default sphere.
// * modelScale {Vec3} scale factor for model
// * indicatorURL {string} url for model to use instead of default sphere.
// * indicatorScale {Vec3} scale factor for model
this.collectEquipHotspots = function(props) {
var result = [];
var entityID = props.id;
var entityXform = new Xform(props.rotation, props.position);
var equipHotspotsProps = getEquipHotspotsData(props);
if (equipHotspotsProps && equipHotspotsProps.length > 0) {
var i, length = equipHotspotsProps.length;
for (i = 0; i < length; i++) {
var hotspot = equipHotspotsProps[i];
if (hotspot.position && hotspot.radius && hotspot.joints) {
result.push({
key: entityID.toString() + i.toString(),
entityID: entityID,
localPosition: hotspot.position,
worldPosition: entityXform.xformPoint(hotspot.position),
radius: hotspot.radius,
joints: hotspot.joints,
modelURL: hotspot.modelURL,
modelScale: hotspot.modelScale
});
}
}
} else {
var wearableProps = getWearableData(props);
var sensorToScaleFactor = MyAvatar.sensorToWorldScale;
if (wearableProps && wearableProps.joints) {
result.push({
key: entityID.toString() + "0",
entityID: entityID,
localPosition: {
x: 0,
y: 0,
z: 0
},
worldPosition: entityXform.pos,
radius: EQUIP_RADIUS * sensorToScaleFactor,
joints: wearableProps.joints,
modelURL: null,
modelScale: null
});
}
var wearableProps = getWearableData(props);
var sensorToScaleFactor = MyAvatar.sensorToWorldScale;
if (wearableProps && wearableProps.joints) {
result.push({
key: entityID.toString() + "0",
entityID: entityID,
localPosition: wearableProps.indicatorOffset,
worldPosition: entityXform.pos,
radius: ((wearableProps.indicatorScale.x +
wearableProps.indicatorScale.y +
wearableProps.indicatorScale.z) / 3) * sensorToScaleFactor,
dimensions: wearableProps.indicatorScale,
joints: wearableProps.joints,
indicatorURL: wearableProps.indicatorURL,
indicatorScale: wearableProps.indicatorScale,
});
}
return result;
};
@ -492,7 +537,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
};
Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message));
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID);
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
var grabData = getGrabbableData(grabbedProperties);
// if an object is "equipped" and has a predefined offset, use it.
if (this.grabbedHotspot) {
@ -510,7 +556,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
var handJointIndex;
if (this.ignoreIK) {
if (grabData.grabFollowsController) {
handJointIndex = this.controllerJointIndex;
} else {
handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
@ -796,7 +842,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
if (intersection.intersects) {
var entityID = intersection.entityID;
var entityProperties = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
var hasEquipData = getWearableData(entityProperties).joints || getEquipHotspotsData(entityProperties).length > 0;
entityProperties.id = entityID;
var hasEquipData = getWearableData(entityProperties);
if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) {
entityProperties.id = entityID;
var rightHandPosition = MyAvatar.getJointPosition("RightHand");
@ -804,7 +851,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition);
var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition);
var leftHandAvailable = leftEquipEntity.targetEntityID === null;
var rightHandAvailable = rightEquipEntity.targetEntityID === null;
var rightHandAvailable = rightEquipEntity.targetEntityID === null;
if (rightHandAvailable && (distanceToRightHand < distanceToLeftHand || !leftHandAvailable)) {
// clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags)
clearGrabActions(entityID);
@ -817,7 +864,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
}
};
var onKeyPress = function(event) {
if (event.text.toLowerCase() === UNEQUIP_KEY) {
if (rightEquipEntity.targetEntityID) {
@ -828,7 +875,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
}
};
var deleteEntity = function(entityID) {
if (rightEquipEntity.targetEntityID === entityID) {
rightEquipEntity.endEquipEntity();
@ -837,7 +884,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
leftEquipEntity.endEquipEntity();
}
};
var clearEntities = function() {
if (rightEquipEntity.targetEntityID) {
rightEquipEntity.endEquipEntity();
@ -846,7 +893,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
leftEquipEntity.endEquipEntity();
}
};
Messages.subscribe('Hifi-Hand-Grab');
Messages.subscribe('Hifi-Hand-Drop');
Messages.messageReceived.connect(handleMessage);

View file

@ -8,38 +8,19 @@
/* jslint bitwise: true */
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat,
getGrabPointSphereOffset, getEnabledModuleByName, makeRunningValues, Entities,
getEnabledModuleByName, makeRunningValues, Entities,
enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable, entityIsGrabbable,
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,
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI
Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST,
worldPositionToRegistrationFrameMatrix
TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD,
Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST,
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, Uuid, Picks
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
Script.include("/~/system/libraries/Xform.js");
(function() {
var GRABBABLE_PROPERTIES = [
"position",
"registrationPoint",
"rotation",
"gravity",
"collidesWith",
"dynamic",
"collisionless",
"locked",
"name",
"shapeType",
"parentID",
"parentJointIndex",
"density",
"dimensions",
"userData"
];
var MARGIN = 25;
@ -106,9 +87,9 @@ Script.include("/~/system/libraries/Xform.js");
this.locked = false;
this.highlightedEntity = null;
this.reticleMinX = MARGIN;
this.reticleMaxX;
this.reticleMaxX = null;
this.reticleMinY = MARGIN;
this.reticleMaxY;
this.reticleMaxY = null;
this.ignoredEntities = [];
@ -212,7 +193,7 @@ Script.include("/~/system/libraries/Xform.js");
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES);
var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES);
var now = Date.now();
var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
this.currentObjectTime = now;
@ -329,7 +310,7 @@ Script.include("/~/system/libraries/Xform.js");
this.notPointingAtEntity = function(controllerData) {
var intersection = controllerData.rayPicks[this.hand];
var entityProperty = Entities.getEntityProperties(intersection.objectID);
var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES);
var entityType = entityProperty.type;
var hudRayPick = controllerData.hudRayPicks[this.hand];
var point2d = this.calculateNewReticlePosition(hudRayPick.intersection);
@ -373,7 +354,7 @@ Script.include("/~/system/libraries/Xform.js");
var worldControllerPosition = controllerLocation.position;
var worldControllerRotation = controllerLocation.orientation;
var grabbedProperties = Entities.getEntityProperties(intersection.objectID, GRABBABLE_PROPERTIES);
var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES);
this.currentObjectPosition = grabbedProperties.position;
this.grabRadius = intersection.distance;
@ -395,7 +376,7 @@ Script.include("/~/system/libraries/Xform.js");
};
this.targetIsNull = function() {
var properties = Entities.getEntityProperties(this.grabbedThingID);
var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES);
if (Object.keys(properties).length === 0 && this.distanceHolding) {
return true;
}
@ -460,8 +441,8 @@ Script.include("/~/system/libraries/Xform.js");
// if we are doing a distance grab and the object or tablet gets close enough to the controller,
// stop the far-grab so the near-grab or equip can take over.
for (var k = 0; k < nearGrabReadiness.length; k++) {
if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID
|| HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) {
if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID ||
HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) {
this.endFarGrabAction();
this.restoreIgnoredEntities();
return makeRunningValues(false, [], []);
@ -487,11 +468,7 @@ Script.include("/~/system/libraries/Xform.js");
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
var targetProps = Entities.getEntityProperties(entityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
if (targetProps.href !== "") {
AddressManager.handleLookupString(targetProps.href);
this.restoreIgnoredEntities();
@ -540,11 +517,7 @@ Script.include("/~/system/libraries/Xform.js");
if (this.highlightedEntity !== targetEntityID) {
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps);
selectionTargetObject.parentProps = getEntityParents(selectionTargetProps);
@ -574,11 +547,12 @@ Script.include("/~/system/libraries/Xform.js");
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var props = Entities.getEntityProperties(rayPickInfo.objectID);
var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse
pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, rayPickInfo.intersection, props),
pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID,
rayPickInfo.intersection, props),
pos3D: rayPickInfo.intersection,
normal: rayPickInfo.surfaceNormal,
direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal),

View file

@ -11,32 +11,14 @@
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable,
makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE,
TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD,
Picks, makeLaserLockInfo, Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST,
Uuid, worldPositionToRegistrationFrameMatrix
Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST,
Uuid, worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
Script.include("/~/system/libraries/Xform.js");
(function() {
var GRABBABLE_PROPERTIES = [
"position",
"registrationPoint",
"rotation",
"gravity",
"collidesWith",
"dynamic",
"collisionless",
"locked",
"name",
"shapeType",
"parentID",
"parentJointIndex",
"density",
"dimensions",
"userData"
];
var MARGIN = 25;
@ -45,7 +27,6 @@ Script.include("/~/system/libraries/Xform.js");
this.entityProps = entityProps;
this.targetEntityID = null;
this.targetEntityProps = null;
this.previousCollisionStatus = null;
this.getTargetEntity = function() {
var parentPropsLength = this.parentProps.length;
@ -74,7 +55,6 @@ Script.include("/~/system/libraries/Xform.js");
this.potentialEntityWithContextOverlay = false;
this.entityWithContextOverlay = false;
this.contextOverlayTimer = false;
this.previousCollisionStatus = false;
this.locked = false;
this.highlightedEntity = null;
this.reticleMinX = MARGIN;
@ -182,7 +162,7 @@ Script.include("/~/system/libraries/Xform.js");
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES);
var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES);
var now = Date.now();
var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
this.currentObjectTime = now;
@ -284,7 +264,7 @@ Script.include("/~/system/libraries/Xform.js");
this.notPointingAtEntity = function(controllerData) {
var intersection = controllerData.rayPicks[this.hand];
var entityProperty = Entities.getEntityProperties(intersection.objectID);
var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES);
var entityType = entityProperty.type;
var hudRayPick = controllerData.hudRayPicks[this.hand];
var point2d = this.calculateNewReticlePosition(hudRayPick.intersection);
@ -319,7 +299,7 @@ Script.include("/~/system/libraries/Xform.js");
var worldControllerPosition = controllerLocation.position;
var worldControllerRotation = controllerLocation.orientation;
var grabbedProperties = Entities.getEntityProperties(intersection.objectID, GRABBABLE_PROPERTIES);
var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES);
this.currentObjectPosition = grabbedProperties.position;
this.grabRadius = intersection.distance;
@ -341,7 +321,7 @@ Script.include("/~/system/libraries/Xform.js");
};
this.targetIsNull = function() {
var properties = Entities.getEntityProperties(this.grabbedThingID);
var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES);
if (Object.keys(properties).length === 0 && this.distanceHolding) {
return true;
}
@ -351,7 +331,7 @@ Script.include("/~/system/libraries/Xform.js");
this.getTargetProps = function (controllerData) {
var targetEntityID = controllerData.rayPicks[this.hand].objectID;
if (targetEntityID) {
return Entities.getEntityProperties(targetEntityID);
return Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
}
return null;
};
@ -435,11 +415,7 @@ Script.include("/~/system/libraries/Xform.js");
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
var targetProps = Entities.getEntityProperties(entityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
if (targetProps.href !== "") {
AddressManager.handleLookupString(targetProps.href);
return makeRunningValues(false, [], []);
@ -488,11 +464,7 @@ Script.include("/~/system/libraries/Xform.js");
if (this.highlightedEntity !== targetEntityID) {
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps);
selectionTargetObject.parentProps = getEntityParents(selectionTargetProps);
@ -522,7 +494,8 @@ Script.include("/~/system/libraries/Xform.js");
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var pEvProps = Entities.getEntityProperties(rayPickInfo.objectID);
var pEvProps = Entities.getEntityProperties(rayPickInfo.objectID,
DISPATCHER_PROPERTIES);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse

View file

@ -10,34 +10,15 @@
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Quat, getEnabledModuleByName, makeRunningValues,
Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC,
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation,
projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, Xform, makeLaserParams, AddressManager,
projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager,
getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, Uuid, findGroupParent,
worldPositionToRegistrationFrameMatrix
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, findFarGrabJointChildEntities
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
Script.include("/~/system/libraries/Xform.js");
(function() {
var GRABBABLE_PROPERTIES = [
"position",
"registrationPoint",
"rotation",
"gravity",
"collidesWith",
"dynamic",
"collisionless",
"locked",
"name",
"shapeType",
"parentID",
"parentJointIndex",
"density",
"dimensions",
"userData"
];
var MARGIN = 25;
function TargetObject(entityID, entityProps) {
@ -68,6 +49,7 @@ Script.include("/~/system/libraries/Xform.js");
this.hand = hand;
this.targetEntityID = null;
this.targetObject = null;
this.previouslyUnhooked = {};
this.previousParentID = {};
this.previousParentJointIndex = {};
this.potentialEntityWithContextOverlay = false;
@ -78,6 +60,7 @@ Script.include("/~/system/libraries/Xform.js");
this.reticleMaxX = 0;
this.reticleMinY = MARGIN;
this.reticleMaxY = 0;
this.lastUnexpectedChildrenCheckTime = 0;
var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX
@ -214,7 +197,7 @@ Script.include("/~/system/libraries/Xform.js");
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, GRABBABLE_PROPERTIES);
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
var now = Date.now();
var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
this.currentObjectTime = now;
@ -275,7 +258,7 @@ Script.include("/~/system/libraries/Xform.js");
this.endFarParentGrab = function (controllerData) {
this.hapticTargetID = null;
// var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID];
var endProps = Entities.getEntityProperties(this.targetEntityID, GRABBABLE_PROPERTIES);
var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
if (this.thisFarGrabJointIsParent(endProps)) {
Entities.editEntity(this.targetEntityID, {
parentID: this.previousParentID[this.targetEntityID],
@ -313,7 +296,7 @@ Script.include("/~/system/libraries/Xform.js");
this.notPointingAtEntity = function(controllerData) {
var intersection = controllerData.rayPicks[this.hand];
var entityProperty = Entities.getEntityProperties(intersection.objectID);
var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES);
var entityType = entityProperty.type;
var hudRayPick = controllerData.hudRayPicks[this.hand];
var point2d = this.calculateNewReticlePosition(hudRayPick.intersection);
@ -348,7 +331,7 @@ Script.include("/~/system/libraries/Xform.js");
var worldControllerPosition = controllerLocation.position;
var worldControllerRotation = controllerLocation.orientation;
var grabbedProperties = Entities.getEntityProperties(intersection.objectID, GRABBABLE_PROPERTIES);
var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES);
this.currentObjectPosition = grabbedProperties.position;
this.grabRadius = intersection.distance;
@ -369,8 +352,51 @@ Script.include("/~/system/libraries/Xform.js");
}
};
this.checkForUnexpectedChildren = function (controllerData) {
// sometimes things can get parented to a hand and this script is unaware. Search for such entities and
// unhook them.
var now = Date.now();
var UNEXPECTED_CHILDREN_CHECK_TIME = 0.1; // seconds
if (now - this.lastUnexpectedChildrenCheckTime > MSECS_PER_SEC * UNEXPECTED_CHILDREN_CHECK_TIME) {
this.lastUnexpectedChildrenCheckTime = now;
var children = findFarGrabJointChildEntities(this.hand);
var _this = this;
children.forEach(function(childID) {
// we appear to be holding something and this script isn't in a state that would be holding something.
// unhook it. if we previously took note of this entity's parent, put it back where it was. This
// works around some problems that happen when more than one hand or avatar is passing something around.
if (_this.previousParentID[childID]) {
var previousParentID = _this.previousParentID[childID];
var previousParentJointIndex = _this.previousParentJointIndex[childID];
// The main flaw with keeping track of previous parentage in individual scripts is:
// (1) A grabs something (2) B takes it from A (3) A takes it from B (4) A releases it
// now A and B will take turns passing it back to the other. Detect this and stop the loop here...
var UNHOOK_LOOP_DETECT_MS = 200;
if (_this.previouslyUnhooked[childID]) {
if (now - _this.previouslyUnhooked[childID] < UNHOOK_LOOP_DETECT_MS) {
previousParentID = Uuid.NULL;
previousParentJointIndex = -1;
}
}
_this.previouslyUnhooked[childID] = now;
Entities.editEntity(childID, {
parentID: previousParentID,
parentJointIndex: previousParentJointIndex
});
} else {
Entities.editEntity(childID, { parentID: Uuid.NULL });
}
});
}
};
this.targetIsNull = function() {
var properties = Entities.getEntityProperties(this.targetEntityID, GRABBABLE_PROPERTIES);
var properties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
if (Object.keys(properties).length === 0 && this.distanceHolding) {
return true;
}
@ -380,7 +406,7 @@ Script.include("/~/system/libraries/Xform.js");
this.getTargetProps = function (controllerData) {
var targetEntity = controllerData.rayPicks[this.hand].objectID;
if (targetEntity) {
var gtProps = Entities.getEntityProperties(targetEntity, GRABBABLE_PROPERTIES);
var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES);
if (entityIsGrabbable(gtProps)) {
// give haptic feedback
if (gtProps.id !== this.hapticTargetID) {
@ -416,6 +442,7 @@ Script.include("/~/system/libraries/Xform.js");
return makeRunningValues(true, [], []);
}
} else {
this.checkForUnexpectedChildren(controllerData);
this.destroyContextOverlay();
return makeRunningValues(false, [], []);
}
@ -480,11 +507,7 @@ Script.include("/~/system/libraries/Xform.js");
var entityID = rayPickInfo.objectID;
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity);
this.highlightedEntity = null;
var targetProps = Entities.getEntityProperties(entityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
if (targetProps.href !== "") {
AddressManager.handleLookupString(targetProps.href);
return makeRunningValues(false, [], []);
@ -533,11 +556,7 @@ Script.include("/~/system/libraries/Xform.js");
var targetEntityID = rayPickInfo.objectID;
if (this.highlightedEntity !== targetEntityID) {
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps);
selectionTargetObject.parentProps = getEntityParents(selectionTargetProps);
@ -567,7 +586,8 @@ Script.include("/~/system/libraries/Xform.js");
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var cotProps = Entities.getEntityProperties(rayPickInfo.objectID);
var cotProps = Entities.getEntityProperties(rayPickInfo.objectID,
DISPATCHER_PROPERTIES);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse

View file

@ -6,19 +6,18 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset,
/* global Script, RIGHT_HAND, LEFT_HAND, MyAvatar,
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData, makeLaserParams
getGrabbableData, makeLaserParams, DISPATCHER_PROPERTIES
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
(function() {
function entityWantsNearTrigger(props) {
function entityWantsFarTrigger(props) {
var grabbableData = getGrabbableData(props);
return grabbableData.triggerable || grabbableData.wantsTrigger;
return grabbableData.triggerable;
}
function FarTriggerEntity(hand) {
@ -37,11 +36,10 @@ Script.include("/~/system/libraries/controllers.js");
makeLaserParams(this.hand, false));
this.getTargetProps = function (controllerData) {
// nearbyEntityProperties is already sorted by length from controller
var targetEntity = controllerData.rayPicks[this.hand].objectID;
if (targetEntity) {
var targetProperties = Entities.getEntityProperties(targetEntity);
if (entityWantsNearTrigger(targetProperties)) {
var targetProperties = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES);
if (entityWantsFarTrigger(targetProperties)) {
return targetProperties;
}
}

View file

@ -8,11 +8,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset,
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData, makeLaserParams, entityIsCloneable, Messages, print
*/
/* global Script, MyAvatar, entityIsCloneable, Messages, print */
"use strict";
@ -134,7 +130,7 @@
rightHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID);
}
} catch (e) {
print("Failed to parse message");
print("highlightNearbyEntities -- Failed to parse message: " + JSON.stringify(message));
}
} else if (channel === 'Hifi-unhighlight-all') {
leftHighlightNearbyEntities.clearAll();

View file

@ -10,16 +10,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat,
getGrabPointSphereOffset, getEnabledModuleByName, makeRunningValues, Entities,
enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable,
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,
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI,
makeLaserParams
*/
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, HMD, makeLaserParams */
(function() {
Script.include("/~/system/libraries/controllers.js");
var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
@ -72,7 +63,7 @@
this.processLaser = function(controllerData) {
var controllerLocation = controllerData.controllerLocations[this.hand];
var otherModuleRunning = this.getOtherModule().running;
// var otherModuleRunning = this.getOtherModule().running;
if ((controllerData.triggerValues[this.hand] < ControllerDispatcherUtils.TRIGGER_ON_VALUE || !controllerLocation.valid) ||
this.pointingAtTablet(controllerData)) {
return false;

View file

@ -8,9 +8,8 @@
/* jslint bitwise: true */
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, Picks, makeLaserParams, Entities
Messages, makeDispatcherModuleParameters, HMD, getEnabledModuleByName, TRIGGER_ON_VALUE, isInEditMode, Picks,
makeLaserParams
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -24,9 +23,9 @@ Script.include("/~/system/libraries/utils.js");
this.triggerClicked = false;
this.selectedTarget = null;
this.reticleMinX = MARGIN;
this.reticleMaxX;
this.reticleMaxX = null;
this.reticleMinY = MARGIN;
this.reticleMaxY;
this.reticleMaxY = null;
this.parameters = makeDispatcherModuleParameters(
160,
@ -49,8 +48,8 @@ Script.include("/~/system/libraries/utils.js");
};
this.pointingAtTablet = function(objectID) {
return (HMD.tabletScreenID && objectID === HMD.tabletScreenID)
|| (HMD.homeButtonID && objectID === HMD.homeButtonID);
return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) ||
(HMD.homeButtonID && objectID === HMD.homeButtonID);
};
this.calculateNewReticlePosition = function(intersection) {

View file

@ -8,7 +8,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
/* global Script, HMD, Messages, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName, makeLaserParams
*/
@ -22,17 +22,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
var NO_HAND_LASER = -1; // Invalid hand parameter so that default laser is not displayed.
this.parameters = makeDispatcherModuleParameters(
200, // Not too high otherwise the tablet laser doesn't work.
this.hand === RIGHT_HAND
? ["rightHand", "rightHandEquip", "rightHandTrigger"]
: ["leftHand", "leftHandEquip", "leftHandTrigger"],
this.hand === RIGHT_HAND ?
["rightHand", "rightHandEquip", "rightHandTrigger"] :
["leftHand", "leftHandEquip", "leftHandTrigger"],
[],
100,
makeLaserParams(NO_HAND_LASER, false)
);
this.pointingAtTablet = function (objectID) {
return (HMD.tabletScreenID && objectID === HMD.tabletScreenID)
|| (HMD.homeButtonID && objectID === HMD.homeButtonID);
return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) ||
(HMD.homeButtonID && objectID === HMD.homeButtonID);
};
this.isReady = function (controllerData) {
@ -49,9 +49,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}
// Tablet stylus.
var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightTabletStylusInput"
: "LeftTabletStylusInput");
var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND ?
"RightTabletStylusInput" :
"LeftTabletStylusInput");
if (tabletStylusInput) {
var tabletReady = tabletStylusInput.isReady(controllerData);
if (tabletReady.active) {
@ -60,9 +60,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}
// Tablet surface.
var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightWebSurfaceLaserInput"
: "LeftWebSurfaceLaserInput");
var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ?
"RightWebSurfaceLaserInput" :
"LeftWebSurfaceLaserInput");
if (overlayLaser) {
var overlayLaserReady = overlayLaser.isReady(controllerData);
var target = controllerData.rayPicks[this.hand].objectID;
@ -72,9 +72,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}
// Tablet grabbing.
var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightNearParentingGrabOverlay"
: "LeftNearParentingGrabOverlay");
var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND ?
"RightNearParentingGrabOverlay" :
"LeftNearParentingGrabOverlay");
if (nearOverlay) {
var nearOverlayReady = nearOverlay.isReady(controllerData);
if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) {
@ -83,9 +83,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}
// Teleport.
var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightTeleporter"
: "LeftTeleporter");
var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND ?
"RightTeleporter" :
"LeftTeleporter");
if (teleporter) {
var teleporterReady = teleporter.isReady(controllerData);
if (teleporterReady.active) {

View file

@ -10,6 +10,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, HMD, Reticle, Vec3, Controller */
(function() {
var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
@ -121,7 +123,7 @@
if (this.mouseActivity.expired(now) || this.triggersPressed(controllerData, now) || !hmdActive) {
if (!hmdActive) {
Reticle.visible = true;
} else {
} else {
Reticle.visible = false;
}

View file

@ -12,7 +12,7 @@
/* jslint bitwise: true */
/* global Script, print, Entities, Picks, HMD, Controller, MyAvatar, isInEditMode*/
/* global Script, print, Entities, Messages, Picks, HMD, MyAvatar, isInEditMode, DISPATCHER_PROPERTIES */
(function() {
@ -46,11 +46,7 @@
var targetEntityID = pickResult.objectID;
if (this.highlightedEntity !== targetEntityID) {
var targetProps = Entities.getEntityProperties(targetEntityID, [
"dynamic", "shapeType", "position",
"rotation", "dimensions", "density",
"userData", "locked", "type", "href"
]);
var targetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
if (this.highlightedEntity) {
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);

View file

@ -10,7 +10,8 @@
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid,
DISPATCHER_PROPERTIES
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -62,12 +63,12 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
var grabbableData = getGrabbableData(targetProps);
this.ignoreIK = grabbableData.ignoreIK;
this.kinematicGrab = grabbableData.kinematic;
this.grabFollowsController = grabbableData.grabFollowsController;
this.kinematicGrab = grabbableData.grabKinematic;
var handRotation;
var handPosition;
if (this.ignoreIK) {
if (this.grabFollowsController) {
var controllerID =
(this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
var controllerLocation = getControllerWorldLocation(controllerID, false);
@ -99,7 +100,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
ttl: ACTION_TTL,
kinematic: this.kinematicGrab,
kinematicSetVelocity: true,
ignoreIK: this.ignoreIK
ignoreIK: this.grabFollowsController
});
if (this.actionID === Uuid.NULL) {
this.actionID = null;
@ -136,7 +137,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
ttl: ACTION_TTL,
kinematic: this.kinematicGrab,
kinematicSetVelocity: true,
ignoreIK: this.ignoreIK
ignoreIK: this.grabFollowsController
});
if (success) {
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
@ -238,7 +239,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
var targetCloneable = entityIsCloneable(targetProps);
if (targetCloneable) {
var cloneID = cloneEntity(targetProps);
var cloneProps = Entities.getEntityProperties(cloneID);
var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES);
this.targetEntityID = cloneID;
this.startNearGrabAction(controllerData, cloneProps);
} else {

View file

@ -12,7 +12,7 @@
findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH,
HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME,
TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity,
distanceBetweenEntityLocalPositionAndBoundingBox, GRAB_POINT_SPHERE_OFFSET
distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -28,16 +28,8 @@ Script.include("/~/system/libraries/controllers.js");
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
function getGrabOffset(handController) {
var offset = GRAB_POINT_SPHERE_OFFSET;
if (handController === Controller.Standard.LeftHand) {
offset = {
x: -GRAB_POINT_SPHERE_OFFSET.x,
y: GRAB_POINT_SPHERE_OFFSET.y,
z: GRAB_POINT_SPHERE_OFFSET.z
};
}
offset.y = -GRAB_POINT_SPHERE_OFFSET.y;
var offset = getGrabPointSphereOffset(handController, true);
offset.y = -offset.y;
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
}
@ -101,6 +93,7 @@ Script.include("/~/system/libraries/controllers.js");
};
this.startNearParentingGrabEntity = function (controllerData, targetProps) {
var grabData = getGrabbableData(targetProps);
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
unhighlightTargetEntity(this.targetEntityID);
this.highlightedEntity = null;
@ -111,12 +104,11 @@ Script.include("/~/system/libraries/controllers.js");
Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message));
var handJointIndex;
// if (this.ignoreIK) {
// handJointIndex = this.controllerJointIndex;
// } else {
// handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
// }
handJointIndex = getControllerJointIndex(this.hand);
if (grabData.grabFollowsController) {
handJointIndex = getControllerJointIndex(this.hand);
} else {
handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
}
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(targetProps.id, "startNearGrab", args);
@ -368,7 +360,7 @@ Script.include("/~/system/libraries/controllers.js");
if (this.cloneAllowed) {
var cloneID = cloneEntity(targetProps);
if (cloneID !== null) {
var cloneProps = Entities.getEntityProperties(cloneID);
var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES);
this.grabbing = true;
this.targetEntityID = cloneID;
this.startNearParentingGrabEntity(controllerData, cloneProps);

View file

@ -16,7 +16,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
function entityWantsNearTrigger(props) {
var grabbableData = getGrabbableData(props);
return grabbableData.triggerable || grabbableData.wantsTrigger;
return grabbableData.triggerable;
}
function NearTriggerEntity(hand) {

View file

@ -7,7 +7,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Vec3, MyAvatar, RIGHT_HAND */
/* global Script, Vec3, MyAvatar, Entities, RIGHT_HAND */
(function() {
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");

View file

@ -5,11 +5,9 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
enableDispatcherModule, disableDispatcherModule, makeRunningValues,
Messages, Quat, Vec3, getControllerWorldLocation, makeDispatcherModuleParameters, Overlays, ZERO_VEC,
HMD, INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, Settings, getGrabPointSphereOffset,
getEnabledModuleByName, Pointers, Picks, PickType
/* global Script, MyAvatar, Controller, Uuid, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
makeRunningValues, Vec3, makeDispatcherModuleParameters, Overlays, HMD, Settings, getEnabledModuleByName, Pointers,
Picks, PickType
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -200,7 +198,7 @@ Script.include("/~/system/libraries/controllers.js");
Overlays.hoverEnterOverlay.connect(mouseHoverEnter);
Overlays.hoverLeaveOverlay.connect(mouseHoverLeave);
Overlays.mousePressOnOverlay.connect(mousePress);
Overlays.mousePressOnOverlay.connect(mousePress);
this.cleanup = function () {
leftTabletStylusInput.cleanup();

View file

@ -10,7 +10,7 @@
/* jslint bitwise: true */
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
/* global Script, Entities, MyAvatar, Controller, Quat, RIGHT_HAND, LEFT_HAND,
enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3,
HMD, Uuid, AvatarList, Picks, Pointers, PickType
*/
@ -680,8 +680,8 @@ Script.include("/~/system/libraries/controllers.js");
this.teleportLocked = function () {
// Lock teleport if in advanced movement mode and have just transitioned from pressing a direction button.
return Controller.getValue(Controller.Hardware.Application.AdvancedMovement)
&& (_this.axisButtonStateX !== 0 || _this.axisButtonStateY !== 0);
return Controller.getValue(Controller.Hardware.Application.AdvancedMovement) &&
(_this.axisButtonStateX !== 0 || _this.axisButtonStateY !== 0);
};
this.buttonPress = function (value) {

View file

@ -5,11 +5,9 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Script, Entities, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, HMD,
INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, ContextOverlay, Picks, makeLaserParams
/* global Script, Entities, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
makeDispatcherModuleParameters, Overlays, HMD, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName,
ContextOverlay, Picks, makeLaserParams, Settings, MyAvatar, RIGHT_HAND, LEFT_HAND, DISPATCHER_PROPERTIES
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -82,7 +80,7 @@ Script.include("/~/system/libraries/controllers.js");
return overlayType === "web3d" || triggerPressed;
}
} else if (intersection.type === Picks.INTERSECTED_ENTITY) {
var entityProperties = Entities.getEntityProperties(objectID);
var entityProperties = Entities.getEntityProperties(objectID, DISPATCHER_PROPERTIES);
var entityType = entityProperties.type;
var isLocked = entityProperties.locked;
return entityType === "Web" && (!isLocked || triggerPressed);
@ -91,8 +89,9 @@ Script.include("/~/system/libraries/controllers.js");
};
this.deleteContextOverlay = function() {
var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND
? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity");
var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND ?
"RightFarActionGrabEntity" :
"LeftFarActionGrabEntity");
if (farGrabModule) {
var entityWithContextOverlay = farGrabModule.entityWithContextOverlay;

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, Menu */
var CONTOLLER_SCRIPTS = [
"squeezeHands.js",
"controllerDisplayManager.js",
@ -19,8 +21,8 @@ var CONTOLLER_SCRIPTS = [
"controllerModules/nearParentGrabEntity.js",
"controllerModules/nearParentGrabOverlay.js",
"controllerModules/nearActionGrabEntity.js",
// "controllerModules/farActionGrabEntity.js",
// "controllerModules/farParentGrabEntity.js",
"controllerModules/farActionGrabEntityDynOnly.js",
"controllerModules/farParentGrabEntity.js",
"controllerModules/stylusInput.js",
"controllerModules/equipEntity.js",
"controllerModules/nearTrigger.js",
@ -38,25 +40,22 @@ var CONTOLLER_SCRIPTS = [
"controllerModules/mouseHighlightEntities.js"
];
if (Settings.getValue("useFarGrabJoints", false)) {
CONTOLLER_SCRIPTS.push("controllerModules/farActionGrabEntityDynOnly.js");
CONTOLLER_SCRIPTS.push("controllerModules/farParentGrabEntity.js");
} else {
CONTOLLER_SCRIPTS.push("controllerModules/farActionGrabEntity.js");
}
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
function runDefaultsTogether() {
for (var j in CONTOLLER_SCRIPTS) {
Script.include(CONTOLLER_SCRIPTS[j]);
if (CONTOLLER_SCRIPTS.hasOwnProperty(j)) {
Script.include(CONTOLLER_SCRIPTS[j]);
}
}
}
function runDefaultsSeparately() {
for (var i in CONTOLLER_SCRIPTS) {
Script.load(CONTOLLER_SCRIPTS[i]);
if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) {
Script.load(CONTOLLER_SCRIPTS[i]);
}
}
}

View file

@ -14,9 +14,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global MyAvatar, Entities, Script, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller,
isInEditMode, HMD entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity*/
/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller,
isInEditMode, entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity, DISPATCHER_PROPERTIES,
entityIsGrabbable, entityIsEquipped, getMainTabletIDs
*/
/* jslint bitwise: true */
(function() { // BEGIN LOCAL_SCOPE
@ -37,7 +39,6 @@ var IDENTITY_QUAT = {
z: 0,
w: 0
};
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js
var DEFAULT_GRABBABLE_DATA = {
grabbable: true,
@ -339,16 +340,14 @@ Grabber.prototype.pressEvent = function(event) {
return;
}
var props = Entities.getEntityProperties(pickResults.objectID, ["dynamic", "userData", "locked", "type"]);
var props = Entities.getEntityProperties(pickResults.objectID, DISPATCHER_PROPERTIES);
var isDynamic = props.dynamic;
var isGrabbable = props.grabbable;
if (!entityIsGrabbable(props)) {
// only grab grabbable objects
return;
}
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, pickResults.objectID, DEFAULT_GRABBABLE_DATA);
if (grabbableData.grabbable === false) {
if (!props.grab.grabbable) {
return;
}
@ -359,7 +358,7 @@ Grabber.prototype.pressEvent = function(event) {
mouse.startDrag(event);
var clickedEntity = pickResults.objectID;
var entityProperties = Entities.getEntityProperties(clickedEntity);
var entityProperties = Entities.getEntityProperties(clickedEntity, DISPATCHER_PROPERTIES);
this.startPosition = entityProperties.position;
this.lastRotation = entityProperties.rotation;
this.madeDynamic = false;
@ -484,7 +483,7 @@ Grabber.prototype.moveEvent = function(event) {
Grabber.prototype.moveEventProcess = function() {
this.moveEventTimer = null;
// see if something added/restored gravity
var entityProperties = Entities.getEntityProperties(this.entityID);
var entityProperties = Entities.getEntityProperties(this.entityID, DISPATCHER_PROPERTIES);
if (!entityProperties || !entityProperties.gravity || HMD.active) {
return;
}

View file

@ -11,7 +11,7 @@
/* jslint bitwise: true */
/* global Script, Overlays, Controller, Vec3, MyAvatar, Entities
/* global Script, Overlays, Controller, Vec3, MyAvatar, Entities, RayPick
*/
(function () {
@ -22,8 +22,8 @@
var MSECONDS_AFTER_LOAD = 2000;
var updateFingerWithIndex = 0;
var untouchableEntities = [];
// Keys to access finger data
// Keys to access finger data
var fingerKeys = ["pinky", "ring", "middle", "index", "thumb"];
// Additionally close the hands to achieve a grabbing effect
@ -47,7 +47,7 @@
left: new Palm(),
right: new Palm()
};
var handJointNames = {left: "LeftHand", right: "RightHand"};
// Store which fingers are touching - if all false restate the default poses

View file

@ -11,6 +11,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, MyAvatar, Messages, Controller */
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
(function() { // BEGIN LOCAL_SCOPE
@ -20,7 +21,7 @@ var lastRightTrigger = 0;
var leftHandOverlayAlpha = 0;
var rightHandOverlayAlpha = 0;
var CONTROLLER_DEAD_SPOT = 0.25;
// var CONTROLLER_DEAD_SPOT = 0.25;
var TRIGGER_SMOOTH_TIMESCALE = 0.1;
var OVERLAY_RAMP_RATE = 8.0;
@ -42,9 +43,9 @@ function clamp(val, min, max) {
return Math.min(Math.max(val, min), max);
}
function normalizeControllerValue(val) {
return clamp((val - CONTROLLER_DEAD_SPOT) / (1 - CONTROLLER_DEAD_SPOT), 0, 1);
}
// function normalizeControllerValue(val) {
// return clamp((val - CONTROLLER_DEAD_SPOT) / (1 - CONTROLLER_DEAD_SPOT), 0, 1);
// }
function lerp(a, b, alpha) {
return a * (1 - alpha) + b * alpha;

View file

@ -8,7 +8,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals TOUCH_CONTROLLER_CONFIGURATION_LEFT:true TOUCH_CONTROLLER_CONFIGURATION_RIGHT:true */
/* globals TOUCH_CONTROLLER_CONFIGURATION_LEFT:true, TOUCH_CONTROLLER_CONFIGURATION_RIGHT:true,
Quat, Vec3, Script, MyAvatar, Controller */
/* eslint camelcase: ["error", { "properties": "never" }] */
var leftBaseRotation = Quat.multiply(
@ -22,9 +23,9 @@ var rightBaseRotation = Quat.multiply(
// keep these in sync with the values from OculusHelpers.cpp
var CONTROLLER_LENGTH_OFFSET = 0.0762;
var CONTROLLER_LATERAL_OFFSET = 0.0381;
var CONTROLLER_VERTICAL_OFFSET = 0.0381;
var CONTROLLER_FORWARD_OFFSET = 0.1524;
// var CONTROLLER_LATERAL_OFFSET = 0.0381;
// var CONTROLLER_VERTICAL_OFFSET = 0.0381;
// var CONTROLLER_FORWARD_OFFSET = 0.1524;
var leftBasePosition = Vec3.multiplyQbyV(leftBaseRotation, {
x: -CONTROLLER_LENGTH_OFFSET / 2.0,

View file

@ -8,11 +8,12 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals VIVE_CONTROLLER_CONFIGURATION_LEFT:true VIVE_CONTROLLER_CONFIGURATION_RIGHT:true */
/* globals VIVE_CONTROLLER_CONFIGURATION_LEFT:true, VIVE_CONTROLLER_CONFIGURATION_RIGHT:true,
MyAvatar, Quat, Script, Vec3, Controller */
/* eslint camelcase: ["error", { "properties": "never" }] */
var LEFT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND");
var RIGHT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND");
// var LEFT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND");
// var RIGHT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND");
var leftBaseRotation = Quat.multiply(
Quat.fromPitchYawRollDegrees(0, 0, 45),
@ -58,10 +59,10 @@ var viveNaturalPosition = {
};
var BASE_URL = Script.resourcesPath();
var TIP_TEXTURE_BASE_URL = BASE_URL + "meshes/controller/vive_tips.fbm/";
// var TIP_TEXTURE_BASE_URL = BASE_URL + "meshes/controller/vive_tips.fbm/";
var viveModelURL = BASE_URL + "meshes/controller/vive_body.fbx";
var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx";
// var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx";
var viveTriggerModelURL = "meshes/controller/vive_trigger.fbx";
VIVE_CONTROLLER_CONFIGURATION_LEFT = {
@ -340,4 +341,3 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
}
]
};

View file

@ -345,11 +345,15 @@ var toolBar = (function () {
position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions);
properties.position = position;
if (!properties.grab) {
properties.grab = {};
}
if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) &&
!(properties.type === "Zone" || properties.type === "Light" || properties.type === "ParticleEffect")) {
properties.userData = JSON.stringify({ grabbableKey: { grabbable: true } });
properties.grab.grabbable = true;
} else {
properties.userData = JSON.stringify({ grabbableKey: { grabbable: false } });
properties.grab.grabbable = false;
}
SelectionManager.saveProperties();

View file

@ -134,8 +134,8 @@
<label for="property-cloneable">Cloneable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-ignore-ik">
<label for="property-ignore-ik">Ignore inverse kinematics</label>
<input type="checkbox" id="property-grab-follows-controller">
<label for="property-grab-follows-controller">Follow Controller</label>
</div>
</div>
</fieldset>

View file

@ -6,8 +6,8 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global alert, augmentSpinButtons, clearTimeout, console, document, Element, EventBridge,
HifiEntityUI, JSONEditor, openEventBridge, setTimeout, window, _ $ */
/* global alert, augmentSpinButtons, clearTimeout, document, Element, EventBridge,
JSONEditor, openEventBridge, setTimeout, window, $ */
var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0;
@ -364,12 +364,6 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults, r
updateProperties(properties);
}
function userDataChanger(groupName, keyName, values, userDataElement, defaultValue, removeKeys) {
var val = {}, def = {};
val[keyName] = values;
def[keyName] = defaultValue;
multiDataUpdater(groupName, val, userDataElement, def, removeKeys);
}
function setMaterialDataFromEditor(noUpdate) {
var json = null;
@ -712,6 +706,8 @@ function loaded() {
var elCollisionSoundURL = document.getElementById("property-collision-sound-url");
var elGrabbable = document.getElementById("property-grabbable");
var elTriggerable = document.getElementById("property-triggerable");
var elGrabFollowsController = document.getElementById("property-grab-follows-controller");
var elCloneable = document.getElementById("property-cloneable");
var elCloneableDynamic = document.getElementById("property-cloneable-dynamic");
@ -720,9 +716,6 @@ function loaded() {
var elCloneableLifetime = document.getElementById("property-cloneable-lifetime");
var elCloneableLimit = document.getElementById("property-cloneable-limit");
var elTriggerable = document.getElementById("property-triggerable");
var elIgnoreIK = document.getElementById("property-ignore-ik");
var elLifetime = document.getElementById("property-lifetime");
var elScriptURL = document.getElementById("property-script-url");
var elScriptTimestamp = document.getElementById("property-script-timestamp");
@ -992,7 +985,7 @@ function loaded() {
elGrabbable.checked = false;
elTriggerable.checked = false;
elIgnoreIK.checked = false;
elGrabFollowsController.checked = false;
elCloneable.checked = false;
elCloneableDynamic.checked = false;
@ -1037,7 +1030,7 @@ function loaded() {
elCompoundShapeURL.value = "";
elShapeType.value = "none";
setDropdownText(elShapeType);
elModelAnimationURL.value = ""
elModelAnimationURL.value = "";
elModelAnimationPlaying.checked = false;
elModelAnimationFPS.value = "";
elModelAnimationFrame.value = "";
@ -1254,10 +1247,9 @@ function loaded() {
elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1;
elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1;
elGrabbable.checked = properties.dynamic;
elTriggerable.checked = false;
elIgnoreIK.checked = true;
elGrabbable.checked = properties.grab.grabbable;
elTriggerable.checked = properties.grab.triggerable;
elGrabFollowsController.checked = properties.grab.grabFollowsController;
elCloneable.checked = properties.cloneable;
elCloneableDynamic.checked = properties.cloneDynamic;
@ -1266,42 +1258,6 @@ function loaded() {
elCloneableLimit.value = properties.cloneLimit;
elCloneableLifetime.value = properties.cloneLifetime;
var grabbablesSet = false;
var parsedUserData = {};
try {
parsedUserData = JSON.parse(properties.userData);
if ("grabbableKey" in parsedUserData) {
grabbablesSet = true;
var grabbableData = parsedUserData.grabbableKey;
if ("grabbable" in grabbableData) {
elGrabbable.checked = grabbableData.grabbable;
} else {
elGrabbable.checked = true;
}
if ("triggerable" in grabbableData) {
elTriggerable.checked = grabbableData.triggerable;
} else if ("wantsTrigger" in grabbableData) {
elTriggerable.checked = grabbableData.wantsTrigger;
} else {
elTriggerable.checked = false;
}
if ("ignoreIK" in grabbableData) {
elIgnoreIK.checked = grabbableData.ignoreIK;
} else {
elIgnoreIK.checked = true;
}
}
} catch (e) {
// TODO: What should go here?
}
if (!grabbablesSet) {
elGrabbable.checked = true;
elTriggerable.checked = false;
elIgnoreIK.checked = true;
elCloneable.checked = false;
}
elCollisionSoundURL.value = properties.collisionSoundURL;
elLifetime.value = properties.lifetime;
elScriptURL.value = properties.script;
@ -1669,26 +1625,18 @@ function loaded() {
updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideOtherAvatar, 'otherAvatar');
});
elGrabbable.addEventListener('change', function() {
if (elCloneable.checked) {
elGrabbable.checked = false;
}
userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true);
});
elGrabbable.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('grab', 'grabbable'));
elTriggerable.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('grab', 'triggerable'));
elGrabFollowsController.addEventListener('change',
createEmitGroupCheckedPropertyUpdateFunction('grab', 'grabFollowsController'));
elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable'));
elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneDynamic'));
elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity'));
elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime'));
elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit'));
elTriggerable.addEventListener('change', function() {
userDataChanger("grabbableKey", "triggerable", elTriggerable, elUserData, false, ['wantsTrigger']);
});
elIgnoreIK.addEventListener('change', function() {
userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData, true);
});
elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL'));
elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime'));

View file

@ -129,9 +129,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
url: modelURL, // for overlay
grabbable: true, // for overlay
loadPriority: 10.0, // for overlay
userData: JSON.stringify({
"grabbableKey": {"grabbable": true}
}),
grab: { grabbable: true },
dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth },
parentID: MyAvatar.SELF_ID,
visible: visible,

View file

@ -48,6 +48,7 @@
BUMPER_ON_VALUE:true,
getEntityParents:true,
findHandChildEntities:true,
findFarGrabJointChildEntities:true,
makeLaserParams:true,
TEAR_AWAY_DISTANCE:true,
TEAR_AWAY_COUNT:true,
@ -127,13 +128,25 @@ DISPATCHER_PROPERTIES = [
"parentJointIndex",
"density",
"dimensions",
"userData",
"type",
"href",
"cloneable",
"cloneDynamic",
"localPosition",
"localRotation"
"localRotation",
"grab.grabbable",
"grab.grabKinematic",
"grab.grabFollowsController",
"grab.triggerable",
"grab.equippable",
"grab.equippableLeftPosition",
"grab.equippableLeftRotation",
"grab.equippableRightPosition",
"grab.equippableRightRotation",
"grab.equippableIndicatorURL",
"grab.equippableIndicatorScale",
"grab.equippableIndicatorOffset",
"userData"
];
// priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step
@ -215,25 +228,56 @@ getGrabbableData = function (ggdProps) {
} catch (err) {
userDataParsed = {};
}
if (userDataParsed.grabbableKey) {
grabbableData = userDataParsed.grabbableKey;
} else {
grabbableData = ggdProps.grab;
}
// extract grab-related properties, provide defaults if any are missing
if (!grabbableData.hasOwnProperty("grabbable")) {
grabbableData.grabbable = true;
}
if (!grabbableData.hasOwnProperty("ignoreIK")) {
grabbableData.ignoreIK = true;
// kinematic has been renamed to grabKinematic
if (!grabbableData.hasOwnProperty("grabKinematic") &&
!grabbableData.hasOwnProperty("kinematic")) {
grabbableData.grabKinematic = true;
}
if (!grabbableData.hasOwnProperty("kinematic")) {
grabbableData.kinematic = true;
if (!grabbableData.hasOwnProperty("grabKinematic")) {
grabbableData.grabKinematic = grabbableData.kinematic;
}
if (!grabbableData.hasOwnProperty("wantsTrigger")) {
grabbableData.wantsTrigger = false;
// ignoreIK has been renamed to grabFollowsController
if (!grabbableData.hasOwnProperty("grabFollowsController") &&
!grabbableData.hasOwnProperty("ignoreIK")) {
grabbableData.grabFollowsController = true;
}
if (!grabbableData.hasOwnProperty("triggerable")) {
if (!grabbableData.hasOwnProperty("grabFollowsController")) {
grabbableData.grabFollowsController = grabbableData.ignoreIK;
}
// wantsTrigger has been renamed to triggerable
if (!grabbableData.hasOwnProperty("triggerable") &&
!grabbableData.hasOwnProperty("wantsTrigger")) {
grabbableData.triggerable = false;
}
if (!grabbableData.hasOwnProperty("triggerable")) {
grabbableData.triggerable = grabbableData.wantsTrigger;
}
if (!grabbableData.hasOwnProperty("equippable")) {
grabbableData.equippable = false;
}
if (!grabbableData.hasOwnProperty("equippableLeftPosition")) {
grabbableData.equippableLeftPosition = { x: 0, y: 0, z: 0 };
}
if (!grabbableData.hasOwnProperty("equippableLeftRotation")) {
grabbableData.equippableLeftPosition = { x: 0, y: 0, z: 0, w: 1 };
}
if (!grabbableData.hasOwnProperty("equippableRightPosition")) {
grabbableData.equippableRightPosition = { x: 0, y: 0, z: 0 };
}
if (!grabbableData.hasOwnProperty("equippableRightRotation")) {
grabbableData.equippableRightPosition = { x: 0, y: 0, z: 0, w: 1 };
}
return grabbableData;
};
@ -417,6 +461,18 @@ findHandChildEntities = function(hand) {
});
};
findFarGrabJointChildEntities = function(hand) {
// find children of avatar's far-grab joint
var farGrabJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ? "_FARGRAB_RIGHTHAND" : "_FARGRAB_LEFTHAND");
var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, farGrabJointIndex);
children = children.concat(Entities.getChildrenIDsOfJoint(MyAvatar.SELF_ID, farGrabJointIndex));
return children.filter(function (childID) {
var childType = Entities.getNestableType(childID);
return childType == "entity";
});
};
distanceBetweenEntityLocalPositionAndBoundingBox = function(entityProps, jointGrabOffset) {
var DEFAULT_REGISTRATION_POINT = { x: 0.5, y: 0.5, z: 0.5 };
var rotInv = Quat.inverse(entityProps.localRotation);

View file

@ -5,20 +5,25 @@
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global MyAvatar, Vec3, Controller, Quat */
/* global MyAvatar, Vec3, HMD, Controller, Camera, Quat, Settings,
getGrabPointSphereOffset:true,
setGrabCommunications:true,
getGrabCommunications:true,
getControllerWorldLocation:true
*/
var GRAB_COMMUNICATIONS_SETTING = "io.highfidelity.isFarGrabbing";
setGrabCommunications = function setFarGrabCommunications(on) {
Settings.setValue(GRAB_COMMUNICATIONS_SETTING, on ? "on" : "");
}
};
getGrabCommunications = function getFarGrabCommunications() {
return !!Settings.getValue(GRAB_COMMUNICATIONS_SETTING, "");
}
};
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
getGrabPointSphereOffset = function(handController, ignoreSensorToWorldScale) {
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
var offset = GRAB_POINT_SPHERE_OFFSET;
if (handController === Controller.Standard.LeftHand) {
offset = {
@ -39,7 +44,7 @@ getControllerWorldLocation = function (handController, doOffset) {
var orientation;
var position;
var valid = false;
if (handController >= 0) {
var pose = Controller.getPoseValue(handController);
valid = pose.valid;

View file

@ -215,7 +215,9 @@ SelectionManager = (function() {
var grabJointNames = [
'RightHand', 'LeftHand',
'_CONTROLLER_RIGHTHAND', '_CONTROLLER_LEFTHAND',
'_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND'];
'_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND',
'_FARGRAB_RIGHTHAND', '_FARGRAB_LEFTHAND', '_FARGRAB_MOUSE'
];
for (var i = 0; i < grabJointNames.length; ++i) {
if (avatar.getJointIndex(grabJointNames[i]) === properties.parentJointIndex) {

View file

@ -312,9 +312,7 @@ function printToPolaroid(image_url) {
"dynamic": true,
"collisionsWillMove": true,
"userData": {
"grabbableKey": { "grabbable" : true }
}
"grab": { "grabbable": true }
};
var polaroid = Entities.addEntity(properties);

View file

@ -45,11 +45,7 @@ var cow = Entities.addEntity({
lifetime: 3600,
shapeType: "box",
script: SCRIPT_URL,
userData: JSON.stringify({
grabbableKey: {
grabbable: true
}
})
grab: { grabbable: true }
});
Script.stop();
Script.stop();

View file

@ -37,11 +37,6 @@ var flashlight = Entities.addEntity({
shapeType: 'box',
lifetime: 3600,
script: SCRIPT_URL,
userData: JSON.stringify({
grabbableKey: {
invertSolidWhileHeld: true
}
})
});
Script.stop();
Script.stop();

View file

@ -53,35 +53,34 @@ var golfClubProperties = {
y: -5.0,
z: 0
},
userData: JSON.stringify({
wearable: {
joints: {
LeftHand: [{
x: -0.1631782054901123,
y: 0.44648152589797974,
z: 0.10100018978118896
}, {
x: -0.9181621670722961,
y: -0.0772884339094162,
z: -0.3870723247528076,
w: -0.0343472845852375
}],
RightHand: [{
x: 0.16826771199703217,
y: 0.4757269620895386,
z: 0.07139724493026733
}, {
x: -0.7976328134536743,
y: -0.0011603273451328278,
z: 0.6030101776123047,
w: -0.012610925361514091
}]
}
grab: {
equippable: true,
equippableLeftPosition: {
x: -0.1631782054901123,
y: 0.44648152589797974,
z: 0.10100018978118896
},
equippableLeftRotation: {
x: -0.9181621670722961,
y: -0.0772884339094162,
z: -0.3870723247528076,
w: -0.0343472845852375
},
equippableRightPosition: {
x: 0.16826771199703217,
y: 0.4757269620895386,
z: 0.07139724493026733
},
equippableRightRotation: {
x: -0.7976328134536743,
y: -0.0011603273451328278,
z: 0.6030101776123047,
w: -0.012610925361514091
}
})
}
}
};
var golfClub = Entities.addEntity(golfClubProperties);
Script.stop();
Script.stop();

View file

@ -37,35 +37,31 @@ var pingPongGunProperties = {
},
lifetime: 3600,
dynamic: true,
userData: JSON.stringify({
grabbableKey: {
invertSolidWhileHeld: true
grab: {
equippable: true,
equippableLeftPosition: {
x: 0.09151676297187805,
y: 0.13639454543590546,
z: 0.09354984760284424
},
wearable: {
joints: {
RightHand: [{
x: 0.1177130937576294,
y: 0.12922893464565277,
z: 0.08307232707738876
}, {
x: 0.4934672713279724,
y: 0.3605862259864807,
z: 0.6394805908203125,
w: -0.4664038419723511
}],
LeftHand: [{
x: 0.09151676297187805,
y: 0.13639454543590546,
z: 0.09354984760284424
}, {
x: -0.19628101587295532,
y: 0.6418180465698242,
z: 0.2830369472503662,
w: 0.6851521730422974
}]
}
equippableLeftRotation: {
x: -0.19628101587295532,
y: 0.6418180465698242,
z: 0.2830369472503662,
w: 0.6851521730422974
},
equippableRightPosition: {
x: 0.1177130937576294,
y: 0.12922893464565277,
z: 0.08307232707738876
},
equippableRightRotation: {
x: 0.4934672713279724,
y: 0.3605862259864807,
z: 0.6394805908203125,
w: -0.4664038419723511
}
})
}
}
var pingPongGun = Entities.addEntity(pingPongGunProperties);

View file

@ -37,38 +37,34 @@ var pistolProperties = {
restitution: 0,
damping: 0.5,
collisionSoundURL: COLLISION_SOUND_URL,
userData: JSON.stringify({
grabbableKey: {
invertSolidWhileHeld: true
grab: {
equippable: true,
equippableLeftPosition: {
x: 0.1802254319190979,
y: 0.13442856073379517,
z: 0.08504903316497803
},
wearable: {
joints: {
RightHand: [{
x: 0.07079616189002991,
y: 0.20177987217903137,
z: 0.06374628841876984
}, {
x: -0.5863648653030396,
y: -0.46007341146469116,
z: 0.46949487924575806,
w: -0.4733745753765106
}],
LeftHand: [{
x: 0.1802254319190979,
y: 0.13442856073379517,
z: 0.08504903316497803
}, {
x: 0.2198076844215393,
y: -0.7377811074256897,
z: 0.2780133783817291,
w: 0.574519157409668
}]
}
equippableLeftRotation: {
x: 0.2198076844215393,
y: -0.7377811074256897,
z: 0.2780133783817291,
w: 0.574519157409668
},
equippableRightPosition: {
x: 0.07079616189002991,
y: 0.20177987217903137,
z: 0.06374628841876984
},
equippableRightRotation: {
x: -0.5863648653030396,
y: -0.46007341146469116,
z: 0.46949487924575806,
w: -0.4733745753765106
}
})
}
};
var pistol = Entities.addEntity(pistolProperties);
Script.stop();
Script.stop();

View file

@ -29,11 +29,7 @@ var sword1 = Entities.addEntity({
angularDamping: 0,
damping: 0,
script: SCRIPT_URL,
userData:JSON.stringify({
grabbableKey:{
grabbable:true
}
})
grab: { grabbable: true }
});
var sword2 = Entities.addEntity({
@ -45,11 +41,7 @@ var sword2 = Entities.addEntity({
angularDamping: 0,
damping: 0,
script: SCRIPT_URL,
userData:JSON.stringify({
grabbableKey:{
grabbable:true
}
})
grab: { grabbable: true }
});
Script.scriptEnding.connect(function scriptEnding() {

View file

@ -1,6 +1,6 @@
"use strict";
/* jslint vars: true, plusplus: true, forin: true*/
/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */
/* globals Script, Entities, MyAvatar, Vec3, Quat */
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
//
// createTetherballStick.js
@ -59,11 +59,7 @@ var ballID = Entities.addEntity({
restitution: BALL_RESTITUTION,
dynamic: true,
collidesWith: "static,dynamic,otherAvatar,",
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
})
grab: { grabbable: false }
});
var lineID = Entities.addEntity({
@ -109,43 +105,38 @@ var STICK_PROPERTIES = {
},
shapeType: 'box',
lifetime: LIFETIME,
userData: JSON.stringify({
grabbableKey: {
invertSolidWhileHeld: true,
ignoreIK: false
grab: {
grabbable: false,
grabFollowsController: false,
equippable: true,
equippableLeftPosition: {
x: -0.14998853206634521,
y: 0.17033983767032623,
z: 0.023199155926704407
},
wearable: {
joints: {
RightHand: [{
x: 0.15539926290512085,
y: 0.14493153989315033,
z: 0.023641478270292282
}, {
x: 0.5481458902359009,
y: -0.4470711946487427,
z: -0.3148134648799896,
w: 0.6328644752502441
}],
LeftHand: [{
x: -0.14998853206634521,
y: 0.17033983767032623,
z: 0.023199155926704407
},
{
x: 0.6623835563659668,
y: -0.1671387255191803,
z: 0.7071226835250854,
w: 0.1823924481868744
}]
}
equippableLeftRotation: {
x: 0.6623835563659668,
y: -0.1671387255191803,
z: 0.7071226835250854,
w: 0.1823924481868744
},
ownerID: MyAvatar.sessionUUID,
ballID: ballID,
lineID: lineID,
actionID: actionID,
lifetime: LIFETIME,
maxDistanceBetweenBallAndStick: ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER
})
equippableRightPosition: {
x: 0.15539926290512085,
y: 0.14493153989315033,
z: 0.023641478270292282
},
equippableRightRotation: {
x: 0.5481458902359009,
y: -0.4470711946487427,
z: -0.3148134648799896,
w: 0.6328644752502441
}
},
ownerID: MyAvatar.sessionUUID,
ballID: ballID,
lineID: lineID,
actionID: actionID,
maxDistanceBetweenBallAndStick: ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER
};
Entities.addEntity(STICK_PROPERTIES);

View file

@ -32,7 +32,7 @@
range: DEFAULT_RANGE,
maxVolume: DEFAULT_VOLUME,
disabled: true,
grabbableKey: { wantsTrigger: true },
grab: { triggerable: true }
};
var soundURL = "";
@ -182,7 +182,7 @@
entity = entityID;
_this = this;
var props = Entities.getEntityProperties(entity, [ "userData" ]);
var props = Entities.getEntityProperties(entity, [ "userData", "grab.triggerable" ]);
var data = {};
if (props.userData) {
data = JSON.parse(props.userData);
@ -194,14 +194,15 @@
changed = true;
}
}
if (!data.grabbableKey.wantsTrigger) {
data.grabbableKey.wantsTrigger = true;
changed = true;
}
if (changed) {
debugPrint("applying default values to userData");
Entities.editEntity(entity, { userData: JSON.stringify(data) });
}
if (!props.grab.triggerable) {
Entities.editEntity(entity, { grab: { triggerable: true } });
}
this._updateColor(data.disabled);
this.updateSettings();

View file

@ -52,32 +52,8 @@
It will behave as the constructor
*/
preload: function(id) {
/*
We will now override any existing userdata with the grabbable property.
Only retrieving userData
*/
var entityProperties = Entities.getEntityProperties(id, ['userData']);
var userData = {
grabbableKey: {}
};
// Check if existing userData field exists.
if (entityProperties.userData && entityProperties.userData.length > 0) {
try {
userData = JSON.parse(entityProperties.userData);
if (!userData.grabbableKey) {
userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData.
}
} catch (e) {
// if user data is not valid json, we will simply overwrite it.
}
}
// Object must be triggerable inorder to bind releaseGrabEvent
userData.grabbableKey.grabbable = true;
// Apply the new properties to entity of id
Entities.editEntity(id, {
userData: JSON.stringify(userData)
});
Entities.editEntity(id, { grab: { grabbable: true } });
Script.scriptEnding.connect(function() {
Script.removeEventHandler(id, "releaseGrab", this.releaseGrab);
});

View file

@ -62,11 +62,7 @@
position: originalProps.position,
shapeType: originalProps.shapeType,
visible: true,
userData:JSON.stringify({
grabbableKey:{
grabbable:false
}
})
grab: { grabbable: false }
};
_this.copy = Entities.addEntity(props);
}

View file

@ -142,11 +142,7 @@
position: originalProps.position,
shapeType: originalProps.shapeType,
visible: true,
userData:JSON.stringify({
grabbableKey:{
grabbable:false
}
})
grab: { grabbable: false }
};
_this.copy = Entities.addEntity(props);
}

View file

@ -53,14 +53,10 @@
y: SIZE,
z: SIZE
},
userData: JSON.stringify({
grabbableKey: {
cloneable: true,
grabbable: true,
cloneLifetime: LIFETIME,
cloneLimit: 9999
}
}),
grab: { grabbable: true },
cloneable: true,
cloneLifetime: LIFETIME,
cloneLimit: 9999
position: Vec3.sum(MyAvatar.position, Vec3.sum(forwardOffset, forwardVector)),
color: newColor(),
script: SCRIPT_URL